Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac6fecee authored by Trond Myklebust's avatar Trond Myklebust
Browse files

SUNRPC: Clean up rpc_populate/depopulate

parent cfeaa4a3
Loading
Loading
Loading
Loading
+101 −86
Original line number Original line Diff line number Diff line
@@ -401,7 +401,6 @@ static const struct file_operations rpc_info_operations = {
 * We have a single directory with 1 node in it.
 * We have a single directory with 1 node in it.
 */
 */
enum {
enum {
	RPCAUTH_Root = 1,
	RPCAUTH_lockd,
	RPCAUTH_lockd,
	RPCAUTH_mount,
	RPCAUTH_mount,
	RPCAUTH_nfs,
	RPCAUTH_nfs,
@@ -415,12 +414,12 @@ enum {
 * Description of fs contents.
 * Description of fs contents.
 */
 */
struct rpc_filelist {
struct rpc_filelist {
	char *name;
	const char *name;
	const struct file_operations *i_fop;
	const struct file_operations *i_fop;
	umode_t mode;
	umode_t mode;
};
};


static struct rpc_filelist files[] = {
static const struct rpc_filelist files[] = {
	[RPCAUTH_lockd] = {
	[RPCAUTH_lockd] = {
		.name = "lockd",
		.name = "lockd",
		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
@@ -448,11 +447,11 @@ static struct rpc_filelist files[] = {
};
};


enum {
enum {
	RPCAUTH_info = 2,
	RPCAUTH_info,
	RPCAUTH_EOF
	RPCAUTH_EOF
};
};


static struct rpc_filelist authfiles[] = {
static const struct rpc_filelist authfiles[] = {
	[RPCAUTH_info] = {
	[RPCAUTH_info] = {
		.name = "info",
		.name = "info",
		.i_fop = &rpc_info_operations,
		.i_fop = &rpc_info_operations,
@@ -564,6 +563,20 @@ out_err:
	return -ENOMEM;
	return -ENOMEM;
}
}


static int __rpc_create(struct inode *dir, struct dentry *dentry,
			umode_t mode,
			const struct file_operations *i_fop,
			void *private)
{
	int err;

	err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private);
	if (err)
		return err;
	fsnotify_create(dir, dentry);
	return 0;
}

static int __rpc_mkdir(struct inode *dir, struct dentry *dentry,
static int __rpc_mkdir(struct inode *dir, struct dentry *dentry,
		       umode_t mode,
		       umode_t mode,
		       const struct file_operations *i_fop,
		       const struct file_operations *i_fop,
@@ -601,6 +614,17 @@ static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry,
	return 0;
	return 0;
}
}


static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
{
	int ret;

	dget(dentry);
	ret = simple_rmdir(dir, dentry);
	d_delete(dentry);
	dput(dentry);
	return ret;
}

static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
{
{
	int ret;
	int ret;
@@ -678,100 +702,96 @@ static struct dentry *rpc_lookup_negative(const char *path,
/*
/*
 * FIXME: This probably has races.
 * FIXME: This probably has races.
 */
 */
static void rpc_depopulate(struct dentry *parent,
static void __rpc_depopulate(struct dentry *parent,
			   unsigned long start, unsigned long eof)
			     const struct rpc_filelist *files,
			     int start, int eof)
{
{
	struct inode *dir = parent->d_inode;
	struct inode *dir = parent->d_inode;
	struct list_head *pos, *next;
	struct dentry *dentry;
	struct dentry *dentry, *dvec[10];
	struct qstr name;
	int n = 0;
	int i;


	mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD);
	for (i = start; i < eof; i++) {
repeat:
		name.name = files[i].name;
	spin_lock(&dcache_lock);
		name.len = strlen(files[i].name);
	list_for_each_safe(pos, next, &parent->d_subdirs) {
		name.hash = full_name_hash(name.name, name.len);
		dentry = list_entry(pos, struct dentry, d_u.d_child);
		dentry = d_lookup(parent, &name);
		if (!dentry->d_inode ||

				dentry->d_inode->i_ino < start ||
		if (dentry == NULL)
				dentry->d_inode->i_ino >= eof)
			continue;
			continue;
		spin_lock(&dentry->d_lock);
		if (dentry->d_inode == NULL)
		if (!d_unhashed(dentry)) {
			goto next;
			dget_locked(dentry);
		switch (dentry->d_inode->i_mode & S_IFMT) {
			__d_drop(dentry);
			default:
			spin_unlock(&dentry->d_lock);
				BUG();
			dvec[n++] = dentry;
			case S_IFREG:
			if (n == ARRAY_SIZE(dvec))
				__rpc_unlink(dir, dentry);
				break;
				break;
		} else
			case S_IFDIR:
			spin_unlock(&dentry->d_lock);
				__rpc_rmdir(dir, dentry);
		}
		}
	spin_unlock(&dcache_lock);
next:
	if (n) {
		do {
			dentry = dvec[--n];
			if (S_ISREG(dentry->d_inode->i_mode))
				simple_unlink(dir, dentry);
			else if (S_ISDIR(dentry->d_inode->i_mode))
				simple_rmdir(dir, dentry);
			d_delete(dentry);
		dput(dentry);
		dput(dentry);
		} while (n);
		goto repeat;
	}
	}
	mutex_unlock(&dir->i_mutex);
}
}


static int
static void rpc_depopulate(struct dentry *parent,
rpc_populate(struct dentry *parent,
			   const struct rpc_filelist *files,
		struct rpc_filelist *files,
			   int start, int eof)
			   int start, int eof)
{
{
	struct inode *inode, *dir = parent->d_inode;
	struct inode *dir = parent->d_inode;
	void *private = RPC_I(dir)->private;

	mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD);
	__rpc_depopulate(parent, files, start, eof);
	mutex_unlock(&dir->i_mutex);
}

static int rpc_populate(struct dentry *parent,
			const struct rpc_filelist *files,
			int start, int eof,
			void *private)
{
	struct inode *dir = parent->d_inode;
	struct dentry *dentry;
	struct dentry *dentry;
	umode_t mode;
	int i, err;
	int i;


	mutex_lock(&dir->i_mutex);
	mutex_lock(&dir->i_mutex);
	for (i = start; i < eof; i++) {
	for (i = start; i < eof; i++) {
		dentry = d_alloc_name(parent, files[i].name);
		struct qstr q;
		if (!dentry)

			goto out_bad;
		q.name = files[i].name;
		dentry->d_op = &rpc_dentry_operations;
		q.len = strlen(files[i].name);
		mode = files[i].mode;
		q.hash = full_name_hash(q.name, q.len);
		inode = rpc_get_inode(dir->i_sb, mode);
		dentry = __rpc_lookup_create_exclusive(parent, &q);
		if (!inode) {
		err = PTR_ERR(dentry);
			dput(dentry);
		if (IS_ERR(dentry))
			goto out_bad;
			goto out_bad;
		switch (files[i].mode & S_IFMT) {
			default:
				BUG();
			case S_IFREG:
				err = __rpc_create(dir, dentry,
						files[i].mode,
						files[i].i_fop,
						private);
				break;
			case S_IFDIR:
				err = __rpc_mkdir(dir, dentry,
						files[i].mode,
						NULL,
						private);
		}
		}
		inode->i_ino = i;
		if (err != 0)
		if (files[i].i_fop)
			goto out_bad;
			inode->i_fop = files[i].i_fop;
		if (private)
			rpc_inode_setowner(inode, private);
		if (S_ISDIR(mode))
			inc_nlink(dir);
		d_add(dentry, inode);
		fsnotify_create(dir, dentry);
	}
	}
	mutex_unlock(&dir->i_mutex);
	mutex_unlock(&dir->i_mutex);
	return 0;
	return 0;
out_bad:
out_bad:
	__rpc_depopulate(parent, files, start, eof);
	mutex_unlock(&dir->i_mutex);
	mutex_unlock(&dir->i_mutex);
	printk(KERN_WARNING "%s: %s failed to populate directory %s\n",
	printk(KERN_WARNING "%s: %s failed to populate directory %s\n",
			__FILE__, __func__, parent->d_name.name);
			__FILE__, __func__, parent->d_name.name);
	return -ENOMEM;
	return err;
}

static int
__rpc_rmdir(struct inode *dir, struct dentry *dentry)
{
	int error;
	error = simple_rmdir(dir, dentry);
	if (!error)
		d_delete(dentry);
	return error;
}
}


/**
/**
@@ -800,16 +820,14 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client)
	if (error != 0)
	if (error != 0)
		goto out_err;
		goto out_err;
	error = rpc_populate(dentry, authfiles,
	error = rpc_populate(dentry, authfiles,
			RPCAUTH_info, RPCAUTH_EOF);
			RPCAUTH_info, RPCAUTH_EOF, rpc_client);
	if (error)
	if (error)
		goto err_depopulate;
		goto err_rmdir;
	dget(dentry);
out:
out:
	mutex_unlock(&dir->i_mutex);
	mutex_unlock(&dir->i_mutex);
	rpc_release_path(&nd);
	rpc_release_path(&nd);
	return dentry;
	return dentry;
err_depopulate:
err_rmdir:
	rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF);
	__rpc_rmdir(dir, dentry);
	__rpc_rmdir(dir, dentry);
out_err:
out_err:
	printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n",
	printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n",
@@ -832,9 +850,8 @@ rpc_rmdir(struct dentry *dentry)
	parent = dget_parent(dentry);
	parent = dget_parent(dentry);
	dir = parent->d_inode;
	dir = parent->d_inode;
	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
	rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF);
	rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF);
	error = __rpc_rmdir(dir, dentry);
	error = __rpc_rmdir(dir, dentry);
	dput(dentry);
	mutex_unlock(&dir->i_mutex);
	mutex_unlock(&dir->i_mutex);
	dput(parent);
	dput(parent);
	return error;
	return error;
@@ -900,7 +917,6 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name,
			   private, ops, flags);
			   private, ops, flags);
	if (err)
	if (err)
		goto out_err;
		goto out_err;
	dget(dentry);
out:
out:
	mutex_unlock(&dir->i_mutex);
	mutex_unlock(&dir->i_mutex);
	return dentry;
	return dentry;
@@ -932,7 +948,6 @@ rpc_unlink(struct dentry *dentry)
	dir = parent->d_inode;
	dir = parent->d_inode;
	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
	mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
	error = __rpc_rmpipe(dir, dentry);
	error = __rpc_rmpipe(dir, dentry);
	dput(dentry);
	mutex_unlock(&dir->i_mutex);
	mutex_unlock(&dir->i_mutex);
	dput(parent);
	dput(parent);
	return error;
	return error;
@@ -970,7 +985,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
		iput(inode);
		iput(inode);
		return -ENOMEM;
		return -ENOMEM;
	}
	}
	if (rpc_populate(root, files, RPCAUTH_Root + 1, RPCAUTH_RootEOF))
	if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
		goto out;
		goto out;
	sb->s_root = root;
	sb->s_root = root;
	return 0;
	return 0;