diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-30 16:53:35 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-30 16:53:35 -0400 |
commit | 64894cf843278c7b2653a6fac2cd1a697ff930dc (patch) | |
tree | 10e03b6cbbeb9065f54321836d0c9c0d5080721f /fs | |
parent | f8310c59201b183ebee2e3fe0c7242f5729be0af (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.c | 51 |
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) | |||
2395 | static int atomic_open(struct nameidata *nd, struct dentry *dentry, | 2395 | static 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: | |||
2556 | static int lookup_open(struct nameidata *nd, struct path *path, | 2553 | static 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 | ||
2702 | retry_lookup: | 2699 | retry_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 | } |
2808 | finish_open_created: | 2815 | finish_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 | } |
2832 | out: | 2839 | out: |
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; |