Commit 499aa1ca authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -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**

Block device freezing and thawing have been moved to holder operations.
+3 −2
Original line number Diff line number Diff line
@@ -145,10 +145,11 @@ spufs_evict_inode(struct inode *inode)

static void spufs_prune_dir(struct dentry *dir)
{
	struct dentry *dentry, *tmp;
	struct dentry *dentry;
	struct hlist_node *n;

	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);
		if (simple_positive(dentry)) {
			dget_dlock(dentry);
+3 −2
Original line number Diff line number Diff line
@@ -373,7 +373,7 @@ int afs_dynroot_populate(struct super_block *sb)
void afs_dynroot_depopulate(struct super_block *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 */
	mutex_lock(&net->proc_cells_lock);
@@ -382,10 +382,11 @@ void afs_dynroot_depopulate(struct super_block *sb)
	mutex_unlock(&net->proc_cells_lock);

	if (root) {
		struct hlist_node *n;
		inode_lock(root->d_inode);

		/* 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) {
				subdir->d_fsdata = NULL;
				dput(subdir);
+2 −5
Original line number Diff line number Diff line
@@ -73,12 +73,9 @@ static int autofs_mount_busy(struct vfsmount *mnt,
/* p->d_lock held */
static struct dentry *positive_after(struct dentry *p, struct dentry *child)
{
	if (child)
		child = list_next_entry(child, d_child);
	else
		child = list_first_entry(&p->d_subdirs, struct dentry, d_child);
	child = child ? d_next_sibling(child) : d_first_child(p);

	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);
		if (simple_positive(child)) {
			dget_dlock(child);
+1 −1
Original line number Diff line number Diff line
@@ -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
 * 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
 * are dropped.
 *
Loading