Loading net/sunrpc/rpc_pipe.c +101 −86 Original line number Original line Diff line number Diff line Loading @@ -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, Loading @@ -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, Loading Loading @@ -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, Loading Loading @@ -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, Loading Loading @@ -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; Loading Loading @@ -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; } } /** /** Loading Loading @@ -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", Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading
net/sunrpc/rpc_pipe.c +101 −86 Original line number Original line Diff line number Diff line Loading @@ -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, Loading @@ -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, Loading Loading @@ -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, Loading Loading @@ -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, Loading Loading @@ -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; Loading Loading @@ -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; } } /** /** Loading Loading @@ -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", Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading