Re: [PATCH v2] ovl: sharing inode with different whiteout files

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

 



 ---- 在 星期五, 2020-04-03 17:18:06 Amir Goldstein <amir73il@xxxxxxxxx> 撰写 ----
 > On Fri, Apr 3, 2020 at 9:45 AM Chengguang Xu <cgxu519@xxxxxxxxxxxx> wrote:
 > >
 > > Sharing inode with different whiteout files for saving
 > > inode and speeding up delete operation.
 > >
 > > Signed-off-by: Chengguang Xu <cgxu519@xxxxxxxxxxxx>
 > 
 > A few more nits.
 > Please wait with v3 until I fix my patches, so you can test in top of
 > them.
 > Please run the overlay xfstests to test your patch.
 > 
 > I suspect this part of test overlay/031 will fail and will need to fix
 > the test to expect at most single whiteout 'residue' in work dir:
 > 
 > # try to remove test dir from overlay dir, trigger ovl_remove_and_whiteout,
 > # it will not clean up the dir and lead to residue.
 > rm -rf $SCRATCH_MNT/testdir 2>&1 | _filter_scratch
 > ls $workdir/work

It seems no effect to current test case, I passed all test cases in overlay dir
except nfs_export and mmap related cases.

 
 > 
 > And you should start writing a test.
 > I suggest setting /sys/module/overlay/parameters/whiteout_link_max to 2
 > (test should _not_run if param does not exist)
 > removing a bunch of files and verify after unmount that:
 > - whiteouts have nlink 2
 > - there is no more than single residue whiteout in work dir
 > 

I‘ll do.

 > > ---
 > >  fs/overlayfs/dir.c       | 50 ++++++++++++++++++++++++++++++++--------
 > >  fs/overlayfs/overlayfs.h | 11 +++++++--
 > >  fs/overlayfs/ovl_entry.h |  4 ++++
 > >  fs/overlayfs/readdir.c   |  3 ++-
 > >  fs/overlayfs/super.c     | 10 ++++++++
 > >  fs/overlayfs/util.c      |  3 ++-
 > >  6 files changed, 68 insertions(+), 13 deletions(-)
 > >
 > > diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
 > > index 279009dee366..e48ba7de1bcb 100644
 > > --- a/fs/overlayfs/dir.c
 > > +++ b/fs/overlayfs/dir.c
 > > @@ -62,35 +62,66 @@ 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 same = true;
 > 
 > 'same' is not the best name, but I expect you won't need it anyway.
 > I would replace this with:
 > bool should_link = (ofs->whiteout_link_max > 1);

