]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Merge tag 'pull-dcache-busy-wait' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 21 Apr 2026 14:30:44 +0000 (07:30 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 21 Apr 2026 14:30:44 +0000 (07:30 -0700)
Pull dcache busy loop updates from Al Viro:
 "Fix livelocks in shrink_dcache_tree()

  If shrink_dcache_tree() finds a dentry in the middle of being killed
  by another thread, it has to wait until the victim finishes dying,
  gets detached from the tree and ceases to pin its parent.

  The way we used to deal with that amounted to busy-wait;
  unfortunately, it's not just inefficient but can lead to reliably
  reproducible hard livelocks.

  Solved by having shrink_dentry_tree() attach a completion to such
  dentry, with dentry_unlist() calling complete() on all objects
  attached to it. With a bit of care it can be done without growing
  struct dentry or adding overhead in normal case"

* tag 'pull-dcache-busy-wait' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  get rid of busy-waiting in shrink_dcache_tree()
  dcache.c: more idiomatic "positives are not allowed" sanity checks
  struct dentry: make ->d_u anonymous
  for_each_alias(): helper macro for iterating through dentries of given inode

1  2 
Documentation/filesystems/porting.rst
fs/affs/amigaffs.c
fs/dcache.c
fs/exportfs/expfs.c
fs/inode.c
fs/nfs/dir.c
fs/overlayfs/dir.c
fs/smb/client/inode.c
include/linux/dcache.h

index d02aa57e44775c042e9b6d4cef3573b9e2606432,9a9babd9ec4869447582c29e68038bdd69ddee6f..fdf074429cd3ab7a4595182926edaba92d331a65
@@@ -1364,14 -1364,10 +1364,24 @@@ lifetime, consider using inode_set_cach
  
  ---
  
 +**mandatory**
 +
 +lookup_one_qstr_excl() is no longer exported - use start_creating() or
 +similar.
++
 +---
 +
 +** mandatory**
 +
 +lock_rename(), lock_rename_child(), unlock_rename() are no
 +longer available.  Use start_renaming() or similar.
 +
++---
++
+ **recommended**
+ If you really need to iterate through dentries for given inode, use
+ for_each_alias(dentry, inode) instead of hlist_for_each_entry; better
+ yet, see if any of the exported primitives could be used instead of
+ the entire loop.  You still need to hold ->i_lock of the inode over
+ either form of manual loop.
index ee512baf57e5af148834a334129c8195df51061f,91966b1f41f64c75aa6c756376bda2ecaff0af41..bed4fc805e8e669bea08b70216442f10a3911686
@@@ -126,9 -126,9 +126,9 @@@ affs_fix_dcache(struct inode *inode, u3
  {
        struct dentry *dentry;
        spin_lock(&inode->i_lock);
-       hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
+       for_each_alias(dentry, inode) {
                if (entry_ino == (u32)(long)dentry->d_fsdata) {
 -                      dentry->d_fsdata = (void *)inode->i_ino;
 +                      dentry->d_fsdata = (void *)(unsigned long)inode->i_ino;
                        break;
                }
        }
diff --cc fs/dcache.c
Simple merge
Simple merge
diff --cc fs/inode.c
index 69e219f0cfcbe980febf271426b89bf2723733e0,9e1ab333d3825e91fe9ce97b701ea08abe3db25a..6a3cbc7dcd28c75723b44d7f69f214e5b35f1443
@@@ -750,10 -754,10 +750,10 @@@ void dump_mapping(const struct address_
                return;
        }
  
-       dentry_ptr = container_of(dentry_first, struct dentry, d_u.d_alias);
+       dentry_ptr = container_of(dentry_first, struct dentry, d_alias);
        if (get_kernel_nofault(dentry, dentry_ptr) ||
            !dentry.d_parent || !dentry.d_name.name) {
 -              pr_warn("aops:%ps ino:%lx invalid dentry:%px\n",
 +              pr_warn("aops:%ps ino:%llx invalid dentry:%px\n",
                                a_ops, ino, dentry_ptr);
                return;
        }
diff --cc fs/nfs/dir.c
Simple merge
Simple merge
Simple merge
Simple merge