add preliminary 2.6.32 support
[openwrt.git] / target / linux / generic-2.6 / patches-2.6.32 / 235-union_mount_fixes.patch
1 --- a/fs/namespace.c
2 +++ b/fs/namespace.c
3 @@ -1656,8 +1656,10 @@ static int do_move_mount(struct path *pa
4  
5         /* moving to or from a union mount is not supported */
6         err = -EINVAL;
7 +#if 0
8         if (IS_MNT_UNION(path->mnt))
9                 goto exit;
10 +#endif
11         if (IS_MNT_UNION(old_path.mnt))
12                 goto exit;
13  
14 --- a/fs/union.c
15 +++ b/fs/union.c
16 @@ -260,8 +260,6 @@ int append_to_union(struct vfsmount *mnt
17         spin_lock(&union_lock);
18         um = union_lookup(dentry, mnt);
19         if (um) {
20 -               BUG_ON((um->u_next.dentry != dest_dentry) ||
21 -                      (um->u_next.mnt != dest_mnt));
22                 spin_unlock(&union_lock);
23                 union_put(this);
24                 return 0;
25 @@ -274,6 +272,23 @@ int append_to_union(struct vfsmount *mnt
26         return 0;
27  }
28  
29 +int follow_union_mountpoint(struct path *path)
30 +{
31 +       struct path new_path = *path;
32 +
33 +       path_get(&new_path);
34 +       while (follow_union_down(&new_path)) {
35 +               if (new_path.dentry != new_path.mnt->mnt_root)
36 +                       continue;
37 +
38 +               path_put(path);
39 +               *path = new_path;
40 +               return 1;
41 +       }
42 +       path_put(&new_path);
43 +       return 0;
44 +}
45 +
46  /*
47   * follow_union_down - follow the union stack one layer down
48   *
49 --- a/include/linux/union.h
50 +++ b/include/linux/union.h
51 @@ -47,6 +47,7 @@ extern int append_to_union(struct vfsmou
52                            struct vfsmount *, struct dentry *);
53  extern int follow_union_down(struct path *);
54  extern int follow_union_mount(struct path *);
55 +extern int follow_union_mountpoint(struct path *path);
56  extern void __d_drop_unions(struct dentry *);
57  extern void shrink_d_unions(struct dentry *);
58  extern void __shrink_d_unions(struct dentry *, struct list_head *);
59 @@ -68,6 +69,7 @@ extern int union_permission(struct path 
60  #define append_to_union(x1, y1, x2, y2)        ({ BUG(); (0); })
61  #define follow_union_down(x)           ({ (0); })
62  #define follow_union_mount(x)  ({ (0); })
63 +#define follow_union_mountpoint(x)     ({ (0); })
64  #define __d_drop_unions(x)             do { } while (0)
65  #define shrink_d_unions(x)             do { } while (0)
66  #define __shrink_d_unions(x,y)         do { } while (0)
67 --- a/fs/namei.c
68 +++ b/fs/namei.c
69 @@ -626,6 +626,9 @@ static int cache_lookup_union(struct nam
70                     !S_ISDIR(path->dentry->d_inode->i_mode))
71                         goto out;
72  
73 +               if (follow_union_mountpoint(path))
74 +                       goto out;
75 +
76                 /* Build the union stack for this part */
77                 res = __cache_lookup_build_union(nd, name, path);
78                 if (res) {
79 @@ -892,6 +895,9 @@ static int real_lookup_union(struct name
80             !S_ISDIR(path->dentry->d_inode->i_mode))
81                 goto out;
82  
83 +       if (follow_union_mountpoint(path))
84 +               goto out;
85 +
86         /* Build the union stack for this part */
87         res = __real_lookup_build_union(nd, name, path);
88         if (res) {
89 @@ -1813,6 +1819,9 @@ int hash_lookup_union(struct nameidata *
90             !S_ISDIR(path->dentry->d_inode->i_mode))
91                 goto out;
92  
93 +       if (follow_union_mountpoint(path))
94 +               goto out;
95 +
96         /* Build the union stack for this part */
97         res = __hash_lookup_build_union(nd, name, path);
98         if (res) {
99 --- a/fs/readdir.c
100 +++ b/fs/readdir.c
101 @@ -17,6 +17,7 @@
102  #include <linux/syscalls.h>
103  #include <linux/unistd.h>
104  #include <linux/union.h>
105 +#include <linux/mount.h>
106  
107  #include <asm/uaccess.h>
108  
109 @@ -45,7 +46,7 @@ int vfs_readdir(struct file *file, filld
110                  * below this one in the union stack.
111                  */
112                 if (is_unionized(file->f_path.dentry, file->f_path.mnt) &&
113 -                   !IS_OPAQUE(inode)) {
114 +                   !IS_OPAQUE(inode) && IS_MNT_UNION(file->f_path.mnt)) {
115                         res = union_copyup_dir(&file->f_path);
116                         if (res)
117                                 goto out_unlock;