]>
Commit | Line | Data |
---|---|---|
c088e31d SF |
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 | * sub-routines for VFS | |
20 | */ | |
21 | ||
22 | #include <linux/mnt_namespace.h> | |
23 | #include <linux/namei.h> | |
24 | #include <linux/nsproxy.h> | |
25 | #include <linux/security.h> | |
26 | #include <linux/splice.h> | |
27 | #include "aufs.h" | |
28 | ||
29 | #ifdef CONFIG_AUFS_BR_FUSE | |
30 | int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb) | |
31 | { | |
32 | if (!au_test_fuse(h_sb) || !au_userns) | |
33 | return 0; | |
34 | ||
35 | return is_current_mnt_ns(mnt) ? 0 : -EACCES; | |
36 | } | |
37 | #endif | |
38 | ||
39 | int vfsub_sync_filesystem(struct super_block *h_sb, int wait) | |
40 | { | |
41 | int err; | |
42 | ||
43 | lockdep_off(); | |
44 | down_read(&h_sb->s_umount); | |
45 | err = __sync_filesystem(h_sb, wait); | |
46 | up_read(&h_sb->s_umount); | |
47 | lockdep_on(); | |
48 | ||
49 | return err; | |
50 | } | |
51 | ||
52 | /* ---------------------------------------------------------------------- */ | |
53 | ||
54 | int vfsub_update_h_iattr(struct path *h_path, int *did) | |
55 | { | |
56 | int err; | |
57 | struct kstat st; | |
58 | struct super_block *h_sb; | |
59 | ||
60 | /* for remote fs, leave work for its getattr or d_revalidate */ | |
61 | /* for bad i_attr fs, handle them in aufs_getattr() */ | |
62 | /* still some fs may acquire i_mutex. we need to skip them */ | |
63 | err = 0; | |
64 | if (!did) | |
65 | did = &err; | |
66 | h_sb = h_path->dentry->d_sb; | |
67 | *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb)); | |
68 | if (*did) | |
69 | err = vfsub_getattr(h_path, &st); | |
70 | ||
71 | return err; | |
72 | } | |
73 | ||
74 | /* ---------------------------------------------------------------------- */ | |
75 | ||
76 | struct file *vfsub_dentry_open(struct path *path, int flags) | |
77 | { | |
78 | struct file *file; | |
79 | ||
80 | file = dentry_open(path, flags /* | __FMODE_NONOTIFY */, | |
81 | current_cred()); | |
82 | if (!IS_ERR_OR_NULL(file) | |
83 | && (file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | |
84 | i_readcount_inc(d_inode(path->dentry)); | |
85 | ||
86 | return file; | |
87 | } | |
88 | ||
89 | struct file *vfsub_filp_open(const char *path, int oflags, int mode) | |
90 | { | |
91 | struct file *file; | |
92 | ||
93 | lockdep_off(); | |
94 | file = filp_open(path, | |
95 | oflags /* | __FMODE_NONOTIFY */, | |
96 | mode); | |
97 | lockdep_on(); | |
98 | if (IS_ERR(file)) | |
99 | goto out; | |
100 | vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ | |
101 | ||
102 | out: | |
103 | return file; | |
104 | } | |
105 | ||
106 | /* | |
107 | * Ideally this function should call VFS:do_last() in order to keep all its | |
108 | * checkings. But it is very hard for aufs to regenerate several VFS internal | |
109 | * structure such as nameidata. This is a second (or third) best approach. | |
110 | * cf. linux/fs/namei.c:do_last(), lookup_open() and atomic_open(). | |
111 | */ | |
112 | int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, | |
113 | struct vfsub_aopen_args *args, struct au_branch *br) | |
114 | { | |
115 | int err; | |
116 | struct file *file = args->file; | |
117 | /* copied from linux/fs/namei.c:atomic_open() */ | |
118 | struct dentry *const DENTRY_NOT_SET = (void *)-1UL; | |
119 | ||
120 | IMustLock(dir); | |
121 | AuDebugOn(!dir->i_op->atomic_open); | |
122 | ||
123 | err = au_br_test_oflag(args->open_flag, br); | |
124 | if (unlikely(err)) | |
125 | goto out; | |
126 | ||
127 | args->file->f_path.dentry = DENTRY_NOT_SET; | |
128 | args->file->f_path.mnt = au_br_mnt(br); | |
129 | err = dir->i_op->atomic_open(dir, dentry, file, args->open_flag, | |
130 | args->create_mode, args->opened); | |
131 | if (err >= 0) { | |
132 | /* some filesystems don't set FILE_CREATED while succeeded? */ | |
133 | if (*args->opened & FILE_CREATED) | |
134 | fsnotify_create(dir, dentry); | |
135 | } else | |
136 | goto out; | |
137 | ||
138 | ||
139 | if (!err) { | |
140 | /* todo: call VFS:may_open() here */ | |
141 | err = open_check_o_direct(file); | |
142 | /* todo: ima_file_check() too? */ | |
143 | if (!err && (args->open_flag & __FMODE_EXEC)) | |
144 | err = deny_write_access(file); | |
145 | if (unlikely(err)) | |
146 | /* note that the file is created and still opened */ | |
147 | goto out; | |
148 | } | |
149 | ||
150 | au_br_get(br); | |
151 | fsnotify_open(file); | |
152 | ||
153 | out: | |
154 | return err; | |
155 | } | |
156 | ||
157 | int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) | |
158 | { | |
159 | int err; | |
160 | ||
161 | err = kern_path(name, flags, path); | |
162 | if (!err && d_is_positive(path->dentry)) | |
163 | vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ | |
164 | return err; | |
165 | } | |
166 | ||
167 | struct dentry *vfsub_lookup_one_len_unlocked(const char *name, | |
168 | struct dentry *parent, int len) | |
169 | { | |
170 | struct path path = { | |
171 | .mnt = NULL | |
172 | }; | |
173 | ||
174 | path.dentry = lookup_one_len_unlocked(name, parent, len); | |
175 | if (IS_ERR(path.dentry)) | |
176 | goto out; | |
177 | if (d_is_positive(path.dentry)) | |
178 | vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ | |
179 | ||
180 | out: | |
181 | AuTraceErrPtr(path.dentry); | |
182 | return path.dentry; | |
183 | } | |
184 | ||
185 | struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, | |
186 | int len) | |
187 | { | |
188 | struct path path = { | |
189 | .mnt = NULL | |
190 | }; | |
191 | ||
192 | /* VFS checks it too, but by WARN_ON_ONCE() */ | |
193 | IMustLock(d_inode(parent)); | |
194 | ||
195 | path.dentry = lookup_one_len(name, parent, len); | |
196 | if (IS_ERR(path.dentry)) | |
197 | goto out; | |
198 | if (d_is_positive(path.dentry)) | |
199 | vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ | |
200 | ||
201 | out: | |
202 | AuTraceErrPtr(path.dentry); | |
203 | return path.dentry; | |
204 | } | |
205 | ||
206 | void vfsub_call_lkup_one(void *args) | |
207 | { | |
208 | struct vfsub_lkup_one_args *a = args; | |
209 | *a->errp = vfsub_lkup_one(a->name, a->parent); | |
210 | } | |
211 | ||
212 | /* ---------------------------------------------------------------------- */ | |
213 | ||
214 | struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, | |
215 | struct dentry *d2, struct au_hinode *hdir2) | |
216 | { | |
217 | struct dentry *d; | |
218 | ||
219 | lockdep_off(); | |
220 | d = lock_rename(d1, d2); | |
221 | lockdep_on(); | |
222 | au_hn_suspend(hdir1); | |
223 | if (hdir1 != hdir2) | |
224 | au_hn_suspend(hdir2); | |
225 | ||
226 | return d; | |
227 | } | |
228 | ||
229 | void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, | |
230 | struct dentry *d2, struct au_hinode *hdir2) | |
231 | { | |
232 | au_hn_resume(hdir1); | |
233 | if (hdir1 != hdir2) | |
234 | au_hn_resume(hdir2); | |
235 | lockdep_off(); | |
236 | unlock_rename(d1, d2); | |
237 | lockdep_on(); | |
238 | } | |
239 | ||
240 | /* ---------------------------------------------------------------------- */ | |
241 | ||
242 | int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl) | |
243 | { | |
244 | int err; | |
245 | struct dentry *d; | |
246 | ||
247 | IMustLock(dir); | |
248 | ||
249 | d = path->dentry; | |
250 | path->dentry = d->d_parent; | |
251 | err = security_path_mknod(path, d, mode, 0); | |
252 | path->dentry = d; | |
253 | if (unlikely(err)) | |
254 | goto out; | |
255 | ||
256 | lockdep_off(); | |
257 | err = vfs_create(dir, path->dentry, mode, want_excl); | |
258 | lockdep_on(); | |
259 | if (!err) { | |
260 | struct path tmp = *path; | |
261 | int did; | |
262 | ||
263 | vfsub_update_h_iattr(&tmp, &did); | |
264 | if (did) { | |
265 | tmp.dentry = path->dentry->d_parent; | |
266 | vfsub_update_h_iattr(&tmp, /*did*/NULL); | |
267 | } | |
268 | /*ignore*/ | |
269 | } | |
270 | ||
271 | out: | |
272 | return err; | |
273 | } | |
274 | ||
275 | int vfsub_symlink(struct inode *dir, struct path *path, const char *symname) | |
276 | { | |
277 | int err; | |
278 | struct dentry *d; | |
279 | ||
280 | IMustLock(dir); | |
281 | ||
282 | d = path->dentry; | |
283 | path->dentry = d->d_parent; | |
284 | err = security_path_symlink(path, d, symname); | |
285 | path->dentry = d; | |
286 | if (unlikely(err)) | |
287 | goto out; | |
288 | ||
289 | lockdep_off(); | |
290 | err = vfs_symlink(dir, path->dentry, symname); | |
291 | lockdep_on(); | |
292 | if (!err) { | |
293 | struct path tmp = *path; | |
294 | int did; | |
295 | ||
296 | vfsub_update_h_iattr(&tmp, &did); | |
297 | if (did) { | |
298 | tmp.dentry = path->dentry->d_parent; | |
299 | vfsub_update_h_iattr(&tmp, /*did*/NULL); | |
300 | } | |
301 | /*ignore*/ | |
302 | } | |
303 | ||
304 | out: | |
305 | return err; | |
306 | } | |
307 | ||
308 | int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev) | |
309 | { | |
310 | int err; | |
311 | struct dentry *d; | |
312 | ||
313 | IMustLock(dir); | |
314 | ||
315 | d = path->dentry; | |
316 | path->dentry = d->d_parent; | |
317 | err = security_path_mknod(path, d, mode, new_encode_dev(dev)); | |
318 | path->dentry = d; | |
319 | if (unlikely(err)) | |
320 | goto out; | |
321 | ||
322 | lockdep_off(); | |
323 | err = vfs_mknod(dir, path->dentry, mode, dev); | |
324 | lockdep_on(); | |
325 | if (!err) { | |
326 | struct path tmp = *path; | |
327 | int did; | |
328 | ||
329 | vfsub_update_h_iattr(&tmp, &did); | |
330 | if (did) { | |
331 | tmp.dentry = path->dentry->d_parent; | |
332 | vfsub_update_h_iattr(&tmp, /*did*/NULL); | |
333 | } | |
334 | /*ignore*/ | |
335 | } | |
336 | ||
337 | out: | |
338 | return err; | |
339 | } | |
340 | ||
341 | static int au_test_nlink(struct inode *inode) | |
342 | { | |
343 | const unsigned int link_max = UINT_MAX >> 1; /* rough margin */ | |
344 | ||
345 | if (!au_test_fs_no_limit_nlink(inode->i_sb) | |
346 | || inode->i_nlink < link_max) | |
347 | return 0; | |
348 | return -EMLINK; | |
349 | } | |
350 | ||
351 | int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path, | |
352 | struct inode **delegated_inode) | |
353 | { | |
354 | int err; | |
355 | struct dentry *d; | |
356 | ||
357 | IMustLock(dir); | |
358 | ||
359 | err = au_test_nlink(d_inode(src_dentry)); | |
360 | if (unlikely(err)) | |
361 | return err; | |
362 | ||
363 | /* we don't call may_linkat() */ | |
364 | d = path->dentry; | |
365 | path->dentry = d->d_parent; | |
366 | err = security_path_link(src_dentry, path, d); | |
367 | path->dentry = d; | |
368 | if (unlikely(err)) | |
369 | goto out; | |
370 | ||
371 | lockdep_off(); | |
372 | err = vfs_link(src_dentry, dir, path->dentry, delegated_inode); | |
373 | lockdep_on(); | |
374 | if (!err) { | |
375 | struct path tmp = *path; | |
376 | int did; | |
377 | ||
378 | /* fuse has different memory inode for the same inumber */ | |
379 | vfsub_update_h_iattr(&tmp, &did); | |
380 | if (did) { | |
381 | tmp.dentry = path->dentry->d_parent; | |
382 | vfsub_update_h_iattr(&tmp, /*did*/NULL); | |
383 | tmp.dentry = src_dentry; | |
384 | vfsub_update_h_iattr(&tmp, /*did*/NULL); | |
385 | } | |
386 | /*ignore*/ | |
387 | } | |
388 | ||
389 | out: | |
390 | return err; | |
391 | } | |
392 | ||
393 | int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, | |
394 | struct inode *dir, struct path *path, | |
395 | struct inode **delegated_inode, unsigned int flags) | |
396 | { | |
397 | int err; | |
398 | struct path tmp = { | |
399 | .mnt = path->mnt | |
400 | }; | |
401 | struct dentry *d; | |
402 | ||
403 | IMustLock(dir); | |
404 | IMustLock(src_dir); | |
405 | ||
406 | d = path->dentry; | |
407 | path->dentry = d->d_parent; | |
408 | tmp.dentry = src_dentry->d_parent; | |
409 | err = security_path_rename(&tmp, src_dentry, path, d, /*flags*/0); | |
410 | path->dentry = d; | |
411 | if (unlikely(err)) | |
412 | goto out; | |
413 | ||
414 | lockdep_off(); | |
415 | err = vfs_rename(src_dir, src_dentry, dir, path->dentry, | |
416 | delegated_inode, flags); | |
417 | lockdep_on(); | |
418 | if (!err) { | |
419 | int did; | |
420 | ||
421 | tmp.dentry = d->d_parent; | |
422 | vfsub_update_h_iattr(&tmp, &did); | |
423 | if (did) { | |
424 | tmp.dentry = src_dentry; | |
425 | vfsub_update_h_iattr(&tmp, /*did*/NULL); | |
426 | tmp.dentry = src_dentry->d_parent; | |
427 | vfsub_update_h_iattr(&tmp, /*did*/NULL); | |
428 | } | |
429 | /*ignore*/ | |
430 | } | |
431 | ||
432 | out: | |
433 | return err; | |
434 | } | |
435 | ||
436 | int vfsub_mkdir(struct inode *dir, struct path *path, int mode) | |
437 | { | |
438 | int err; | |
439 | struct dentry *d; | |
440 | ||
441 | IMustLock(dir); | |
442 | ||
443 | d = path->dentry; | |
444 | path->dentry = d->d_parent; | |
445 | err = security_path_mkdir(path, d, mode); | |
446 | path->dentry = d; | |
447 | if (unlikely(err)) | |
448 | goto out; | |
449 | ||
450 | lockdep_off(); | |
451 | err = vfs_mkdir(dir, path->dentry, mode); | |
452 | lockdep_on(); | |
453 | if (!err) { | |
454 | struct path tmp = *path; | |
455 | int did; | |
456 | ||
457 | vfsub_update_h_iattr(&tmp, &did); | |
458 | if (did) { | |
459 | tmp.dentry = path->dentry->d_parent; | |
460 | vfsub_update_h_iattr(&tmp, /*did*/NULL); | |
461 | } | |
462 | /*ignore*/ | |
463 | } | |
464 | ||
465 | out: | |
466 | return err; | |
467 | } | |
468 | ||
469 | int vfsub_rmdir(struct inode *dir, struct path *path) | |
470 | { | |
471 | int err; | |
472 | struct dentry *d; | |
473 | ||
474 | IMustLock(dir); | |
475 | ||
476 | d = path->dentry; | |
477 | path->dentry = d->d_parent; | |
478 | err = security_path_rmdir(path, d); | |
479 | path->dentry = d; | |
480 | if (unlikely(err)) | |
481 | goto out; | |
482 | ||
483 | lockdep_off(); | |
484 | err = vfs_rmdir(dir, path->dentry); | |
485 | lockdep_on(); | |
486 | if (!err) { | |
487 | struct path tmp = { | |
488 | .dentry = path->dentry->d_parent, | |
489 | .mnt = path->mnt | |
490 | }; | |
491 | ||
492 | vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ | |
493 | } | |
494 | ||
495 | out: | |
496 | return err; | |
497 | } | |
498 | ||
499 | /* ---------------------------------------------------------------------- */ | |
500 | ||
501 | /* todo: support mmap_sem? */ | |
502 | ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, | |
503 | loff_t *ppos) | |
504 | { | |
505 | ssize_t err; | |
506 | ||
507 | lockdep_off(); | |
508 | err = vfs_read(file, ubuf, count, ppos); | |
509 | lockdep_on(); | |
510 | if (err >= 0) | |
511 | vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ | |
512 | return err; | |
513 | } | |
514 | ||
515 | /* todo: kernel_read()? */ | |
516 | ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, | |
517 | loff_t *ppos) | |
518 | { | |
519 | ssize_t err; | |
520 | mm_segment_t oldfs; | |
521 | union { | |
522 | void *k; | |
523 | char __user *u; | |
524 | } buf; | |
525 | ||
526 | buf.k = kbuf; | |
527 | oldfs = get_fs(); | |
528 | set_fs(KERNEL_DS); | |
529 | err = vfsub_read_u(file, buf.u, count, ppos); | |
530 | set_fs(oldfs); | |
531 | return err; | |
532 | } | |
533 | ||
534 | ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, | |
535 | loff_t *ppos) | |
536 | { | |
537 | ssize_t err; | |
538 | ||
539 | lockdep_off(); | |
540 | err = vfs_write(file, ubuf, count, ppos); | |
541 | lockdep_on(); | |
542 | if (err >= 0) | |
543 | vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ | |
544 | return err; | |
545 | } | |
546 | ||
547 | ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos) | |
548 | { | |
549 | ssize_t err; | |
550 | mm_segment_t oldfs; | |
551 | union { | |
552 | void *k; | |
553 | const char __user *u; | |
554 | } buf; | |
555 | ||
556 | buf.k = kbuf; | |
557 | oldfs = get_fs(); | |
558 | set_fs(KERNEL_DS); | |
559 | err = vfsub_write_u(file, buf.u, count, ppos); | |
560 | set_fs(oldfs); | |
561 | return err; | |
562 | } | |
563 | ||
564 | int vfsub_flush(struct file *file, fl_owner_t id) | |
565 | { | |
566 | int err; | |
567 | ||
568 | err = 0; | |
569 | if (file->f_op->flush) { | |
570 | if (!au_test_nfs(file->f_path.dentry->d_sb)) | |
571 | err = file->f_op->flush(file, id); | |
572 | else { | |
573 | lockdep_off(); | |
574 | err = file->f_op->flush(file, id); | |
575 | lockdep_on(); | |
576 | } | |
577 | if (!err) | |
578 | vfsub_update_h_iattr(&file->f_path, /*did*/NULL); | |
579 | /*ignore*/ | |
580 | } | |
581 | return err; | |
582 | } | |
583 | ||
584 | int vfsub_iterate_dir(struct file *file, struct dir_context *ctx) | |
585 | { | |
586 | int err; | |
587 | ||
588 | AuDbg("%pD, ctx{%pf, %llu}\n", file, ctx->actor, ctx->pos); | |
589 | ||
590 | lockdep_off(); | |
591 | err = iterate_dir(file, ctx); | |
592 | lockdep_on(); | |
593 | if (err >= 0) | |
594 | vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ | |
595 | ||
596 | return err; | |
597 | } | |
598 | ||
599 | long vfsub_splice_to(struct file *in, loff_t *ppos, | |
600 | struct pipe_inode_info *pipe, size_t len, | |
601 | unsigned int flags) | |
602 | { | |
603 | long err; | |
604 | ||
605 | lockdep_off(); | |
606 | err = do_splice_to(in, ppos, pipe, len, flags); | |
607 | lockdep_on(); | |
608 | file_accessed(in); | |
609 | if (err >= 0) | |
610 | vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/ | |
611 | return err; | |
612 | } | |
613 | ||
614 | long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, | |
615 | loff_t *ppos, size_t len, unsigned int flags) | |
616 | { | |
617 | long err; | |
618 | ||
619 | lockdep_off(); | |
620 | err = do_splice_from(pipe, out, ppos, len, flags); | |
621 | lockdep_on(); | |
622 | if (err >= 0) | |
623 | vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/ | |
624 | return err; | |
625 | } | |
626 | ||
627 | int vfsub_fsync(struct file *file, struct path *path, int datasync) | |
628 | { | |
629 | int err; | |
630 | ||
631 | /* file can be NULL */ | |
632 | lockdep_off(); | |
633 | err = vfs_fsync(file, datasync); | |
634 | lockdep_on(); | |
635 | if (!err) { | |
636 | if (!path) { | |
637 | AuDebugOn(!file); | |
638 | path = &file->f_path; | |
639 | } | |
640 | vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ | |
641 | } | |
642 | return err; | |
643 | } | |
644 | ||
645 | /* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ | |
646 | int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, | |
647 | struct file *h_file) | |
648 | { | |
649 | int err; | |
650 | struct inode *h_inode; | |
651 | struct super_block *h_sb; | |
652 | ||
653 | if (!h_file) { | |
654 | err = vfsub_truncate(h_path, length); | |
655 | goto out; | |
656 | } | |
657 | ||
658 | h_inode = d_inode(h_path->dentry); | |
659 | h_sb = h_inode->i_sb; | |
660 | lockdep_off(); | |
661 | sb_start_write(h_sb); | |
662 | lockdep_on(); | |
663 | err = locks_verify_truncate(h_inode, h_file, length); | |
664 | if (!err) | |
665 | err = security_path_truncate(h_path); | |
666 | if (!err) { | |
667 | lockdep_off(); | |
668 | err = do_truncate(h_path->dentry, length, attr, h_file); | |
669 | lockdep_on(); | |
670 | } | |
671 | lockdep_off(); | |
672 | sb_end_write(h_sb); | |
673 | lockdep_on(); | |
674 | ||
675 | out: | |
676 | return err; | |
677 | } | |
678 | ||
679 | /* ---------------------------------------------------------------------- */ | |
680 | ||
681 | struct au_vfsub_mkdir_args { | |
682 | int *errp; | |
683 | struct inode *dir; | |
684 | struct path *path; | |
685 | int mode; | |
686 | }; | |
687 | ||
688 | static void au_call_vfsub_mkdir(void *args) | |
689 | { | |
690 | struct au_vfsub_mkdir_args *a = args; | |
691 | *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); | |
692 | } | |
693 | ||
694 | int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) | |
695 | { | |
696 | int err, do_sio, wkq_err; | |
697 | ||
698 | do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); | |
699 | if (!do_sio) { | |
700 | lockdep_off(); | |
701 | err = vfsub_mkdir(dir, path, mode); | |
702 | lockdep_on(); | |
703 | } else { | |
704 | struct au_vfsub_mkdir_args args = { | |
705 | .errp = &err, | |
706 | .dir = dir, | |
707 | .path = path, | |
708 | .mode = mode | |
709 | }; | |
710 | wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); | |
711 | if (unlikely(wkq_err)) | |
712 | err = wkq_err; | |
713 | } | |
714 | ||
715 | return err; | |
716 | } | |
717 | ||
718 | struct au_vfsub_rmdir_args { | |
719 | int *errp; | |
720 | struct inode *dir; | |
721 | struct path *path; | |
722 | }; | |
723 | ||
724 | static void au_call_vfsub_rmdir(void *args) | |
725 | { | |
726 | struct au_vfsub_rmdir_args *a = args; | |
727 | *a->errp = vfsub_rmdir(a->dir, a->path); | |
728 | } | |
729 | ||
730 | int vfsub_sio_rmdir(struct inode *dir, struct path *path) | |
731 | { | |
732 | int err, do_sio, wkq_err; | |
733 | ||
734 | do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); | |
735 | if (!do_sio) { | |
736 | lockdep_off(); | |
737 | err = vfsub_rmdir(dir, path); | |
738 | lockdep_on(); | |
739 | } else { | |
740 | struct au_vfsub_rmdir_args args = { | |
741 | .errp = &err, | |
742 | .dir = dir, | |
743 | .path = path | |
744 | }; | |
745 | wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args); | |
746 | if (unlikely(wkq_err)) | |
747 | err = wkq_err; | |
748 | } | |
749 | ||
750 | return err; | |
751 | } | |
752 | ||
753 | /* ---------------------------------------------------------------------- */ | |
754 | ||
755 | struct notify_change_args { | |
756 | int *errp; | |
757 | struct path *path; | |
758 | struct iattr *ia; | |
759 | struct inode **delegated_inode; | |
760 | }; | |
761 | ||
762 | static void call_notify_change(void *args) | |
763 | { | |
764 | struct notify_change_args *a = args; | |
765 | struct inode *h_inode; | |
766 | ||
767 | h_inode = d_inode(a->path->dentry); | |
768 | IMustLock(h_inode); | |
769 | ||
770 | *a->errp = -EPERM; | |
771 | if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { | |
772 | lockdep_off(); | |
773 | *a->errp = notify_change(a->path->dentry, a->ia, | |
774 | a->delegated_inode); | |
775 | lockdep_on(); | |
776 | if (!*a->errp) | |
777 | vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/ | |
778 | } | |
779 | AuTraceErr(*a->errp); | |
780 | } | |
781 | ||
782 | int vfsub_notify_change(struct path *path, struct iattr *ia, | |
783 | struct inode **delegated_inode) | |
784 | { | |
785 | int err; | |
786 | struct notify_change_args args = { | |
787 | .errp = &err, | |
788 | .path = path, | |
789 | .ia = ia, | |
790 | .delegated_inode = delegated_inode | |
791 | }; | |
792 | ||
793 | call_notify_change(&args); | |
794 | ||
795 | return err; | |
796 | } | |
797 | ||
798 | int vfsub_sio_notify_change(struct path *path, struct iattr *ia, | |
799 | struct inode **delegated_inode) | |
800 | { | |
801 | int err, wkq_err; | |
802 | struct notify_change_args args = { | |
803 | .errp = &err, | |
804 | .path = path, | |
805 | .ia = ia, | |
806 | .delegated_inode = delegated_inode | |
807 | }; | |
808 | ||
809 | wkq_err = au_wkq_wait(call_notify_change, &args); | |
810 | if (unlikely(wkq_err)) | |
811 | err = wkq_err; | |
812 | ||
813 | return err; | |
814 | } | |
815 | ||
816 | /* ---------------------------------------------------------------------- */ | |
817 | ||
818 | struct unlink_args { | |
819 | int *errp; | |
820 | struct inode *dir; | |
821 | struct path *path; | |
822 | struct inode **delegated_inode; | |
823 | }; | |
824 | ||
825 | static void call_unlink(void *args) | |
826 | { | |
827 | struct unlink_args *a = args; | |
828 | struct dentry *d = a->path->dentry; | |
829 | struct inode *h_inode; | |
830 | const int stop_sillyrename = (au_test_nfs(d->d_sb) | |
831 | && au_dcount(d) == 1); | |
832 | ||
833 | IMustLock(a->dir); | |
834 | ||
835 | a->path->dentry = d->d_parent; | |
836 | *a->errp = security_path_unlink(a->path, d); | |
837 | a->path->dentry = d; | |
838 | if (unlikely(*a->errp)) | |
839 | return; | |
840 | ||
841 | if (!stop_sillyrename) | |
842 | dget(d); | |
843 | h_inode = NULL; | |
844 | if (d_is_positive(d)) { | |
845 | h_inode = d_inode(d); | |
846 | ihold(h_inode); | |
847 | } | |
848 | ||
849 | lockdep_off(); | |
850 | *a->errp = vfs_unlink(a->dir, d, a->delegated_inode); | |
851 | lockdep_on(); | |
852 | if (!*a->errp) { | |
853 | struct path tmp = { | |
854 | .dentry = d->d_parent, | |
855 | .mnt = a->path->mnt | |
856 | }; | |
857 | vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ | |
858 | } | |
859 | ||
860 | if (!stop_sillyrename) | |
861 | dput(d); | |
862 | if (h_inode) | |
863 | iput(h_inode); | |
864 | ||
865 | AuTraceErr(*a->errp); | |
866 | } | |
867 | ||
868 | /* | |
869 | * @dir: must be locked. | |
870 | * @dentry: target dentry. | |
871 | */ | |
872 | int vfsub_unlink(struct inode *dir, struct path *path, | |
873 | struct inode **delegated_inode, int force) | |
874 | { | |
875 | int err; | |
876 | struct unlink_args args = { | |
877 | .errp = &err, | |
878 | .dir = dir, | |
879 | .path = path, | |
880 | .delegated_inode = delegated_inode | |
881 | }; | |
882 | ||
883 | if (!force) | |
884 | call_unlink(&args); | |
885 | else { | |
886 | int wkq_err; | |
887 | ||
888 | wkq_err = au_wkq_wait(call_unlink, &args); | |
889 | if (unlikely(wkq_err)) | |
890 | err = wkq_err; | |
891 | } | |
892 | ||
893 | return err; | |
894 | } |