Commit 499aa1ca authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pull-dcache' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull dcache updates from Al Viro:
 "Change of locking rules for __dentry_kill(), regularized refcounting
  rules in that area, assorted cleanups and removal of weird corner
  cases (e.g. now ->d_iput() on child is always called before the parent
  might hit __dentry_kill(), etc)"

* tag 'pull-dcache' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (40 commits)
  dcache: remove unnecessary NULL check in dget_dlock()
  kill DCACHE_MAY_FREE
  __d_unalias() doesn't use inode argument
  d_alloc_parallel(): in-lookup hash insertion doesn't need an RCU variant
  get rid of DCACHE_GENOCIDE
  d_genocide(): move the extern into fs/internal.h
  simple_fill_super(): don't bother with d_genocide() on failure
  nsfs: use d_make_root()
  d_alloc_pseudo(): move setting ->d_op there from the (sole) caller
  kill d_instantate_anon(), fold __d_instantiate_anon() into remaining caller
  retain_dentry(): introduce a trimmed-down lockless variant
  __dentry_kill(): new locking scheme
  d_prune_aliases(): use a shrink list
  switch select_collect{,2}() to use of to_shrink_list()
  to_shrink_list(): call only if refcount is 0
  fold dentry_kill() into dput()
  don't try to cut corners in shrink_lock_dentry()
  fold the call of retain_dentry() into fast_dput()
  Call retain_dentry() with refcount 0
  dentry_kill(): don't bother with retain_dentry() on slow path
  ...
