Re: [PATCH v3] ovl: whiteout inode sharing

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

 



 ---- 在 星期三, 2020-04-15 16:12:04 Amir Goldstein <amir73il@xxxxxxxxx> 撰写 ----
 > On Wed, Apr 15, 2020 at 11:01 AM Chengguang Xu <cgxu519@xxxxxxxxxxxx> wrote:
 > >
 > >  ---- 在 星期三, 2020-04-15 15:03:09 Amir Goldstein <amir73il@xxxxxxxxx> 撰写 ----
 > >  > On Wed, Apr 15, 2020 at 4:03 AM Chengguang Xu <cgxu519@xxxxxxxxxxxx> wrote:
 > >  > >
 > >  > >  ---- 在 星期二, 2020-04-14 21:44:39 Amir Goldstein <amir73il@xxxxxxxxx> 撰写 ----
 > >  > >  > On Tue, Apr 14, 2020 at 12:53 PM Chengguang Xu <cgxu519@xxxxxxxxxxxx> wrote:
 > >  > >  > >
 > >  > >  > > Sharing inode with different whiteout files for saving
 > >  > >  > > inode and speeding up deleting operation.
 > >  > >  > >
 > >  > >  > > Signed-off-by: Chengguang Xu <cgxu519@xxxxxxxxxxxx>
 > >  > >  > > ---
 > >  > >  > > v1->v2:
 > >  > >  > > - Address Amir's comments in v1
 > >  > >  > >
 > >  > >  > > v2->v3:
 > >  > >  > > - Address Amir's comments in v2
 > >  > >  > > - Rebase on Amir's "Overlayfs use index dir as work dir" patch set
 > >  > >  > > - Keep at most one whiteout tmpfile in work dir
 > >  > >  > >
 > >  > >  > >  fs/overlayfs/dir.c       | 35 ++++++++++++++++++++++++++++-------
 > >  > >  > >  fs/overlayfs/overlayfs.h |  9 +++++++--
 > >  > >  > >  fs/overlayfs/ovl_entry.h |  4 ++++
 > >  > >  > >  fs/overlayfs/readdir.c   |  3 ++-
 > >  > >  > >  fs/overlayfs/super.c     |  9 +++++++++
 > >  > >  > >  fs/overlayfs/util.c      |  3 ++-
 > >  > >  > >  6 files changed, 52 insertions(+), 11 deletions(-)
 > >  > >  > >
 > >  > >  > > diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
 > >  > >  > > index 279009dee366..dbe5e54dcb16 100644
 > >  > >  > > --- a/fs/overlayfs/dir.c
 > >  > >  > > +++ b/fs/overlayfs/dir.c
 > >  > >  > > @@ -62,35 +62,55 @@ struct dentry *ovl_lookup_temp(struct dentry *workdir)
 > >  > >  > >  }
 > >  > >  > >
 > >  > >  > >  /* caller holds i_mutex on workdir */
 > >  > >  > > -static struct dentry *ovl_whiteout(struct dentry *workdir)
 > >  > >  > > +static struct dentry *ovl_whiteout(struct ovl_fs *ofs, struct dentry *workdir)
 > >  > >  > >  {
 > >  > >  > >         int err;
 > >  > >  > > +       bool retried = false;
 > >  > >  > > +       bool should_link = (ofs->whiteout_link_max > 1);
 > >  > >  > >         struct dentry *whiteout;
 > >  > >  > >         struct inode *wdir = workdir->d_inode;
 > >  > >  > >
 > >  > >  > > +retry:
 > >  > >  > >         whiteout = ovl_lookup_temp(workdir);
 > >  > >  > >         if (IS_ERR(whiteout))
 > >  > >  > >                 return whiteout;
 > >  > >  > >
 > >  > >  > > +       if (should_link && ofs->whiteout) {
 > >  > >  >
 > >  > >  > What happens with ofs->whiteout_link_max == 2 is that half of the
 > >  > >  > times, whiteout gets linked and then unlinked.
 > >  > >  > That is not needed.
 > >  > >  > I think code would look better like this:
 > >  > >  >
 > >  > >  >           if (ovl_whiteout_linkable(ofs)) {
 > >  > >  >                   err = ovl_do_link(ofs->whiteout, wdir, whiteout);
 > >  > >  > ...
 > >  > >  >           } else if (ofs->whiteout) {
 > >  > >  >                   ovl_cleanup(wdir, ofs->whiteout);
 > >  > >  > ....
 > >  > >  >
 > >  > >  > With:
 > >  > >  >
 > >  > >  > static inline bool ovl_whiteout_linkable(struct ovl_fs *ofs)
 > >  > >  > {
 > >  > >  >        return ofs->whiteout &&
 > >  > >  >                  ofs->whiteout->d_inode->i_nlink < ofs->whiteout_link_max;
 > >  > >  > }
 > >  > >  >
 > >  > >
 > >  > > tmpfile has occupied one link, so the maximum link count of whiteout inode
 > >  > > in your code will be ofs->whiteout_link_max - 1, right?
 > >  > >
 > >  >
 > >  > Right, but I wrote wrong pseudo code to use this helper.
 > >  > The intention is that ovl_whiteout_linkable(ofs) means there is a tmp whiteout
 > >  > and it may be linked to a new tmp whiteout.
 > >  > The only reason to cleanup tmp whiteout is if link has unexpectedly failed and
 > >  > in this case I think we should disable whiteout sharing.
 > >  >
 > >  > Let me try again:
 > >  >
 > >  > +       err = -EMLINK;
 > >  > +       if (ovl_whiteout_linkable(ofs)) {
 > >  > +               err = ovl_do_link(ofs->whiteout, wdir, whiteout);
 > >  > +               if (!err)
 > >  > +                       return whiteout;
 > >  > +        }
 > >  > +        if (err && ofs->whiteout) {
 > >  > +               pr_warn("failed to link whiteout - disabling whiteout
 > >  > sharing (nlink=%u, err = %i)\n",
 > >  > +                             ofs->whiteout->d_inode->i_nlink, err);
 > >  > +               ofs->whiteout_link_max = 0;
 > >  > +               should_link = false;
 > >  > +               ovl_cleanup(wdir, ofs->whiteout);
 > >  > +               dput(ofs->whiteout);
 > >  > +               ofs->whiteout = NULL;
 > >  > +       }
 > >  > +
 > >  >          err = ovl_do_whiteout(wdir, whiteout);
 > >  >
 > >  > Is that better?
 > >  >
 > >
 > > I don't fully understand why should we limit to share only one inode for whiteout files.
 > > Consider deleting a lot of files(not dir) in lowerdir, we will get -EMLINK error because
 > > the link count of shared inode exceeds the maximum link limit in underlying file system.
 > > In this case, we can choose another whiteout inode for sharing.
 > >
 > 
 > I got it wrong again. I forgot the maxed out case. Take #3:
 > 
 > +       err = 0;
 > +       if (ovl_whiteout_linkable(ofs)) {
 > +               err = ovl_do_link(ofs->whiteout, wdir, whiteout);
 > +               if (!err)
 > +                       return whiteout;
 > +        } else if (ofs->whiteout) {
 > +               dput(whiteout);
 > +               whiteout = ofs->whiteout;
 > +               ofs->whiteout = NULL;
 > +               return whiteout;
 > +        }
 > +        if (err) {
 > +               pr_warn("failed to link whiteout - disabling whiteout
 > sharing (nlink=%u, err = %i)\n",
 > +                             ofs->whiteout->d_inode->i_nlink, err);
 > +               ofs->whiteout_link_max = 0;
 > +               should_link = false;
 > +               ovl_cleanup(wdir, ofs->whiteout);
 > +       }
 > +
 >          err = ovl_do_whiteout(wdir, whiteout);
 > 
 > 
 > I hope I got the logic right this time.
 > Feel free to organize differently.
 > Disabling should be in the case where failure is not expected
 > so we want to avoid having every whiteout creation try and fail.
 > For example if filesystem reported s_max_links is incorrect.
 > 
 
In case of any unexpected errors, we could set a error limit(for example, 10),
if link error count exceeds the limit then we disable the feature.

Thanks,
cgxu 






[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