On Thu, Jan 25, 2018 at 10:58 AM, Hou Tao <houtao1@xxxxxxxxxx> wrote: > Now each whiteout file will be assigned a new inode. To reduce the > overhead of allocating and freeing inodes in upper fs, creating a > whiteout file under workbasedir and hardlink all whiteout files into it. > > The effect is obvious: under my VM, the time used for removing the > linux kernel source tree will be reduced from 17s to 10s. > > Got the idea from autofs. Yep, this was talked about, then forgotten. Thanks for bringing it up. The implementation is a little more difficult though, because there's a limit to how many hard links to a single file are allowed. So it should be something like: - try hard linking "singleton", if succeeds then fine - else unlink old singleton from workdir, create new one and use that one If it's possible to get a filesystem as upper that doesn't support hard links at all, then that also needs to be taken care of, to fall back to non-hard linked whiteouts. Thanks, Miklos > > Signed-off-by: Hou Tao <houtao1@xxxxxxxxxx> > --- > fs/overlayfs/dir.c | 13 +++++++++++- > fs/overlayfs/ovl_entry.h | 5 +++++ > fs/overlayfs/super.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++- > 3 files changed, 68 insertions(+), 2 deletions(-) > > diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c > index f9788bc..ef02477 100644 > --- a/fs/overlayfs/dir.c > +++ b/fs/overlayfs/dir.c > @@ -62,11 +62,19 @@ struct dentry *ovl_lookup_temp(struct dentry *workdir) > return temp; > } > > +static inline struct dentry *ovl_singleton_whiteout(struct dentry *dentry) > +{ > + struct ovl_fs *ofs = dentry->d_sb->s_fs_info; > + > + return ofs->whiteout; > +} > + > /* caller holds i_mutex on workdir */ > static struct dentry *ovl_whiteout(struct dentry *workdir, > struct dentry *dentry) > { > int err; > + struct dentry *singleton = ovl_singleton_whiteout(dentry); > struct dentry *whiteout; > struct inode *wdir = workdir->d_inode; > > @@ -74,7 +82,10 @@ static struct dentry *ovl_whiteout(struct dentry *workdir, > if (IS_ERR(whiteout)) > return whiteout; > > - err = ovl_do_whiteout(wdir, whiteout); > + if (singleton) > + err = ovl_do_link(singleton, wdir, whiteout, false); > + else > + err = ovl_do_whiteout(wdir, whiteout); > if (err) { > dput(whiteout); > whiteout = ERR_PTR(err); > diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h > index 9d0bc03..c435538 100644 > --- a/fs/overlayfs/ovl_entry.h > +++ b/fs/overlayfs/ovl_entry.h > @@ -40,6 +40,11 @@ struct ovl_fs { > struct dentry *workdir; > /* index directory listing overlay inodes by origin file handle */ > struct dentry *indexdir; > + /* > + * the singleton whiteout file under workbasedir > + * all newly created whiteout files will be linked to it > + */ > + struct dentry *whiteout; > long namelen; > /* pathnames of lower and upper dirs, for show_options */ > struct ovl_config config; > diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c > index 76440fe..16a7d7f 100644 > --- a/fs/overlayfs/super.c > +++ b/fs/overlayfs/super.c > @@ -223,6 +223,7 @@ static void ovl_free_fs(struct ovl_fs *ofs) > unsigned i; > > dput(ofs->indexdir); > + dput(ofs->whiteout); > dput(ofs->workdir); > if (ofs->workdir_locked) > ovl_inuse_unlock(ofs->workbasedir); > @@ -509,6 +510,7 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) > > #define OVL_WORKDIR_NAME "work" > #define OVL_INDEXDIR_NAME "index" > +#define OVL_WHITEOUT_FILE_NAME "whiteout" > > static struct dentry *ovl_workdir_create(struct ovl_fs *ofs, > const char *name, bool persist) > @@ -1023,6 +1025,48 @@ static int ovl_get_workdir(struct ovl_fs *ofs, struct path *upperpath) > return err; > } > > +/* > + * create a new whiteout file under workbasedir if it doesn't exist. > + * If a non-whiteout file has existed, the singleton whiteout will > + * not be created. > + */ > +static int ovl_make_singleton_whiteout(struct ovl_fs *ofs, const char *name) > +{ > + int err = 0; > + struct vfsmount *mnt = ofs->upper_mnt; > + struct inode *dir = d_inode(ofs->workbasedir); > + struct dentry *whiteout; > + > + err = mnt_want_write(mnt); > + if (err) > + return err; > + > + inode_lock_nested(dir, I_MUTEX_PARENT); > + > + whiteout = lookup_one_len(name, ofs->workbasedir, strlen(name)); > + if (!IS_ERR(whiteout)) { > + if (ovl_is_whiteout(whiteout)) { > + ofs->whiteout = whiteout; > + } else if (!whiteout->d_inode) { > + err = ovl_do_whiteout(dir, whiteout); > + if (!err) > + ofs->whiteout = whiteout; > + else > + dput(whiteout); > + } else { > + dput(whiteout); > + ofs->whiteout = NULL; > + } > + } else { > + err = PTR_ERR(whiteout); > + } > + > + inode_unlock(dir); > + mnt_drop_write(mnt); > + > + return err; > +} > + > static int ovl_get_indexdir(struct ovl_fs *ofs, struct ovl_entry *oe, > struct path *upperpath) > { > @@ -1234,8 +1278,14 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) > if (err) > goto out_err; > > - if (!ofs->workdir) > + if (ofs->workdir) { > + err = ovl_make_singleton_whiteout(ofs, > + OVL_WHITEOUT_FILE_NAME); > + if (err) > + goto out_err; > + } else { > sb->s_flags |= SB_RDONLY; > + } > > sb->s_stack_depth = ofs->upper_mnt->mnt_sb->s_stack_depth; > sb->s_time_gran = ofs->upper_mnt->mnt_sb->s_time_gran; > -- > 2.9.5 > -- To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html