From: Felix Fietkau Date: Fri, 10 Apr 2015 11:52:59 +0000 (+0000) Subject: kernel: add jffs2 RENAME_WHITEOUT support, fixes overlayfs renames (#19432) X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=9428c5609bd02c456dafe5fa21da4190014bea75;p=openwrt%2Fstaging%2Fadrian.git kernel: add jffs2 RENAME_WHITEOUT support, fixes overlayfs renames (#19432) Signed-off-by: Felix Fietkau SVN-Revision: 45362 --- diff --git a/target/linux/generic/patches-3.18/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch b/target/linux/generic/patches-3.18/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch new file mode 100644 index 0000000000..4ffa3c26fe --- /dev/null +++ b/target/linux/generic/patches-3.18/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch @@ -0,0 +1,86 @@ +From: Felix Fietkau +Date: Fri, 10 Apr 2015 13:35:29 +0200 +Subject: [PATCH] jffs2: use .rename2 and add RENAME_WHITEOUT support + +It is required for renames on overlayfs + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -35,7 +35,7 @@ static int jffs2_mkdir (struct inode *,s + static int jffs2_rmdir (struct inode *,struct dentry *); + static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t); + static int jffs2_rename (struct inode *, struct dentry *, +- struct inode *, struct dentry *); ++ struct inode *, struct dentry *, unsigned int); + + const struct file_operations jffs2_dir_operations = + { +@@ -57,7 +57,7 @@ const struct inode_operations jffs2_dir_ + .mkdir = jffs2_mkdir, + .rmdir = jffs2_rmdir, + .mknod = jffs2_mknod, +- .rename = jffs2_rename, ++ .rename2 = jffs2_rename, + .get_acl = jffs2_get_acl, + .set_acl = jffs2_set_acl, + .setattr = jffs2_setattr, +@@ -756,8 +756,27 @@ static int jffs2_mknod (struct inode *di + return ret; + } + ++static int jffs2_whiteout(struct inode *old_dir, struct dentry *old_dentry) ++{ ++ struct dentry *wh; ++ int err; ++ ++ wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name); ++ if (!wh) ++ return -ENOMEM; ++ ++ err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE, ++ WHITEOUT_DEV); ++ if (err) ++ return err; ++ ++ d_rehash(wh); ++ return 0; ++} ++ + static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, +- struct inode *new_dir_i, struct dentry *new_dentry) ++ struct inode *new_dir_i, struct dentry *new_dentry, ++ unsigned int flags) + { + int ret; + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); +@@ -765,6 +784,9 @@ static int jffs2_rename (struct inode *o + uint8_t type; + uint32_t now; + ++ if (flags & ~RENAME_WHITEOUT) ++ return -EINVAL; ++ + /* The VFS will check for us and prevent trying to rename a + * file over a directory and vice versa, but if it's a directory, + * the VFS can't check whether the victim is empty. The filesystem +@@ -828,9 +850,14 @@ static int jffs2_rename (struct inode *o + if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f) + inc_nlink(new_dir_i); + +- /* Unlink the original */ +- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); ++ if (flags & RENAME_WHITEOUT) ++ /* Replace with whiteout */ ++ ret = jffs2_whiteout(old_dir_i, old_dentry); ++ else ++ /* Unlink the original */ ++ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), ++ old_dentry->d_name.name, ++ old_dentry->d_name.len, NULL, now); + + /* We don't touch inode->i_nlink */ + diff --git a/target/linux/generic/patches-4.0/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch b/target/linux/generic/patches-4.0/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch new file mode 100644 index 0000000000..4ffa3c26fe --- /dev/null +++ b/target/linux/generic/patches-4.0/110-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch @@ -0,0 +1,86 @@ +From: Felix Fietkau +Date: Fri, 10 Apr 2015 13:35:29 +0200 +Subject: [PATCH] jffs2: use .rename2 and add RENAME_WHITEOUT support + +It is required for renames on overlayfs + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -35,7 +35,7 @@ static int jffs2_mkdir (struct inode *,s + static int jffs2_rmdir (struct inode *,struct dentry *); + static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t); + static int jffs2_rename (struct inode *, struct dentry *, +- struct inode *, struct dentry *); ++ struct inode *, struct dentry *, unsigned int); + + const struct file_operations jffs2_dir_operations = + { +@@ -57,7 +57,7 @@ const struct inode_operations jffs2_dir_ + .mkdir = jffs2_mkdir, + .rmdir = jffs2_rmdir, + .mknod = jffs2_mknod, +- .rename = jffs2_rename, ++ .rename2 = jffs2_rename, + .get_acl = jffs2_get_acl, + .set_acl = jffs2_set_acl, + .setattr = jffs2_setattr, +@@ -756,8 +756,27 @@ static int jffs2_mknod (struct inode *di + return ret; + } + ++static int jffs2_whiteout(struct inode *old_dir, struct dentry *old_dentry) ++{ ++ struct dentry *wh; ++ int err; ++ ++ wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name); ++ if (!wh) ++ return -ENOMEM; ++ ++ err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE, ++ WHITEOUT_DEV); ++ if (err) ++ return err; ++ ++ d_rehash(wh); ++ return 0; ++} ++ + static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, +- struct inode *new_dir_i, struct dentry *new_dentry) ++ struct inode *new_dir_i, struct dentry *new_dentry, ++ unsigned int flags) + { + int ret; + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); +@@ -765,6 +784,9 @@ static int jffs2_rename (struct inode *o + uint8_t type; + uint32_t now; + ++ if (flags & ~RENAME_WHITEOUT) ++ return -EINVAL; ++ + /* The VFS will check for us and prevent trying to rename a + * file over a directory and vice versa, but if it's a directory, + * the VFS can't check whether the victim is empty. The filesystem +@@ -828,9 +850,14 @@ static int jffs2_rename (struct inode *o + if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f) + inc_nlink(new_dir_i); + +- /* Unlink the original */ +- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); ++ if (flags & RENAME_WHITEOUT) ++ /* Replace with whiteout */ ++ ret = jffs2_whiteout(old_dir_i, old_dentry); ++ else ++ /* Unlink the original */ ++ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), ++ old_dentry->d_name.name, ++ old_dentry->d_name.len, NULL, now); + + /* We don't touch inode->i_nlink */ +