]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ovl: change ovl_create_index() to take dir locks
authorNeilBrown <neil@brown.name>
Wed, 16 Jul 2025 00:44:13 +0000 (10:44 +1000)
committerChristian Brauner <brauner@kernel.org>
Fri, 18 Jul 2025 09:10:40 +0000 (11:10 +0200)
ovl_copy_up_workdir() currently take a rename lock on two directories,
then use the lock to both create a file in one directory, perform a
rename, and possibly unlink the file for cleanup.  This is incompatible
with proposed changes which will lock just the dentry of objects being
acted on.

This patch moves the call to ovl_create_index() earlier in
ovl_copy_up_workdir() to before the lock is taken.

ovl_create_index() then takes the required lock only when needed.

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

index 79f41ef6ffa7dcdb33839feb0f8e340caf199a0c..d485bd7edd8ff640a0cf4acb9165f3f52957a1ed 100644 (file)
@@ -517,8 +517,6 @@ static int ovl_set_upper_fh(struct ovl_fs *ofs, struct dentry *upper,
 
 /*
  * Create and install index entry.
- *
- * Caller must hold i_mutex on indexdir.
  */
 static int ovl_create_index(struct dentry *dentry, const struct ovl_fh *fh,
                            struct dentry *upper)
@@ -550,7 +548,9 @@ static int ovl_create_index(struct dentry *dentry, const struct ovl_fh *fh,
        if (err)
                return err;
 
+       inode_lock(dir);
        temp = ovl_create_temp(ofs, indexdir, OVL_CATTR(S_IFDIR | 0));
+       inode_unlock(dir);
        err = PTR_ERR(temp);
        if (IS_ERR(temp))
                goto free_name;
@@ -559,6 +559,9 @@ static int ovl_create_index(struct dentry *dentry, const struct ovl_fh *fh,
        if (err)
                goto out;
 
+       err = ovl_parent_lock(indexdir, temp);
+       if (err)
+               goto out;
        index = ovl_lookup_upper(ofs, name.name, indexdir, name.len);
        if (IS_ERR(index)) {
                err = PTR_ERR(index);
@@ -566,9 +569,10 @@ static int ovl_create_index(struct dentry *dentry, const struct ovl_fh *fh,
                err = ovl_do_rename(ofs, indexdir, temp, indexdir, index, 0);
                dput(index);
        }
+       ovl_parent_unlock(indexdir);
 out:
        if (err)
-               ovl_cleanup(ofs, dir, temp);
+               ovl_cleanup_unlocked(ofs, indexdir, temp);
        dput(temp);
 free_name:
        kfree(name.name);
@@ -798,6 +802,12 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
        if (err)
                goto cleanup_unlocked;
 
+       if (S_ISDIR(c->stat.mode) && c->indexed) {
+               err = ovl_create_index(c->dentry, c->origin_fh, temp);
+               if (err)
+                       goto cleanup_unlocked;
+       }
+
        /*
         * We cannot hold lock_rename() throughout this helper, because of
         * lock ordering with sb_writers, which shouldn't be held when calling
@@ -818,12 +828,6 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
        if (err)
                goto cleanup;
 
-       if (S_ISDIR(c->stat.mode) && c->indexed) {
-               err = ovl_create_index(c->dentry, c->origin_fh, temp);
-               if (err)
-                       goto cleanup;
-       }
-
        upper = ovl_lookup_upper(ofs, c->destname.name, c->destdir,
                                 c->destname.len);
        err = PTR_ERR(upper);