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,