tl-wr1043nd: Register missing leds.
[lede.git] / target / linux / generic-2.6 / patches-2.6.31 / 233-jffs2_whiteout_support.patch
1 --- a/fs/jffs2/dir.c
2 +++ b/fs/jffs2/dir.c
3 @@ -34,6 +34,9 @@ static int jffs2_mknod (struct inode *,s
4  static int jffs2_rename (struct inode *, struct dentry *,
5                          struct inode *, struct dentry *);
6  
7 +static int jffs2_whiteout (struct inode *, struct dentry *, struct dentry *);
8 +static int jffs2_fallthru (struct inode *, struct dentry *);
9 +
10  const struct file_operations jffs2_dir_operations =
11  {
12         .read =         generic_read_dir,
13 @@ -55,6 +58,8 @@ const struct inode_operations jffs2_dir_
14         .rmdir =        jffs2_rmdir,
15         .mknod =        jffs2_mknod,
16         .rename =       jffs2_rename,
17 +       .fallthru =     jffs2_fallthru,
18 +       .whiteout =     jffs2_whiteout,
19         .permission =   jffs2_permission,
20         .setattr =      jffs2_setattr,
21         .setxattr =     jffs2_setxattr,
22 @@ -98,8 +103,21 @@ static struct dentry *jffs2_lookup(struc
23                         fd = fd_list;
24                 }
25         }
26 -       if (fd)
27 -               ino = fd->ino;
28 +       if (fd) {
29 +               spin_lock(&target->d_lock);
30 +               switch(fd->type) {
31 +               case DT_WHT:
32 +                       target->d_flags |= DCACHE_WHITEOUT;
33 +                       break;
34 +               case DT_UNKNOWN:
35 +                       target->d_flags |= DCACHE_FALLTHRU;
36 +                       break;
37 +               default:
38 +                       ino = fd->ino;
39 +                       break;
40 +               }
41 +               spin_unlock(&target->d_lock);
42 +       }
43         mutex_unlock(&dir_f->sem);
44         if (ino) {
45                 inode = jffs2_iget(dir_i->i_sb, ino);
46 @@ -155,7 +173,9 @@ static int jffs2_readdir(struct file *fi
47                                   fd->name, fd->ino, fd->type, curofs, offset));
48                         continue;
49                 }
50 -               if (!fd->ino) {
51 +               if (fd->type == DT_UNKNOWN)
52 +                       fd->ino = 100; /* XXX: arbitrary */
53 +               else if (!fd->ino && (fd->type != DT_WHT)) {
54                         D2(printk(KERN_DEBUG "Skipping deletion dirent \"%s\"\n", fd->name));
55                         offset++;
56                         continue;
57 @@ -498,6 +518,11 @@ static int jffs2_mkdir (struct inode *di
58                 return PTR_ERR(inode);
59         }
60  
61 +       if (dentry->d_flags & DCACHE_WHITEOUT) {
62 +               inode->i_flags |= S_OPAQUE;
63 +               ri->flags = cpu_to_je16(JFFS2_INO_FLAG_OPAQUE);
64 +       }
65 +
66         inode->i_op = &jffs2_dir_inode_operations;
67         inode->i_fop = &jffs2_dir_operations;
68  
69 @@ -779,6 +804,82 @@ static int jffs2_mknod (struct inode *di
70         return 0;
71  }
72  
73 +static int jffs2_fallthru (struct inode *dir, struct dentry *dentry)
74 +{
75 +       struct jffs2_sb_info *c = JFFS2_SB_INFO(dir->i_sb);
76 +       uint32_t now;
77 +       int ret;
78 +
79 +       now = get_seconds();
80 +       ret = jffs2_do_link(c, JFFS2_INODE_INFO(dir), 0, DT_UNKNOWN,
81 +                           dentry->d_name.name, dentry->d_name.len, now);
82 +       if (ret)
83 +               return ret;
84 +
85 +       d_instantiate(dentry, NULL);
86 +       spin_lock(&dentry->d_lock);
87 +       dentry->d_flags |= DCACHE_FALLTHRU;
88 +       spin_unlock(&dentry->d_lock);
89 +
90 +       return 0;
91 +}
92 +
93 +static int jffs2_whiteout (struct inode *dir, struct dentry *old_dentry,
94 +                          struct dentry *new_dentry)
95 +{
96 +       struct jffs2_sb_info *c = JFFS2_SB_INFO(dir->i_sb);
97 +       struct jffs2_inode_info *victim_f = NULL;
98 +       uint32_t now;
99 +       int ret;
100 +
101 +       /* If it's a directory, then check whether it is really empty
102 +        */
103 +       if (new_dentry->d_inode) {
104 +               victim_f = JFFS2_INODE_INFO(old_dentry->d_inode);
105 +               if (S_ISDIR(old_dentry->d_inode->i_mode)) {
106 +                       struct jffs2_full_dirent *fd;
107 +
108 +                       mutex_lock(&victim_f->sem);
109 +                       for (fd = victim_f->dents; fd; fd = fd->next) {
110 +                               if (fd->ino) {
111 +                                       mutex_unlock(&victim_f->sem);
112 +                                       return -ENOTEMPTY;
113 +                               }
114 +                       }
115 +                       mutex_unlock(&victim_f->sem);
116 +               }
117 +       }
118 +
119 +       now = get_seconds();
120 +       ret = jffs2_do_link(c, JFFS2_INODE_INFO(dir), 0, DT_WHT,
121 +                           new_dentry->d_name.name, new_dentry->d_name.len, now);
122 +       if (ret)
123 +               return ret;
124 +
125 +       spin_lock(&new_dentry->d_lock);
126 +       new_dentry->d_flags &= ~DCACHE_FALLTHRU;
127 +       new_dentry->d_flags |= DCACHE_WHITEOUT;
128 +       spin_unlock(&new_dentry->d_lock);
129 +       d_add(new_dentry, NULL);
130 +
131 +       if (victim_f) {
132 +               /* There was a victim. Kill it off nicely */
133 +               drop_nlink(old_dentry->d_inode);
134 +               /* Don't oops if the victim was a dirent pointing to an
135 +                  inode which didn't exist. */
136 +               if (victim_f->inocache) {
137 +                       mutex_lock(&victim_f->sem);
138 +                       if (S_ISDIR(old_dentry->d_inode->i_mode))
139 +                               victim_f->inocache->pino_nlink = 0;
140 +                       else
141 +                               victim_f->inocache->pino_nlink--;
142 +                       mutex_unlock(&victim_f->sem);
143 +               }
144 +       }
145 +
146 +       return 0;
147 +}
148 +
149  static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
150                          struct inode *new_dir_i, struct dentry *new_dentry)
151  {
152 --- a/fs/jffs2/fs.c
153 +++ b/fs/jffs2/fs.c
154 @@ -301,6 +301,10 @@ struct inode *jffs2_iget(struct super_bl
155  
156                 inode->i_op = &jffs2_dir_inode_operations;
157                 inode->i_fop = &jffs2_dir_operations;
158 +
159 +               if (je16_to_cpu(latest_node.flags) & JFFS2_INO_FLAG_OPAQUE)
160 +                       inode->i_flags |= S_OPAQUE;
161 +
162                 break;
163         }
164         case S_IFREG:
165 --- a/fs/jffs2/super.c
166 +++ b/fs/jffs2/super.c
167 @@ -172,7 +172,7 @@ static int jffs2_fill_super(struct super
168  
169         sb->s_op = &jffs2_super_operations;
170         sb->s_export_op = &jffs2_export_ops;
171 -       sb->s_flags = sb->s_flags | MS_NOATIME;
172 +       sb->s_flags = sb->s_flags | MS_NOATIME | MS_WHITEOUT;
173         sb->s_xattr = jffs2_xattr_handlers;
174  #ifdef CONFIG_JFFS2_FS_POSIX_ACL
175         sb->s_flags |= MS_POSIXACL;
176 --- a/include/linux/jffs2.h
177 +++ b/include/linux/jffs2.h
178 @@ -87,6 +87,8 @@
179  #define JFFS2_INO_FLAG_USERCOMPR  2    /* User has requested a specific
180                                            compression type */
181  
182 +#define JFFS2_INO_FLAG_OPAQUE     4    /* Directory is opaque (for union mounts) */
183 +
184  
185  /* These can go once we've made sure we've caught all uses without
186     byteswapping */