Re: [PATCH v2 1/3] ovl: reorder ovl_want_write() after ovl_inode_lock()

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

 



On Tue, Aug 15, 2023 at 1:50 PM Miklos Szeredi <miklos@xxxxxxxxxx> wrote:
>
> On Mon, 14 Aug 2023 at 16:05, Amir Goldstein <amir73il@xxxxxxxxx> wrote:
> >
> > Make the locking order of ovl_inode_lock() strictly between the two
> > vfs stacked layers, i.e.:
> > - ovl vfs locks: sb_writers, inode_lock, ...
> > - ovl_inode_lock
> > - upper vfs locks: sb_writers, inode_lock, ...
> >
> > To that effect, move ovl_want_write() into the helpers ovl_nlink_start()
> > and ovl_copy_up_one() which currently take the ovl_inode_lock() after
> > ovl_want_write().
> >
> > Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
> > ---
> >  fs/overlayfs/copy_up.c | 36 ++++++++++-----------
> >  fs/overlayfs/dir.c     | 71 ++++++++++++++++++------------------------
> >  fs/overlayfs/export.c  |  7 +----
> >  fs/overlayfs/inode.c   | 56 ++++++++++++++++-----------------
> >  fs/overlayfs/util.c    |  7 +++++
> >  5 files changed, 83 insertions(+), 94 deletions(-)
> >
> > diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
> > index bae404a1bad4..c998dab440f8 100644
> > --- a/fs/overlayfs/copy_up.c
> > +++ b/fs/overlayfs/copy_up.c
> > @@ -1085,15 +1085,22 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
> >         if (unlikely(err)) {
> >                 if (err > 0)
> >                         err = 0;
> > -       } else {
> > -               if (!ovl_dentry_upper(dentry))
> > -                       err = ovl_do_copy_up(&ctx);
> > -               if (!err && parent && !ovl_dentry_has_upper_alias(dentry))
> > -                       err = ovl_link_up(&ctx);
> > -               if (!err && ovl_dentry_needs_data_copy_up_locked(dentry, flags))
> > -                       err = ovl_copy_up_meta_inode_data(&ctx);
> > -               ovl_copy_up_end(dentry);
> > +               goto out;
> >         }
> > +
> > +       err = ovl_want_write(dentry);
> > +       if (err)
> > +               goto out;
>
> Needs ovl_copy_up_end.

Right. though those lines are removed in the next patch..

>
> > +
> > +       if (!ovl_dentry_upper(dentry))
> > +               err = ovl_do_copy_up(&ctx);
> > +       if (!err && parent && !ovl_dentry_has_upper_alias(dentry))
> > +               err = ovl_link_up(&ctx);
> > +       if (!err && ovl_dentry_needs_data_copy_up_locked(dentry, flags))
> > +               err = ovl_copy_up_meta_inode_data(&ctx);
> > +       ovl_drop_write(dentry);
> > +       ovl_copy_up_end(dentry);
> > +out:
> >         do_delayed_call(&done);
> >
> >         return err;
> > @@ -1169,17 +1176,10 @@ static bool ovl_open_need_copy_up(struct dentry *dentry, int flags)
> >
> >  int ovl_maybe_copy_up(struct dentry *dentry, int flags)
> >  {
> > -       int err = 0;
> > -
> > -       if (ovl_open_need_copy_up(dentry, flags)) {
> > -               err = ovl_want_write(dentry);
> > -               if (!err) {
> > -                       err = ovl_copy_up_flags(dentry, flags);
> > -                       ovl_drop_write(dentry);
> > -               }
> > -       }
> > +       if (!ovl_open_need_copy_up(dentry, flags))
> > +               return 0;
> >
> > -       return err;
> > +       return ovl_copy_up_flags(dentry, flags);
> >  }
> >
> >  int ovl_copy_up_with_data(struct dentry *dentry)
> > diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
> > index 033fc0458a3d..f01031fe7b97 100644
> > --- a/fs/overlayfs/dir.c
> > +++ b/fs/overlayfs/dir.c
> > @@ -559,10 +559,6 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
> >         struct cred *override_cred;
> >         struct dentry *parent = dentry->d_parent;
> >
> > -       err = ovl_copy_up(parent);
> > -       if (err)
> > -               return err;
> > -
> >         old_cred = ovl_override_creds(dentry->d_sb);
> >
> >         /*
> > @@ -626,15 +622,11 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
> >                 .link = link,
> >         };
> >
> > -       err = ovl_want_write(dentry);
> > -       if (err)
> > -               goto out;
> > -
> >         /* Preallocate inode to be used by ovl_get_inode() */
> >         err = -ENOMEM;
> >         inode = ovl_new_inode(dentry->d_sb, mode, rdev);
> >         if (!inode)
> > -               goto out_drop_write;
> > +               goto out;
> >
> >         spin_lock(&inode->i_lock);
> >         inode->i_state |= I_CREATING;
> > @@ -643,12 +635,19 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
> >         inode_init_owner(&nop_mnt_idmap, inode, dentry->d_parent->d_inode, mode);
> >         attr.mode = inode->i_mode;
> >
> > +       err = ovl_copy_up(dentry->d_parent);
> > +       if (err)
> > +               return err;
>
> Needs iput().
>
> > +
> > +       err = ovl_want_write(dentry);
> > +       if (err)
> > +               goto out;
>
> This as well.
>
> Also I don't understand the reason behind moving ovl_want_write().
> I'd just put the copy_up(dentry->parent) above ovl_mnt_write().
>

