mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Chuck Lever" <cel@kernel.org>
To: NeilBrown <neil@brown.name>, "Ian Kent" <raven@themaw.net>,
	"Jake Edge" <jake@lwn.net>, "Ilya Dryomov" <idryomov@gmail.com>,
	"Alex Markuze" <amarkuze@redhat.com>,
	"Viacheslav Dubeyko" <slava@dubeyko.com>,
	"Jan Harkes" <jaharkes@cs.cmu.edu>,
	coda@cs.cmu.edu, "Alexander Viro" <viro@zeniv.linux.org.uk>,
	"Christian Brauner" <brauner@kernel.org>,
	"Jan Kara" <jack@suse.cz>, "Trond Myklebust" <trondmy@kernel.org>,
	"Anna Schumaker" <anna@kernel.org>,
	"Amir Goldstein" <amir73il@gmail.com>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Miklos Szeredi" <mszeredi@redhat.com>
Cc: autofs@vger.kernel.org, linux-kernel@vger.kernel.org,
	ceph-devel@vger.kernel.org, codalist@coda.cs.cmu.edu,
	linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org
Subject: Re: [PATCH v2 13/18] VFS: don't move dentries in d_sib list when they have the same parent
Date: Thu, 20 Aug 2026 09:39:00 -0400	[thread overview]
Message-ID: <c3cc4175-1ca3-467d-849b-22462a7514fc@app.fastmail.com> (raw)
In-Reply-To: <20260815042707.2535717-14-neilb@ownmail.net>



