aboutsummaryrefslogtreecommitdiffstats
path: root/fs/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/open.c')
-rw-r--r--fs/open.c99
1 files changed, 67 insertions, 32 deletions
diff --git a/fs/open.c b/fs/open.c
index 59071f55bf7f..9b33c0cbfacf 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -61,33 +61,22 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
61 return ret; 61 return ret;
62} 62}
63 63
64static long do_sys_truncate(const char __user *pathname, loff_t length) 64long vfs_truncate(struct path *path, loff_t length)
65{ 65{
66 struct path path;
67 struct inode *inode; 66 struct inode *inode;
68 int error; 67 long error;
69
70 error = -EINVAL;
71 if (length < 0) /* sorry, but loff_t says... */
72 goto out;
73 68
74 error = user_path(pathname, &path); 69 inode = path->dentry->d_inode;
75 if (error)
76 goto out;
77 inode = path.dentry->d_inode;
78 70
79 /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ 71 /* For directories it's -EISDIR, for other non-regulars - -EINVAL */
80 error = -EISDIR;
81 if (S_ISDIR(inode->i_mode)) 72 if (S_ISDIR(inode->i_mode))
82 goto dput_and_out; 73 return -EISDIR;
83
84 error = -EINVAL;
85 if (!S_ISREG(inode->i_mode)) 74 if (!S_ISREG(inode->i_mode))
86 goto dput_and_out; 75 return -EINVAL;
87 76
88 error = mnt_want_write(path.mnt); 77 error = mnt_want_write(path->mnt);
89 if (error) 78 if (error)
90 goto dput_and_out; 79 goto out;
91 80
92 error = inode_permission(inode, MAY_WRITE); 81 error = inode_permission(inode, MAY_WRITE);
93 if (error) 82 if (error)
@@ -111,19 +100,40 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
111 100
112 error = locks_verify_truncate(inode, NULL, length); 101 error = locks_verify_truncate(inode, NULL, length);
113 if (!error) 102 if (!error)
114 error = security_path_truncate(&path); 103 error = security_path_truncate(path);
115 if (!error) 104 if (!error)
116 error = do_truncate(path.dentry, length, 0, NULL); 105 error = do_truncate(path->dentry, length, 0, NULL);
117 106
118put_write_and_out: 107put_write_and_out:
119 put_write_access(inode); 108 put_write_access(inode);
120mnt_drop_write_and_out: 109mnt_drop_write_and_out:
121 mnt_drop_write(path.mnt); 110 mnt_drop_write(path->mnt);
122dput_and_out:
123 path_put(&path);
124out: 111out:
125 return error; 112 return error;
126} 113}
114EXPORT_SYMBOL_GPL(vfs_truncate);
115
116static long do_sys_truncate(const char __user *pathname, loff_t length)
117{
118 unsigned int lookup_flags = LOOKUP_FOLLOW;
119 struct path path;
120 int error;
121
122 if (length < 0) /* sorry, but loff_t says... */
123 return -EINVAL;
124
125retry:
126 error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
127 if (!error) {
128 error = vfs_truncate(&path, length);
129 path_put(&path);
130 }
131 if (retry_estale(error, lookup_flags)) {
132 lookup_flags |= LOOKUP_REVAL;
133 goto retry;
134 }
135 return error;
136}
127 137
128SYSCALL_DEFINE2(truncate, const char __user *, path, long, length) 138SYSCALL_DEFINE2(truncate, const char __user *, path, long, length)
129{ 139{
@@ -306,6 +316,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
306 struct path path; 316 struct path path;
307 struct inode *inode; 317 struct inode *inode;
308 int res; 318 int res;
319 unsigned int lookup_flags = LOOKUP_FOLLOW;
309 320
310 if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ 321 if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
311 return -EINVAL; 322 return -EINVAL;
@@ -328,8 +339,8 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
328 } 339 }
329 340
330 old_cred = override_creds(override_cred); 341 old_cred = override_creds(override_cred);
331 342retry:
332 res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); 343 res = user_path_at(dfd, filename, lookup_flags, &path);
333 if (res) 344 if (res)
334 goto out; 345 goto out;
335 346
@@ -364,6 +375,10 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
364 375
365out_path_release: 376out_path_release:
366 path_put(&path); 377 path_put(&path);
378 if (retry_estale(res, lookup_flags)) {
379 lookup_flags |= LOOKUP_REVAL;
380 goto retry;
381 }
367out: 382out:
368 revert_creds(old_cred); 383 revert_creds(old_cred);
369 put_cred(override_cred); 384 put_cred(override_cred);
@@ -379,8 +394,9 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
379{ 394{
380 struct path path; 395 struct path path;
381 int error; 396 int error;
382 397 unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
383 error = user_path_dir(filename, &path); 398retry:
399 error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
384 if (error) 400 if (error)
385 goto out; 401 goto out;
386 402
@@ -392,6 +408,10 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
392 408
393dput_and_out: 409dput_and_out:
394 path_put(&path); 410 path_put(&path);
411 if (retry_estale(error, lookup_flags)) {
412 lookup_flags |= LOOKUP_REVAL;
413 goto retry;
414 }
395out: 415out:
396 return error; 416 return error;
397} 417}
@@ -425,8 +445,9 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
425{ 445{
426 struct path path; 446 struct path path;
427 int error; 447 int error;
428 448 unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
429 error = user_path_dir(filename, &path); 449retry:
450 error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
430 if (error) 451 if (error)
431 goto out; 452 goto out;
432 453
@@ -435,7 +456,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
435 goto dput_and_out; 456 goto dput_and_out;
436 457
437 error = -EPERM; 458 error = -EPERM;
438 if (!capable(CAP_SYS_CHROOT)) 459 if (!nsown_capable(CAP_SYS_CHROOT))
439 goto dput_and_out; 460 goto dput_and_out;
440 error = security_path_chroot(&path); 461 error = security_path_chroot(&path);
441 if (error) 462 if (error)
@@ -445,6 +466,10 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
445 error = 0; 466 error = 0;
446dput_and_out: 467dput_and_out:
447 path_put(&path); 468 path_put(&path);
469 if (retry_estale(error, lookup_flags)) {
470 lookup_flags |= LOOKUP_REVAL;
471 goto retry;
472 }
448out: 473out:
449 return error; 474 return error;
450} 475}
@@ -489,11 +514,16 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode
489{ 514{
490 struct path path; 515 struct path path;
491 int error; 516 int error;
492 517 unsigned int lookup_flags = LOOKUP_FOLLOW;
493 error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); 518retry:
519 error = user_path_at(dfd, filename, lookup_flags, &path);
494 if (!error) { 520 if (!error) {
495 error = chmod_common(&path, mode); 521 error = chmod_common(&path, mode);
496 path_put(&path); 522 path_put(&path);
523 if (retry_estale(error, lookup_flags)) {
524 lookup_flags |= LOOKUP_REVAL;
525 goto retry;
526 }
497 } 527 }
498 return error; 528 return error;
499} 529}
@@ -552,6 +582,7 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
552 lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; 582 lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
553 if (flag & AT_EMPTY_PATH) 583 if (flag & AT_EMPTY_PATH)
554 lookup_flags |= LOOKUP_EMPTY; 584 lookup_flags |= LOOKUP_EMPTY;
585retry:
555 error = user_path_at(dfd, filename, lookup_flags, &path); 586 error = user_path_at(dfd, filename, lookup_flags, &path);
556 if (error) 587 if (error)
557 goto out; 588 goto out;
@@ -562,6 +593,10 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
562 mnt_drop_write(path.mnt); 593 mnt_drop_write(path.mnt);
563out_release: 594out_release:
564 path_put(&path); 595 path_put(&path);
596 if (retry_estale(error, lookup_flags)) {
597 lookup_flags |= LOOKUP_REVAL;
598 goto retry;
599 }
565out: 600out:
566 return error; 601 return error;
567} 602}