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

📄 dir.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	struct configfs_dirent *sd;	/*	 * Since we can trust everything is pinned, we just need i_mutex	 * on the item.	 */	mutex_lock(&target->ci_dentry->d_inode->i_mutex);	sd = target->ci_dentry->d_fsdata;	BUG_ON(sd->s_dependent_count < 1);	sd->s_dependent_count -= 1;	/*	 * After this unlock, we cannot trust the item to stay alive!	 * DO NOT REFERENCE item after this unlock.	 */	mutex_unlock(&target->ci_dentry->d_inode->i_mutex);}EXPORT_SYMBOL(configfs_undepend_item);static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode){	int ret, module_got = 0;	struct config_group *group;	struct config_item *item;	struct config_item *parent_item;	struct configfs_subsystem *subsys;	struct configfs_dirent *sd;	struct config_item_type *type;	struct module *owner = NULL;	char *name;	if (dentry->d_parent == configfs_sb->s_root) {		ret = -EPERM;		goto out;	}	sd = dentry->d_parent->d_fsdata;	if (!(sd->s_type & CONFIGFS_USET_DIR)) {		ret = -EPERM;		goto out;	}	/* Get a working ref for the duration of this function */	parent_item = configfs_get_config_item(dentry->d_parent);	type = parent_item->ci_type;	subsys = to_config_group(parent_item)->cg_subsys;	BUG_ON(!subsys);	if (!type || !type->ct_group_ops ||	    (!type->ct_group_ops->make_group &&	     !type->ct_group_ops->make_item)) {		ret = -EPERM;  /* Lack-of-mkdir returns -EPERM */		goto out_put;	}	name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL);	if (!name) {		ret = -ENOMEM;		goto out_put;	}	snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name);	mutex_lock(&subsys->su_mutex);	group = NULL;	item = NULL;	if (type->ct_group_ops->make_group) {		group = type->ct_group_ops->make_group(to_config_group(parent_item), name);		if (group) {			link_group(to_config_group(parent_item), group);			item = &group->cg_item;		}	} else {		item = type->ct_group_ops->make_item(to_config_group(parent_item), name);		if (item)			link_obj(parent_item, item);	}	mutex_unlock(&subsys->su_mutex);	kfree(name);	if (!item) {		/*		 * If item == NULL, then link_obj() was never called.		 * There are no extra references to clean up.		 */		ret = -ENOMEM;		goto out_put;	}	/*	 * link_obj() has been called (via link_group() for groups).	 * From here on out, errors must clean that up.	 */	type = item->ci_type;	if (!type) {		ret = -EINVAL;		goto out_unlink;	}	owner = type->ct_owner;	if (!try_module_get(owner)) {		ret = -EINVAL;		goto out_unlink;	}	/*	 * I hate doing it this way, but if there is	 * an error,  module_put() probably should	 * happen after any cleanup.	 */	module_got = 1;	if (group)		ret = configfs_attach_group(parent_item, item, dentry);	else		ret = configfs_attach_item(parent_item, item, dentry);out_unlink:	if (ret) {		/* Tear down everything we built up */		mutex_lock(&subsys->su_mutex);		client_disconnect_notify(parent_item, item);		if (group)			unlink_group(group);		else			unlink_obj(item);		client_drop_item(parent_item, item);		mutex_unlock(&subsys->su_mutex);		if (module_got)			module_put(owner);	}out_put:	/*	 * link_obj()/link_group() took a reference from child->parent,	 * so the parent is safely pinned.  We can drop our working	 * reference.	 */	config_item_put(parent_item);out:	return ret;}static int configfs_rmdir(struct inode *dir, struct dentry *dentry){	struct config_item *parent_item;	struct config_item *item;	struct configfs_subsystem *subsys;	struct configfs_dirent *sd;	struct module *owner = NULL;	int ret;	if (dentry->d_parent == configfs_sb->s_root)		return -EPERM;	sd = dentry->d_fsdata;	if (sd->s_type & CONFIGFS_USET_DEFAULT)		return -EPERM;	/*	 * Here's where we check for dependents.  We're protected by	 * i_mutex.	 */	if (sd->s_dependent_count)		return -EBUSY;	/* Get a working ref until we have the child */	parent_item = configfs_get_config_item(dentry->d_parent);	subsys = to_config_group(parent_item)->cg_subsys;	BUG_ON(!subsys);	if (!parent_item->ci_type) {		config_item_put(parent_item);		return -EINVAL;	}	ret = configfs_detach_prep(dentry);	if (ret) {		configfs_detach_rollback(dentry);		config_item_put(parent_item);		return ret;	}	/* Get a working ref for the duration of this function */	item = configfs_get_config_item(dentry);	/* Drop reference from above, item already holds one. */	config_item_put(parent_item);	if (item->ci_type)		owner = item->ci_type->ct_owner;	if (sd->s_type & CONFIGFS_USET_DIR) {		configfs_detach_group(item);		mutex_lock(&subsys->su_mutex);		client_disconnect_notify(parent_item, item);		unlink_group(to_config_group(item));	} else {		configfs_detach_item(item);		mutex_lock(&subsys->su_mutex);		client_disconnect_notify(parent_item, item);		unlink_obj(item);	}	client_drop_item(parent_item, item);	mutex_unlock(&subsys->su_mutex);	/* Drop our reference from above */	config_item_put(item);	module_put(owner);	return 0;}const struct inode_operations configfs_dir_inode_operations = {	.mkdir		= configfs_mkdir,	.rmdir		= configfs_rmdir,	.symlink	= configfs_symlink,	.unlink		= configfs_unlink,	.lookup		= configfs_lookup,	.setattr	= configfs_setattr,};#if 0int configfs_rename_dir(struct config_item * item, const char *new_name){	int error = 0;	struct dentry * new_dentry, * parent;	if (!strcmp(config_item_name(item), new_name))		return -EINVAL;	if (!item->parent)		return -EINVAL;	down_write(&configfs_rename_sem);	parent = item->parent->dentry;	mutex_lock(&parent->d_inode->i_mutex);	new_dentry = lookup_one_len(new_name, parent, strlen(new_name));	if (!IS_ERR(new_dentry)) {		if (!new_dentry->d_inode) {			error = config_item_set_name(item, "%s", new_name);			if (!error) {				d_add(new_dentry, NULL);				d_move(item->dentry, new_dentry);			}			else				d_delete(new_dentry);		} else			error = -EEXIST;		dput(new_dentry);	}	mutex_unlock(&parent->d_inode->i_mutex);	up_write(&configfs_rename_sem);	return error;}#endifstatic int configfs_dir_open(struct inode *inode, struct file *file){	struct dentry * dentry = file->f_path.dentry;	struct configfs_dirent * parent_sd = dentry->d_fsdata;	mutex_lock(&dentry->d_inode->i_mutex);	file->private_data = configfs_new_dirent(parent_sd, NULL);	mutex_unlock(&dentry->d_inode->i_mutex);	return file->private_data ? 0 : -ENOMEM;}static int configfs_dir_close(struct inode *inode, struct file *file){	struct dentry * dentry = file->f_path.dentry;	struct configfs_dirent * cursor = file->private_data;	mutex_lock(&dentry->d_inode->i_mutex);	list_del_init(&cursor->s_sibling);	mutex_unlock(&dentry->d_inode->i_mutex);	release_configfs_dirent(cursor);	return 0;}/* Relationship between s_mode and the DT_xxx types */static inline unsigned char dt_type(struct configfs_dirent *sd){	return (sd->s_mode >> 12) & 15;}static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir){	struct dentry *dentry = filp->f_path.dentry;	struct configfs_dirent * parent_sd = dentry->d_fsdata;	struct configfs_dirent *cursor = filp->private_data;	struct list_head *p, *q = &cursor->s_sibling;	ino_t ino;	int i = filp->f_pos;	switch (i) {		case 0:			ino = dentry->d_inode->i_ino;			if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)				break;			filp->f_pos++;			i++;			/* fallthrough */		case 1:			ino = parent_ino(dentry);			if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)				break;			filp->f_pos++;			i++;			/* fallthrough */		default:			if (filp->f_pos == 2) {				list_move(q, &parent_sd->s_children);			}			for (p=q->next; p!= &parent_sd->s_children; p=p->next) {				struct configfs_dirent *next;				const char * name;				int len;				next = list_entry(p, struct configfs_dirent,						   s_sibling);				if (!next->s_element)					continue;				name = configfs_get_name(next);				len = strlen(name);				if (next->s_dentry)					ino = next->s_dentry->d_inode->i_ino;				else					ino = iunique(configfs_sb, 2);				if (filldir(dirent, name, len, filp->f_pos, ino,						 dt_type(next)) < 0)					return 0;				list_move(q, p);				p = q;				filp->f_pos++;			}	}	return 0;}static loff_t configfs_dir_lseek(struct file * file, loff_t offset, int origin){	struct dentry * dentry = file->f_path.dentry;	mutex_lock(&dentry->d_inode->i_mutex);	switch (origin) {		case 1:			offset += file->f_pos;		case 0:			if (offset >= 0)				break;		default:			mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);			return -EINVAL;	}	if (offset != file->f_pos) {		file->f_pos = offset;		if (file->f_pos >= 2) {			struct configfs_dirent *sd = dentry->d_fsdata;			struct configfs_dirent *cursor = file->private_data;			struct list_head *p;			loff_t n = file->f_pos - 2;			list_del(&cursor->s_sibling);			p = sd->s_children.next;			while (n && p != &sd->s_children) {				struct configfs_dirent *next;				next = list_entry(p, struct configfs_dirent,						   s_sibling);				if (next->s_element)					n--;				p = p->next;			}			list_add_tail(&cursor->s_sibling, p);		}	}	mutex_unlock(&dentry->d_inode->i_mutex);	return offset;}const struct file_operations configfs_dir_operations = {	.open		= configfs_dir_open,	.release	= configfs_dir_close,	.llseek		= configfs_dir_lseek,	.read		= generic_read_dir,	.readdir	= configfs_readdir,};int configfs_register_subsystem(struct configfs_subsystem *subsys){	int err;	struct config_group *group = &subsys->su_group;	struct qstr name;	struct dentry *dentry;	struct configfs_dirent *sd;	err = configfs_pin_fs();	if (err)		return err;	if (!group->cg_item.ci_name)		group->cg_item.ci_name = group->cg_item.ci_namebuf;	sd = configfs_sb->s_root->d_fsdata;	link_group(to_config_group(sd->s_element), group);	mutex_lock(&configfs_sb->s_root->d_inode->i_mutex);	name.name = group->cg_item.ci_name;	name.len = strlen(name.name);	name.hash = full_name_hash(name.name, name.len);	err = -ENOMEM;	dentry = d_alloc(configfs_sb->s_root, &name);	if (dentry) {		d_add(dentry, NULL);		err = configfs_attach_group(sd->s_element, &group->cg_item,					    dentry);		if (err) {			d_delete(dentry);			dput(dentry);		}	}	mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex);	if (err) {		unlink_group(group);		configfs_release_fs();	}	return err;}void configfs_unregister_subsystem(struct configfs_subsystem *subsys){	struct config_group *group = &subsys->su_group;	struct dentry *dentry = group->cg_item.ci_dentry;	if (dentry->d_parent != configfs_sb->s_root) {		printk(KERN_ERR "configfs: Tried to unregister non-subsystem!\n");		return;	}	mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex,			  I_MUTEX_PARENT);	mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);	if (configfs_detach_prep(dentry)) {		printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n");	}	configfs_detach_group(&group->cg_item);	dentry->d_inode->i_flags |= S_DEAD;	mutex_unlock(&dentry->d_inode->i_mutex);	d_delete(dentry);	mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex);	dput(dentry);	unlink_group(group);	configfs_release_fs();}EXPORT_SYMBOL(configfs_register_subsystem);EXPORT_SYMBOL(configfs_unregister_subsystem);

⌨️ 快捷键说明

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