On Sat, Aug 15, 2026, at 12:21 AM, NeilBrown wrote:
> From: NeilBrown <neil@brown.name>
>
> When __d_move() moves or exchanges dentries it currently always moves
> both dentries to the head of the ->d_children list of the respective
> parents.
>
> When they have the same parent, this simply moves them from where they
> are to the start in the same list.  So it achieves nothing useful.
>
> A future patch will allow d_for_each_positive_child() to drop and retake
> the parent's d_lock during the iteration.  With the current __d_move
> behaviour this would allow a dentry to be moved to the front and so
> missed, even though it is still in the same directory.  This might be
> unexpected.
>
> With this change the only dentries that d_for_each_positive_child()
> might miss are those moved out of the directory, or those moved in after
> the iteration started.  These are unavoidable and should not be
> unexpected.
>
> Signed-off-by: NeilBrown <neil@brown.name>
> ---
>  fs/dcache.c | 20 ++++++++++++++------
>  1 file changed, 14 insertions(+), 6 deletions(-)
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index ae726f3ff0cb..50fbbcceca01 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -3052,6 +3052,9 @@ static void copy_name(struct dentry *dentry, 
> struct dentry *target)
>   * entries should not be moved in this way. Caller must hold 
> rename_lock, the
>   * i_rwsem of the source and target directories (exclusively), and the 
> sb->
>   * s_vfs_rename_mutex if they differ. See lock_rename().
> + *
> + * If @dentry and @target have the same parent, then neither is
> + * moved in the d_sib list.
>   */
>  static void __d_move(struct dentry *dentry, struct dentry *target,
>  		     bool exchange)
> @@ -3119,15 +3122,20 @@ static void __d_move(struct dentry *dentry, 
> struct dentry *target,
>  	} else {
>  		target->d_parent = old_parent;
>  		swap_names(dentry, target);
> -		if (!hlist_unhashed(&target->d_sib))
> -			__hlist_del(&target->d_sib);
> -		hlist_add_head(&target->d_sib, &target->d_parent->d_children);
> +		if (target->d_parent != dentry->d_parent) {
> +			if (!hlist_unhashed(&target->d_sib))
> +				__hlist_del(&target->d_sib);
> +			hlist_add_head(&target->d_sib,
> +				       &target->d_parent->d_children);
> +		}
>  		__d_rehash(target);
>  		fsnotify_update_flags(target);
>  	}
> -	if (!hlist_unhashed(&dentry->d_sib))
> -		__hlist_del(&dentry->d_sib);
> -	hlist_add_head(&dentry->d_sib, &dentry->d_parent->d_children);
> +	if (dentry->d_parent != old_parent) {
> +		if (!hlist_unhashed(&dentry->d_sib))
> +			__hlist_del(&dentry->d_sib);
> +		hlist_add_head(&dentry->d_sib, &dentry->d_parent->d_children);
> +	}
> 
>  	/*
>  	 * Adjust parent refcounts if either d_children ended up empty.
> -- 
> 2.50.0.107.gf914562f5916.dirty

Both new guards are correct. In the exchange branch target->d_parent has
already been set to old_parent, so testing it against dentry->d_parent
asks whether the two dentries started in the same directory. In the
common branch dentry->d_parent has been set to target's parent, so
testing it against old_parent asks the same question. IS_ROOT()
still takes the move, which it needs to because a root dentry has an
unhashed d_sib, and the BUG_ON(p) above guarantees target->d_parent
is not dentry.

The opening sentence needs a qualifier. For an ordinary move only
dentry->d_sib is relocated. target->d_sib is touched only on the
exchange path, so "both dentries" describes just that case.

This patch also does more for libfs than the patch description claims.
I would like the description to say so, because it makes the patch
worth applying on its own.

offset_readdir() resolves a stale cookie with mas_find_rev() and then
walks d_children from the dentry it lands on. That is correct only
while offset order is the reverse of d_children order. d_alloc()
inserts at the head and mtree_alloc_cyclic() hands out increasing
offsets, so the two agree in a directory that is only created into.

A rename within one directory breaks the agreement today.
simple_offset_rename() gives the surviving dentry the offset of the
entry it replaced, and d_move() then sends that dentry to the head of
d_children. Create a, b and c in that order and the offsets are 3, 4
and 5, with d_children holding c, b, a. After rename("a", "b") the
dentry for a carries offset 4 and sits at the head, so d_children
holds a, c while offset order still says c, a. Stop a readdir with a
reported and c pending, remove c, and the next call resolves the
cookie to a and reports a a second time.

With this patch a stays where it is, d_children holds c, a, and the
two orders agree again. Thus this is a fix for tmpfs readdir, not
just preparation for 14/18.

Reviewed-by: Chuck Lever <cel@kernel.org>


-- 
Chuck Lever

  reply	other threads:[~2026-08-20 13:39 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-15  4:21 [PATCH RFC/RFT v2 00/18] Fix easy bits of the negative dentry problem NeilBrown
2026-08-15  4:21 ` [PATCH v2 01/18] VFS: don't count references through ->d_parent NeilBrown
2026-08-15  4:21 ` [PATCH v2 02/18] autofs: change positive_after() so it takes d_lock rather than the caller NeilBrown
2026-08-15  4:21 ` [PATCH v2 03/18] coda: don't take rcu_read_lock() in coda_flag_children() NeilBrown
2026-08-15  4:21 ` [PATCH v2 04/18] nfs: separate locked regions in nfs_clear_verifier_directory() NeilBrown
2026-08-24 17:49   ` Chuck Lever
2026-08-25  4:09     ` NeilBrown
2026-08-15  4:21 ` [PATCH v2 05/18] Add and use d_for_each_positive_child family of iterators NeilBrown
2026-08-15  4:21 ` [PATCH v2 06/18] fsnotify: don't hold a spin_lock across fsnotify_recalc_mask() calls NeilBrown
2026-08-15  4:21 ` [PATCH v2 07/18] fsnotify: reduce i_lock hold time in fsnotify_set_children_dentry_flags() NeilBrown
2026-08-15  4:21 ` [PATCH v2 08/18] libfs: simplify scan_positives() NeilBrown
2026-08-15  4:21 ` [PATCH v2 09/18] libfs: change scan_positives() to use d_for_each_positive_child_continue() NeilBrown
2026-08-15  4:21 ` [PATCH v2 10/18] libfs: allow scan_positives() to be called without a cursor NeilBrown
2026-08-15  4:21 ` [PATCH v2 11/18] libfs: replace find_positive_dentry() with scan_positives() NeilBrown
2026-08-15  4:21 ` [PATCH v2 12/18] autofs: don't hold ->lookup_lock in get_next_positive_* NeilBrown
2026-08-15  4:21 ` [PATCH v2 13/18] VFS: don't move dentries in d_sib list when they have the same parent NeilBrown
2026-08-20 13:39   ` Chuck Lever [this message]
2026-08-25 21:56     ` NeilBrown
2026-08-26  1:45       ` Chuck Lever
2026-08-15  4:21 ` [PATCH v2 14/18] Call cond_reshed() as needed in d_for_each_positive_child() NeilBrown
2026-08-15  4:21 ` [PATCH v2 15/18] libfs: remove cond_resched() from scan_positives() NeilBrown
2026-08-15  4:21 ` [PATCH v2 16/18] libfs: rename and export scan_positives() NeilBrown
2026-08-15  4:21 ` [PATCH v2 17/18] autofs: replace positive_after() with d_scan_positives() NeilBrown
2026-08-15  4:21 ` [PATCH v2 18/18] autofs: change get_next_positive_dentry() to NOT accept NULL for start-up NeilBrown
2026-08-15  5:03 ` [PATCH RFC/RFT v2 00/18] Fix easy bits of the negative dentry problem Al Viro
2026-08-15  6:12   ` NeilBrown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c3cc4175-1ca3-467d-849b-22462a7514fc@app.fastmail.com \
    --to=cel@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=amarkuze@redhat.com \
    --cc=amir73il@gmail.com \
    --cc=anna@kernel.org \
    --cc=autofs@vger.kernel.org \
    --cc=brauner@kernel.org \
    --cc=ceph-devel@vger.kernel.org \
    --cc=coda@cs.cmu.edu \
    --cc=codalist@coda.cs.cmu.edu \
    --cc=idryomov@gmail.com \
    --cc=jack@suse.cz \
    --cc=jaharkes@cs.cmu.edu \
    --cc=jake@lwn.net \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=mszeredi@redhat.com \
    --cc=neil@brown.name \
    --cc=raven@themaw.net \
    --cc=slava@dubeyko.com \
    --cc=trondmy@kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®