Re: [PATCH v1 01/12] VFS: don't count references through ->d_parent

NeilBrown <[email protected]>
Newsgroups gmane.linux.nfs,gmane.linux.kernel.autofs,gmane.linux.kernel,gmane.comp.file-systems.ceph.devel,gmane.comp.file-systems.coda.general,gmane.linux.file-systems
Message-ID <[email protected]>
On Mon, 10 Aug 2026, Miklos Szeredi wrote:
> On Mon, 3 Aug 2026 at 03:37, NeilBrown <[email protected]> wrote:
> 
> > When a DCACHE_CURSOR dentry is added to d_children, it is only ever
> > added "before" or "behind" an existing child, so it will never be the
> > first and so never needs to adjust the refcount on the parent.  If it
> > remains on the list until dput() it could be the last child to be
> > removed, in which case normal handling applies in dentry_unlist() (where
> > it has been moved from dentry_kill().
> 
> Not handling the parent refcount together with cursor removal can
> result in inconsistency, e.g:
> 
>  - add cursor (seek between two positive dentries)
>  - remove all real children (parent refcount not touched, since cursor
> is still on d_children)
>  - remove cursor (seek to zero offset)
>  - close directory (dentry_unlist() will skip parent refcount update
> since dentry->d_sib is no longer linked)
> 
> Repro attached, produces "BUG: Dentry ffff888107ef75d0{i=143e,n=dir}
> still in use (1) [unm
> ount of hugetlbfs hugetlbfs]".
> 
> Thanks,
> Milklos
> 

Thanks for the review.  I realised that when I was doing patch 11 which
changes d_for_each_positive_child() to use a cursor, but I didn't think
the apply that understand back at this patch.

There is only on user of cursors so it can be easily fixed as follows.

Thanks,
NeilBrown

index 5a0d276379d1..91f535192ee2 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -169,6 +169,8 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
 		hlist_del_init(&cursor->d_sib);
 		if (to)
 			hlist_add_behind(&cursor->d_sib, &to->d_sib);
+		else if (hlist_empty(&dentry->d_children)
+			dput_dlock(dentry);
 		spin_unlock(&dentry->d_lock);
 		dput(to);
 
@@ -213,6 +215,8 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
 	hlist_del_init(&cursor->d_sib);
 	if (next)
 		hlist_add_before(&cursor->d_sib, &next->d_sib);
+	else if (hlist_empty(&dentry->d_children))
+		dput_dlock(dentry);
 	spin_unlock(&dentry->d_lock);
 	dput(next);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.