]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - fs/aufs/rdu.c
UBUNTU: Ubuntu-4.13.0-45.50
[mirror_ubuntu-artful-kernel.git] / fs / aufs / rdu.c
1 /*
2 * Copyright (C) 2005-2017 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, see <http://www.gnu.org/licenses/>.
16 */
17
18 /*
19 * readdir in userspace.
20 */
21
22 #include <linux/compat.h>
23 #include <linux/fs_stack.h>
24 #include <linux/security.h>
25 #include "aufs.h"
26
27 /* bits for struct aufs_rdu.flags */
28 #define AuRdu_CALLED 1
29 #define AuRdu_CONT (1 << 1)
30 #define AuRdu_FULL (1 << 2)
31 #define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name)
32 #define au_fset_rdu(flags, name) \
33 do { (flags) |= AuRdu_##name; } while (0)
34 #define au_fclr_rdu(flags, name) \
35 do { (flags) &= ~AuRdu_##name; } while (0)
36
37 struct au_rdu_arg {
38 struct dir_context ctx;
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(struct dir_context *ctx, 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 = container_of(ctx, struct au_rdu_arg, ctx);
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 /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */
99 offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET);
100 err = offset;
101 if (unlikely(offset != cookie->h_pos))
102 goto out;
103
104 err = 0;
105 do {
106 arg->err = 0;
107 au_fclr_rdu(cookie->flags, CALLED);
108 /* smp_mb(); */
109 err = vfsub_iterate_dir(h_file, &arg->ctx);
110 if (err >= 0)
111 err = arg->err;
112 } while (!err
113 && au_ftest_rdu(cookie->flags, CALLED)
114 && !au_ftest_rdu(cookie->flags, FULL));
115 cookie->h_pos = h_file->f_pos;
116
117 out:
118 AuTraceErr(err);
119 return err;
120 }
121
122 static int au_rdu(struct file *file, struct aufs_rdu *rdu)
123 {
124 int err;
125 aufs_bindex_t bbot;
126 struct au_rdu_arg arg = {
127 .ctx = {
128 .actor = au_rdu_fill
129 }
130 };
131 struct dentry *dentry;
132 struct inode *inode;
133 struct file *h_file;
134 struct au_rdu_cookie *cookie = &rdu->cookie;
135
136 err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz);
137 if (unlikely(err)) {
138 err = -EFAULT;
139 AuTraceErr(err);
140 goto out;
141 }
142 rdu->rent = 0;
143 rdu->tail = rdu->ent;
144 rdu->full = 0;
145 arg.rdu = rdu;
146 arg.ent = rdu->ent;
147 arg.end = arg.ent.ul;
148 arg.end += rdu->sz;
149
150 err = -ENOTDIR;
151 if (unlikely(!file->f_op->iterate && !file->f_op->iterate_shared))
152 goto out;
153
154 err = security_file_permission(file, MAY_READ);
155 AuTraceErr(err);
156 if (unlikely(err))
157 goto out;
158
159 dentry = file->f_path.dentry;
160 inode = d_inode(dentry);
161 inode_lock_shared(inode);
162
163 arg.sb = inode->i_sb;
164 err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM);
165 if (unlikely(err))
166 goto out_mtx;
167 err = au_alive_dir(dentry);
168 if (unlikely(err))
169 goto out_si;
170 /* todo: reval? */
171 fi_read_lock(file);
172
173 err = -EAGAIN;
174 if (unlikely(au_ftest_rdu(cookie->flags, CONT)
175 && cookie->generation != au_figen(file)))
176 goto out_unlock;
177
178 err = 0;
179 if (!rdu->blk) {
180 rdu->blk = au_sbi(arg.sb)->si_rdblk;
181 if (!rdu->blk)
182 rdu->blk = au_dir_size(file, /*dentry*/NULL);
183 }
184 bbot = au_fbtop(file);
185 if (cookie->bindex < bbot)
186 cookie->bindex = bbot;
187 bbot = au_fbbot_dir(file);
188 /* AuDbg("b%d, b%d\n", cookie->bindex, bbot); */
189 for (; !err && cookie->bindex <= bbot;
190 cookie->bindex++, cookie->h_pos = 0) {
191 h_file = au_hf_dir(file, cookie->bindex);
192 if (!h_file)
193 continue;
194
195 au_fclr_rdu(cookie->flags, FULL);
196 err = au_rdu_do(h_file, &arg);
197 AuTraceErr(err);
198 if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err))
199 break;
200 }
201 AuDbg("rent %llu\n", rdu->rent);
202
203 if (!err && !au_ftest_rdu(cookie->flags, CONT)) {
204 rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH);
205 au_fset_rdu(cookie->flags, CONT);
206 cookie->generation = au_figen(file);
207 }
208
209 ii_read_lock_child(inode);
210 fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibtop(inode)));
211 ii_read_unlock(inode);
212
213 out_unlock:
214 fi_read_unlock(file);
215 out_si:
216 si_read_unlock(arg.sb);
217 out_mtx:
218 inode_unlock_shared(inode);
219 out:
220 AuTraceErr(err);
221 return err;
222 }
223
224 static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu)
225 {
226 int err;
227 ino_t ino;
228 unsigned long long nent;
229 union au_rdu_ent_ul *u;
230 struct au_rdu_ent ent;
231 struct super_block *sb;
232
233 err = 0;
234 nent = rdu->nent;
235 u = &rdu->ent;
236 sb = file->f_path.dentry->d_sb;
237 si_read_lock(sb, AuLock_FLUSH);
238 while (nent-- > 0) {
239 /* unnecessary to support mmap_sem since this is a dir */
240 err = copy_from_user(&ent, u->e, sizeof(ent));
241 if (!err)
242 err = !access_ok(VERIFY_WRITE, &u->e->ino, sizeof(ino));
243 if (unlikely(err)) {
244 err = -EFAULT;
245 AuTraceErr(err);
246 break;
247 }
248
249 /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */
250 if (!ent.wh)
251 err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino);
252 else
253 err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type,
254 &ino);
255 if (unlikely(err)) {
256 AuTraceErr(err);
257 break;
258 }
259
260 err = __put_user(ino, &u->e->ino);
261 if (unlikely(err)) {
262 err = -EFAULT;
263 AuTraceErr(err);
264 break;
265 }
266 u->ul += au_rdu_len(ent.nlen);
267 }
268 si_read_unlock(sb);
269
270 return err;
271 }
272
273 /* ---------------------------------------------------------------------- */
274
275 static int au_rdu_verify(struct aufs_rdu *rdu)
276 {
277 AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | "
278 "%llu, b%d, 0x%x, g%u}\n",
279 rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ],
280 rdu->blk,
281 rdu->rent, rdu->shwh, rdu->full,
282 rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags,
283 rdu->cookie.generation);
284
285 if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu))
286 return 0;
287
288 AuDbg("%u:%u\n",
289 rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu));
290 return -EINVAL;
291 }
292
293 long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
294 {
295 long err, e;
296 struct aufs_rdu rdu;
297 void __user *p = (void __user *)arg;
298
299 err = copy_from_user(&rdu, p, sizeof(rdu));
300 if (unlikely(err)) {
301 err = -EFAULT;
302 AuTraceErr(err);
303 goto out;
304 }
305 err = au_rdu_verify(&rdu);
306 if (unlikely(err))
307 goto out;
308
309 switch (cmd) {
310 case AUFS_CTL_RDU:
311 err = au_rdu(file, &rdu);
312 if (unlikely(err))
313 break;
314
315 e = copy_to_user(p, &rdu, sizeof(rdu));
316 if (unlikely(e)) {
317 err = -EFAULT;
318 AuTraceErr(err);
319 }
320 break;
321 case AUFS_CTL_RDU_INO:
322 err = au_rdu_ino(file, &rdu);
323 break;
324
325 default:
326 /* err = -ENOTTY; */
327 err = -EINVAL;
328 }
329
330 out:
331 AuTraceErr(err);
332 return err;
333 }
334
335 #ifdef CONFIG_COMPAT
336 long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
337 {
338 long err, e;
339 struct aufs_rdu rdu;
340 void __user *p = compat_ptr(arg);
341
342 /* todo: get_user()? */
343 err = copy_from_user(&rdu, p, sizeof(rdu));
344 if (unlikely(err)) {
345 err = -EFAULT;
346 AuTraceErr(err);
347 goto out;
348 }
349 rdu.ent.e = compat_ptr(rdu.ent.ul);
350 err = au_rdu_verify(&rdu);
351 if (unlikely(err))
352 goto out;
353
354 switch (cmd) {
355 case AUFS_CTL_RDU:
356 err = au_rdu(file, &rdu);
357 if (unlikely(err))
358 break;
359
360 rdu.ent.ul = ptr_to_compat(rdu.ent.e);
361 rdu.tail.ul = ptr_to_compat(rdu.tail.e);
362 e = copy_to_user(p, &rdu, sizeof(rdu));
363 if (unlikely(e)) {
364 err = -EFAULT;
365 AuTraceErr(err);
366 }
367 break;
368 case AUFS_CTL_RDU_INO:
369 err = au_rdu_ino(file, &rdu);
370 break;
371
372 default:
373 /* err = -ENOTTY; */
374 err = -EINVAL;
375 }
376
377 out:
378 AuTraceErr(err);
379 return err;
380 }
381 #endif