diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 90 |
1 files changed, 38 insertions, 52 deletions
diff --git a/fs/namei.c b/fs/namei.c index d1a5dfeaf999..1f561dc495a1 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2111,57 +2111,6 @@ static int open_will_truncate(int flag, struct inode *inode) | |||
2111 | return (flag & O_TRUNC); | 2111 | return (flag & O_TRUNC); |
2112 | } | 2112 | } |
2113 | 2113 | ||
2114 | static struct file *finish_open(struct nameidata *nd, | ||
2115 | int open_flag, int acc_mode) | ||
2116 | { | ||
2117 | struct file *filp; | ||
2118 | int will_truncate; | ||
2119 | int error; | ||
2120 | |||
2121 | will_truncate = open_will_truncate(open_flag, nd->path.dentry->d_inode); | ||
2122 | if (will_truncate) { | ||
2123 | error = mnt_want_write(nd->path.mnt); | ||
2124 | if (error) | ||
2125 | goto exit; | ||
2126 | } | ||
2127 | error = may_open(&nd->path, acc_mode, open_flag); | ||
2128 | if (error) { | ||
2129 | if (will_truncate) | ||
2130 | mnt_drop_write(nd->path.mnt); | ||
2131 | goto exit; | ||
2132 | } | ||
2133 | filp = nameidata_to_filp(nd); | ||
2134 | if (!IS_ERR(filp)) { | ||
2135 | error = ima_file_check(filp, acc_mode); | ||
2136 | if (error) { | ||
2137 | fput(filp); | ||
2138 | filp = ERR_PTR(error); | ||
2139 | } | ||
2140 | } | ||
2141 | if (!IS_ERR(filp)) { | ||
2142 | if (will_truncate) { | ||
2143 | error = handle_truncate(filp); | ||
2144 | if (error) { | ||
2145 | fput(filp); | ||
2146 | filp = ERR_PTR(error); | ||
2147 | } | ||
2148 | } | ||
2149 | } | ||
2150 | /* | ||
2151 | * It is now safe to drop the mnt write | ||
2152 | * because the filp has had a write taken | ||
2153 | * on its behalf. | ||
2154 | */ | ||
2155 | if (will_truncate) | ||
2156 | mnt_drop_write(nd->path.mnt); | ||
2157 | path_put(&nd->path); | ||
2158 | return filp; | ||
2159 | |||
2160 | exit: | ||
2161 | path_put(&nd->path); | ||
2162 | return ERR_PTR(error); | ||
2163 | } | ||
2164 | |||
2165 | /* | 2114 | /* |
2166 | * Handle the last step of open() | 2115 | * Handle the last step of open() |
2167 | */ | 2116 | */ |
@@ -2169,6 +2118,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2169 | const struct open_flags *op, const char *pathname) | 2118 | const struct open_flags *op, const char *pathname) |
2170 | { | 2119 | { |
2171 | struct dentry *dir = nd->path.dentry; | 2120 | struct dentry *dir = nd->path.dentry; |
2121 | int will_truncate; | ||
2172 | struct file *filp; | 2122 | struct file *filp; |
2173 | struct inode *inode; | 2123 | struct inode *inode; |
2174 | int error; | 2124 | int error; |
@@ -2329,7 +2279,43 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2329 | if (S_ISDIR(nd->inode->i_mode)) | 2279 | if (S_ISDIR(nd->inode->i_mode)) |
2330 | goto exit; | 2280 | goto exit; |
2331 | ok: | 2281 | ok: |
2332 | filp = finish_open(nd, op->open_flag, op->acc_mode); | 2282 | will_truncate = open_will_truncate(op->open_flag, nd->path.dentry->d_inode); |
2283 | if (will_truncate) { | ||
2284 | error = mnt_want_write(nd->path.mnt); | ||
2285 | if (error) | ||
2286 | goto exit; | ||
2287 | } | ||
2288 | error = may_open(&nd->path, op->acc_mode, op->open_flag); | ||
2289 | if (error) { | ||
2290 | if (will_truncate) | ||
2291 | mnt_drop_write(nd->path.mnt); | ||
2292 | goto exit; | ||
2293 | } | ||
2294 | filp = nameidata_to_filp(nd); | ||
2295 | if (!IS_ERR(filp)) { | ||
2296 | error = ima_file_check(filp, op->acc_mode); | ||
2297 | if (error) { | ||
2298 | fput(filp); | ||
2299 | filp = ERR_PTR(error); | ||
2300 | } | ||
2301 | } | ||
2302 | if (!IS_ERR(filp)) { | ||
2303 | if (will_truncate) { | ||
2304 | error = handle_truncate(filp); | ||
2305 | if (error) { | ||
2306 | fput(filp); | ||
2307 | filp = ERR_PTR(error); | ||
2308 | } | ||
2309 | } | ||
2310 | } | ||
2311 | /* | ||
2312 | * It is now safe to drop the mnt write | ||
2313 | * because the filp has had a write taken | ||
2314 | * on its behalf. | ||
2315 | */ | ||
2316 | if (will_truncate) | ||
2317 | mnt_drop_write(nd->path.mnt); | ||
2318 | path_put(&nd->path); | ||
2333 | return filp; | 2319 | return filp; |
2334 | 2320 | ||
2335 | exit_mutex_unlock: | 2321 | exit_mutex_unlock: |