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

📄 dir.c

📁 ocfs1.2.7 源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * dir.c - Operations for configfs directories. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. * * Based on sysfs: * 	sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel * * configfs Copyright (C) 2005 Oracle.  All rights reserved. */#undef DEBUG#include <linux/fs.h>#include <linux/mount.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/configfs.h>#include "configfs_internal.h"DECLARE_RWSEM(configfs_rename_sem);static void configfs_d_iput(struct dentry * dentry,			    struct inode * inode){	struct configfs_dirent * sd = dentry->d_fsdata;	if (sd) {		BUG_ON(sd->s_dentry != dentry);		sd->s_dentry = NULL;		configfs_put(sd);	}	iput(inode);}/* * We _must_ delete our dentries on last dput, as the chain-to-parent * behavior is required to clear the parents of default_groups. */static int configfs_d_delete(struct dentry *dentry){	return 1;}static struct dentry_operations configfs_dentry_ops = {	.d_iput		= configfs_d_iput,	/* simple_delete_dentry() isn't exported */	.d_delete	= configfs_d_delete,};/* * Allocates a new configfs_dirent and links it to the parent configfs_dirent */static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * parent_sd,						void * element){	struct configfs_dirent * sd;	sd = kmalloc(sizeof(*sd), GFP_KERNEL);	if (!sd)		return NULL;	memset(sd, 0, sizeof(*sd));	atomic_set(&sd->s_count, 1);	INIT_LIST_HEAD(&sd->s_links);	INIT_LIST_HEAD(&sd->s_children);	list_add(&sd->s_sibling, &parent_sd->s_children);	sd->s_element = element;	return sd;}int configfs_make_dirent(struct configfs_dirent * parent_sd,			 struct dentry * dentry, void * element,			 umode_t mode, int type){	struct configfs_dirent * sd;	sd = configfs_new_dirent(parent_sd, element);	if (!sd)		return -ENOMEM;	sd->s_mode = mode;	sd->s_type = type;	sd->s_dentry = dentry;	if (dentry) {		dentry->d_fsdata = configfs_get(sd);		dentry->d_op = &configfs_dentry_ops;	}	return 0;}static int init_dir(struct inode * inode){	inode->i_op = &configfs_dir_inode_operations;	inode->i_fop = &configfs_dir_operations;	/* directory inodes start off with i_nlink == 2 (for "." entry) */	inode->i_nlink++;	return 0;}static int init_file(struct inode * inode){	inode->i_size = PAGE_SIZE;	inode->i_fop = &configfs_file_operations;	return 0;}static int init_symlink(struct inode * inode){	inode->i_op = &configfs_symlink_inode_operations;	return 0;}static int create_dir(struct config_item * k, struct dentry * p,		      struct dentry * d){	int error;	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;	error = configfs_create(d, mode, init_dir);	if (!error) {		error = configfs_make_dirent(p->d_fsdata, d, k, mode,					   CONFIGFS_DIR);		if (!error) {			p->d_inode->i_nlink++;			(d)->d_op = &configfs_dentry_ops;		}	}	return error;}/** *	configfs_create_dir - create a directory for an config_item. *	@item:		config_itemwe're creating directory for. *	@dentry:	config_item's dentry. */static int configfs_create_dir(struct config_item * item, struct dentry *dentry){	struct dentry * parent;	int error = 0;	BUG_ON(!item);	if (item->ci_parent)		parent = item->ci_parent->ci_dentry;	else if (configfs_mount && configfs_mount->mnt_sb)		parent = configfs_mount->mnt_sb->s_root;	else		return -EFAULT;	error = create_dir(item,parent,dentry);	if (!error)		item->ci_dentry = dentry;	return error;}int configfs_create_link(struct configfs_symlink *sl,			 struct dentry *parent,			 struct dentry *dentry){	int err = 0;	umode_t mode = S_IFLNK | S_IRWXUGO;	err = configfs_create(dentry, mode, init_symlink);	if (!err) {		err = configfs_make_dirent(parent->d_fsdata, dentry, sl,					 mode, CONFIGFS_ITEM_LINK);		if (!err)			dentry->d_op = &configfs_dentry_ops;	}	return err;}static void remove_dir(struct dentry * d){	struct dentry * parent = dget(d->d_parent);	struct configfs_dirent * sd;	sd = d->d_fsdata; 	list_del_init(&sd->s_sibling);	configfs_put(sd);	if (d->d_inode)		simple_rmdir(parent->d_inode,d);	pr_debug(" o %s removing done (%d)\n",d->d_name.name,		 atomic_read(&d->d_count));	dput(parent);}/** * configfs_remove_dir - remove an config_item's directory. * @item:	config_item we're removing. * * 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 configfs_rmdir() below, instead of calling separately. */static void configfs_remove_dir(struct config_item * item){	struct dentry * dentry = dget(item->ci_dentry);	if (!dentry)		return;	remove_dir(dentry);	/**	 * Drop reference from dget() on entrance.	 */	dput(dentry);}/* attaches attribute's configfs_dirent to the dentry corresponding to the * attribute file */static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * dentry){	struct configfs_attribute * attr = sd->s_element;	int error;	error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, init_file);	if (error)		return error;	dentry->d_op = &configfs_dentry_ops;	dentry->d_fsdata = configfs_get(sd);	sd->s_dentry = dentry;	d_rehash(dentry);	return 0;}static struct dentry * configfs_lookup(struct inode *dir,				       struct dentry *dentry,				       struct nameidata *nd){	struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata;	struct configfs_dirent * sd;	int found = 0;	int err = 0;	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {		if (sd->s_type & CONFIGFS_NOT_PINNED) {			const unsigned char * name = configfs_get_name(sd);			if (strcmp(name, dentry->d_name.name))				continue;			found = 1;			err = configfs_attach_attr(sd, dentry);			break;		}	}	if (!found) {		/*		 * If it doesn't exist and it isn't a NOT_PINNED item,		 * it must be negative.		 */		return simple_lookup(dir, dentry, nd);	}	return ERR_PTR(err);}/* * Only subdirectories count here.  Files (CONFIGFS_NOT_PINNED) are * attributes and are removed by rmdir().  We recurse, taking i_mutex * on all children that are candidates for default detach.  If the * result is clean, then configfs_detach_group() will handle dropping * i_mutex.  If there is an error, the caller will clean up the i_mutex * holders via configfs_detach_rollback(). */static int configfs_detach_prep(struct dentry *dentry){	struct configfs_dirent *parent_sd = dentry->d_fsdata;	struct configfs_dirent *sd;	int ret;	ret = -EBUSY;	if (!list_empty(&parent_sd->s_links))		goto out;	ret = 0;	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {		if (sd->s_type & CONFIGFS_NOT_PINNED)			continue;		if (sd->s_type & CONFIGFS_USET_DEFAULT) {			mutex_lock(&sd->s_dentry->d_inode->i_mutex);			/* Mark that we've taken i_mutex */			sd->s_type |= CONFIGFS_USET_DROPPING;			ret = configfs_detach_prep(sd->s_dentry);			if (!ret)			       	continue;		} else			ret = -ENOTEMPTY;		break;	}out:	return ret;}/* * Walk the tree, dropping i_mutex wherever CONFIGFS_USET_DROPPING is * set. */static void configfs_detach_rollback(struct dentry *dentry){	struct configfs_dirent *parent_sd = dentry->d_fsdata;	struct configfs_dirent *sd;	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {		if (sd->s_type & CONFIGFS_USET_DEFAULT) {			configfs_detach_rollback(sd->s_dentry);			if (sd->s_type & CONFIGFS_USET_DROPPING) {				sd->s_type &= ~CONFIGFS_USET_DROPPING;				mutex_unlock(&sd->s_dentry->d_inode->i_mutex);			}		}	}}static void detach_attrs(struct config_item * item){	struct dentry * dentry = dget(item->ci_dentry);	struct configfs_dirent * parent_sd;	struct configfs_dirent * sd, * tmp;	if (!dentry)		return;	pr_debug("configfs %s: dropping attrs for  dir\n",		 dentry->d_name.name);	parent_sd = dentry->d_fsdata;	list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {		if (!sd->s_element || !(sd->s_type & CONFIGFS_NOT_PINNED))			continue;		list_del_init(&sd->s_sibling);		configfs_drop_dentry(sd, dentry);		configfs_put(sd);	}	/**	 * Drop reference from dget() on entrance.	 */	dput(dentry);}static int populate_attrs(struct config_item *item){	struct config_item_type *t = item->ci_type;	struct configfs_attribute *attr;	int error = 0;	int i;	if (!t)		return -EINVAL;	if (t->ct_attrs) {		for (i = 0; (attr = t->ct_attrs[i]) != NULL; i++) {			if ((error = configfs_create_file(item, attr)))				break;		}	}	if (error)		detach_attrs(item);	return error;}static int configfs_attach_group(struct config_item *parent_item,				 struct config_item *item,				 struct dentry *dentry);static void configfs_detach_group(struct config_item *item);static void detach_groups(struct config_group *group){	struct dentry * dentry = dget(group->cg_item.ci_dentry);	struct dentry *child;	struct configfs_dirent *parent_sd;	struct configfs_dirent *sd, *tmp;	if (!dentry)		return;	parent_sd = dentry->d_fsdata;	list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {		if (!sd->s_element ||		    !(sd->s_type & CONFIGFS_USET_DEFAULT))			continue;		child = sd->s_dentry;		configfs_detach_group(sd->s_element);		child->d_inode->i_flags |= S_DEAD;		/*		 * From rmdir/unregister, a configfs_detach_prep() pass		 * has taken our i_mutex for us.  Drop it.		 * From mkdir/register cleanup, there is no sem held.		 */		if (sd->s_type & CONFIGFS_USET_DROPPING)			mutex_unlock(&child->d_inode->i_mutex);		d_delete(child);		dput(child);	}	/**	 * Drop reference from dget() on entrance.	 */	dput(dentry);}/* * This fakes mkdir(2) on a default_groups[] entry.  It * creates a dentry, attachs it, and then does fixup * on the sd->s_type. * * We could, perhaps, tweak our parent's ->mkdir for a minute and * try using vfs_mkdir.  Just a thought. */static int create_default_group(struct config_group *parent_group,				struct config_group *group){	int ret;	struct qstr name;	struct configfs_dirent *sd;	/* We trust the caller holds a reference to parent */	struct dentry *child, *parent = parent_group->cg_item.ci_dentry;	if (!group->cg_item.ci_name)		group->cg_item.ci_name = group->cg_item.ci_namebuf;	name.name = group->cg_item.ci_name;	name.len = strlen(name.name);	name.hash = full_name_hash(name.name, name.len);	ret = -ENOMEM;	child = d_alloc(parent, &name);	if (child) {		d_add(child, NULL);		ret = configfs_attach_group(&parent_group->cg_item,					    &group->cg_item, child);		if (!ret) {			sd = child->d_fsdata;			sd->s_type |= CONFIGFS_USET_DEFAULT;		} else {			d_delete(child);			dput(child);		}	}	return ret;}static int populate_groups(struct config_group *group){	struct config_group *new_group;	struct dentry *dentry = group->cg_item.ci_dentry;	int ret = 0;	int i;	if (group && group->default_groups) {		/* FYI, we're faking mkdir here		 * I'm not sure we need this semaphore, as we're called		 * from our parent's mkdir.  That holds our parent's		 * i_mutex, so afaik lookup cannot continue through our		 * parent to find us, let alone mess with our tree.		 * That said, taking our i_mutex is closer to mkdir		 * emulation, and shouldn't hurt. */		mutex_lock(&dentry->d_inode->i_mutex);		for (i = 0; group->default_groups[i]; i++) {			new_group = group->default_groups[i];			ret = create_default_group(group, new_group);			if (ret)				break;		}		mutex_unlock(&dentry->d_inode->i_mutex);	}	if (ret)		detach_groups(group);	return ret;}/* * All of link_obj/unlink_obj/link_group/unlink_group require that * subsys->su_sem is held. */static void unlink_obj(struct config_item *item){	struct config_group *group;	group = item->ci_group;	if (group) {		list_del_init(&item->ci_entry);		item->ci_group = NULL;		item->ci_parent = NULL;		config_item_put(item);		config_group_put(group);	}}static void link_obj(struct config_item *parent_item, struct config_item *item){	/* Parent seems redundant with group, but it makes certain	 * traversals much nicer. */	item->ci_parent = parent_item;	item->ci_group = config_group_get(to_config_group(parent_item));	list_add_tail(&item->ci_entry, &item->ci_group->cg_children);	config_item_get(item);}static void unlink_group(struct config_group *group){

⌨️ 快捷键说明

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