]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ovl: narrow locking in ovl_workdir_cleanup_recurse()
authorNeilBrown <neil@brown.name>
Wed, 16 Jul 2025 00:44:25 +0000 (10:44 +1000)
committerChristian Brauner <brauner@kernel.org>
Fri, 18 Jul 2025 09:10:42 +0000 (11:10 +0200)
Only take the dir lock when needed, rather than for the whole loop.

Signed-off-by: NeilBrown <neil@brown.name>
Link: https://lore.kernel.org/20250716004725.1206467-15-neil@brown.name
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/overlayfs/readdir.c

index 95d5284daf8d915ef5d728b43c07dc58a7297a62..b0f9e5a00c1a587d71555c500ffda2b4d0d59fcf 100644 (file)
@@ -1122,7 +1122,6 @@ static int ovl_workdir_cleanup_recurse(struct ovl_fs *ofs, const struct path *pa
        if (err)
                goto out;
 
-       inode_lock_nested(dir, I_MUTEX_PARENT);
        list_for_each_entry(p, &list, l_node) {
                struct dentry *dentry;
 
@@ -1137,16 +1136,21 @@ static int ovl_workdir_cleanup_recurse(struct ovl_fs *ofs, const struct path *pa
                        err = -EINVAL;
                        break;
                }
-               dentry = ovl_lookup_upper(ofs, p->name, path->dentry, p->len);
+               dentry = ovl_lookup_upper_unlocked(ofs, p->name, path->dentry, p->len);
                if (IS_ERR(dentry))
                        continue;
-               if (dentry->d_inode)
-                       err = ovl_workdir_cleanup(ofs, dir, path->mnt, dentry, level);
+               if (dentry->d_inode) {
+                       err = ovl_parent_lock(path->dentry, dentry);
+                       if (!err) {
+                               err = ovl_workdir_cleanup(ofs, dir, path->mnt,
+                                                         dentry, level);
+                               ovl_parent_unlock(path->dentry);
+                       }
+               }
                dput(dentry);
                if (err)
                        break;
        }
-       inode_unlock(dir);
 out:
        ovl_cache_free(&list);
        return err;