parents bf4e7080 1b6ae9f6
...@@ -1091,6 +1091,40 @@ would need to do so. ...@@ -1091,6 +1091,40 @@ would need to do so.
--- ---
**mandatory**
The list of children anchored in parent dentry got turned into hlist now.
Field names got changed (->d_children/->d_sib instead of ->d_subdirs/->d_child
for anchor/entries resp.), so any affected places will be immediately caught
by compiler.
---
**mandatory**
->d_delete() instances are now called for dentries with ->d_lock held
and refcount equal to 0. They are not permitted to drop/regain ->d_lock.
None of in-tree instances did anything of that sort. Make sure yours do not...
---
**mandatory**
->d_prune() instances are now called without ->d_lock held on the parent.
->d_lock on dentry itself is still held; if you need per-parent exclusions (none
of the in-tree instances did), use your own spinlock.
->d_iput() and ->d_release() are called with victim dentry still in the
list of parent's children. It is still unhashed, marked killed, etc., just not
removed from parent's ->d_children yet.
Anyone iterating through the list of children needs to be aware of the
half-killed dentries that might be seen there; taking ->d_lock on those will
see them negative, unhashed and with negative refcount, which means that most
of the in-kernel users would've done the right thing anyway without any adjustment.
---
**recommended** **recommended**
Block device freezing and thawing have been moved to holder operations. Block device freezing and thawing have been moved to holder operations.
......
...@@ -145,10 +145,11 @@ spufs_evict_inode(struct inode *inode) ...@@ -145,10 +145,11 @@ spufs_evict_inode(struct inode *inode)
static void spufs_prune_dir(struct dentry *dir) static void spufs_prune_dir(struct dentry *dir)
{ {
struct dentry *dentry, *tmp; struct dentry *dentry;
struct hlist_node *n;
inode_lock(d_inode(dir)); inode_lock(d_inode(dir));
list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) { hlist_for_each_entry_safe(dentry, n, &dir->d_children, d_sib) {
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
if (simple_positive(dentry)) { if (simple_positive(dentry)) {
dget_dlock(dentry); dget_dlock(dentry);
......
...@@ -373,7 +373,7 @@ int afs_dynroot_populate(struct super_block *sb) ...@@ -373,7 +373,7 @@ int afs_dynroot_populate(struct super_block *sb)
void afs_dynroot_depopulate(struct super_block *sb) void afs_dynroot_depopulate(struct super_block *sb)
{ {
struct afs_net *net = afs_sb2net(sb); struct afs_net *net = afs_sb2net(sb);
struct dentry *root = sb->s_root, *subdir, *tmp; struct dentry *root = sb->s_root, *subdir;
/* Prevent more subdirs from being created */ /* Prevent more subdirs from being created */
mutex_lock(&net->proc_cells_lock); mutex_lock(&net->proc_cells_lock);
...@@ -382,10 +382,11 @@ void afs_dynroot_depopulate(struct super_block *sb) ...@@ -382,10 +382,11 @@ void afs_dynroot_depopulate(struct super_block *sb)
mutex_unlock(&net->proc_cells_lock); mutex_unlock(&net->proc_cells_lock);
if (root) { if (root) {
struct hlist_node *n;
inode_lock(root->d_inode); inode_lock(root->d_inode);
/* Remove all the pins for dirs created for manually added cells */ /* Remove all the pins for dirs created for manually added cells */
list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) { hlist_for_each_entry_safe(subdir, n, &root->d_children, d_sib) {
if (subdir->d_fsdata) { if (subdir->d_fsdata) {
subdir->d_fsdata = NULL; subdir->d_fsdata = NULL;
dput(subdir); dput(subdir);
......
...@@ -73,12 +73,9 @@ static int autofs_mount_busy(struct vfsmount *mnt, ...@@ -73,12 +73,9 @@ static int autofs_mount_busy(struct vfsmount *mnt,
/* p->d_lock held */ /* p->d_lock held */
static struct dentry *positive_after(struct dentry *p, struct dentry *child) static struct dentry *positive_after(struct dentry *p, struct dentry *child)
{ {
if (child) child = child ? d_next_sibling(child) : d_first_child(p);
child = list_next_entry(child, d_child);
else
child = list_first_entry(&p->d_subdirs, struct dentry, d_child);
list_for_each_entry_from(child, &p->d_subdirs, d_child) { hlist_for_each_entry_from(child, d_sib) {
spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(child)) { if (simple_positive(child)) {
dget_dlock(child); dget_dlock(child);
......
...@@ -174,7 +174,7 @@ __dcache_find_get_entry(struct dentry *parent, u64 idx, ...@@ -174,7 +174,7 @@ __dcache_find_get_entry(struct dentry *parent, u64 idx,
/* /*
* When possible, we try to satisfy a readdir by peeking at the * When possible, we try to satisfy a readdir by peeking at the
* dcache. We make this work by carefully ordering dentries on * dcache. We make this work by carefully ordering dentries on
* d_child when we initially get results back from the MDS, and * d_children when we initially get results back from the MDS, and
* falling back to a "normal" sync readdir if any dentries in the dir * falling back to a "normal" sync readdir if any dentries in the dir
* are dropped. * are dropped.
* *
......
...@@ -2128,7 +2128,7 @@ static bool drop_negative_children(struct dentry *dentry) ...@@ -2128,7 +2128,7 @@ static bool drop_negative_children(struct dentry *dentry)
goto out; goto out;
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
list_for_each_entry(child, &dentry->d_subdirs, d_child) { hlist_for_each_entry(child, &dentry->d_children, d_sib) {
if (d_really_is_positive(child)) { if (d_really_is_positive(child)) {
all_negative = false; all_negative = false;
break; break;
......
...@@ -93,13 +93,13 @@ static void coda_flag_children(struct dentry *parent, int flag) ...@@ -93,13 +93,13 @@ static void coda_flag_children(struct dentry *parent, int flag)
struct dentry *de; struct dentry *de;
spin_lock(&parent->d_lock); spin_lock(&parent->d_lock);
list_for_each_entry(de, &parent->d_subdirs, d_child) { hlist_for_each_entry(de, &parent->d_children, d_sib) {
struct inode *inode = d_inode_rcu(de);
/* don't know what to do with negative dentries */ /* don't know what to do with negative dentries */
if (d_inode(de) ) if (inode)
coda_flag_inode(d_inode(de), flag); coda_flag_inode(inode, flag);
} }
spin_unlock(&parent->d_lock); spin_unlock(&parent->d_lock);
return;
} }
void coda_flag_inode_children(struct inode *inode, int flag) void coda_flag_inode_children(struct inode *inode, int flag)
......
This diff is collapsed.
...@@ -316,9 +316,6 @@ struct file *alloc_file_pseudo(struct inode *inode, struct vfsmount *mnt, ...@@ -316,9 +316,6 @@ struct file *alloc_file_pseudo(struct inode *inode, struct vfsmount *mnt,
const char *name, int flags, const char *name, int flags,
const struct file_operations *fops) const struct file_operations *fops)
{ {
static const struct dentry_operations anon_ops = {
.d_dname = simple_dname
};
struct qstr this = QSTR_INIT(name, strlen(name)); struct qstr this = QSTR_INIT(name, strlen(name));
struct path path; struct path path;
struct file *file; struct file *file;
...@@ -326,8 +323,6 @@ struct file *alloc_file_pseudo(struct inode *inode, struct vfsmount *mnt, ...@@ -326,8 +323,6 @@ struct file *alloc_file_pseudo(struct inode *inode, struct vfsmount *mnt,
path.dentry = d_alloc_pseudo(mnt->mnt_sb, &this); path.dentry = d_alloc_pseudo(mnt->mnt_sb, &this);
if (!path.dentry) if (!path.dentry)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
if (!mnt->mnt_sb->s_d_op)
d_set_d_op(path.dentry, &anon_ops);
path.mnt = mntget(mnt); path.mnt = mntget(mnt);
d_instantiate(path.dentry, inode); d_instantiate(path.dentry, inode);
file = alloc_file(&path, flags, fops); file = alloc_file(&path, flags, fops);
......
...@@ -214,6 +214,11 @@ extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *) ...@@ -214,6 +214,11 @@ extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *)
extern char *simple_dname(struct dentry *, char *, int); extern char *simple_dname(struct dentry *, char *, int);
extern void dput_to_list(struct dentry *, struct list_head *); extern void dput_to_list(struct dentry *, struct list_head *);
extern void shrink_dentry_list(struct list_head *); extern void shrink_dentry_list(struct list_head *);
extern void shrink_dcache_for_umount(struct super_block *);
extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *);
extern struct dentry *__d_lookup_rcu(const struct dentry *parent,
const struct qstr *name, unsigned *seq);
extern void d_genocide(struct dentry *);
/* /*
* pipe.c * pipe.c
......
...@@ -104,15 +104,16 @@ EXPORT_SYMBOL(dcache_dir_close); ...@@ -104,15 +104,16 @@ EXPORT_SYMBOL(dcache_dir_close);
* If no such element exists, NULL is returned. * If no such element exists, NULL is returned.
*/ */
static struct dentry *scan_positives(struct dentry *cursor, static struct dentry *scan_positives(struct dentry *cursor,
struct list_head *p, struct hlist_node **p,
loff_t count, loff_t count,
struct dentry *last) struct dentry *last)
{ {
struct dentry *dentry = cursor->d_parent, *found = NULL; struct dentry *dentry = cursor->d_parent, *found = NULL;
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
while ((p = p->next) != &dentry->d_subdirs) { while (*p) {
struct dentry *d = list_entry(p, struct dentry, d_child); struct dentry *d = hlist_entry(*p, struct dentry, d_sib);
p = &d->d_sib.next;
// we must at least skip cursors, to avoid livelocks // we must at least skip cursors, to avoid livelocks
if (d->d_flags & DCACHE_DENTRY_CURSOR) if (d->d_flags & DCACHE_DENTRY_CURSOR)
continue; continue;
...@@ -126,8 +127,10 @@ static struct dentry *scan_positives(struct dentry *cursor, ...@@ -126,8 +127,10 @@ static struct dentry *scan_positives(struct dentry *cursor,
count = 1; count = 1;
} }
if (need_resched()) { if (need_resched()) {
list_move(&cursor->d_child, p); if (!hlist_unhashed(&cursor->d_sib))
p = &cursor->d_child; __hlist_del(&cursor->d_sib);
hlist_add_behind(&cursor->d_sib, &d->d_sib);
p = &cursor->d_sib.next;
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
cond_resched(); cond_resched();
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
...@@ -159,13 +162,12 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence) ...@@ -159,13 +162,12 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
inode_lock_shared(dentry->d_inode); inode_lock_shared(dentry->d_inode);
if (offset > 2) if (offset > 2)
to = scan_positives(cursor, &dentry->d_subdirs, to = scan_positives(cursor, &dentry->d_children.first,
offset - 2, NULL); offset - 2, NULL);
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
hlist_del_init(&cursor->d_sib);
if (to) if (to)
list_move(&cursor->d_child, &to->d_child); hlist_add_behind(&cursor->d_sib, &to->d_sib);
else
list_del_init(&cursor->d_child);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
dput(to); dput(to);
...@@ -187,19 +189,16 @@ int dcache_readdir(struct file *file, struct dir_context *ctx) ...@@ -187,19 +189,16 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
{ {
struct dentry *dentry = file->f_path.dentry; struct dentry *dentry = file->f_path.dentry;
struct dentry *cursor = file->private_data; struct dentry *cursor = file->private_data;
struct list_head *anchor = &dentry->d_subdirs;
struct dentry *next = NULL; struct dentry *next = NULL;
struct list_head *p; struct hlist_node **p;
if (!dir_emit_dots(file, ctx)) if (!dir_emit_dots(file, ctx))
return 0; return 0;
if (ctx->pos == 2) if (ctx->pos == 2)
p = anchor; p = &dentry->d_children.first;
else if (!list_empty(&cursor->d_child))
p = &cursor->d_child;
else else
return 0; p = &cursor->d_sib.next;
while ((next = scan_positives(cursor, p, 1, next)) != NULL) { while ((next = scan_positives(cursor, p, 1, next)) != NULL) {
if (!dir_emit(ctx, next->d_name.name, next->d_name.len, if (!dir_emit(ctx, next->d_name.name, next->d_name.len,
...@@ -207,13 +206,12 @@ int dcache_readdir(struct file *file, struct dir_context *ctx) ...@@ -207,13 +206,12 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
fs_umode_to_dtype(d_inode(next)->i_mode))) fs_umode_to_dtype(d_inode(next)->i_mode)))
break; break;
ctx->pos++; ctx->pos++;
p = &next->d_child; p = &next->d_sib.next;
} }
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
hlist_del_init(&cursor->d_sib);
if (next) if (next)
list_move_tail(&cursor->d_child, &next->d_child); hlist_add_before(&cursor->d_sib, &next->d_sib);
else
list_del_init(&cursor->d_child);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
dput(next); dput(next);
...@@ -500,12 +498,11 @@ const struct file_operations simple_offset_dir_operations = { ...@@ -500,12 +498,11 @@ const struct file_operations simple_offset_dir_operations = {
static struct dentry *find_next_child(struct dentry *parent, struct dentry *prev) static struct dentry *find_next_child(struct dentry *parent, struct dentry *prev)
{ {
struct dentry *child = NULL; struct dentry *child = NULL, *d;
struct list_head *p = prev ? &prev->d_child : &parent->d_subdirs;
spin_lock(&parent->d_lock); spin_lock(&parent->d_lock);
while ((p = p->next) != &parent->d_subdirs) { d = prev ? d_next_sibling(prev) : d_first_child(parent);
struct dentry *d = container_of(p, struct dentry, d_child); hlist_for_each_entry_from(d, d_sib) {
if (simple_positive(d)) { if (simple_positive(d)) {
spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(d)) if (simple_positive(d))
...@@ -666,7 +663,7 @@ int simple_empty(struct dentry *dentry) ...@@ -666,7 +663,7 @@ int simple_empty(struct dentry *dentry)
int ret = 0; int ret = 0;
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
list_for_each_entry(child, &dentry->d_subdirs, d_child) { hlist_for_each_entry(child, &dentry->d_children, d_sib) {
spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(child)) { if (simple_positive(child)) {
spin_unlock(&child->d_lock); spin_unlock(&child->d_lock);
...@@ -920,7 +917,6 @@ int simple_fill_super(struct super_block *s, unsigned long magic, ...@@ -920,7 +917,6 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
const struct tree_descr *files) const struct tree_descr *files)
{ {
struct inode *inode; struct inode *inode;
struct dentry *root;
struct dentry *dentry; struct dentry *dentry;
int i; int i;
...@@ -943,8 +939,8 @@ int simple_fill_super(struct super_block *s, unsigned long magic, ...@@ -943,8 +939,8 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
inode->i_op = &simple_dir_inode_operations; inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations; inode->i_fop = &simple_dir_operations;
set_nlink(inode, 2); set_nlink(inode, 2);
root = d_make_root(inode); s->s_root = d_make_root(inode);
if (!root) if (!s->s_root)
return -ENOMEM; return -ENOMEM;
for (i = 0; !files->name || files->name[0]; i++, files++) { for (i = 0; !files->name || files->name[0]; i++, files++) {
if (!files->name) if (!files->name)
...@@ -956,13 +952,13 @@ int simple_fill_super(struct super_block *s, unsigned long magic, ...@@ -956,13 +952,13 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
"with an index of 1!\n", __func__, "with an index of 1!\n", __func__,
s->s_type->name); s->s_type->name);
dentry = d_alloc_name(root, files->name); dentry = d_alloc_name(s->s_root, files->name);
if (!dentry) if (!dentry)
goto out; return -ENOMEM;
inode = new_inode(s); inode = new_inode(s);
if (!inode) { if (!inode) {
dput(dentry); dput(dentry);
goto out; return -ENOMEM;
} }
inode->i_mode = S_IFREG | files->mode; inode->i_mode = S_IFREG | files->mode;
simple_inode_init_ts(inode); simple_inode_init_ts(inode);
...@@ -970,13 +966,7 @@ int simple_fill_super(struct super_block *s, unsigned long magic, ...@@ -970,13 +966,7 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
inode->i_ino = i; inode->i_ino = i;
d_add(dentry, inode); d_add(dentry, inode);
} }
s->s_root = root;
return 0; return 0;
out:
d_genocide(root);
shrink_dcache_parent(root);
dput(root);
return -ENOMEM;
} }
EXPORT_SYMBOL(simple_fill_super); EXPORT_SYMBOL(simple_fill_super);
......
...@@ -1242,63 +1242,34 @@ static inline void _nfsd_symlink(struct dentry *parent, const char *name, ...@@ -1242,63 +1242,34 @@ static inline void _nfsd_symlink(struct dentry *parent, const char *name,
#endif #endif
static void clear_ncl(struct inode *inode) static void clear_ncl(struct dentry *dentry)
{ {
struct inode *inode = d_inode(dentry);
struct nfsdfs_client *ncl = inode->i_private; struct nfsdfs_client *ncl = inode->i_private;
spin_lock(&inode->i_lock);
inode->i_private = NULL; inode->i_private = NULL;
spin_unlock(&inode->i_lock);
kref_put(&ncl->cl_ref, ncl->cl_release); kref_put(&ncl->cl_ref, ncl->cl_release);
} }
static struct nfsdfs_client *__get_nfsdfs_client(struct inode *inode)
{
struct nfsdfs_client *nc = inode->i_private;
if (nc)
kref_get(&nc->cl_ref);
return nc;
}
struct nfsdfs_client *get_nfsdfs_client(struct inode *inode) struct nfsdfs_client *get_nfsdfs_client(struct inode *inode)
{ {
struct nfsdfs_client *nc; struct nfsdfs_client *nc;
inode_lock_shared(inode); spin_lock(&inode->i_lock);
nc = __get_nfsdfs_client(inode); nc = inode->i_private;
inode_unlock_shared(inode); if (nc)
kref_get(&nc->cl_ref);
spin_unlock(&inode->i_lock);
return nc; return nc;
} }
/* from __rpc_unlink */
static void nfsdfs_remove_file(struct inode *dir, struct dentry *dentry)
{
int ret;
clear_ncl(d_inode(dentry));
dget(dentry);
ret = simple_unlink(dir, dentry);
d_drop(dentry);
fsnotify_unlink(dir, dentry);
dput(dentry);
WARN_ON_ONCE(ret);
}
static void nfsdfs_remove_files(struct dentry *root)
{
struct dentry *dentry, *tmp;
list_for_each_entry_safe(dentry, tmp, &root->d_subdirs, d_child) {
if (!simple_positive(dentry)) {
WARN_ON_ONCE(1); /* I think this can't happen? */
continue;
}
nfsdfs_remove_file(d_inode(root), dentry);
}
}
/* XXX: cut'n'paste from simple_fill_super; figure out if we could share /* XXX: cut'n'paste from simple_fill_super; figure out if we could share
* code instead. */ * code instead. */
static int nfsdfs_create_files(struct dentry *root, static int nfsdfs_create_files(struct dentry *root,
const struct tree_descr *files, const struct tree_descr *files,
struct nfsdfs_client *ncl,
struct dentry **fdentries) struct dentry **fdentries)
{ {
struct inode *dir = d_inode(root); struct inode *dir = d_inode(root);
...@@ -1317,8 +1288,9 @@ static int nfsdfs_create_files(struct dentry *root, ...@@ -1317,8 +1288,9 @@ static int nfsdfs_create_files(struct dentry *root,
dput(dentry); dput(dentry);
goto out; goto out;
} }
kref_get(&ncl->cl_ref);
inode->i_fop = files->ops; inode->i_fop = files->ops;
inode->i_private = __get_nfsdfs_client(dir); inode->i_private = ncl;
d_add(dentry, inode); d_add(dentry, inode);
fsnotify_create(dir, dentry); fsnotify_create(dir, dentry);
if (fdentries) if (fdentries)
...@@ -1327,7 +1299,6 @@ static int nfsdfs_create_files(struct dentry *root, ...@@ -1327,7 +1299,6 @@ static int nfsdfs_create_files(struct dentry *root,
inode_unlock(dir); inode_unlock(dir);
return 0; return 0;
out: out:
nfsdfs_remove_files(root);
inode_unlock(dir); inode_unlock(dir);
return -ENOMEM; return -ENOMEM;
} }
...@@ -1347,7 +1318,7 @@ struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, ...@@ -1347,7 +1318,7 @@ struct dentry *nfsd_client_mkdir(struct nfsd_net *nn,
dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name); dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name);
if (IS_ERR(dentry)) /* XXX: tossing errors? */ if (IS_ERR(dentry)) /* XXX: tossing errors? */
return NULL; return NULL;
ret = nfsdfs_create_files(dentry, files, fdentries); ret = nfsdfs_create_files(dentry, files, ncl, fdentries);
if (ret) { if (ret) {
nfsd_client_rmdir(dentry); nfsd_client_rmdir(dentry);
return NULL; return NULL;
...@@ -1358,20 +1329,7 @@ struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, ...@@ -1358,20 +1329,7 @@ struct dentry *nfsd_client_mkdir(struct nfsd_net *nn,
/* Taken from __rpc_rmdir: */ /* Taken from __rpc_rmdir: */
void nfsd_client_rmdir(struct dentry *dentry) void nfsd_client_rmdir(struct dentry *dentry)
{ {
struct inode *dir = d_inode(dentry->d_parent); simple_recursive_removal(dentry, clear_ncl);
struct inode *inode = d_inode(dentry);
int ret;
inode_lock(dir);
nfsdfs_remove_files(dentry);
clear_ncl(inode);
dget(dentry);
ret = simple_rmdir(dir, dentry);
WARN_ON_ONCE(ret);
d_drop(dentry);
fsnotify_rmdir(dir, dentry);
dput(dentry);
inode_unlock(dir);
} }
static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc)
......
...@@ -124,7 +124,7 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode) ...@@ -124,7 +124,7 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
* d_flags to indicate parental interest (their parent is the * d_flags to indicate parental interest (their parent is the
* original inode) */ * original inode) */
spin_lock(&alias->d_lock); spin_lock(&alias->d_lock);
list_for_each_entry(child, &alias->d_subdirs, d_child) { hlist_for_each_entry(child, &alias->d_children, d_sib) {
if (!child->d_inode) if (!child->d_inode)
continue; continue;
......
...@@ -90,12 +90,9 @@ static int __ns_get_path(struct path *path, struct ns_common *ns) ...@@ -90,12 +90,9 @@ static int __ns_get_path(struct path *path, struct ns_common *ns)
inode->i_fop = &ns_file_operations; inode->i_fop = &ns_file_operations;
inode->i_private = ns; inode->i_private = ns;
dentry = d_alloc_anon(mnt->mnt_sb); dentry = d_make_root(inode); /* not the normal use, but... */
if (!dentry) { if (!dentry)
iput(inode);
return -ENOMEM; return -ENOMEM;
}
d_instantiate(dentry, inode);
dentry->d_fsdata = (void *)ns->ops; dentry->d_fsdata = (void *)ns->ops;
d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry); d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
if (d) { if (d) {
......
...@@ -289,7 +289,6 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb, ...@@ -289,7 +289,6 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb,
{ {
struct dentry *lower = lowerpath ? lowerpath->dentry : NULL; struct dentry *lower = lowerpath ? lowerpath->dentry : NULL;
struct dentry *upper = upper_alias ?: index; struct dentry *upper = upper_alias ?: index;
struct dentry *dentry;
struct inode *inode = NULL; struct inode *inode = NULL;
struct ovl_entry *oe; struct ovl_entry *oe;
struct ovl_inode_params oip = { struct ovl_inode_params oip = {
...@@ -320,27 +319,7 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb, ...@@ -320,27 +319,7 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb,
if (upper) if (upper)
ovl_set_flag(OVL_UPPERDATA, inode); ovl_set_flag(OVL_UPPERDATA, inode);
dentry = d_find_any_alias(inode); return d_obtain_alias(inode);
if (dentry)
goto out_iput;
dentry = d_alloc_anon(inode->i_sb);
if (unlikely(!dentry))
goto nomem;
if (upper_alias)
ovl_dentry_set_upper_alias(dentry);
ovl_dentry_init_reval(dentry, upper, OVL_I_E(inode));
return d_instantiate_anon(dentry, inode);
nomem:
dput(dentry);
dentry = ERR_PTR(-ENOMEM);
out_iput:
iput(inode);
return dentry;
} }
/* Get the upper or lower dentry in stack whose on layer @idx */ /* Get the upper or lower dentry in stack whose on layer @idx */
......
...@@ -199,21 +199,17 @@ static void change_gid(struct dentry *dentry, kgid_t gid) ...@@ -199,21 +199,17 @@ static void change_gid(struct dentry *dentry, kgid_t gid)
*/ */
static void set_gid(struct dentry *parent, kgid_t gid) static void set_gid(struct dentry *parent, kgid_t gid)
{ {
struct dentry *this_parent; struct dentry *this_parent, *dentry;
struct list_head *next;
this_parent = parent; this_parent = parent;
spin_lock(&this_parent->d_lock); spin_lock(&this_parent->d_lock);
change_gid(this_parent, gid); change_gid(this_parent, gid);
repeat: repeat:
next = this_parent->d_subdirs.next; dentry = d_first_child(this_parent);
resume: resume:
while (next != &this_parent->d_subdirs) { hlist_for_each_entry_from(dentry, d_sib) {
struct tracefs_inode *ti; struct tracefs_inode *ti;
struct list_head *tmp = next;
struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
next = tmp->next;
/* Note, getdents() can add a cursor dentry with no inode */ /* Note, getdents() can add a cursor dentry with no inode */
if (!dentry->d_inode) if (!dentry->d_inode)
...@@ -228,7 +224,7 @@ static void set_gid(struct dentry *parent, kgid_t gid) ...@@ -228,7 +224,7 @@ static void set_gid(struct dentry *parent, kgid_t gid)
if (ti && (ti->flags & TRACEFS_EVENT_INODE)) if (ti && (ti->flags & TRACEFS_EVENT_INODE))
eventfs_update_gid(dentry, gid); eventfs_update_gid(dentry, gid);
if (!list_empty(&dentry->d_subdirs)) { if (!hlist_empty(&dentry->d_children)) {
spin_unlock(&this_parent->d_lock); spin_unlock(&this_parent->d_lock);
spin_release(&dentry->d_lock.dep_map, _RET_IP_); spin_release(&dentry->d_lock.dep_map, _RET_IP_);
this_parent = dentry; this_parent = dentry;
...@@ -243,22 +239,21 @@ static void set_gid(struct dentry *parent, kgid_t gid) ...@@ -243,22 +239,21 @@ static void set_gid(struct dentry *parent, kgid_t gid)
rcu_read_lock(); rcu_read_lock();
ascend: ascend:
if (this_parent != parent) { if (this_parent != parent) {
struct dentry *child = this_parent; dentry = this_parent;
this_parent = child->d_parent; this_parent = dentry->d_parent;
spin_unlock(&child->d_lock); spin_unlock(&dentry->d_lock);
spin_lock(&this_parent->d_lock); spin_lock(&this_parent->d_lock);
/* go into the first sibling still alive */ /* go into the first sibling still alive */
do { hlist_for_each_entry_continue(dentry, d_sib) {
next = child->d_child.next; if (likely(!(dentry->d_flags & DCACHE_DENTRY_KILLED))) {
if (next == &this_parent->d_subdirs)
goto ascend;
child = list_entry(next, struct dentry, d_child);
} while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED));
rcu_read_unlock(); rcu_read_unlock();
goto resume; goto resume;
} }
}
goto ascend;
}
rcu_read_unlock(); rcu_read_unlock();
spin_unlock(&this_parent->d_lock); spin_unlock(&this_parent->d_lock);
return; return;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment