Commit 64894cf843278c7b2653a6fac2cd1a697ff930dc
1 parent
f8310c5920
Exists in
master
and in
20 other branches
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>
Showing 1 changed file with 29 additions and 22 deletions Side-by-side Diff
fs/namei.c
... | ... | @@ -2395,7 +2395,7 @@ |
2395 | 2395 | static int atomic_open(struct nameidata *nd, struct dentry *dentry, |
2396 | 2396 | struct path *path, struct file *file, |
2397 | 2397 | const struct open_flags *op, |
2398 | - bool *want_write, bool need_lookup, | |
2398 | + bool got_write, bool need_lookup, | |
2399 | 2399 | int *opened) |
2400 | 2400 | { |
2401 | 2401 | struct inode *dir = nd->path.dentry->d_inode; |
... | ... | @@ -2432,12 +2432,9 @@ |
2432 | 2432 | * Another problem is returing the "right" error value (e.g. for an |
2433 | 2433 | * O_EXCL open we want to return EEXIST not EROFS). |
2434 | 2434 | */ |
2435 | - if ((open_flag & (O_CREAT | O_TRUNC)) || | |
2436 | - (open_flag & O_ACCMODE) != O_RDONLY) { | |
2437 | - error = mnt_want_write(nd->path.mnt); | |
2438 | - if (!error) { | |
2439 | - *want_write = true; | |
2440 | - } else if (!(open_flag & O_CREAT)) { | |
2435 | + if (((open_flag & (O_CREAT | O_TRUNC)) || | |
2436 | + (open_flag & O_ACCMODE) != O_RDONLY) && unlikely(!got_write)) { | |
2437 | + if (!(open_flag & O_CREAT)) { | |
2441 | 2438 | /* |
2442 | 2439 | * No O_CREATE -> atomicity not a requirement -> fall |
2443 | 2440 | * back to lookup + open |
2444 | 2441 | |
... | ... | @@ -2445,11 +2442,11 @@ |
2445 | 2442 | goto no_open; |
2446 | 2443 | } else if (open_flag & (O_EXCL | O_TRUNC)) { |
2447 | 2444 | /* Fall back and fail with the right error */ |
2448 | - create_error = error; | |
2445 | + create_error = -EROFS; | |
2449 | 2446 | goto no_open; |
2450 | 2447 | } else { |
2451 | 2448 | /* No side effects, safe to clear O_CREAT */ |
2452 | - create_error = error; | |
2449 | + create_error = -EROFS; | |
2453 | 2450 | open_flag &= ~O_CREAT; |
2454 | 2451 | } |
2455 | 2452 | } |
... | ... | @@ -2556,7 +2553,7 @@ |
2556 | 2553 | static int lookup_open(struct nameidata *nd, struct path *path, |
2557 | 2554 | struct file *file, |
2558 | 2555 | const struct open_flags *op, |
2559 | - bool *want_write, int *opened) | |
2556 | + bool got_write, int *opened) | |
2560 | 2557 | { |
2561 | 2558 | struct dentry *dir = nd->path.dentry; |
2562 | 2559 | struct inode *dir_inode = dir->d_inode; |
... | ... | @@ -2574,7 +2571,7 @@ |
2574 | 2571 | goto out_no_open; |
2575 | 2572 | |
2576 | 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 | 2575 | need_lookup, opened); |
2579 | 2576 | } |
2580 | 2577 | |
2581 | 2578 | |
... | ... | @@ -2598,10 +2595,10 @@ |
2598 | 2595 | * a permanent write count is taken through |
2599 | 2596 | * the 'struct file' in finish_open(). |
2600 | 2597 | */ |
2601 | - error = mnt_want_write(nd->path.mnt); | |
2602 | - if (error) | |
2598 | + if (!got_write) { | |
2599 | + error = -EROFS; | |
2603 | 2600 | goto out_dput; |
2604 | - *want_write = true; | |
2601 | + } | |
2605 | 2602 | *opened |= FILE_CREATED; |
2606 | 2603 | error = security_path_mknod(&nd->path, dentry, mode, 0); |
2607 | 2604 | if (error) |
... | ... | @@ -2631,7 +2628,7 @@ |
2631 | 2628 | struct dentry *dir = nd->path.dentry; |
2632 | 2629 | int open_flag = op->open_flag; |
2633 | 2630 | bool will_truncate = (open_flag & O_TRUNC) != 0; |
2634 | - bool want_write = false; | |
2631 | + bool got_write = false; | |
2635 | 2632 | int acc_mode = op->acc_mode; |
2636 | 2633 | struct inode *inode; |
2637 | 2634 | bool symlink_ok = false; |
2638 | 2635 | |
... | ... | @@ -2700,8 +2697,18 @@ |
2700 | 2697 | } |
2701 | 2698 | |
2702 | 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 | 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 | 2712 | mutex_unlock(&dir->d_inode->i_mutex); |
2706 | 2713 | |
2707 | 2714 | if (error <= 0) { |
2708 | 2715 | |
... | ... | @@ -2736,9 +2743,9 @@ |
2736 | 2743 | * possible mount and symlink following (this might be optimized away if |
2737 | 2744 | * necessary...) |
2738 | 2745 | */ |
2739 | - if (want_write) { | |
2746 | + if (got_write) { | |
2740 | 2747 | mnt_drop_write(nd->path.mnt); |
2741 | - want_write = false; | |
2748 | + got_write = false; | |
2742 | 2749 | } |
2743 | 2750 | |
2744 | 2751 | error = -EEXIST; |
... | ... | @@ -2803,7 +2810,7 @@ |
2803 | 2810 | error = mnt_want_write(nd->path.mnt); |
2804 | 2811 | if (error) |
2805 | 2812 | goto out; |
2806 | - want_write = true; | |
2813 | + got_write = true; | |
2807 | 2814 | } |
2808 | 2815 | finish_open_created: |
2809 | 2816 | error = may_open(&nd->path, acc_mode, open_flag); |
... | ... | @@ -2830,7 +2837,7 @@ |
2830 | 2837 | goto exit_fput; |
2831 | 2838 | } |
2832 | 2839 | out: |
2833 | - if (want_write) | |
2840 | + if (got_write) | |
2834 | 2841 | mnt_drop_write(nd->path.mnt); |
2835 | 2842 | path_put(&save_parent); |
2836 | 2843 | terminate_walk(nd); |
2837 | 2844 | |
... | ... | @@ -2854,9 +2861,9 @@ |
2854 | 2861 | nd->inode = dir->d_inode; |
2855 | 2862 | save_parent.mnt = NULL; |
2856 | 2863 | save_parent.dentry = NULL; |
2857 | - if (want_write) { | |
2864 | + if (got_write) { | |
2858 | 2865 | mnt_drop_write(nd->path.mnt); |
2859 | - want_write = false; | |
2866 | + got_write = false; | |
2860 | 2867 | } |
2861 | 2868 | retried = true; |
2862 | 2869 | goto retry_lookup; |