⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dir.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	inode = ilookup(sysfs_sb, sd->s_ino);	if (!inode)		return;	/* Drop any existing dentries associated with sd.	 *	 * For the dentry to be properly freed we need to grab a	 * reference to the dentry under the dcache lock,  unhash it,	 * and then put it.  The playing with the dentry count allows	 * dput to immediately free the dentry  if it is not in use.	 */repeat:	spin_lock(&dcache_lock);	list_for_each_entry(dentry, &inode->i_dentry, d_alias) {		if (d_unhashed(dentry))			continue;		dget_locked(dentry);		spin_lock(&dentry->d_lock);		__d_drop(dentry);		spin_unlock(&dentry->d_lock);		spin_unlock(&dcache_lock);		dput(dentry);		goto repeat;	}	spin_unlock(&dcache_lock);	/* adjust nlink and update timestamp */	mutex_lock(&inode->i_mutex);	inode->i_ctime = CURRENT_TIME;	drop_nlink(inode);	if (sysfs_type(sd) == SYSFS_DIR)		drop_nlink(inode);	mutex_unlock(&inode->i_mutex);	iput(inode);}/** *	sysfs_addrm_finish - finish up sysfs_dirent add/remove *	@acxt: addrm context to finish up * *	Finish up sysfs_dirent add/remove.  Resources acquired by *	sysfs_addrm_start() are released and removed sysfs_dirents are *	cleaned up.  Timestamps on the parent inode are updated. * *	LOCKING: *	All mutexes acquired by sysfs_addrm_start() are released. */void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt){	/* release resources acquired by sysfs_addrm_start() */	mutex_unlock(&sysfs_mutex);	if (acxt->parent_inode) {		struct inode *inode = acxt->parent_inode;		/* if added/removed, update timestamps on the parent */		if (acxt->cnt)			inode->i_ctime = inode->i_mtime = CURRENT_TIME;		mutex_unlock(&inode->i_mutex);		iput(inode);	}	/* kill removed sysfs_dirents */	while (acxt->removed) {		struct sysfs_dirent *sd = acxt->removed;		acxt->removed = sd->s_sibling;		sd->s_sibling = NULL;		sysfs_drop_dentry(sd);		sysfs_deactivate(sd);		sysfs_put(sd);	}}/** *	sysfs_find_dirent - find sysfs_dirent with the given name *	@parent_sd: sysfs_dirent to search under *	@name: name to look for * *	Look for sysfs_dirent with name @name under @parent_sd. * *	LOCKING: *	mutex_lock(sysfs_mutex) * *	RETURNS: *	Pointer to sysfs_dirent if found, NULL if not. */struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,				       const unsigned char *name){	struct sysfs_dirent *sd;	for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)		if (!strcmp(sd->s_name, name))			return sd;	return NULL;}/** *	sysfs_get_dirent - find and get sysfs_dirent with the given name *	@parent_sd: sysfs_dirent to search under *	@name: name to look for * *	Look for sysfs_dirent with name @name under @parent_sd and get *	it if found. * *	LOCKING: *	Kernel thread context (may sleep).  Grabs sysfs_mutex. * *	RETURNS: *	Pointer to sysfs_dirent if found, NULL if not. */struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,				      const unsigned char *name){	struct sysfs_dirent *sd;	mutex_lock(&sysfs_mutex);	sd = sysfs_find_dirent(parent_sd, name);	sysfs_get(sd);	mutex_unlock(&sysfs_mutex);	return sd;}static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,		      const char *name, struct sysfs_dirent **p_sd){	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;	struct sysfs_addrm_cxt acxt;	struct sysfs_dirent *sd;	int rc;	/* allocate */	sd = sysfs_new_dirent(name, mode, SYSFS_DIR);	if (!sd)		return -ENOMEM;	sd->s_dir.kobj = kobj;	/* link in */	sysfs_addrm_start(&acxt, parent_sd);	rc = sysfs_add_one(&acxt, sd);	sysfs_addrm_finish(&acxt);	if (rc == 0)		*p_sd = sd;	else		sysfs_put(sd);	return rc;}int sysfs_create_subdir(struct kobject *kobj, const char *name,			struct sysfs_dirent **p_sd){	return create_dir(kobj, kobj->sd, name, p_sd);}/** *	sysfs_create_dir - create a directory for an object. *	@kobj:		object we're creating directory for.  */int sysfs_create_dir(struct kobject * kobj){	struct sysfs_dirent *parent_sd, *sd;	int error = 0;	BUG_ON(!kobj);	if (kobj->parent)		parent_sd = kobj->parent->sd;	else		parent_sd = &sysfs_root;	error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);	if (!error)		kobj->sd = sd;	return error;}static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,				struct nameidata *nd){	struct dentry *ret = NULL;	struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata;	struct sysfs_dirent *sd;	struct inode *inode;	mutex_lock(&sysfs_mutex);	sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);	/* no such entry */	if (!sd) {		ret = ERR_PTR(-ENOENT);		goto out_unlock;	}	/* attach dentry and inode */	inode = sysfs_get_inode(sd);	if (!inode) {		ret = ERR_PTR(-ENOMEM);		goto out_unlock;	}	/* instantiate and hash dentry */	dentry->d_op = &sysfs_dentry_ops;	dentry->d_fsdata = sysfs_get(sd);	d_instantiate(dentry, inode);	d_rehash(dentry); out_unlock:	mutex_unlock(&sysfs_mutex);	return ret;}const struct inode_operations sysfs_dir_inode_operations = {	.lookup		= sysfs_lookup,	.setattr	= sysfs_setattr,};static void remove_dir(struct sysfs_dirent *sd){	struct sysfs_addrm_cxt acxt;	sysfs_addrm_start(&acxt, sd->s_parent);	sysfs_remove_one(&acxt, sd);	sysfs_addrm_finish(&acxt);}void sysfs_remove_subdir(struct sysfs_dirent *sd){	remove_dir(sd);}static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd){	struct sysfs_addrm_cxt acxt;	struct sysfs_dirent **pos;	if (!dir_sd)		return;	pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);	sysfs_addrm_start(&acxt, dir_sd);	pos = &dir_sd->s_dir.children;	while (*pos) {		struct sysfs_dirent *sd = *pos;		if (sysfs_type(sd) != SYSFS_DIR)			sysfs_remove_one(&acxt, sd);		else			pos = &(*pos)->s_sibling;	}	sysfs_addrm_finish(&acxt);	remove_dir(dir_sd);}/** *	sysfs_remove_dir - remove an object's directory. *	@kobj:	object. * *	The only thing special about this is that we remove any files in *	the directory before we remove the directory, and we've inlined *	what used to be sysfs_rmdir() below, instead of calling separately. */void sysfs_remove_dir(struct kobject * kobj){	struct sysfs_dirent *sd = kobj->sd;	spin_lock(&sysfs_assoc_lock);	kobj->sd = NULL;	spin_unlock(&sysfs_assoc_lock);	__sysfs_remove_dir(sd);}int sysfs_rename_dir(struct kobject * kobj, const char *new_name){	struct sysfs_dirent *sd = kobj->sd;	struct dentry *parent = NULL;	struct dentry *old_dentry = NULL, *new_dentry = NULL;	const char *dup_name = NULL;	int error;	mutex_lock(&sysfs_rename_mutex);	error = 0;	if (strcmp(sd->s_name, new_name) == 0)		goto out;	/* nothing to rename */	/* get the original dentry */	old_dentry = sysfs_get_dentry(sd);	if (IS_ERR(old_dentry)) {		error = PTR_ERR(old_dentry);		old_dentry = NULL;		goto out;	}	parent = old_dentry->d_parent;	/* lock parent and get dentry for new name */	mutex_lock(&parent->d_inode->i_mutex);	mutex_lock(&sysfs_mutex);	error = -EEXIST;	if (sysfs_find_dirent(sd->s_parent, new_name))		goto out_unlock;	error = -ENOMEM;	new_dentry = d_alloc_name(parent, new_name);	if (!new_dentry)		goto out_unlock;	/* rename kobject and sysfs_dirent */	error = -ENOMEM;	new_name = dup_name = kstrdup(new_name, GFP_KERNEL);	if (!new_name)		goto out_unlock;	error = kobject_set_name(kobj, "%s", new_name);	if (error)		goto out_unlock;	dup_name = sd->s_name;	sd->s_name = new_name;	/* rename */	d_add(new_dentry, NULL);	d_move(old_dentry, new_dentry);	error = 0; out_unlock:	mutex_unlock(&sysfs_mutex);	mutex_unlock(&parent->d_inode->i_mutex);	kfree(dup_name);	dput(old_dentry);	dput(new_dentry); out:	mutex_unlock(&sysfs_rename_mutex);	return error;}int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj){	struct sysfs_dirent *sd = kobj->sd;	struct sysfs_dirent *new_parent_sd;	struct dentry *old_parent, *new_parent = NULL;	struct dentry *old_dentry = NULL, *new_dentry = NULL;	int error;	mutex_lock(&sysfs_rename_mutex);	BUG_ON(!sd->s_parent);	new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root;	error = 0;	if (sd->s_parent == new_parent_sd)		goto out;	/* nothing to move */	/* get dentries */	old_dentry = sysfs_get_dentry(sd);	if (IS_ERR(old_dentry)) {		error = PTR_ERR(old_dentry);		old_dentry = NULL;		goto out;	}	old_parent = old_dentry->d_parent;	new_parent = sysfs_get_dentry(new_parent_sd);	if (IS_ERR(new_parent)) {		error = PTR_ERR(new_parent);		new_parent = NULL;		goto out;	}again:	mutex_lock(&old_parent->d_inode->i_mutex);	if (!mutex_trylock(&new_parent->d_inode->i_mutex)) {		mutex_unlock(&old_parent->d_inode->i_mutex);		goto again;	}	mutex_lock(&sysfs_mutex);	error = -EEXIST;	if (sysfs_find_dirent(new_parent_sd, sd->s_name))		goto out_unlock;	error = -ENOMEM;	new_dentry = d_alloc_name(new_parent, sd->s_name);	if (!new_dentry)		goto out_unlock;	error = 0;	d_add(new_dentry, NULL);	d_move(old_dentry, new_dentry);	/* Remove from old parent's list and insert into new parent's list. */	sysfs_unlink_sibling(sd);	sysfs_get(new_parent_sd);	sysfs_put(sd->s_parent);	sd->s_parent = new_parent_sd;	sysfs_link_sibling(sd); out_unlock:	mutex_unlock(&sysfs_mutex);	mutex_unlock(&new_parent->d_inode->i_mutex);	mutex_unlock(&old_parent->d_inode->i_mutex); out:	dput(new_parent);	dput(old_dentry);	dput(new_dentry);	mutex_unlock(&sysfs_rename_mutex);	return error;}/* Relationship between s_mode and the DT_xxx types */static inline unsigned char dt_type(struct sysfs_dirent *sd){	return (sd->s_mode >> 12) & 15;}static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir){	struct dentry *dentry = filp->f_path.dentry;	struct sysfs_dirent * parent_sd = dentry->d_fsdata;	struct sysfs_dirent *pos;	ino_t ino;	if (filp->f_pos == 0) {		ino = parent_sd->s_ino;		if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0)			filp->f_pos++;	}	if (filp->f_pos == 1) {		if (parent_sd->s_parent)			ino = parent_sd->s_parent->s_ino;		else			ino = parent_sd->s_ino;		if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0)			filp->f_pos++;	}	if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) {		mutex_lock(&sysfs_mutex);		/* Skip the dentries we have already reported */		pos = parent_sd->s_dir.children;		while (pos && (filp->f_pos > pos->s_ino))			pos = pos->s_sibling;		for ( ; pos; pos = pos->s_sibling) {			const char * name;			int len;			name = pos->s_name;			len = strlen(name);			filp->f_pos = ino = pos->s_ino;			if (filldir(dirent, name, len, filp->f_pos, ino,					 dt_type(pos)) < 0)				break;		}		if (!pos)			filp->f_pos = INT_MAX;		mutex_unlock(&sysfs_mutex);	}	return 0;}const struct file_operations sysfs_dir_operations = {	.read		= generic_read_dir,	.readdir	= sysfs_readdir,};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -