Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / fs / aufs / rdu.c
1 /*
2  * Copyright (C) 2005-2012 Junjiro R. Okajima
3  *
4  * This program, aufs is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 /*
20  * readdir in userspace.
21  */
22
23 #include <linux/compat.h>
24 #include <linux/fs_stack.h>
25 #include <linux/security.h>
26 #include "aufs.h"
27
28 /* bits for struct aufs_rdu.flags */
29 #define AuRdu_CALLED    1
30 #define AuRdu_CONT      (1 << 1)
31 #define AuRdu_FULL      (1 << 2)
32 #define au_ftest_rdu(flags, name)       ((flags) & AuRdu_##name)
33 #define au_fset_rdu(flags, name) \
34         do { (flags) |= AuRdu_##name; } while (0)
35 #define au_fclr_rdu(flags, name) \
36         do { (flags) &= ~AuRdu_##name; } while (0)
37
38 struct au_rdu_arg {
39         struct aufs_rdu                 *rdu;
40         union au_rdu_ent_ul             ent;
41         unsigned long                   end;
42
43         struct super_block              *sb;
44         int                             err;
45 };
46
47 static int au_rdu_fill(void *__arg, const char *name, int nlen,
48                        loff_t offset, u64 h_ino, unsigned int d_type)
49 {
50         int err, len;
51         struct au_rdu_arg *arg = __arg;
52         struct aufs_rdu *rdu = arg->rdu;
53         struct au_rdu_ent ent;
54
55         err = 0;
56         arg->err = 0;
57         au_fset_rdu(rdu->cookie.flags, CALLED);
58         len = au_rdu_len(nlen);
59         if (arg->ent.ul + len  < arg->end) {
60                 ent.ino = h_ino;
61                 ent.bindex = rdu->cookie.bindex;
62                 ent.type = d_type;
63                 ent.nlen = nlen;
64                 if (unlikely(nlen > AUFS_MAX_NAMELEN))
65                         ent.type = DT_UNKNOWN;
66
67                 /* unnecessary to support mmap_sem since this is a dir */
68                 err = -EFAULT;
69                 if (copy_to_user(arg->ent.e, &ent, sizeof(ent)))
70                         goto out;
71                 if (copy_to_user(arg->ent.e->name, name, nlen))
72                         goto out;
73                 /* the terminating NULL */
74                 if (__put_user(0, arg->ent.e->name + nlen))
75                         goto out;
76                 err = 0;
77                 /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */
78                 arg->ent.ul += len;
79                 rdu->rent++;
80         } else {
81                 err = -EFAULT;
82                 au_fset_rdu(rdu->cookie.flags, FULL);
83                 rdu->full = 1;
84                 rdu->tail = arg->ent;
85         }
86
87 out:
88         /* AuTraceErr(err); */
89         return err;
90 }
91
92 static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg)
93 {
94         int err;
95         loff_t offset;
96         struct au_rdu_cookie *cookie = &arg->rdu->cookie;
97
98         offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET);
99         err = offset;
100         if (unlikely(offset != cookie->h_pos))
101                 goto out;
102
103         err = 0;
104         do {
105                 arg->err = 0;
106                 au_fclr_rdu(cookie->flags, CALLED);
107                 /* smp_mb(); */
108                 err = vfsub_readdir(h_file, au_rdu_fill, arg);
109                 if (err >= 0)
110                         err = arg->err;
111         } while (!err
112                  && au_ftest_rdu(cookie->flags, CALLED)
113                  && !au_ftest_rdu(cookie->flags, FULL));
114         cookie->h_pos = h_file->f_pos;
115
116 out:
117         AuTraceErr(err);
118         return err;
119 }
120
121 static int au_rdu(struct file *file, struct aufs_rdu *rdu)
122 {
123         int err;
124         aufs_bindex_t bend;
125         struct au_rdu_arg arg;
126         struct dentry *dentry;
127         struct inode *inode;
128         struct file *h_file;
129         struct au_rdu_cookie *cookie = &rdu->cookie;
130
131         err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz);
132         if (unlikely(err)) {
133                 err = -EFAULT;
134                 AuTraceErr(err);
135                 goto out;
136         }
137         rdu->rent = 0;
138         rdu->tail = rdu->ent;
139         rdu->full = 0;
140         arg.rdu = rdu;
141         arg.ent = rdu->ent;
142         arg.end = arg.ent.ul;
143         arg.end += rdu->sz;
144
145         err = -ENOTDIR;
146         if (unlikely(!file->f_op || !file->f_op->readdir))
147                 goto out;
148
149         err = security_file_permission(file, MAY_READ);
150         AuTraceErr(err);
151         if (unlikely(err))
152                 goto out;
153
154         dentry = file->f_dentry;
155         inode = dentry->d_inode;
156 #if 1
157         mutex_lock(&inode->i_mutex);
158 #else
159         err = mutex_lock_killable(&inode->i_mutex);
160         AuTraceErr(err);
161         if (unlikely(err))
162                 goto out;
163 #endif
164
165         arg.sb = inode->i_sb;
166         err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM);
167         if (unlikely(err))
168                 goto out_mtx;
169         err = au_alive_dir(dentry);
170         if (unlikely(err))
171                 goto out_si;
172         /* todo: reval? */
173         fi_read_lock(file);
174
175         err = -EAGAIN;
176         if (unlikely(au_ftest_rdu(cookie->flags, CONT)
177                      && cookie->generation != au_figen(file)))
178                 goto out_unlock;
179
180         err = 0;
181         if (!rdu->blk) {
182                 rdu->blk = au_sbi(arg.sb)->si_rdblk;
183                 if (!rdu->blk)
184                         rdu->blk = au_dir_size(file, /*dentry*/NULL);
185         }
186         bend = au_fbstart(file);
187         if (cookie->bindex < bend)
188                 cookie->bindex = bend;
189         bend = au_fbend_dir(file);
190         /* AuDbg("b%d, b%d\n", cookie->bindex, bend); */
191         for (; !err && cookie->bindex <= bend;
192              cookie->bindex++, cookie->h_pos = 0) {
193                 h_file = au_hf_dir(file, cookie->bindex);
194                 if (!h_file)
195                         continue;
196
197                 au_fclr_rdu(cookie->flags, FULL);
198                 err = au_rdu_do(h_file, &arg);
199                 AuTraceErr(err);
200                 if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err))
201                         break;
202         }
203         AuDbg("rent %llu\n", rdu->rent);
204
205         if (!err && !au_ftest_rdu(cookie->flags, CONT)) {
206                 rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH);
207                 au_fset_rdu(cookie->flags, CONT);
208                 cookie->generation = au_figen(file);
209         }
210
211         ii_read_lock_child(inode);
212         fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode)));
213         ii_read_unlock(inode);
214
215 out_unlock:
216         fi_read_unlock(file);
217 out_si:
218         si_read_unlock(arg.sb);
219 out_mtx:
220         mutex_unlock(&inode->i_mutex);
221 out:
222         AuTraceErr(err);
223         return err;
224 }
225
226 static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu)
227 {
228         int err;
229         ino_t ino;
230         unsigned long long nent;
231         union au_rdu_ent_ul *u;
232         struct au_rdu_ent ent;
233         struct super_block *sb;
234
235         err = 0;
236         nent = rdu->nent;
237         u = &rdu->ent;
238         sb = file->f_dentry->d_sb;
239         si_read_lock(sb, AuLock_FLUSH);
240         while (nent-- > 0) {
241                 /* unnecessary to support mmap_sem since this is a dir */
242                 err = copy_from_user(&ent, u->e, sizeof(ent));
243                 if (!err)
244                         err = !access_ok(VERIFY_WRITE, &u->e->ino, sizeof(ino));
245                 if (unlikely(err)) {
246                         err = -EFAULT;
247                         AuTraceErr(err);
248                         break;
249                 }
250
251                 /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */
252                 if (!ent.wh)
253                         err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino);
254                 else
255                         err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type,
256                                         &ino);
257                 if (unlikely(err)) {
258                         AuTraceErr(err);
259                         break;
260                 }
261
262                 err = __put_user(ino, &u->e->ino);
263                 if (unlikely(err)) {
264                         err = -EFAULT;
265                         AuTraceErr(err);
266                         break;
267                 }
268                 u->ul += au_rdu_len(ent.nlen);
269         }
270         si_read_unlock(sb);
271
272         return err;
273 }
274
275 /* ---------------------------------------------------------------------- */
276
277 static int au_rdu_verify(struct aufs_rdu *rdu)
278 {
279         AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | "
280               "%llu, b%d, 0x%x, g%u}\n",
281               rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ],
282               rdu->blk,
283               rdu->rent, rdu->shwh, rdu->full,
284               rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags,
285               rdu->cookie.generation);
286
287         if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu))
288                 return 0;
289
290         AuDbg("%u:%u\n",
291               rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu));
292         return -EINVAL;
293 }
294
295 long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
296 {
297         long err, e;
298         struct aufs_rdu rdu;
299         void __user *p = (void __user *)arg;
300
301         err = copy_from_user(&rdu, p, sizeof(rdu));
302         if (unlikely(err)) {
303                 err = -EFAULT;
304                 AuTraceErr(err);
305                 goto out;
306         }
307         err = au_rdu_verify(&rdu);
308         if (unlikely(err))
309                 goto out;
310
311         switch (cmd) {
312         case AUFS_CTL_RDU:
313                 err = au_rdu(file, &rdu);
314                 if (unlikely(err))
315                         break;
316
317                 e = copy_to_user(p, &rdu, sizeof(rdu));
318                 if (unlikely(e)) {
319                         err = -EFAULT;
320                         AuTraceErr(err);
321                 }
322                 break;
323         case AUFS_CTL_RDU_INO:
324                 err = au_rdu_ino(file, &rdu);
325                 break;
326
327         default:
328                 /* err = -ENOTTY; */
329                 err = -EINVAL;
330         }
331
332 out:
333         AuTraceErr(err);
334         return err;
335 }
336
337 #ifdef CONFIG_COMPAT
338 long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
339 {
340         long err, e;
341         struct aufs_rdu rdu;
342         void __user *p = compat_ptr(arg);
343
344         /* todo: get_user()? */
345         err = copy_from_user(&rdu, p, sizeof(rdu));
346         if (unlikely(err)) {
347                 err = -EFAULT;
348                 AuTraceErr(err);
349                 goto out;
350         }
351         rdu.ent.e = compat_ptr(rdu.ent.ul);
352         err = au_rdu_verify(&rdu);
353         if (unlikely(err))
354                 goto out;
355
356         switch (cmd) {
357         case AUFS_CTL_RDU:
358                 err = au_rdu(file, &rdu);
359                 if (unlikely(err))
360                         break;
361
362                 rdu.ent.ul = ptr_to_compat(rdu.ent.e);
363                 rdu.tail.ul = ptr_to_compat(rdu.tail.e);
364                 e = copy_to_user(p, &rdu, sizeof(rdu));
365                 if (unlikely(e)) {
366                         err = -EFAULT;
367                         AuTraceErr(err);
368                 }
369                 break;
370         case AUFS_CTL_RDU_INO:
371                 err = au_rdu_ino(file, &rdu);
372                 break;
373
374         default:
375                 /* err = -ENOTTY; */
376                 err = -EINVAL;
377         }
378
379 out:
380         AuTraceErr(err);
381         return err;
382 }
383 #endif