diff options
Diffstat (limited to 'target/linux/generic-2.6')
-rw-r--r-- | target/linux/generic-2.6/patches-2.6.31/235-union_mount_fixes.patch | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/target/linux/generic-2.6/patches-2.6.31/235-union_mount_fixes.patch b/target/linux/generic-2.6/patches-2.6.31/235-union_mount_fixes.patch new file mode 100644 index 000000000..cea135105 --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.31/235-union_mount_fixes.patch @@ -0,0 +1,117 @@ +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -1656,8 +1656,10 @@ static int do_move_mount(struct path *pa + + /* moving to or from a union mount is not supported */ + err = -EINVAL; ++#if 0 + if (IS_MNT_UNION(path->mnt)) + goto exit; ++#endif + if (IS_MNT_UNION(old_path.mnt)) + goto exit; + +--- a/fs/union.c ++++ b/fs/union.c +@@ -260,8 +260,6 @@ int append_to_union(struct vfsmount *mnt + spin_lock(&union_lock); + um = union_lookup(dentry, mnt); + if (um) { +- BUG_ON((um->u_next.dentry != dest_dentry) || +- (um->u_next.mnt != dest_mnt)); + spin_unlock(&union_lock); + union_put(this); + return 0; +@@ -274,6 +272,23 @@ int append_to_union(struct vfsmount *mnt + return 0; + } + ++int follow_union_mountpoint(struct path *path) ++{ ++ struct path new_path = *path; ++ ++ path_get(&new_path); ++ while (follow_union_down(&new_path)) { ++ if (new_path.dentry != new_path.mnt->mnt_root) ++ continue; ++ ++ path_put(path); ++ *path = new_path; ++ return 1; ++ } ++ path_put(&new_path); ++ return 0; ++} ++ + /* + * follow_union_down - follow the union stack one layer down + * +--- a/include/linux/union.h ++++ b/include/linux/union.h +@@ -47,6 +47,7 @@ extern int append_to_union(struct vfsmou + struct vfsmount *, struct dentry *); + extern int follow_union_down(struct path *); + extern int follow_union_mount(struct path *); ++extern int follow_union_mountpoint(struct path *path); + extern void __d_drop_unions(struct dentry *); + extern void shrink_d_unions(struct dentry *); + extern void __shrink_d_unions(struct dentry *, struct list_head *); +@@ -68,6 +69,7 @@ extern int union_permission(struct path + #define append_to_union(x1, y1, x2, y2) ({ BUG(); (0); }) + #define follow_union_down(x) ({ (0); }) + #define follow_union_mount(x) ({ (0); }) ++#define follow_union_mountpoint(x) ({ (0); }) + #define __d_drop_unions(x) do { } while (0) + #define shrink_d_unions(x) do { } while (0) + #define __shrink_d_unions(x,y) do { } while (0) +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -613,6 +613,9 @@ static int cache_lookup_union(struct nam + !S_ISDIR(path->dentry->d_inode->i_mode)) + goto out; + ++ if (follow_union_mountpoint(path)) ++ goto out; ++ + /* Build the union stack for this part */ + res = __cache_lookup_build_union(nd, name, path); + if (res) { +@@ -886,6 +889,9 @@ static int real_lookup_union(struct name + !S_ISDIR(path->dentry->d_inode->i_mode)) + goto out; + ++ if (follow_union_mountpoint(path)) ++ goto out; ++ + /* Build the union stack for this part */ + res = __real_lookup_build_union(nd, name, path); + if (res) { +@@ -1813,6 +1819,9 @@ int hash_lookup_union(struct nameidata * + !S_ISDIR(path->dentry->d_inode->i_mode)) + goto out; + ++ if (follow_union_mountpoint(path)) ++ goto out; ++ + /* Build the union stack for this part */ + res = __hash_lookup_build_union(nd, name, path); + if (res) { +--- a/fs/readdir.c ++++ b/fs/readdir.c +@@ -17,6 +17,7 @@ + #include <linux/syscalls.h> + #include <linux/unistd.h> + #include <linux/union.h> ++#include <linux/mount.h> + + #include <asm/uaccess.h> + +@@ -45,7 +46,7 @@ int vfs_readdir(struct file *file, filld + * below this one in the union stack. + */ + if (is_unionized(file->f_path.dentry, file->f_path.mnt) && +- !IS_OPAQUE(inode)) { ++ !IS_OPAQUE(inode) && IS_MNT_UNION(file->f_path.mnt)) { + res = union_copyup_dir(&file->f_path); + if (res) + goto out_unlock; |