You're right. not sure why I did that.

> > +
> >         err = ovl_create_or_link(dentry, inode, &attr, false);
> >         /* Did we end up using the preallocated inode? */
> >         if (inode != d_inode(dentry))
> >                 iput(inode);
> >
> > -out_drop_write:
> >         ovl_drop_write(dentry);
> >  out:
> >         return err;
> > @@ -700,28 +699,24 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
> >         int err;
> >         struct inode *inode;
> >
> > -       err = ovl_want_write(old);
> > +       err = ovl_copy_up(old);
> >         if (err)
> >                 goto out;
> >
> > -       err = ovl_copy_up(old);
> > +       err = ovl_copy_up(new->d_parent);
> >         if (err)
> > -               goto out_drop_write;
> > +               goto out;
> >
> > -       err = ovl_copy_up(new->d_parent);
> > +       err = ovl_nlink_start(old);
> >         if (err)
> > -               goto out_drop_write;
> > +               goto out;
> >
> >         if (ovl_is_metacopy_dentry(old)) {
> >                 err = ovl_set_link_redirect(old);
> >                 if (err)
> > -                       goto out_drop_write;
> > +                       goto out_nlink_end;
> >         }
> >
> > -       err = ovl_nlink_start(old);
> > -       if (err)
> > -               goto out_drop_write;
> > -
> >         inode = d_inode(old);
> >         ihold(inode);
> >
> > @@ -731,9 +726,8 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
> >         if (err)
> >                 iput(inode);
> >
> > +out_nlink_end:
> >         ovl_nlink_end(old);
> > -out_drop_write:
> > -       ovl_drop_write(old);
> >  out:
> >         return err;
> >  }
> > @@ -891,17 +885,13 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
> >                         goto out;
> >         }
> >
> > -       err = ovl_want_write(dentry);
> > -       if (err)
> > -               goto out;
> > -
> >         err = ovl_copy_up(dentry->d_parent);
> >         if (err)
> > -               goto out_drop_write;
> > +               goto out;
> >
> >         err = ovl_nlink_start(dentry);
> >         if (err)
> > -               goto out_drop_write;
> > +               goto out;
> >
> >         old_cred = ovl_override_creds(dentry->d_sb);
> >         if (!lower_positive)
> > @@ -926,8 +916,6 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
> >         if (ovl_dentry_upper(dentry))
> >                 ovl_copyattr(d_inode(dentry));
> >
> > -out_drop_write:
> > -       ovl_drop_write(dentry);
> >  out:
> >         ovl_cache_free(&list);
> >         return err;
> > @@ -1131,29 +1119,32 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
> >                 }
> >         }
> >
> > -       err = ovl_want_write(old);
> > -       if (err)
> > -               goto out;
> > -
> >         err = ovl_copy_up(old);
> >         if (err)
> > -               goto out_drop_write;
> > +               goto out;
> >
> >         err = ovl_copy_up(new->d_parent);
> >         if (err)
> > -               goto out_drop_write;
> > +               goto out;
> >         if (!overwrite) {
> >                 err = ovl_copy_up(new);
> >                 if (err)
> > -                       goto out_drop_write;
> > +                       goto out;
> >         } else if (d_inode(new)) {
> >                 err = ovl_nlink_start(new);
> >                 if (err)
> > -                       goto out_drop_write;
> > +                       goto out;
> >
> >                 update_nlink = true;
> >         }
> >
> > +       if (!update_nlink) {
> > +               /* ovl_nlink_start() took ovl_want_write() */
> > +               err = ovl_want_write(old);
> > +               if (err)
> > +                       goto out;
> > +       }
> > +
> >         old_cred = ovl_override_creds(old->d_sb);
> >
> >         if (!list_empty(&list)) {
> > @@ -1286,8 +1277,8 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
> >         revert_creds(old_cred);
> >         if (update_nlink)
> >                 ovl_nlink_end(new);
> > -out_drop_write:
> > -       ovl_drop_write(old);
> > +       else
> > +               ovl_drop_write(old);
> >  out:
> >         dput(opaquedir);
> >         ovl_cache_free(&list);
> > diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
> > index c8c8588bd98c..4a79c479c971 100644
> > --- a/fs/overlayfs/export.c
> > +++ b/fs/overlayfs/export.c
> > @@ -23,12 +23,7 @@ static int ovl_encode_maybe_copy_up(struct dentry *dentry)
> >         if (ovl_dentry_upper(dentry))
> >                 return 0;
> >
> > -       err = ovl_want_write(dentry);
> > -       if (!err) {
> > -               err = ovl_copy_up(dentry);
> > -               ovl_drop_write(dentry);
> > -       }
> > -
> > +       err = ovl_copy_up(dentry);
> >         if (err) {
> >                 pr_warn_ratelimited("failed to copy up on encode (%pd2, err=%i)\n",
> >                                     dentry, err);
> > diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
> > index b395cd84bfce..f5638cfe8f6d 100644
> > --- a/fs/overlayfs/inode.c
> > +++ b/fs/overlayfs/inode.c
> > @@ -32,10 +32,6 @@ int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> >         if (err)
> >                 return err;
> >
> > -       err = ovl_want_write(dentry);
> > -       if (err)
> > -               goto out;
> > -
> >         if (attr->ia_valid & ATTR_SIZE) {
> >                 /* Truncate should trigger data copy up as well */
> >                 full_copy_up = true;
> > @@ -54,7 +50,7 @@ int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> >                         winode = d_inode(upperdentry);
> >                         err = get_write_access(winode);
> >                         if (err)
> > -                               goto out_drop_write;
> > +                               goto out;
> >                 }
> >
> >                 if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
> > @@ -78,6 +74,10 @@ int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> >                  */
> >                 attr->ia_valid &= ~ATTR_OPEN;
> >
> > +               err = ovl_want_write(dentry);
> > +               if (err)
> > +                       goto out;
>
> Need to put write access.
>

ok.

> > +
> >                 inode_lock(upperdentry->d_inode);
> >                 old_cred = ovl_override_creds(dentry->d_sb);
> >                 err = ovl_do_notify_change(ofs, upperdentry, attr);
> > @@ -85,12 +85,11 @@ int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> >                 if (!err)
> >                         ovl_copyattr(dentry->d_inode);
> >                 inode_unlock(upperdentry->d_inode);
> > +               ovl_drop_write(dentry);
> >
> >                 if (winode)
> >                         put_write_access(winode);
> >         }
> > -out_drop_write:
> > -       ovl_drop_write(dentry);
> >  out:
> >         return err;
> >  }
> > @@ -361,27 +360,27 @@ int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
> >         struct path realpath;
> >         const struct cred *old_cred;
> >
> > -       err = ovl_want_write(dentry);
> > -       if (err)
> > -               goto out;
> > -
> >         if (!value && !upperdentry) {
> >                 ovl_path_lower(dentry, &realpath);
> >                 old_cred = ovl_override_creds(dentry->d_sb);
> >                 err = vfs_getxattr(mnt_idmap(realpath.mnt), realdentry, name, NULL, 0);
> >                 revert_creds(old_cred);
> >                 if (err < 0)
> > -                       goto out_drop_write;
> > +                       goto out;
> >         }
> >
> >         if (!upperdentry) {
> >                 err = ovl_copy_up(dentry);
> >                 if (err)
> > -                       goto out_drop_write;
> > +                       goto out;
> >
> >                 realdentry = ovl_dentry_upper(dentry);
> >         }
> >
> > +       err = ovl_want_write(dentry);
> > +       if (err)
> > +               goto out;
> > +
> >         old_cred = ovl_override_creds(dentry->d_sb);
> >         if (value) {
> >                 err = ovl_do_setxattr(ofs, realdentry, name, value, size,
> > @@ -391,12 +390,10 @@ int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
> >                 err = ovl_do_removexattr(ofs, realdentry, name);
> >         }
> >         revert_creds(old_cred);
> > +       ovl_drop_write(dentry);
> >
> >         /* copy c/mtime */
> >         ovl_copyattr(inode);
> > -
> > -out_drop_write:
> > -       ovl_drop_write(dentry);
> >  out:
> >         return err;
> >  }
> > @@ -611,10 +608,6 @@ static int ovl_set_or_remove_acl(struct dentry *dentry, struct inode *inode,
> >         struct dentry *upperdentry = ovl_dentry_upper(dentry);
> >         struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
> >
> > -       err = ovl_want_write(dentry);
> > -       if (err)
> > -               return err;
> > -
> >         /*
> >          * If ACL is to be removed from a lower file, check if it exists in
> >          * the first place before copying it up.
> > @@ -630,7 +623,7 @@ static int ovl_set_or_remove_acl(struct dentry *dentry, struct inode *inode,
> >                 revert_creds(old_cred);
> >                 if (IS_ERR(real_acl)) {
> >                         err = PTR_ERR(real_acl);
> > -                       goto out_drop_write;
> > +                       goto out;
> >                 }
> >                 posix_acl_release(real_acl);
> >         }
> > @@ -638,23 +631,26 @@ static int ovl_set_or_remove_acl(struct dentry *dentry, struct inode *inode,
> >         if (!upperdentry) {
> >                 err = ovl_copy_up(dentry);
> >                 if (err)
> > -                       goto out_drop_write;
> > +                       goto out;
> >
> >                 realdentry = ovl_dentry_upper(dentry);
> >         }
> >
> > +       err = ovl_want_write(dentry);
> > +       if (err)
> > +               goto out;
> > +
> >         old_cred = ovl_override_creds(dentry->d_sb);
> >         if (acl)
> >                 err = ovl_do_set_acl(ofs, realdentry, acl_name, acl);
> >         else
> >                 err = ovl_do_remove_acl(ofs, realdentry, acl_name);
> >         revert_creds(old_cred);
> > +       ovl_drop_write(dentry);
> >
> >         /* copy c/mtime */
> >         ovl_copyattr(inode);
> > -
> > -out_drop_write:
> > -       ovl_drop_write(dentry);
> > +out:
> >         return err;
> >  }
> >
> > @@ -777,14 +773,14 @@ int ovl_fileattr_set(struct mnt_idmap *idmap,
> >         unsigned int flags;
> >         int err;
> >
> > -       err = ovl_want_write(dentry);
> > -       if (err)
> > -               goto out;
> > -
> >         err = ovl_copy_up(dentry);
> >         if (!err) {
> >                 ovl_path_real(dentry, &upperpath);
> >
> > +               err = ovl_want_write(dentry);
> > +               if (err)
> > +                       goto out;
> > +
> >                 old_cred = ovl_override_creds(inode->i_sb);
> >                 /*
> >                  * Store immutable/append-only flags in xattr and clear them
> > @@ -797,6 +793,7 @@ int ovl_fileattr_set(struct mnt_idmap *idmap,
> >                 if (!err)
> >                         err = ovl_real_fileattr_set(&upperpath, fa);
> >                 revert_creds(old_cred);
> > +               ovl_drop_write(dentry);
> >
> >                 /*
> >                  * Merge real inode flags with inode flags read from
> > @@ -811,7 +808,6 @@ int ovl_fileattr_set(struct mnt_idmap *idmap,
> >                 /* Update ctime */
> >                 ovl_copyattr(inode);
> >         }
> > -       ovl_drop_write(dentry);
> >  out:
> >         return err;
> >  }
> > diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
> > index 0f387092450e..4deed8a2a112 100644
> > --- a/fs/overlayfs/util.c
> > +++ b/fs/overlayfs/util.c
> > @@ -1062,6 +1062,10 @@ int ovl_nlink_start(struct dentry *dentry)
> >         if (err)
> >                 return err;
> >
> > +       err = ovl_want_write(dentry);
> > +       if (err)
> > +               goto out;
>
> Need to unlock.

goto out does unlock, but I will make this more explicit
with out_unlock label.

>
>
> > +
> >         if (d_is_dir(dentry) || !ovl_test_flag(OVL_INDEX, inode))
> >                 goto out;
>
> Need to drop write.

This one is not an error case, it is a success and it returns with
both inode lock and sb write held, so it can just be return 0;

>
> >
> > @@ -1074,6 +1078,8 @@ int ovl_nlink_start(struct dentry *dentry)
> >          */
> >         err = ovl_set_nlink_upper(dentry);
> >         revert_creds(old_cred);
> > +       if (err)
> > +               ovl_drop_write(dentry);
> >
> >  out:
> >         if (err)
>
> I'd just separate out error handling into separate labels.
>

OK.

I hope the two other patches have less mistakes :-/

Thanks,
Amir.




[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