I'll fix in V3.

 > 
 > > +       bool again = true;
 > >         struct dentry *whiteout;
 > >         struct inode *wdir = workdir->d_inode;
 > >
 > > +       if (ofs->workdir != workdir)
 > > +               same = false;
 > > +retry:
 > >         whiteout = ovl_lookup_temp(workdir);
 > >         if (IS_ERR(whiteout))
 > >                 return whiteout;
 > >
 > > +       if (same && ofs->whiteout) {
 > > +               if (ovl_whiteout_linkable(ofs, workdir, ofs->whiteout)) {
 > > +                       err = ovl_do_link(ofs->whiteout, wdir, whiteout);
 > > +                       if (!err)
 > > +                               return whiteout;
 > > +
 > > +                       if (!again)
 > > +                               goto out;
 > > +               }
 > > +
 > 
 > We actually need to also cleanup this whiteout:
 > 

I slightly changed the logic here and in this case it will be work just like before.

 > ovl_cleanup(wdir, ofs->whiteout);
 > 
 > > +               dput(ofs->whiteout);
 > > +               ofs->whiteout = NULL;
 > > +       }
 > > +
 > >         err = ovl_do_whiteout(wdir, whiteout);
 > > -       if (err) {
 > > -               dput(whiteout);
 > > -               whiteout = ERR_PTR(err);
 > > +       if (!err) {
 > 
 > save the nesting:
 > if (err)
 >     goto out;
 > 

I'll fix in V3.

 > > +               if (!same || ofs->whiteout_link_max == 1)
 > > +                       return whiteout;
 > > +
 > > +               if (!again) {
 > > +                       WARN_ON_ONCE(1);
 > 
 > Definitely no WARN on this case.
 > We can consider setting whiteout_link_max to 0 and pr_warn()
 > about auto disabling whiteout linking due to unexpected failure.
 > 

I'll fix in V3.

 > > +                       return whiteout;
 > > +               }
 > > +
 > > +               dget(whiteout);
 > > +               ofs->whiteout = whiteout;
 > 
 > Shorter:
 >                ofs->whiteout = dget(whiteout);
 > 

Here, we don't need to grab the dentry again, I think we have already got
the reference in lookup.


 > > +               again = false;
 > > +               goto retry;
 > >         }
 > >
 > > -       return whiteout;
 > > +out:
 > > +       dput(whiteout);
 > > +       return ERR_PTR(err);
 > >  }
 > >
 > >  /* Caller must hold i_mutex on both workdir and dir */
 > > -int ovl_cleanup_and_whiteout(struct dentry *workdir, struct inode *dir,
 > > -                            struct dentry *dentry)
 > > +int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct dentry *workdir,
 > > +                            struct inode *dir, struct dentry *dentry)
 > >  {
 > >         struct inode *wdir = workdir->d_inode;
 > >         struct dentry *whiteout;
 > >         int err;
 > >         int flags = 0;
 > >
 > > -       whiteout = ovl_whiteout(workdir);
 > > +       whiteout = ovl_whiteout(ofs, workdir);
 > >         err = PTR_ERR(whiteout);
 > >         if (IS_ERR(whiteout))
 > >                 return err;
 > > @@ -715,6 +746,7 @@ static bool ovl_matches_upper(struct dentry *dentry, struct dentry *upper)
 > >  static int ovl_remove_and_whiteout(struct dentry *dentry,
 > >                                    struct list_head *list)
 > >  {
 > > +       struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
 > >         struct dentry *workdir = ovl_workdir(dentry);
 > >         struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
 > >         struct dentry *upper;
 > > @@ -748,7 +780,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
 > >                 goto out_dput_upper;
 > >         }
 > >
 > > -       err = ovl_cleanup_and_whiteout(workdir, d_inode(upperdir), upper);
 > > +       err = ovl_cleanup_and_whiteout(ofs, workdir, d_inode(upperdir), upper);
 > >         if (err)
 > >                 goto out_d_drop;
 > >
 > > diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
 > > index e6f3670146ed..cc7bcc3fb916 100644
 > > --- a/fs/overlayfs/overlayfs.h
 > > +++ b/fs/overlayfs/overlayfs.h
 > > @@ -225,6 +225,13 @@ static inline bool ovl_open_flags_need_copy_up(int flags)
 > >         return ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC));
 > >  }
 > >
 > > +static inline bool ovl_whiteout_linkable(struct ovl_fs *ofs,
 > > +                                        struct dentry *workdir,
 > 
 > workdir unused.

I'll fix in V3.

 > 
 > > +                                        struct dentry *dentry)
 > > +{
 > > +       return dentry->d_inode->i_nlink < ofs->whiteout_link_max;
 > > +}
 > > +
 > >  /* util.c */
 > >  int ovl_want_write(struct dentry *dentry);
 > >  void ovl_drop_write(struct dentry *dentry);
 > > @@ -455,8 +462,8 @@ static inline void ovl_copyflags(struct inode *from, struct inode *to)
 > >
 > >  /* dir.c */
 > >  extern const struct inode_operations ovl_dir_inode_operations;
 > > -int ovl_cleanup_and_whiteout(struct dentry *workdir, struct inode *dir,
 > > -                            struct dentry *dentry);
 > > +int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct dentry *workdir,
 > > +                            struct inode *dir, struct dentry *dentry);
 > >  struct ovl_cattr {
 > >         dev_t rdev;
 > >         umode_t mode;
 > > diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
 > > index 5762d802fe01..de5f230b6e6b 100644
 > > --- a/fs/overlayfs/ovl_entry.h
 > > +++ b/fs/overlayfs/ovl_entry.h
 > > @@ -77,6 +77,10 @@ struct ovl_fs {
 > >         int xino_mode;
 > >         /* For allocation of non-persistent inode numbers */
 > >         atomic_long_t last_ino;
 > > +       /* Whiteout dentry cache */
 > > +       struct dentry *whiteout;
 > > +       /* Whiteout max link count */
 > > +       unsigned int whiteout_link_max;
 > >  };
 > >
 > >  static inline struct ovl_fs *OVL_FS(struct super_block *sb)
 > > diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
 > > index e452ff7d583d..1e921115e6aa 100644
 > > --- a/fs/overlayfs/readdir.c
 > > +++ b/fs/overlayfs/readdir.c
 > > @@ -1146,7 +1146,8 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
 > >                          * Whiteout orphan index to block future open by
 > >                          * handle after overlay nlink dropped to zero.
 > >                          */
 > > -                       err = ovl_cleanup_and_whiteout(indexdir, dir, index);
 > > +                       err = ovl_cleanup_and_whiteout(ofs, indexdir, dir,
 > > +                                                      index);
 > >                 } else {
 > >                         /* Cleanup orphan index entries */
 > >                         err = ovl_cleanup(dir, index);
 > > diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
 > > index 732ad5495c92..340c4c05c410 100644
 > > --- a/fs/overlayfs/super.c
 > > +++ b/fs/overlayfs/super.c
 > > @@ -26,6 +26,10 @@ struct ovl_dir_cache;
 > >
 > >  #define OVL_MAX_STACK 500
 > >
 > > +static unsigned int ovl_whiteout_link_max_def = 60000;
 > > +module_param_named(whiteout_link_max, ovl_whiteout_link_max_def, uint, 0644);
 > > +MODULE_PARM_DESC(whiteout_link_max, "Maximum count of whiteout file link");
 > > +
 > >  static bool ovl_redirect_dir_def = IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_DIR);
 > >  module_param_named(redirect_dir, ovl_redirect_dir_def, bool, 0644);
 > >  MODULE_PARM_DESC(redirect_dir,
 > > @@ -219,6 +223,7 @@ static void ovl_free_fs(struct ovl_fs *ofs)
 > >         iput(ofs->upperdir_trap);
 > >         dput(ofs->indexdir);
 > >         dput(ofs->workdir);
 > > +       dput(ofs->whiteout);
 > >         if (ofs->workdir_locked)
 > >                 ovl_inuse_unlock(ofs->workbasedir);
 > >         dput(ofs->workbasedir);
 > > @@ -1762,6 +1767,11 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 > >
 > >                 if (!ofs->workdir)
 > >                         sb->s_flags |= SB_RDONLY;
 > > +               else
 > > +                       ofs->whiteout_link_max = min_not_zero(
 > > +                                       ofs->workdir->d_sb->s_max_links,
 > > +                                       ovl_whiteout_link_max_def ?
 > > +                                       ovl_whiteout_link_max_def : 1);
 > >
 > 
 > ovl_whiteout_link_max_def ?: 1);

I'll fix in V3.

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