[PATCH] overlay: hardlink all whiteout files into a single whiteout

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

 



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.

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



[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