overlayfs patches for ovl_copy_up & ovl_rename

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

 



Hello,

Here are some comments obtained from past days testing overlayfs in Live 
systems,

- to improve copy_up performance I have redesigned the procedure,
it traverses the tree looking for the topmost lower dentry, anotating the 
concerning dentries and locking them; after, for each dentry from top to 
bottom, it copies the inodes and releases the dentry.

- a repeated line is found in overlayfs.h

- a few days ago we talked about an error when repetitive sed instructions 
were executed, also it happens in other processes, like mantaining list of 
installed files for actual packages,
that is solved in ovl_rename issuing a dget for the old-dentry and parent 
dentries. (This code is inspired on rename.c from unionfs)

Now Overlayfs is working properly on my desktop Live system, it is fast and 
reliable,

Thanks,

Jordi Pujol

Live never ending Tale
GNU/Linux Live forever!
http://livenet.selfip.com
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -315,69 +315,70 @@ out_free_link:
 	return err;
 }
 
-int ovl_copy_up(struct dentry *dentry)
+/* Optimize by not copying up the file first and truncating later */
+int ovl_copy_up_truncate(struct dentry *dentry, loff_t size)
 {
 	int err;
+	struct dentry *next;
+	struct dentry *parent;
+	struct path lowerpath;
+	struct kstat stat;
+	enum ovl_path_type type;
+	struct dentry **adentry;
+	struct dentry **adentryr;
+	int sc, st, i;
 
 	err = 0;
-	while (!err) {
-		struct dentry *next;
-		struct dentry *parent;
-		struct path lowerpath;
-		struct kstat stat;
-		enum ovl_path_type type = ovl_path_type(dentry);
-
-		if (type != OVL_PATH_LOWER)
-			break;
 
-		next = dget(dentry);
-		/* find the topmost dentry not yet copied up */
-		for (;;) {
-			parent = dget_parent(next);
-
-			type = ovl_path_type(parent);
-			if (type != OVL_PATH_LOWER)
+	/* look for dentries that are pending to copy */
+	st = 5;
+	adentry = kmalloc(st * sizeof(struct dentry *), GFP_KERNEL);
+	if (!adentry)
+		return -ENOMEM;
+
+	next = dentry;
+	for (sc = 0; ; sc++) {
+		if (sc >= st) {
+			st += 5;
+			adentryr = krealloc(adentry, st * sizeof(struct dentry *), GFP_KERNEL);
+			if (!adentryr) {
+				err = -ENOMEM;
 				break;
-
-			dput(next);
-			next = parent;
+			}
+			adentry = adentryr;
 		}
 
-		ovl_path_lower(next, &lowerpath);
-		err = vfs_getattr(lowerpath.mnt, lowerpath.dentry, &stat);
-		if (!err)
-			err = ovl_copy_up_one(parent, next, &lowerpath, &stat);
+		adentry[sc] = dget(next);
+		type = ovl_path_type(adentry[sc]);
+		if (type != OVL_PATH_LOWER) {
+			dput(adentry[sc]);
+			break;
+		}
+		next = adentry[sc]->d_parent;
+	}
 
-		dput(parent);
-		dput(next);
+	/* copy the dentries */
+	for (i = sc - 1; i >= 0; i--) {
+		if (!err) {
+			parent = dget_parent(adentry[i]);
+			ovl_path_lower(adentry[i], &lowerpath);
+			err = vfs_getattr(lowerpath.mnt, lowerpath.dentry, &stat);
+			if (!err) {
+				if (i == 0 && size >= 0 && size < stat.size)
+					stat.size = size;
+				err = ovl_copy_up_one(parent, adentry[i], &lowerpath, &stat);
+			}
+			dput(parent);
+		}
+		dput(adentry[i]);
 	}
 
+	kfree(adentry);
+
 	return err;
 }
 
-/* Optimize by not copying up the file first and truncating later */
-int ovl_copy_up_truncate(struct dentry *dentry, loff_t size)
+int ovl_copy_up(struct dentry *dentry)
 {
-	int err;
-	struct kstat stat;
-	struct path lowerpath;
-	struct dentry *parent = dget_parent(dentry);
-
-	err = ovl_copy_up(parent);
-	if (err)
-		goto out_dput_parent;
-
-	ovl_path_lower(dentry, &lowerpath);
-	err = vfs_getattr(lowerpath.mnt, lowerpath.dentry, &stat);
-	if (err)
-		goto out_dput_parent;
-
-	if (size < stat.size)
-		stat.size = size;
-
-	err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat);
-
-out_dput_parent:
-	dput(parent);
-	return err;
+	return ovl_copy_up_truncate(dentry, -1LL);
 }
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -512,12 +512,17 @@ static int ovl_rename(struct inode *oldd
 	old_upperdir = ovl_dentry_upper(old->d_parent);
 	new_upperdir = ovl_dentry_upper(new->d_parent);
 
+	(void) dget(old_upperdir);
+	(void) dget(new_upperdir);
+
 	trap = lock_rename(new_upperdir, old_upperdir);
 
 	olddentry = ovl_dentry_upper(old);
-	newdentry = ovl_dentry_upper(new);
-	if (newdentry) {
-		dget(newdentry);
+	(void) dget(olddentry);
+
+	if (!ovl_is_whiteout(new) &&
+	(newdentry = ovl_dentry_upper(new))) {
+		(void) dget(newdentry);
 	} else {
 		new_create = true;
 		newdentry = ovl_lookup_create(new_upperdir, new);
@@ -570,7 +575,13 @@ static int ovl_rename(struct inode *oldd
 out_dput:
 	dput(newdentry);
 out_unlock:
+	dput(olddentry);
+
 	unlock_rename(new_upperdir, old_upperdir);
+
+	dput(old_upperdir);
+	dput(new_upperdir);
+
 	return err;
 }
 
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -33,7 +33,6 @@
 void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
 bool ovl_is_whiteout(struct dentry *dentry);
 void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
-void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
 int ovl_do_lookup(struct dentry *dentry);
 
 struct dentry *ovl_upper_create(struct dentry *upperdir, struct dentry *dentry,

[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