[PATCH 1/2] overlayfs: optimize empty dir removal

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

 



From: Miklos Szeredi <mszeredi@xxxxxxx>

Previously the victim directory of rmdir and rename was read twice,
first to check if empty, and second to remove all whiteouts.  The
second reading is unnecessary, the list of whiteouts is already
available from the first reading.

Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxx>
---
 fs/overlayfs/overlayfs.c |   96 ++++++++++++++++++-----------------------------
 1 file changed, 37 insertions(+), 59 deletions(-)

Index: linux-2.6/fs/overlayfs/overlayfs.c
===================================================================
--- linux-2.6.orig/fs/overlayfs/overlayfs.c	2011-03-18 15:07:07.000000000 +0100
+++ linux-2.6/fs/overlayfs/overlayfs.c	2011-03-18 15:07:34.000000000 +0100
@@ -1656,14 +1656,13 @@ static int ovl_unlink(struct inode *dir,
 	return ovl_do_remove(dentry, false);
 }
 
-static int ovl_check_empty_dir(struct dentry *dentry)
+static int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
 {
 	int err;
 	struct path lowerpath;
 	struct path upperpath;
 	struct ovl_cache_entry *p;
-	LIST_HEAD(list);
-	struct ovl_readdir_data rdd = { .list = &list };
+	struct ovl_readdir_data rdd = { .list = list };
 
 	ovl_path_upper(dentry, &upperpath);
 	ovl_path_lower(dentry, &lowerpath);
@@ -1674,7 +1673,7 @@ static int ovl_check_empty_dir(struct de
 
 	err = 0;
 
-	list_for_each_entry(p, &list, l_node) {
+	list_for_each_entry(p, list, l_node) {
 		if (p->is_whiteout)
 			continue;
 
@@ -1688,64 +1687,55 @@ static int ovl_check_empty_dir(struct de
 		break;
 	}
 
-	ovl_cache_free(&list);
-
 	return err;
 }
 
-static int ovl_fill_links(void *buf, const char *name, int namelen,
-			  loff_t offset, u64 ino, unsigned int d_type)
-{
-	struct ovl_readdir_data *rdd = buf;
-	struct ovl_cache_entry *p;
-
-	rdd->count++;
-	if (d_type != DT_LNK)
-		return 0;
-
-	p = ovl_cache_entry_new(name, namelen, ino, d_type);
-	if (!p)
-		return -ENOMEM;
-
-	list_add(&p->l_node, rdd->list);
-	return 0;
-}
-
-static int ovl_remove_whiteouts(struct dentry *dentry)
+static int ovl_remove_whiteouts(struct dentry *dir, struct list_head *list)
 {
 	struct path upperpath;
-	LIST_HEAD(list);
-	struct ovl_readdir_data rdd = {	.list = &list };
-	struct ovl_cache_entry *p, *t;
-	int ret;
-
-	ovl_path_upper(dentry, &upperpath);
-	rdd.dir = upperpath.dentry;
+	struct dentry *upperdir;
+	struct ovl_cache_entry *p;
+	int ret = 0;
 
-	ret = ovl_dir_read(&upperpath, &rdd, ovl_fill_links);
+	ovl_path_upper(dir, &upperpath);
+	upperdir = upperpath.dentry;
 
-	mutex_lock(&rdd.dir->d_inode->i_mutex);
-	list_for_each_entry_safe(p, t, &list, l_node) {
-		struct dentry *dentry;
+	mutex_lock(&upperdir->d_inode->i_mutex);
+	list_for_each_entry(p, list, l_node) {
+		if (p->is_whiteout) {
+			struct dentry *dentry;
 
-		if (!ret) {
-			dentry = lookup_one_len(p->name, rdd.dir, p->len);
+			dentry = lookup_one_len(p->name, upperdir, p->len);
 			if (IS_ERR(dentry)) {
 				ret = PTR_ERR(dentry);
-			} else {
-				ret = vfs_unlink(rdd.dir->d_inode, dentry);
-				dput(dentry);
+				break;
 			}
+			ret = vfs_unlink(upperdir->d_inode, dentry);
+			dput(dentry);
+			if (ret)
+				break;
 		}
-
-		list_del(&p->l_node);
-		kfree(p);
 	}
-	mutex_unlock(&rdd.dir->d_inode->i_mutex);
+	mutex_unlock(&upperdir->d_inode->i_mutex);
 
 	return ret;
 }
 
+static int ovl_check_empty_and_clear(struct dentry *dentry,
+				     enum ovl_path_type type)
+{
+	int err;
+	LIST_HEAD(list);
+
+	err = ovl_check_empty_dir(dentry, &list);
+	if (!err && type == OVL_PATH_MERGE)
+		err = ovl_remove_whiteouts(dentry, &list);
+
+	ovl_cache_free(&list);
+
+	return err;
+}
+
 static int ovl_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	int err;
@@ -1753,15 +1743,9 @@ static int ovl_rmdir(struct inode *dir,
 
 	type = ovl_path_type(dentry);
 	if (type != OVL_PATH_UPPER) {
-		err = ovl_check_empty_dir(dentry);
+		err = ovl_check_empty_and_clear(dentry, type);
 		if (err)
 			return err;
-
-		if (type == OVL_PATH_MERGE) {
-			err = ovl_remove_whiteouts(dentry);
-			if (err)
-				return err;
-		}
 	}
 
 	return ovl_do_remove(dentry, true);
@@ -1843,15 +1827,9 @@ static int ovl_rename(struct inode *oldd
 
 		if (new_type != OVL_PATH_UPPER &&
 		    S_ISDIR(new->d_inode->i_mode)) {
-			err = ovl_check_empty_dir(new);
+			err = ovl_check_empty_and_clear(new, new_type);
 			if (err)
 				return err;
-
-			if (new_type == OVL_PATH_MERGE) {
-				err = ovl_remove_whiteouts(new);
-				if (err)
-					return err;
-			}
 		}
 	}
 
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux