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