SUNRPC: Clean up rpc_populate/depopulate
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
@@ -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 dentry *dentry;
|
||||||
|
struct qstr name;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = start; i < eof; i++) {
|
||||||
|
name.name = files[i].name;
|
||||||
|
name.len = strlen(files[i].name);
|
||||||
|
name.hash = full_name_hash(name.name, name.len);
|
||||||
|
dentry = d_lookup(parent, &name);
|
||||||
|
|
||||||
|
if (dentry == NULL)
|
||||||
|
continue;
|
||||||
|
if (dentry->d_inode == NULL)
|
||||||
|
goto next;
|
||||||
|
switch (dentry->d_inode->i_mode & S_IFMT) {
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
case S_IFREG:
|
||||||
|
__rpc_unlink(dir, dentry);
|
||||||
|
break;
|
||||||
|
case S_IFDIR:
|
||||||
|
__rpc_rmdir(dir, dentry);
|
||||||
|
}
|
||||||
|
next:
|
||||||
|
dput(dentry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rpc_depopulate(struct dentry *parent,
|
||||||
|
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, *dvec[10];
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD);
|
mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD);
|
||||||
repeat:
|
__rpc_depopulate(parent, files, start, eof);
|
||||||
spin_lock(&dcache_lock);
|
|
||||||
list_for_each_safe(pos, next, &parent->d_subdirs) {
|
|
||||||
dentry = list_entry(pos, struct dentry, d_u.d_child);
|
|
||||||
if (!dentry->d_inode ||
|
|
||||||
dentry->d_inode->i_ino < start ||
|
|
||||||
dentry->d_inode->i_ino >= eof)
|
|
||||||
continue;
|
|
||||||
spin_lock(&dentry->d_lock);
|
|
||||||
if (!d_unhashed(dentry)) {
|
|
||||||
dget_locked(dentry);
|
|
||||||
__d_drop(dentry);
|
|
||||||
spin_unlock(&dentry->d_lock);
|
|
||||||
dvec[n++] = dentry;
|
|
||||||
if (n == ARRAY_SIZE(dvec))
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
spin_unlock(&dentry->d_lock);
|
|
||||||
}
|
|
||||||
spin_unlock(&dcache_lock);
|
|
||||||
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);
|
|
||||||
} while (n);
|
|
||||||
goto repeat;
|
|
||||||
}
|
|
||||||
mutex_unlock(&dir->i_mutex);
|
mutex_unlock(&dir->i_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int rpc_populate(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)
|
void *private)
|
||||||
{
|
{
|
||||||
struct inode *inode, *dir = parent->d_inode;
|
struct inode *dir = parent->d_inode;
|
||||||
void *private = RPC_I(dir)->private;
|
|
||||||
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;
|
||||||
|
Reference in New Issue
Block a user