Re: [PATCH 08/20] ovl: narrow locking in ovl_rename()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jul 11, 2025 at 1:21 AM NeilBrown <neil@xxxxxxxxxx> wrote:
>
> Drop the rename lock immediately after the rename, and use
> ovl_cleanup_unlocked() for cleanup.
>
> This makes way for future changes where locks are taken on individual
> dentries rather than the whole directory.
>
> Signed-off-by: NeilBrown <neil@xxxxxxxxxx>
> ---
>  fs/overlayfs/dir.c | 15 ++++++++++-----
>  1 file changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
> index 687d5e12289c..d01e83f9d800 100644
> --- a/fs/overlayfs/dir.c
> +++ b/fs/overlayfs/dir.c
> @@ -1262,9 +1262,10 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
>                             new_upperdir, newdentry, flags);
>         if (err)
>                 goto out_dput;
> +       unlock_rename(new_upperdir, old_upperdir);
>
>         if (cleanup_whiteout)
> -               ovl_cleanup(ofs, old_upperdir->d_inode, newdentry);
> +               ovl_cleanup_unlocked(ofs, old_upperdir, newdentry);
>
>         if (overwrite && d_inode(new)) {
>                 if (new_is_dir)
> @@ -1283,12 +1284,8 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
>         if (d_inode(new) && ovl_dentry_upper(new))
>                 ovl_copyattr(d_inode(new));
>
> -out_dput:
>         dput(newdentry);
> -out_dput_old:
>         dput(olddentry);
> -out_unlock:
> -       unlock_rename(new_upperdir, old_upperdir);
>  out_revert_creds:
>         ovl_revert_creds(old_cred);
>         if (update_nlink)
> @@ -1299,6 +1296,14 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
>         dput(opaquedir);
>         ovl_cache_free(&list);
>         return err;
> +
> +out_dput:
> +       dput(newdentry);
> +out_dput_old:
> +       dput(olddentry);
> +out_unlock:
> +       unlock_rename(new_upperdir, old_upperdir);
> +       goto out_revert_creds;
>  }
>
>  static int ovl_create_tmpfile(struct file *file, struct dentry *dentry,
> --
> 2.49.0
>

I think we get end up with fewer and clearer to understand goto labels
with a relatively simple trick:

diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index fe493f3ed6b6..7cddaa7b263e 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -1069,8 +1069,8 @@ static int ovl_rename(struct mnt_idmap *idmap,
struct inode *olddir,
        int err;
        struct dentry *old_upperdir;
        struct dentry *new_upperdir;
-       struct dentry *olddentry;
-       struct dentry *newdentry;
+       struct dentry *olddentry = NULL;
+       struct dentry *newdentry = NULL;
        struct dentry *trap;
        bool old_opaque;
        bool new_opaque;
@@ -1187,18 +1187,22 @@ static int ovl_rename(struct mnt_idmap *idmap,
struct inode *olddir,
        olddentry = ovl_lookup_upper(ofs, old->d_name.name, old_upperdir,
                                     old->d_name.len);
        err = PTR_ERR(olddentry);
-       if (IS_ERR(olddentry))
+       if (IS_ERR(olddentry)) {
+               olddentry = NULL;
                goto out_unlock;
+       }

        err = -ESTALE;
        if (!ovl_matches_upper(old, olddentry))
-               goto out_dput_old;
+               goto out_unlock;

        newdentry = ovl_lookup_upper(ofs, new->d_name.name, new_upperdir,
                                     new->d_name.len);
        err = PTR_ERR(newdentry);
-       if (IS_ERR(newdentry))
-               goto out_dput_old;
+       if (IS_ERR(newdentry)) {
+               newdentry = NULL;
+               goto out_unlock;
+       }

        old_opaque = ovl_dentry_is_opaque(old);
        new_opaque = ovl_dentry_is_opaque(new);
@@ -1207,28 +1211,28 @@ static int ovl_rename(struct mnt_idmap *idmap,
struct inode *olddir,
        if (d_inode(new) && ovl_dentry_upper(new)) {
                if (opaquedir) {
                        if (newdentry != opaquedir)
-                               goto out_dput;
+                               goto out_unlock;
                } else {
                        if (!ovl_matches_upper(new, newdentry))
-                               goto out_dput;
+                               goto out_unlock;
                }
        } else {
                if (!d_is_negative(newdentry)) {
                        if (!new_opaque || !ovl_upper_is_whiteout(ofs,
newdentry))
-                               goto out_dput;
+                               goto out_unlock;
                } else {
                        if (flags & RENAME_EXCHANGE)
-                               goto out_dput;
+                               goto out_unlock;
                }
        }

        if (olddentry == trap)
-               goto out_dput;
+               goto out_unlock;
        if (newdentry == trap)
-               goto out_dput;
+               goto out_unlock;

        if (olddentry->d_inode == newdentry->d_inode)
-               goto out_dput;
+               goto out_unlock;

        err = 0;
        if (ovl_type_merge_or_lower(old))
@@ -1236,7 +1240,7 @@ static int ovl_rename(struct mnt_idmap *idmap,
struct inode *olddir,
        else if (is_dir && !old_opaque && ovl_type_merge(new->d_parent))
                err = ovl_set_opaque_xerr(old, olddentry, -EXDEV);
        if (err)
-               goto out_dput;
+               goto out_unlock;

        if (!overwrite && ovl_type_merge_or_lower(new))
                err = ovl_set_redirect(new, samedir);
@@ -1244,15 +1248,16 @@ static int ovl_rename(struct mnt_idmap *idmap,
struct inode *olddir,
                 ovl_type_merge(old->d_parent))
                err = ovl_set_opaque_xerr(new, newdentry, -EXDEV);
        if (err)
-               goto out_dput;
+               goto out_unlock;

        err = ovl_do_rename(ofs, old_upperdir->d_inode, olddentry,
                            new_upperdir->d_inode, newdentry, flags);
        if (err)
-               goto out_dput;
+               goto out_unlock;
+       unlock_rename(new_upperdir, old_upperdir);

        if (cleanup_whiteout)
-               ovl_cleanup(ofs, old_upperdir->d_inode, newdentry);
+               ovl_cleanup_unlocked(ofs, old_upperdir->d_inode, newdentry);

        if (overwrite && d_inode(new)) {
                if (new_is_dir)
@@ -1271,12 +1276,6 @@ static int ovl_rename(struct mnt_idmap *idmap,
struct inode *olddir,
        if (d_inode(new) && ovl_dentry_upper(new))
                ovl_copyattr(d_inode(new));

-out_dput:
-       dput(newdentry);
-out_dput_old:
-       dput(olddentry);
-out_unlock:
-       unlock_rename(new_upperdir, old_upperdir);
 out_revert_creds:
        ovl_revert_creds(old_cred);
        if (update_nlink)
@@ -1284,9 +1283,15 @@ static int ovl_rename(struct mnt_idmap *idmap,
struct inode *olddir,
        else
                ovl_drop_write(old);
 out:
+       dput(newdentry);
+       dput(olddentry);
        dput(opaquedir);
        ovl_cache_free(&list);
        return err;
+
+out_unlock:
+       unlock_rename(new_upperdir, old_upperdir);
+       goto out_revert_creds;
 }





[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux