diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-04-27 19:14:10 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-05-02 19:51:15 -0400 |
commit | 1643b43fbd0524e7da7259075032936c8fb68a05 (patch) | |
tree | 66547bd78ecd6c7dd922e1784c51ab352e1a1cba | |
parent | b3d58eaffb98e1b5bbf2d6756c59398213caba57 (diff) |
lookup_open(): lift the "fallback to !O_CREAT" logics from atomic_open()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/namei.c | 144 |
1 files changed, 55 insertions, 89 deletions
diff --git a/fs/namei.c b/fs/namei.c index 8d562a7a7e01..4359d22f43f4 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2824,63 +2824,19 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode) | |||
2824 | static int atomic_open(struct nameidata *nd, struct dentry *dentry, | 2824 | static int atomic_open(struct nameidata *nd, struct dentry *dentry, |
2825 | struct path *path, struct file *file, | 2825 | struct path *path, struct file *file, |
2826 | const struct open_flags *op, | 2826 | const struct open_flags *op, |
2827 | bool got_write, bool need_lookup, | 2827 | int open_flag, umode_t mode, |
2828 | int *opened) | 2828 | int *opened) |
2829 | { | 2829 | { |
2830 | struct inode *dir = nd->path.dentry->d_inode; | 2830 | struct inode *dir = nd->path.dentry->d_inode; |
2831 | unsigned open_flag = op->open_flag; | ||
2832 | umode_t mode; | ||
2833 | int error; | 2831 | int error; |
2834 | int acc_mode; | 2832 | int acc_mode; |
2835 | int create_error = 0; | ||
2836 | struct dentry *const DENTRY_NOT_SET = (void *) -1UL; | 2833 | struct dentry *const DENTRY_NOT_SET = (void *) -1UL; |
2837 | bool excl; | 2834 | bool excl; |
2838 | 2835 | ||
2839 | BUG_ON(dentry->d_inode); | ||
2840 | |||
2841 | mode = op->mode; | ||
2842 | if ((open_flag & O_CREAT) && !IS_POSIXACL(dir)) | ||
2843 | mode &= ~current_umask(); | ||
2844 | |||
2845 | excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT); | 2836 | excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT); |
2846 | if (excl) | 2837 | if (excl) |
2847 | open_flag &= ~O_TRUNC; | 2838 | open_flag &= ~O_TRUNC; |
2848 | 2839 | ||
2849 | /* | ||
2850 | * Checking write permission is tricky, bacuse we don't know if we are | ||
2851 | * going to actually need it: O_CREAT opens should work as long as the | ||
2852 | * file exists. But checking existence breaks atomicity. The trick is | ||
2853 | * to check access and if not granted clear O_CREAT from the flags. | ||
2854 | * | ||
2855 | * Another problem is returing the "right" error value (e.g. for an | ||
2856 | * O_EXCL open we want to return EEXIST not EROFS). | ||
2857 | */ | ||
2858 | if (open_flag & O_CREAT) { | ||
2859 | if (unlikely(!got_write)) { | ||
2860 | create_error = -EROFS; | ||
2861 | if (open_flag & (O_EXCL | O_TRUNC)) { | ||
2862 | /* Fall back and fail with the right error */ | ||
2863 | goto no_open; | ||
2864 | } | ||
2865 | /* No side effects, safe to clear O_CREAT */ | ||
2866 | open_flag &= ~O_CREAT; | ||
2867 | } else { | ||
2868 | create_error = may_o_create(&nd->path, dentry, mode); | ||
2869 | if (create_error) { | ||
2870 | if (open_flag & O_EXCL) | ||
2871 | goto no_open; | ||
2872 | open_flag &= ~O_CREAT; | ||
2873 | } | ||
2874 | } | ||
2875 | } else if ((open_flag & (O_TRUNC|O_WRONLY|O_RDWR)) && | ||
2876 | unlikely(!got_write)) { | ||
2877 | /* | ||
2878 | * No O_CREATE -> atomicity not a requirement -> fall | ||
2879 | * back to lookup + open | ||
2880 | */ | ||
2881 | goto no_open; | ||
2882 | } | ||
2883 | |||
2884 | if (nd->flags & LOOKUP_DIRECTORY) | 2840 | if (nd->flags & LOOKUP_DIRECTORY) |
2885 | open_flag |= O_DIRECTORY; | 2841 | open_flag |= O_DIRECTORY; |
2886 | 2842 | ||
@@ -2889,11 +2845,8 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, | |||
2889 | error = dir->i_op->atomic_open(dir, dentry, file, | 2845 | error = dir->i_op->atomic_open(dir, dentry, file, |
2890 | open_to_namei_flags(open_flag), | 2846 | open_to_namei_flags(open_flag), |
2891 | mode, opened); | 2847 | mode, opened); |
2892 | if (error < 0) { | 2848 | if (error < 0) |
2893 | if (create_error && error == -ENOENT) | ||
2894 | error = create_error; | ||
2895 | goto out; | 2849 | goto out; |
2896 | } | ||
2897 | 2850 | ||
2898 | if (error) { /* returned 1, that is */ | 2851 | if (error) { /* returned 1, that is */ |
2899 | if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) { | 2852 | if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) { |
@@ -2906,7 +2859,9 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, | |||
2906 | } | 2859 | } |
2907 | if (*opened & FILE_CREATED) | 2860 | if (*opened & FILE_CREATED) |
2908 | fsnotify_create(dir, dentry); | 2861 | fsnotify_create(dir, dentry); |
2909 | goto looked_up; | 2862 | path->dentry = dentry; |
2863 | path->mnt = nd->path.mnt; | ||
2864 | return 1; | ||
2910 | } | 2865 | } |
2911 | 2866 | ||
2912 | /* | 2867 | /* |
@@ -2925,21 +2880,6 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry, | |||
2925 | out: | 2880 | out: |
2926 | dput(dentry); | 2881 | dput(dentry); |
2927 | return error; | 2882 | return error; |
2928 | |||
2929 | no_open: | ||
2930 | if (need_lookup) { | ||
2931 | dentry = lookup_real(dir, dentry, nd->flags); | ||
2932 | if (IS_ERR(dentry)) | ||
2933 | return PTR_ERR(dentry); | ||
2934 | } | ||
2935 | looked_up: | ||
2936 | if (create_error && !dentry->d_inode) { | ||
2937 | error = create_error; | ||
2938 | goto out; | ||
2939 | } | ||
2940 | path->dentry = dentry; | ||
2941 | path->mnt = nd->path.mnt; | ||
2942 | return 1; | ||
2943 | } | 2883 | } |
2944 | 2884 | ||
2945 | /* | 2885 | /* |
@@ -2967,9 +2907,11 @@ static int lookup_open(struct nameidata *nd, struct path *path, | |||
2967 | { | 2907 | { |
2968 | struct dentry *dir = nd->path.dentry; | 2908 | struct dentry *dir = nd->path.dentry; |
2969 | struct inode *dir_inode = dir->d_inode; | 2909 | struct inode *dir_inode = dir->d_inode; |
2910 | int open_flag = op->open_flag; | ||
2970 | struct dentry *dentry; | 2911 | struct dentry *dentry; |
2971 | int error; | 2912 | int error, create_error = 0; |
2972 | bool need_lookup = false; | 2913 | bool need_lookup = false; |
2914 | umode_t mode = op->mode; | ||
2973 | 2915 | ||
2974 | if (unlikely(IS_DEADDIR(dir_inode))) | 2916 | if (unlikely(IS_DEADDIR(dir_inode))) |
2975 | return -ENOENT; | 2917 | return -ENOENT; |
@@ -2989,50 +2931,74 @@ static int lookup_open(struct nameidata *nd, struct path *path, | |||
2989 | goto out_no_open; | 2931 | goto out_no_open; |
2990 | } | 2932 | } |
2991 | 2933 | ||
2934 | /* | ||
2935 | * Checking write permission is tricky, bacuse we don't know if we are | ||
2936 | * going to actually need it: O_CREAT opens should work as long as the | ||
2937 | * file exists. But checking existence breaks atomicity. The trick is | ||
2938 | * to check access and if not granted clear O_CREAT from the flags. | ||
2939 | * | ||
2940 | * Another problem is returing the "right" error value (e.g. for an | ||
2941 | * O_EXCL open we want to return EEXIST not EROFS). | ||
2942 | */ | ||
2943 | if (open_flag & O_CREAT) { | ||
2944 | if (!IS_POSIXACL(dir->d_inode)) | ||
2945 | mode &= ~current_umask(); | ||
2946 | if (unlikely(!got_write)) { | ||
2947 | create_error = -EROFS; | ||
2948 | open_flag &= ~O_CREAT; | ||
2949 | if (open_flag & (O_EXCL | O_TRUNC)) | ||
2950 | goto no_open; | ||
2951 | /* No side effects, safe to clear O_CREAT */ | ||
2952 | } else { | ||
2953 | create_error = may_o_create(&nd->path, dentry, mode); | ||
2954 | if (create_error) { | ||
2955 | open_flag &= ~O_CREAT; | ||
2956 | if (open_flag & O_EXCL) | ||
2957 | goto no_open; | ||
2958 | } | ||
2959 | } | ||
2960 | } else if ((open_flag & (O_TRUNC|O_WRONLY|O_RDWR)) && | ||
2961 | unlikely(!got_write)) { | ||
2962 | /* | ||
2963 | * No O_CREATE -> atomicity not a requirement -> fall | ||
2964 | * back to lookup + open | ||
2965 | */ | ||
2966 | goto no_open; | ||
2967 | } | ||
2968 | |||
2992 | if (dir_inode->i_op->atomic_open) { | 2969 | if (dir_inode->i_op->atomic_open) { |
2993 | return atomic_open(nd, dentry, path, file, op, got_write, | 2970 | error = atomic_open(nd, dentry, path, file, op, open_flag, |
2994 | need_lookup, opened); | 2971 | mode, opened); |
2972 | if (unlikely(error == -ENOENT) && create_error) | ||
2973 | error = create_error; | ||
2974 | return error; | ||
2995 | } | 2975 | } |
2996 | 2976 | ||
2977 | no_open: | ||
2997 | if (need_lookup) { | 2978 | if (need_lookup) { |
2998 | BUG_ON(dentry->d_inode); | ||
2999 | |||
3000 | dentry = lookup_real(dir_inode, dentry, nd->flags); | 2979 | dentry = lookup_real(dir_inode, dentry, nd->flags); |
3001 | if (IS_ERR(dentry)) | 2980 | if (IS_ERR(dentry)) |
3002 | return PTR_ERR(dentry); | 2981 | return PTR_ERR(dentry); |
3003 | } | 2982 | } |
3004 | 2983 | ||
3005 | /* Negative dentry, just create the file */ | 2984 | /* Negative dentry, just create the file */ |
3006 | if (!dentry->d_inode && (op->open_flag & O_CREAT)) { | 2985 | if (!dentry->d_inode && (open_flag & O_CREAT)) { |
3007 | umode_t mode = op->mode; | ||
3008 | if (!IS_POSIXACL(dir->d_inode)) | ||
3009 | mode &= ~current_umask(); | ||
3010 | /* | ||
3011 | * This write is needed to ensure that a | ||
3012 | * rw->ro transition does not occur between | ||
3013 | * the time when the file is created and when | ||
3014 | * a permanent write count is taken through | ||
3015 | * the 'struct file' in finish_open(). | ||
3016 | */ | ||
3017 | if (!got_write) { | ||
3018 | error = -EROFS; | ||
3019 | goto out_dput; | ||
3020 | } | ||
3021 | *opened |= FILE_CREATED; | 2986 | *opened |= FILE_CREATED; |
3022 | audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE); | 2987 | audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE); |
3023 | error = may_o_create(&nd->path, dentry, mode); | ||
3024 | if (error) | ||
3025 | goto out_dput; | ||
3026 | if (!dir_inode->i_op->create) { | 2988 | if (!dir_inode->i_op->create) { |
3027 | error = -EACCES; | 2989 | error = -EACCES; |
3028 | goto out_dput; | 2990 | goto out_dput; |
3029 | } | 2991 | } |
3030 | error = dir_inode->i_op->create(dir_inode, dentry, mode, | 2992 | error = dir_inode->i_op->create(dir_inode, dentry, mode, |
3031 | op->open_flag & O_EXCL); | 2993 | open_flag & O_EXCL); |
3032 | if (error) | 2994 | if (error) |
3033 | goto out_dput; | 2995 | goto out_dput; |
3034 | fsnotify_create(dir_inode, dentry); | 2996 | fsnotify_create(dir_inode, dentry); |
3035 | } | 2997 | } |
2998 | if (unlikely(create_error) && !dentry->d_inode) { | ||
2999 | error = create_error; | ||
3000 | goto out_dput; | ||
3001 | } | ||
3036 | out_no_open: | 3002 | out_no_open: |
3037 | path->dentry = dentry; | 3003 | path->dentry = dentry; |
3038 | path->mnt = nd->path.mnt; | 3004 | path->mnt = nd->path.mnt; |