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

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

 



On Mon, Jul 14, 2025 at 3:00 AM NeilBrown <neil@xxxxxxxxxx> wrote:
>
> On Fri, 11 Jul 2025, Amir Goldstein wrote:
> > 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;
> >  }
> >
>
> I decided to make the goto changed into a separate patch as follows.

Good idea.

> My version is slightly different to yours (see new var "de").
>

Looks nicer.

Thanks,
Amir.

> Thanks,
> NeilBrown
>
> From: NeilBrown <neil@xxxxxxxxxx>
> Date: Mon, 14 Jul 2025 10:44:03 +1000
> Subject: [PATCH] ovl: simplify gotos in ovl_rename()
>
> Rather than having three separate goto label: out_unlock, out_dput_old,
> and out_dput, make use of that fact that dput() happily accepts a NULL
> point to reduce this to just one goto label: out_unlock.
>
> olddentry and newdentry are initialised to NULL and only set once a
> value dentry is found.  They are then put late in the function.
>
> Suggested-by: Amir Goldstein <amir73il@xxxxxxxxx>
> Signed-off-by: NeilBrown <neil@xxxxxxxxxx>
> ---
>  fs/overlayfs/dir.c | 54 +++++++++++++++++++++++-----------------------
>  1 file changed, 27 insertions(+), 27 deletions(-)
>
> diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
> index e094adf9d169..63460bdd71cf 100644
> --- a/fs/overlayfs/dir.c
> +++ b/fs/overlayfs/dir.c
> @@ -1082,9 +1082,9 @@ 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 *trap;
> +       struct dentry *olddentry = NULL;
> +       struct dentry *newdentry = NULL;
> +       struct dentry *trap, *de;
>         bool old_opaque;
>         bool new_opaque;
>         bool cleanup_whiteout = false;
> @@ -1197,21 +1197,23 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
>                 goto out_revert_creds;
>         }
>
> -       olddentry = ovl_lookup_upper(ofs, old->d_name.name, old_upperdir,
> -                                    old->d_name.len);
> -       err = PTR_ERR(olddentry);
> -       if (IS_ERR(olddentry))
> +       de = ovl_lookup_upper(ofs, old->d_name.name, old_upperdir,
> +                             old->d_name.len);
> +       err = PTR_ERR(de);
> +       if (IS_ERR(de))
>                 goto out_unlock;
> +       olddentry = de;
>
>         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;
> +       de = ovl_lookup_upper(ofs, new->d_name.name, new_upperdir,
> +                             new->d_name.len);
> +       err = PTR_ERR(de);
> +       if (IS_ERR(de))
> +               goto out_unlock;
> +       newdentry = de;
>
>         old_opaque = ovl_dentry_is_opaque(old);
>         new_opaque = ovl_dentry_is_opaque(new);
> @@ -1220,28 +1222,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))
> @@ -1249,7 +1251,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);
> @@ -1257,12 +1259,12 @@ 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, olddentry,
>                             new_upperdir, newdentry, flags);
>         if (err)
> -               goto out_dput;
> +               goto out_unlock;
>
>         if (cleanup_whiteout)
>                 ovl_cleanup(ofs, old_upperdir->d_inode, newdentry);
> @@ -1284,10 +1286,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:
> @@ -1297,6 +1295,8 @@ 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;
> --
> 2.49.0
>





[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux