aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-07-30 16:53:35 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-07-30 16:53:35 -0400
commit64894cf843278c7b2653a6fac2cd1a697ff930dc (patch)
tree10e03b6cbbeb9065f54321836d0c9c0d5080721f /fs
parentf8310c59201b183ebee2e3fe0c7242f5729be0af (diff)
simplify lookup_open()/atomic_open() - do the temporary mnt_want_write() early
The write ref to vfsmount taken in lookup_open()/atomic_open() is going to be dropped; we take the one to stay in dentry_open(). Just grab the temporary in caller if it looks like we are going to need it (create/truncate/writable open) and pass (by value) "has it succeeded" flag. Instead of doing mnt_want_write() inside, check that flag and treat "false" as "mnt_want_write() has just failed". mnt_want_write() is cheap and the things get considerably simpler and more robust that way - we get it and drop it in the same function, to start with, rather than passing a "has something in the guts of really scary functions taken it" back to caller. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/namei.c51
1 files changed, 29 insertions, 22 deletions
diff --git a/fs/namei.c b/fs/namei.c
index e133bf3bbb03..35291ac6f42b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2395,7 +2395,7 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
2395static int atomic_open(struct nameidata *nd, struct dentry *dentry, 2395static int atomic_open(struct nameidata *nd, struct dentry *dentry,
2396 struct path *path, struct file *file, 2396 struct path *path, struct file *file,
2397 const struct open_flags *op, 2397 const struct open_flags *op,
2398 bool *want_write, bool need_lookup, 2398 bool got_write, bool need_lookup,
2399 int *opened) 2399 int *opened)
2400{ 2400{
2401 struct inode *dir = nd->path.dentry->d_inode; 2401 struct inode *dir = nd->path.dentry->d_inode;
@@ -2432,12 +2432,9 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
2432 * Another problem is returing the "right" error value (e.g. for an 2432 * Another problem is returing the "right" error value (e.g. for an
2433 * O_EXCL open we want to return EEXIST not EROFS). 2433 * O_EXCL open we want to return EEXIST not EROFS).
2434 */ 2434 */
2435 if ((open_flag & (O_CREAT | O_TRUNC)) || 2435 if (((open_flag & (O_CREAT | O_TRUNC)) ||
2436 (open_flag & O_ACCMODE) != O_RDONLY) { 2436 (open_flag & O_ACCMODE) != O_RDONLY) && unlikely(!got_write)) {
2437 error = mnt_want_write(nd->path.mnt); 2437 if (!(open_flag & O_CREAT)) {
2438 if (!error) {
2439 *want_write = true;
2440 } else if (!(open_flag & O_CREAT)) {
2441 /* 2438 /*
2442 * No O_CREATE -> atomicity not a requirement -> fall 2439 * No O_CREATE -> atomicity not a requirement -> fall
2443 * back to lookup + open 2440 * back to lookup + open
@@ -2445,11 +2442,11 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
2445 goto no_open; 2442 goto no_open;
2446 } else if (open_flag & (O_EXCL | O_TRUNC)) { 2443 } else if (open_flag & (O_EXCL | O_TRUNC)) {
2447 /* Fall back and fail with the right error */ 2444 /* Fall back and fail with the right error */
2448 create_error = error; 2445 create_error = -EROFS;
2449 goto no_open; 2446 goto no_open;
2450 } else { 2447 } else {
2451 /* No side effects, safe to clear O_CREAT */ 2448 /* No side effects, safe to clear O_CREAT */
2452 create_error = error; 2449 create_error = -EROFS;
2453 open_flag &= ~O_CREAT; 2450 open_flag &= ~O_CREAT;
2454 } 2451 }
2455 } 2452 }
@@ -2556,7 +2553,7 @@ looked_up:
2556static int lookup_open(struct nameidata *nd, struct path *path, 2553static int lookup_open(struct nameidata *nd, struct path *path,
2557 struct file *file, 2554 struct file *file,
2558 const struct open_flags *op, 2555 const struct open_flags *op,
2559 bool *want_write, int *opened) 2556 bool got_write, int *opened)
2560{ 2557{
2561 struct dentry *dir = nd->path.dentry; 2558 struct dentry *dir = nd->path.dentry;
2562 struct inode *dir_inode = dir->d_inode; 2559 struct inode *dir_inode = dir->d_inode;
@@ -2574,7 +2571,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
2574 goto out_no_open; 2571 goto out_no_open;
2575 2572
2576 if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) { 2573 if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) {
2577 return atomic_open(nd, dentry, path, file, op, want_write, 2574 return atomic_open(nd, dentry, path, file, op, got_write,
2578 need_lookup, opened); 2575 need_lookup, opened);
2579 } 2576 }
2580 2577
@@ -2598,10 +2595,10 @@ static int lookup_open(struct nameidata *nd, struct path *path,
2598 * a permanent write count is taken through 2595 * a permanent write count is taken through
2599 * the 'struct file' in finish_open(). 2596 * the 'struct file' in finish_open().
2600 */ 2597 */
2601 error = mnt_want_write(nd->path.mnt); 2598 if (!got_write) {
2602 if (error) 2599 error = -EROFS;
2603 goto out_dput; 2600 goto out_dput;
2604 *want_write = true; 2601 }
2605 *opened |= FILE_CREATED; 2602 *opened |= FILE_CREATED;
2606 error = security_path_mknod(&nd->path, dentry, mode, 0); 2603 error = security_path_mknod(&nd->path, dentry, mode, 0);
2607 if (error) 2604 if (error)
@@ -2631,7 +2628,7 @@ static int do_last(struct nameidata *nd, struct path *path,
2631 struct dentry *dir = nd->path.dentry; 2628 struct dentry *dir = nd->path.dentry;
2632 int open_flag = op->open_flag; 2629 int open_flag = op->open_flag;
2633 bool will_truncate = (open_flag & O_TRUNC) != 0; 2630 bool will_truncate = (open_flag & O_TRUNC) != 0;
2634 bool want_write = false; 2631 bool got_write = false;
2635 int acc_mode = op->acc_mode; 2632 int acc_mode = op->acc_mode;
2636 struct inode *inode; 2633 struct inode *inode;
2637 bool symlink_ok = false; 2634 bool symlink_ok = false;
@@ -2700,8 +2697,18 @@ static int do_last(struct nameidata *nd, struct path *path,
2700 } 2697 }
2701 2698
2702retry_lookup: 2699retry_lookup:
2700 if (op->open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) {
2701 error = mnt_want_write(nd->path.mnt);
2702 if (!error)
2703 got_write = true;
2704 /*
2705 * do _not_ fail yet - we might not need that or fail with
2706 * a different error; let lookup_open() decide; we'll be
2707 * dropping this one anyway.
2708 */
2709 }
2703 mutex_lock(&dir->d_inode->i_mutex); 2710 mutex_lock(&dir->d_inode->i_mutex);
2704 error = lookup_open(nd, path, file, op, &want_write, opened); 2711 error = lookup_open(nd, path, file, op, got_write, opened);
2705 mutex_unlock(&dir->d_inode->i_mutex); 2712 mutex_unlock(&dir->d_inode->i_mutex);
2706 2713
2707 if (error <= 0) { 2714 if (error <= 0) {
@@ -2736,9 +2743,9 @@ retry_lookup:
2736 * possible mount and symlink following (this might be optimized away if 2743 * possible mount and symlink following (this might be optimized away if
2737 * necessary...) 2744 * necessary...)
2738 */ 2745 */
2739 if (want_write) { 2746 if (got_write) {
2740 mnt_drop_write(nd->path.mnt); 2747 mnt_drop_write(nd->path.mnt);
2741 want_write = false; 2748 got_write = false;
2742 } 2749 }
2743 2750
2744 error = -EEXIST; 2751 error = -EEXIST;
@@ -2803,7 +2810,7 @@ finish_open:
2803 error = mnt_want_write(nd->path.mnt); 2810 error = mnt_want_write(nd->path.mnt);
2804 if (error) 2811 if (error)
2805 goto out; 2812 goto out;
2806 want_write = true; 2813 got_write = true;
2807 } 2814 }
2808finish_open_created: 2815finish_open_created:
2809 error = may_open(&nd->path, acc_mode, open_flag); 2816 error = may_open(&nd->path, acc_mode, open_flag);
@@ -2830,7 +2837,7 @@ opened:
2830 goto exit_fput; 2837 goto exit_fput;
2831 } 2838 }
2832out: 2839out:
2833 if (want_write) 2840 if (got_write)
2834 mnt_drop_write(nd->path.mnt); 2841 mnt_drop_write(nd->path.mnt);
2835 path_put(&save_parent); 2842 path_put(&save_parent);
2836 terminate_walk(nd); 2843 terminate_walk(nd);
@@ -2854,9 +2861,9 @@ stale_open:
2854 nd->inode = dir->d_inode; 2861 nd->inode = dir->d_inode;
2855 save_parent.mnt = NULL; 2862 save_parent.mnt = NULL;
2856 save_parent.dentry = NULL; 2863 save_parent.dentry = NULL;
2857 if (want_write) { 2864 if (got_write) {
2858 mnt_drop_write(nd->path.mnt); 2865 mnt_drop_write(nd->path.mnt);
2859 want_write = false; 2866 got_write = false;
2860 } 2867 }
2861 retried = true; 2868 retried = true;
2862 goto retry_lookup; 2869 goto retry_lookup;