]>
Commit | Line | Data |
---|---|---|
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 | * export via nfs | |
20 | */ | |
21 | ||
22 | #include <linux/exportfs.h> | |
23 | #include <linux/fs_struct.h> | |
24 | #include <linux/namei.h> | |
25 | #include <linux/nsproxy.h> | |
26 | #include <linux/random.h> | |
27 | #include <linux/writeback.h> | |
28 | #include "aufs.h" | |
29 | ||
30 | union conv { | |
31 | #ifdef CONFIG_AUFS_INO_T_64 | |
32 | __u32 a[2]; | |
33 | #else | |
34 | __u32 a[1]; | |
35 | #endif | |
36 | ino_t ino; | |
37 | }; | |
38 | ||
39 | static ino_t decode_ino(__u32 *a) | |
40 | { | |
41 | union conv u; | |
42 | ||
43 | BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); | |
44 | u.a[0] = a[0]; | |
45 | #ifdef CONFIG_AUFS_INO_T_64 | |
46 | u.a[1] = a[1]; | |
47 | #endif | |
48 | return u.ino; | |
49 | } | |
50 | ||
51 | static void encode_ino(__u32 *a, ino_t ino) | |
52 | { | |
53 | union conv u; | |
54 | ||
55 | u.ino = ino; | |
56 | a[0] = u.a[0]; | |
57 | #ifdef CONFIG_AUFS_INO_T_64 | |
58 | a[1] = u.a[1]; | |
59 | #endif | |
60 | } | |
61 | ||
62 | /* NFS file handle */ | |
63 | enum { | |
64 | Fh_br_id, | |
65 | Fh_sigen, | |
66 | #ifdef CONFIG_AUFS_INO_T_64 | |
67 | /* support 64bit inode number */ | |
68 | Fh_ino1, | |
69 | Fh_ino2, | |
70 | Fh_dir_ino1, | |
71 | Fh_dir_ino2, | |
72 | #else | |
73 | Fh_ino1, | |
74 | Fh_dir_ino1, | |
75 | #endif | |
76 | Fh_igen, | |
77 | Fh_h_type, | |
78 | Fh_tail, | |
79 | ||
80 | Fh_ino = Fh_ino1, | |
81 | Fh_dir_ino = Fh_dir_ino1 | |
82 | }; | |
83 | ||
84 | static int au_test_anon(struct dentry *dentry) | |
85 | { | |
86 | /* note: read d_flags without d_lock */ | |
87 | return !!(dentry->d_flags & DCACHE_DISCONNECTED); | |
88 | } | |
89 | ||
90 | int au_test_nfsd(void) | |
91 | { | |
92 | int ret; | |
93 | struct task_struct *tsk = current; | |
94 | char comm[sizeof(tsk->comm)]; | |
95 | ||
96 | ret = 0; | |
97 | if (tsk->flags & PF_KTHREAD) { | |
98 | get_task_comm(comm, tsk); | |
99 | ret = !strcmp(comm, "nfsd"); | |
100 | } | |
101 | ||
102 | return ret; | |
103 | } | |
104 | ||
105 | /* ---------------------------------------------------------------------- */ | |
106 | /* inode generation external table */ | |
107 | ||
108 | void au_xigen_inc(struct inode *inode) | |
109 | { | |
110 | loff_t pos; | |
111 | ssize_t sz; | |
112 | __u32 igen; | |
113 | struct super_block *sb; | |
114 | struct au_sbinfo *sbinfo; | |
115 | ||
116 | sb = inode->i_sb; | |
117 | AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); | |
118 | ||
119 | sbinfo = au_sbi(sb); | |
120 | pos = inode->i_ino; | |
121 | pos *= sizeof(igen); | |
122 | igen = inode->i_generation + 1; | |
123 | sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen, | |
124 | sizeof(igen), &pos); | |
125 | if (sz == sizeof(igen)) | |
126 | return; /* success */ | |
127 | ||
128 | if (unlikely(sz >= 0)) | |
129 | AuIOErr("xigen error (%zd)\n", sz); | |
130 | } | |
131 | ||
132 | int au_xigen_new(struct inode *inode) | |
133 | { | |
134 | int err; | |
135 | loff_t pos; | |
136 | ssize_t sz; | |
137 | struct super_block *sb; | |
138 | struct au_sbinfo *sbinfo; | |
139 | struct file *file; | |
140 | ||
141 | err = 0; | |
142 | /* todo: dirty, at mount time */ | |
143 | if (inode->i_ino == AUFS_ROOT_INO) | |
144 | goto out; | |
145 | sb = inode->i_sb; | |
146 | SiMustAnyLock(sb); | |
147 | if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) | |
148 | goto out; | |
149 | ||
150 | err = -EFBIG; | |
151 | pos = inode->i_ino; | |
152 | if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) { | |
153 | AuIOErr1("too large i%lld\n", pos); | |
154 | goto out; | |
155 | } | |
156 | pos *= sizeof(inode->i_generation); | |
157 | ||
158 | err = 0; | |
159 | sbinfo = au_sbi(sb); | |
160 | file = sbinfo->si_xigen; | |
161 | BUG_ON(!file); | |
162 | ||
163 | if (vfsub_f_size_read(file) | |
164 | < pos + sizeof(inode->i_generation)) { | |
165 | inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); | |
166 | sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation, | |
167 | sizeof(inode->i_generation), &pos); | |
168 | } else | |
169 | sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation, | |
170 | sizeof(inode->i_generation), &pos); | |
171 | if (sz == sizeof(inode->i_generation)) | |
172 | goto out; /* success */ | |
173 | ||
174 | err = sz; | |
175 | if (unlikely(sz >= 0)) { | |
176 | err = -EIO; | |
177 | AuIOErr("xigen error (%zd)\n", sz); | |
178 | } | |
179 | ||
180 | out: | |
181 | return err; | |
182 | } | |
183 | ||
184 | int au_xigen_set(struct super_block *sb, struct file *base) | |
185 | { | |
186 | int err; | |
187 | struct au_sbinfo *sbinfo; | |
188 | struct file *file; | |
189 | ||
190 | SiMustWriteLock(sb); | |
191 | ||
192 | sbinfo = au_sbi(sb); | |
193 | file = au_xino_create2(base, sbinfo->si_xigen); | |
194 | err = PTR_ERR(file); | |
195 | if (IS_ERR(file)) | |
196 | goto out; | |
197 | err = 0; | |
198 | if (sbinfo->si_xigen) | |
199 | fput(sbinfo->si_xigen); | |
200 | sbinfo->si_xigen = file; | |
201 | ||
202 | out: | |
203 | return err; | |
204 | } | |
205 | ||
206 | void au_xigen_clr(struct super_block *sb) | |
207 | { | |
208 | struct au_sbinfo *sbinfo; | |
209 | ||
210 | SiMustWriteLock(sb); | |
211 | ||
212 | sbinfo = au_sbi(sb); | |
213 | if (sbinfo->si_xigen) { | |
214 | fput(sbinfo->si_xigen); | |
215 | sbinfo->si_xigen = NULL; | |
216 | } | |
217 | } | |
218 | ||
219 | /* ---------------------------------------------------------------------- */ | |
220 | ||
221 | static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, | |
222 | ino_t dir_ino) | |
223 | { | |
224 | struct dentry *dentry, *d; | |
225 | struct inode *inode; | |
226 | unsigned int sigen; | |
227 | ||
228 | dentry = NULL; | |
229 | inode = ilookup(sb, ino); | |
230 | if (!inode) | |
231 | goto out; | |
232 | ||
233 | dentry = ERR_PTR(-ESTALE); | |
234 | sigen = au_sigen(sb); | |
235 | if (unlikely(au_is_bad_inode(inode) | |
236 | || IS_DEADDIR(inode) | |
237 | || sigen != au_iigen(inode, NULL))) | |
238 | goto out_iput; | |
239 | ||
240 | dentry = NULL; | |
241 | if (!dir_ino || S_ISDIR(inode->i_mode)) | |
242 | dentry = d_find_alias(inode); | |
243 | else { | |
244 | spin_lock(&inode->i_lock); | |
245 | hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { | |
246 | spin_lock(&d->d_lock); | |
247 | if (!au_test_anon(d) | |
248 | && d_inode(d->d_parent)->i_ino == dir_ino) { | |
249 | dentry = dget_dlock(d); | |
250 | spin_unlock(&d->d_lock); | |
251 | break; | |
252 | } | |
253 | spin_unlock(&d->d_lock); | |
254 | } | |
255 | spin_unlock(&inode->i_lock); | |
256 | } | |
257 | if (unlikely(dentry && au_digen_test(dentry, sigen))) { | |
258 | /* need to refresh */ | |
259 | dput(dentry); | |
260 | dentry = NULL; | |
261 | } | |
262 | ||
263 | out_iput: | |
264 | iput(inode); | |
265 | out: | |
266 | AuTraceErrPtr(dentry); | |
267 | return dentry; | |
268 | } | |
269 | ||
270 | /* ---------------------------------------------------------------------- */ | |
271 | ||
272 | /* todo: dirty? */ | |
273 | /* if exportfs_decode_fh() passed vfsmount*, we could be happy */ | |
274 | ||
275 | struct au_compare_mnt_args { | |
276 | /* input */ | |
277 | struct super_block *sb; | |
278 | ||
279 | /* output */ | |
280 | struct vfsmount *mnt; | |
281 | }; | |
282 | ||
283 | static int au_compare_mnt(struct vfsmount *mnt, void *arg) | |
284 | { | |
285 | struct au_compare_mnt_args *a = arg; | |
286 | ||
287 | if (mnt->mnt_sb != a->sb) | |
288 | return 0; | |
289 | a->mnt = mntget(mnt); | |
290 | return 1; | |
291 | } | |
292 | ||
293 | static struct vfsmount *au_mnt_get(struct super_block *sb) | |
294 | { | |
295 | int err; | |
296 | struct path root; | |
297 | struct au_compare_mnt_args args = { | |
298 | .sb = sb | |
299 | }; | |
300 | ||
301 | get_fs_root(current->fs, &root); | |
302 | rcu_read_lock(); | |
303 | err = iterate_mounts(au_compare_mnt, &args, root.mnt); | |
304 | rcu_read_unlock(); | |
305 | path_put(&root); | |
306 | AuDebugOn(!err); | |
307 | AuDebugOn(!args.mnt); | |
308 | return args.mnt; | |
309 | } | |
310 | ||
311 | struct au_nfsd_si_lock { | |
312 | unsigned int sigen; | |
313 | aufs_bindex_t bindex, br_id; | |
314 | unsigned char force_lock; | |
315 | }; | |
316 | ||
317 | static int si_nfsd_read_lock(struct super_block *sb, | |
318 | struct au_nfsd_si_lock *nsi_lock) | |
319 | { | |
320 | int err; | |
321 | aufs_bindex_t bindex; | |
322 | ||
323 | si_read_lock(sb, AuLock_FLUSH); | |
324 | ||
325 | /* branch id may be wrapped around */ | |
326 | err = 0; | |
327 | bindex = au_br_index(sb, nsi_lock->br_id); | |
328 | if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb)) | |
329 | goto out; /* success */ | |
330 | ||
331 | err = -ESTALE; | |
332 | bindex = -1; | |
333 | if (!nsi_lock->force_lock) | |
334 | si_read_unlock(sb); | |
335 | ||
336 | out: | |
337 | nsi_lock->bindex = bindex; | |
338 | return err; | |
339 | } | |
340 | ||
341 | struct find_name_by_ino { | |
342 | struct dir_context ctx; | |
343 | int called, found; | |
344 | ino_t ino; | |
345 | char *name; | |
346 | int namelen; | |
347 | }; | |
348 | ||
349 | static int | |
350 | find_name_by_ino(struct dir_context *ctx, const char *name, int namelen, | |
351 | loff_t offset, u64 ino, unsigned int d_type) | |
352 | { | |
353 | struct find_name_by_ino *a = container_of(ctx, struct find_name_by_ino, | |
354 | ctx); | |
355 | ||
356 | a->called++; | |
357 | if (a->ino != ino) | |
358 | return 0; | |
359 | ||
360 | memcpy(a->name, name, namelen); | |
361 | a->namelen = namelen; | |
362 | a->found = 1; | |
363 | return 1; | |
364 | } | |
365 | ||
366 | static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, | |
367 | struct au_nfsd_si_lock *nsi_lock) | |
368 | { | |
369 | struct dentry *dentry, *parent; | |
370 | struct file *file; | |
371 | struct inode *dir; | |
372 | struct find_name_by_ino arg = { | |
373 | .ctx = { | |
374 | .actor = find_name_by_ino | |
375 | } | |
376 | }; | |
377 | int err; | |
378 | ||
379 | parent = path->dentry; | |
380 | if (nsi_lock) | |
381 | si_read_unlock(parent->d_sb); | |
382 | file = vfsub_dentry_open(path, au_dir_roflags); | |
383 | dentry = (void *)file; | |
384 | if (IS_ERR(file)) | |
385 | goto out; | |
386 | ||
387 | dentry = ERR_PTR(-ENOMEM); | |
388 | arg.name = (void *)__get_free_page(GFP_NOFS); | |
389 | if (unlikely(!arg.name)) | |
390 | goto out_file; | |
391 | arg.ino = ino; | |
392 | arg.found = 0; | |
393 | do { | |
394 | arg.called = 0; | |
395 | /* smp_mb(); */ | |
396 | err = vfsub_iterate_dir(file, &arg.ctx); | |
397 | } while (!err && !arg.found && arg.called); | |
398 | dentry = ERR_PTR(err); | |
399 | if (unlikely(err)) | |
400 | goto out_name; | |
401 | /* instead of ENOENT */ | |
402 | dentry = ERR_PTR(-ESTALE); | |
403 | if (!arg.found) | |
404 | goto out_name; | |
405 | ||
406 | /* do not call vfsub_lkup_one() */ | |
407 | dir = d_inode(parent); | |
408 | dentry = vfsub_lookup_one_len_unlocked(arg.name, parent, arg.namelen); | |
409 | AuTraceErrPtr(dentry); | |
410 | if (IS_ERR(dentry)) | |
411 | goto out_name; | |
412 | AuDebugOn(au_test_anon(dentry)); | |
413 | if (unlikely(d_really_is_negative(dentry))) { | |
414 | dput(dentry); | |
415 | dentry = ERR_PTR(-ENOENT); | |
416 | } | |
417 | ||
418 | out_name: | |
419 | free_page((unsigned long)arg.name); | |
420 | out_file: | |
421 | fput(file); | |
422 | out: | |
423 | if (unlikely(nsi_lock | |
424 | && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) | |
425 | if (!IS_ERR(dentry)) { | |
426 | dput(dentry); | |
427 | dentry = ERR_PTR(-ESTALE); | |
428 | } | |
429 | AuTraceErrPtr(dentry); | |
430 | return dentry; | |
431 | } | |
432 | ||
433 | static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, | |
434 | ino_t dir_ino, | |
435 | struct au_nfsd_si_lock *nsi_lock) | |
436 | { | |
437 | struct dentry *dentry; | |
438 | struct path path; | |
439 | ||
440 | if (dir_ino != AUFS_ROOT_INO) { | |
441 | path.dentry = decode_by_ino(sb, dir_ino, 0); | |
442 | dentry = path.dentry; | |
443 | if (!path.dentry || IS_ERR(path.dentry)) | |
444 | goto out; | |
445 | AuDebugOn(au_test_anon(path.dentry)); | |
446 | } else | |
447 | path.dentry = dget(sb->s_root); | |
448 | ||
449 | path.mnt = au_mnt_get(sb); | |
450 | dentry = au_lkup_by_ino(&path, ino, nsi_lock); | |
451 | path_put(&path); | |
452 | ||
453 | out: | |
454 | AuTraceErrPtr(dentry); | |
455 | return dentry; | |
456 | } | |
457 | ||
458 | /* ---------------------------------------------------------------------- */ | |
459 | ||
460 | static int h_acceptable(void *expv, struct dentry *dentry) | |
461 | { | |
462 | return 1; | |
463 | } | |
464 | ||
465 | static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, | |
466 | char *buf, int len, struct super_block *sb) | |
467 | { | |
468 | char *p; | |
469 | int n; | |
470 | struct path path; | |
471 | ||
472 | p = d_path(h_rootpath, buf, len); | |
473 | if (IS_ERR(p)) | |
474 | goto out; | |
475 | n = strlen(p); | |
476 | ||
477 | path.mnt = h_rootpath->mnt; | |
478 | path.dentry = h_parent; | |
479 | p = d_path(&path, buf, len); | |
480 | if (IS_ERR(p)) | |
481 | goto out; | |
482 | if (n != 1) | |
483 | p += n; | |
484 | ||
485 | path.mnt = au_mnt_get(sb); | |
486 | path.dentry = sb->s_root; | |
487 | p = d_path(&path, buf, len - strlen(p)); | |
488 | mntput(path.mnt); | |
489 | if (IS_ERR(p)) | |
490 | goto out; | |
491 | if (n != 1) | |
492 | p[strlen(p)] = '/'; | |
493 | ||
494 | out: | |
495 | AuTraceErrPtr(p); | |
496 | return p; | |
497 | } | |
498 | ||
499 | static | |
500 | struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh, | |
501 | int fh_len, struct au_nfsd_si_lock *nsi_lock) | |
502 | { | |
503 | struct dentry *dentry, *h_parent, *root; | |
504 | struct super_block *h_sb; | |
505 | char *pathname, *p; | |
506 | struct vfsmount *h_mnt; | |
507 | struct au_branch *br; | |
508 | int err; | |
509 | struct path path; | |
510 | ||
511 | br = au_sbr(sb, nsi_lock->bindex); | |
512 | h_mnt = au_br_mnt(br); | |
513 | h_sb = h_mnt->mnt_sb; | |
514 | /* todo: call lower fh_to_dentry()? fh_to_parent()? */ | |
515 | lockdep_off(); | |
516 | h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), | |
517 | fh_len - Fh_tail, fh[Fh_h_type], | |
518 | h_acceptable, /*context*/NULL); | |
519 | lockdep_on(); | |
520 | dentry = h_parent; | |
521 | if (unlikely(!h_parent || IS_ERR(h_parent))) { | |
522 | AuWarn1("%s decode_fh failed, %ld\n", | |
523 | au_sbtype(h_sb), PTR_ERR(h_parent)); | |
524 | goto out; | |
525 | } | |
526 | dentry = NULL; | |
527 | if (unlikely(au_test_anon(h_parent))) { | |
528 | AuWarn1("%s decode_fh returned a disconnected dentry\n", | |
529 | au_sbtype(h_sb)); | |
530 | goto out_h_parent; | |
531 | } | |
532 | ||
533 | dentry = ERR_PTR(-ENOMEM); | |
534 | pathname = (void *)__get_free_page(GFP_NOFS); | |
535 | if (unlikely(!pathname)) | |
536 | goto out_h_parent; | |
537 | ||
538 | root = sb->s_root; | |
539 | path.mnt = h_mnt; | |
540 | di_read_lock_parent(root, !AuLock_IR); | |
541 | path.dentry = au_h_dptr(root, nsi_lock->bindex); | |
542 | di_read_unlock(root, !AuLock_IR); | |
543 | p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); | |
544 | dentry = (void *)p; | |
545 | if (IS_ERR(p)) | |
546 | goto out_pathname; | |
547 | ||
548 | si_read_unlock(sb); | |
549 | err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); | |
550 | dentry = ERR_PTR(err); | |
551 | if (unlikely(err)) | |
552 | goto out_relock; | |
553 | ||
554 | dentry = ERR_PTR(-ENOENT); | |
555 | AuDebugOn(au_test_anon(path.dentry)); | |
556 | if (unlikely(d_really_is_negative(path.dentry))) | |
557 | goto out_path; | |
558 | ||
559 | if (ino != d_inode(path.dentry)->i_ino) | |
560 | dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); | |
561 | else | |
562 | dentry = dget(path.dentry); | |
563 | ||
564 | out_path: | |
565 | path_put(&path); | |
566 | out_relock: | |
567 | if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) | |
568 | if (!IS_ERR(dentry)) { | |
569 | dput(dentry); | |
570 | dentry = ERR_PTR(-ESTALE); | |
571 | } | |
572 | out_pathname: | |
573 | free_page((unsigned long)pathname); | |
574 | out_h_parent: | |
575 | dput(h_parent); | |
576 | out: | |
577 | AuTraceErrPtr(dentry); | |
578 | return dentry; | |
579 | } | |
580 | ||
581 | /* ---------------------------------------------------------------------- */ | |
582 | ||
583 | static struct dentry * | |
584 | aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, | |
585 | int fh_type) | |
586 | { | |
587 | struct dentry *dentry; | |
588 | __u32 *fh = fid->raw; | |
589 | struct au_branch *br; | |
590 | ino_t ino, dir_ino; | |
591 | struct au_nfsd_si_lock nsi_lock = { | |
592 | .force_lock = 0 | |
593 | }; | |
594 | ||
595 | dentry = ERR_PTR(-ESTALE); | |
596 | /* it should never happen, but the file handle is unreliable */ | |
597 | if (unlikely(fh_len < Fh_tail)) | |
598 | goto out; | |
599 | nsi_lock.sigen = fh[Fh_sigen]; | |
600 | nsi_lock.br_id = fh[Fh_br_id]; | |
601 | ||
602 | /* branch id may be wrapped around */ | |
603 | br = NULL; | |
604 | if (unlikely(si_nfsd_read_lock(sb, &nsi_lock))) | |
605 | goto out; | |
606 | nsi_lock.force_lock = 1; | |
607 | ||
608 | /* is this inode still cached? */ | |
609 | ino = decode_ino(fh + Fh_ino); | |
610 | /* it should never happen */ | |
611 | if (unlikely(ino == AUFS_ROOT_INO)) | |
612 | goto out_unlock; | |
613 | ||
614 | dir_ino = decode_ino(fh + Fh_dir_ino); | |
615 | dentry = decode_by_ino(sb, ino, dir_ino); | |
616 | if (IS_ERR(dentry)) | |
617 | goto out_unlock; | |
618 | if (dentry) | |
619 | goto accept; | |
620 | ||
621 | /* is the parent dir cached? */ | |
622 | br = au_sbr(sb, nsi_lock.bindex); | |
623 | au_br_get(br); | |
624 | dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); | |
625 | if (IS_ERR(dentry)) | |
626 | goto out_unlock; | |
627 | if (dentry) | |
628 | goto accept; | |
629 | ||
630 | /* lookup path */ | |
631 | dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock); | |
632 | if (IS_ERR(dentry)) | |
633 | goto out_unlock; | |
634 | if (unlikely(!dentry)) | |
635 | /* todo?: make it ESTALE */ | |
636 | goto out_unlock; | |
637 | ||
638 | accept: | |
639 | if (!au_digen_test(dentry, au_sigen(sb)) | |
640 | && d_inode(dentry)->i_generation == fh[Fh_igen]) | |
641 | goto out_unlock; /* success */ | |
642 | ||
643 | dput(dentry); | |
644 | dentry = ERR_PTR(-ESTALE); | |
645 | out_unlock: | |
646 | if (br) | |
647 | au_br_put(br); | |
648 | si_read_unlock(sb); | |
649 | out: | |
650 | AuTraceErrPtr(dentry); | |
651 | return dentry; | |
652 | } | |
653 | ||
654 | #if 0 /* reserved for future use */ | |
655 | /* support subtreecheck option */ | |
656 | static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, | |
657 | int fh_len, int fh_type) | |
658 | { | |
659 | struct dentry *parent; | |
660 | __u32 *fh = fid->raw; | |
661 | ino_t dir_ino; | |
662 | ||
663 | dir_ino = decode_ino(fh + Fh_dir_ino); | |
664 | parent = decode_by_ino(sb, dir_ino, 0); | |
665 | if (IS_ERR(parent)) | |
666 | goto out; | |
667 | if (!parent) | |
668 | parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), | |
669 | dir_ino, fh, fh_len); | |
670 | ||
671 | out: | |
672 | AuTraceErrPtr(parent); | |
673 | return parent; | |
674 | } | |
675 | #endif | |
676 | ||
677 | /* ---------------------------------------------------------------------- */ | |
678 | ||
679 | static int aufs_encode_fh(struct inode *inode, __u32 *fh, int *max_len, | |
680 | struct inode *dir) | |
681 | { | |
682 | int err; | |
683 | aufs_bindex_t bindex; | |
684 | struct super_block *sb, *h_sb; | |
685 | struct dentry *dentry, *parent, *h_parent; | |
686 | struct inode *h_dir; | |
687 | struct au_branch *br; | |
688 | ||
689 | err = -ENOSPC; | |
690 | if (unlikely(*max_len <= Fh_tail)) { | |
691 | AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); | |
692 | goto out; | |
693 | } | |
694 | ||
695 | err = FILEID_ROOT; | |
696 | if (inode->i_ino == AUFS_ROOT_INO) { | |
697 | AuDebugOn(inode->i_ino != AUFS_ROOT_INO); | |
698 | goto out; | |
699 | } | |
700 | ||
701 | h_parent = NULL; | |
702 | sb = inode->i_sb; | |
703 | err = si_read_lock(sb, AuLock_FLUSH); | |
704 | if (unlikely(err)) | |
705 | goto out; | |
706 | ||
707 | #ifdef CONFIG_AUFS_DEBUG | |
708 | if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) | |
709 | AuWarn1("NFS-exporting requires xino\n"); | |
710 | #endif | |
711 | err = -EIO; | |
712 | parent = NULL; | |
713 | ii_read_lock_child(inode); | |
714 | bindex = au_ibtop(inode); | |
715 | if (!dir) { | |
716 | dentry = d_find_any_alias(inode); | |
717 | if (unlikely(!dentry)) | |
718 | goto out_unlock; | |
719 | AuDebugOn(au_test_anon(dentry)); | |
720 | parent = dget_parent(dentry); | |
721 | dput(dentry); | |
722 | if (unlikely(!parent)) | |
723 | goto out_unlock; | |
724 | if (d_really_is_positive(parent)) | |
725 | dir = d_inode(parent); | |
726 | } | |
727 | ||
728 | ii_read_lock_parent(dir); | |
729 | h_dir = au_h_iptr(dir, bindex); | |
730 | ii_read_unlock(dir); | |
731 | if (unlikely(!h_dir)) | |
732 | goto out_parent; | |
733 | h_parent = d_find_any_alias(h_dir); | |
734 | if (unlikely(!h_parent)) | |
735 | goto out_hparent; | |
736 | ||
737 | err = -EPERM; | |
738 | br = au_sbr(sb, bindex); | |
739 | h_sb = au_br_sb(br); | |
740 | if (unlikely(!h_sb->s_export_op)) { | |
741 | AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); | |
742 | goto out_hparent; | |
743 | } | |
744 | ||
745 | fh[Fh_br_id] = br->br_id; | |
746 | fh[Fh_sigen] = au_sigen(sb); | |
747 | encode_ino(fh + Fh_ino, inode->i_ino); | |
748 | encode_ino(fh + Fh_dir_ino, dir->i_ino); | |
749 | fh[Fh_igen] = inode->i_generation; | |
750 | ||
751 | *max_len -= Fh_tail; | |
752 | fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), | |
753 | max_len, | |
754 | /*connectable or subtreecheck*/0); | |
755 | err = fh[Fh_h_type]; | |
756 | *max_len += Fh_tail; | |
757 | /* todo: macros? */ | |
758 | if (err != FILEID_INVALID) | |
759 | err = 99; | |
760 | else | |
761 | AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); | |
762 | ||
763 | out_hparent: | |
764 | dput(h_parent); | |
765 | out_parent: | |
766 | dput(parent); | |
767 | out_unlock: | |
768 | ii_read_unlock(inode); | |
769 | si_read_unlock(sb); | |
770 | out: | |
771 | if (unlikely(err < 0)) | |
772 | err = FILEID_INVALID; | |
773 | return err; | |
774 | } | |
775 | ||
776 | /* ---------------------------------------------------------------------- */ | |
777 | ||
778 | static int aufs_commit_metadata(struct inode *inode) | |
779 | { | |
780 | int err; | |
781 | aufs_bindex_t bindex; | |
782 | struct super_block *sb; | |
783 | struct inode *h_inode; | |
784 | int (*f)(struct inode *inode); | |
785 | ||
786 | sb = inode->i_sb; | |
787 | si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); | |
788 | ii_write_lock_child(inode); | |
789 | bindex = au_ibtop(inode); | |
790 | AuDebugOn(bindex < 0); | |
791 | h_inode = au_h_iptr(inode, bindex); | |
792 | ||
793 | f = h_inode->i_sb->s_export_op->commit_metadata; | |
794 | if (f) | |
795 | err = f(h_inode); | |
796 | else { | |
797 | struct writeback_control wbc = { | |
798 | .sync_mode = WB_SYNC_ALL, | |
799 | .nr_to_write = 0 /* metadata only */ | |
800 | }; | |
801 | ||
802 | err = sync_inode(h_inode, &wbc); | |
803 | } | |
804 | ||
805 | au_cpup_attr_timesizes(inode); | |
806 | ii_write_unlock(inode); | |
807 | si_read_unlock(sb); | |
808 | return err; | |
809 | } | |
810 | ||
811 | /* ---------------------------------------------------------------------- */ | |
812 | ||
813 | static struct export_operations aufs_export_op = { | |
814 | .fh_to_dentry = aufs_fh_to_dentry, | |
815 | /* .fh_to_parent = aufs_fh_to_parent, */ | |
816 | .encode_fh = aufs_encode_fh, | |
817 | .commit_metadata = aufs_commit_metadata | |
818 | }; | |
819 | ||
820 | void au_export_init(struct super_block *sb) | |
821 | { | |
822 | struct au_sbinfo *sbinfo; | |
823 | __u32 u; | |
824 | ||
825 | BUILD_BUG_ON_MSG(IS_BUILTIN(CONFIG_AUFS_FS) | |
826 | && IS_MODULE(CONFIG_EXPORTFS), | |
827 | AUFS_NAME ": unsupported configuration " | |
828 | "CONFIG_EXPORTFS=m and CONFIG_AUFS_FS=y"); | |
829 | ||
830 | sb->s_export_op = &aufs_export_op; | |
831 | sbinfo = au_sbi(sb); | |
832 | sbinfo->si_xigen = NULL; | |
833 | get_random_bytes(&u, sizeof(u)); | |
834 | BUILD_BUG_ON(sizeof(u) != sizeof(int)); | |
835 | atomic_set(&sbinfo->si_xigen_next, u); | |
836 | } |