diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/namei.c | 57 |
1 files changed, 35 insertions, 22 deletions
diff --git a/fs/namei.c b/fs/namei.c index e0f59031be87..5e4206f45371 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2169,17 +2169,26 @@ exit: | |||
2169 | return ERR_PTR(error); | 2169 | return ERR_PTR(error); |
2170 | } | 2170 | } |
2171 | 2171 | ||
2172 | struct open_flags { | ||
2173 | int open_flag; | ||
2174 | int mode; | ||
2175 | int acc_mode; | ||
2176 | int intent; | ||
2177 | }; | ||
2178 | |||
2172 | /* | 2179 | /* |
2173 | * Handle O_CREAT case for do_filp_open | 2180 | * Handle O_CREAT case for do_filp_open |
2174 | */ | 2181 | */ |
2175 | static struct file *do_last(struct nameidata *nd, struct path *path, | 2182 | static struct file *do_last(struct nameidata *nd, struct path *path, |
2176 | int open_flag, int acc_mode, | 2183 | const struct open_flags *op, const char *pathname) |
2177 | int mode, const char *pathname) | ||
2178 | { | 2184 | { |
2179 | struct dentry *dir = nd->path.dentry; | 2185 | struct dentry *dir = nd->path.dentry; |
2180 | struct file *filp; | 2186 | struct file *filp; |
2181 | int error; | 2187 | int error; |
2182 | 2188 | ||
2189 | nd->flags &= ~LOOKUP_PARENT; | ||
2190 | nd->flags |= op->intent; | ||
2191 | |||
2183 | switch (nd->last_type) { | 2192 | switch (nd->last_type) { |
2184 | case LAST_DOTDOT: | 2193 | case LAST_DOTDOT: |
2185 | follow_dotdot(nd); | 2194 | follow_dotdot(nd); |
@@ -2233,7 +2242,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2233 | error = mnt_want_write(nd->path.mnt); | 2242 | error = mnt_want_write(nd->path.mnt); |
2234 | if (error) | 2243 | if (error) |
2235 | goto exit_mutex_unlock; | 2244 | goto exit_mutex_unlock; |
2236 | error = __open_namei_create(nd, path, open_flag, mode); | 2245 | error = __open_namei_create(nd, path, op->open_flag, op->mode); |
2237 | if (error) { | 2246 | if (error) { |
2238 | mnt_drop_write(nd->path.mnt); | 2247 | mnt_drop_write(nd->path.mnt); |
2239 | goto exit; | 2248 | goto exit; |
@@ -2242,7 +2251,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2242 | mnt_drop_write(nd->path.mnt); | 2251 | mnt_drop_write(nd->path.mnt); |
2243 | path_put(&nd->path); | 2252 | path_put(&nd->path); |
2244 | if (!IS_ERR(filp)) { | 2253 | if (!IS_ERR(filp)) { |
2245 | error = ima_file_check(filp, acc_mode); | 2254 | error = ima_file_check(filp, op->acc_mode); |
2246 | if (error) { | 2255 | if (error) { |
2247 | fput(filp); | 2256 | fput(filp); |
2248 | filp = ERR_PTR(error); | 2257 | filp = ERR_PTR(error); |
@@ -2258,7 +2267,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2258 | audit_inode(pathname, path->dentry); | 2267 | audit_inode(pathname, path->dentry); |
2259 | 2268 | ||
2260 | error = -EEXIST; | 2269 | error = -EEXIST; |
2261 | if (open_flag & O_EXCL) | 2270 | if (op->open_flag & O_EXCL) |
2262 | goto exit_dput; | 2271 | goto exit_dput; |
2263 | 2272 | ||
2264 | error = follow_managed(path, nd->flags); | 2273 | error = follow_managed(path, nd->flags); |
@@ -2278,7 +2287,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2278 | if (S_ISDIR(nd->inode->i_mode)) | 2287 | if (S_ISDIR(nd->inode->i_mode)) |
2279 | goto exit; | 2288 | goto exit; |
2280 | ok: | 2289 | ok: |
2281 | filp = finish_open(nd, open_flag, acc_mode); | 2290 | filp = finish_open(nd, op->open_flag, op->acc_mode); |
2282 | return filp; | 2291 | return filp; |
2283 | 2292 | ||
2284 | exit_mutex_unlock: | 2293 | exit_mutex_unlock: |
@@ -2304,7 +2313,8 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
2304 | struct path path; | 2313 | struct path path; |
2305 | int count = 0; | 2314 | int count = 0; |
2306 | int flag = open_to_namei_flags(open_flag); | 2315 | int flag = open_to_namei_flags(open_flag); |
2307 | int flags; | 2316 | int flags = 0; |
2317 | struct open_flags op; | ||
2308 | 2318 | ||
2309 | if (!(open_flag & O_CREAT)) | 2319 | if (!(open_flag & O_CREAT)) |
2310 | mode = 0; | 2320 | mode = 0; |
@@ -2321,6 +2331,8 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
2321 | if (open_flag & __O_SYNC) | 2331 | if (open_flag & __O_SYNC) |
2322 | open_flag |= O_DSYNC; | 2332 | open_flag |= O_DSYNC; |
2323 | 2333 | ||
2334 | op.open_flag = open_flag; | ||
2335 | |||
2324 | if (!acc_mode) | 2336 | if (!acc_mode) |
2325 | acc_mode = MAY_OPEN | ACC_MODE(open_flag); | 2337 | acc_mode = MAY_OPEN | ACC_MODE(open_flag); |
2326 | 2338 | ||
@@ -2333,12 +2345,15 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
2333 | if (open_flag & O_APPEND) | 2345 | if (open_flag & O_APPEND) |
2334 | acc_mode |= MAY_APPEND; | 2346 | acc_mode |= MAY_APPEND; |
2335 | 2347 | ||
2336 | flags = LOOKUP_OPEN; | 2348 | op.acc_mode = acc_mode; |
2349 | |||
2350 | op.intent = LOOKUP_OPEN; | ||
2337 | if (open_flag & O_CREAT) { | 2351 | if (open_flag & O_CREAT) { |
2338 | flags |= LOOKUP_CREATE; | 2352 | op.intent |= LOOKUP_CREATE; |
2339 | if (open_flag & O_EXCL) | 2353 | if (open_flag & O_EXCL) |
2340 | flags |= LOOKUP_EXCL; | 2354 | op.intent |= LOOKUP_EXCL; |
2341 | } | 2355 | } |
2356 | |||
2342 | if (open_flag & O_DIRECTORY) | 2357 | if (open_flag & O_DIRECTORY) |
2343 | flags |= LOOKUP_DIRECTORY; | 2358 | flags |= LOOKUP_DIRECTORY; |
2344 | if (!(open_flag & O_NOFOLLOW)) | 2359 | if (!(open_flag & O_NOFOLLOW)) |
@@ -2357,7 +2372,7 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
2357 | goto creat; | 2372 | goto creat; |
2358 | 2373 | ||
2359 | /* !O_CREAT, simple open */ | 2374 | /* !O_CREAT, simple open */ |
2360 | error = do_path_lookup(dfd, pathname, flags, &nd); | 2375 | error = do_path_lookup(dfd, pathname, flags | op.intent, &nd); |
2361 | if (unlikely(error)) | 2376 | if (unlikely(error)) |
2362 | goto out_filp2; | 2377 | goto out_filp2; |
2363 | error = -ELOOP; | 2378 | error = -ELOOP; |
@@ -2384,14 +2399,14 @@ out_filp2: | |||
2384 | 2399 | ||
2385 | creat: | 2400 | creat: |
2386 | /* OK, have to create the file. Find the parent. */ | 2401 | /* OK, have to create the file. Find the parent. */ |
2387 | error = path_lookupat(dfd, pathname, LOOKUP_PARENT | LOOKUP_RCU, &nd); | 2402 | error = path_lookupat(dfd, pathname, |
2403 | LOOKUP_PARENT | LOOKUP_RCU | flags, &nd); | ||
2388 | if (unlikely(error == -ECHILD)) | 2404 | if (unlikely(error == -ECHILD)) |
2389 | error = path_lookupat(dfd, pathname, LOOKUP_PARENT, &nd); | 2405 | error = path_lookupat(dfd, pathname, LOOKUP_PARENT | flags, &nd); |
2390 | if (unlikely(error == -ESTALE)) { | 2406 | if (unlikely(error == -ESTALE)) { |
2391 | reval: | 2407 | reval: |
2392 | flags |= LOOKUP_REVAL; | 2408 | flags |= LOOKUP_REVAL; |
2393 | error = path_lookupat(dfd, pathname, | 2409 | error = path_lookupat(dfd, pathname, LOOKUP_PARENT | flags, &nd); |
2394 | LOOKUP_PARENT | LOOKUP_REVAL, &nd); | ||
2395 | } | 2410 | } |
2396 | if (unlikely(error)) | 2411 | if (unlikely(error)) |
2397 | goto out_filp; | 2412 | goto out_filp; |
@@ -2401,8 +2416,7 @@ reval: | |||
2401 | /* | 2416 | /* |
2402 | * We have the parent and last component. | 2417 | * We have the parent and last component. |
2403 | */ | 2418 | */ |
2404 | nd.flags = (nd.flags & ~LOOKUP_PARENT) | flags; | 2419 | filp = do_last(&nd, &path, &op, pathname); |
2405 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | ||
2406 | while (unlikely(!filp)) { /* trailing symlink */ | 2420 | while (unlikely(!filp)) { /* trailing symlink */ |
2407 | struct path link = path; | 2421 | struct path link = path; |
2408 | struct inode *linki = link.dentry->d_inode; | 2422 | struct inode *linki = link.dentry->d_inode; |
@@ -2424,13 +2438,12 @@ reval: | |||
2424 | * just set LAST_BIND. | 2438 | * just set LAST_BIND. |
2425 | */ | 2439 | */ |
2426 | nd.flags |= LOOKUP_PARENT; | 2440 | nd.flags |= LOOKUP_PARENT; |
2441 | nd.flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); | ||
2427 | error = __do_follow_link(&link, &nd, &cookie); | 2442 | error = __do_follow_link(&link, &nd, &cookie); |
2428 | if (unlikely(error)) { | 2443 | if (unlikely(error)) |
2429 | filp = ERR_PTR(error); | 2444 | filp = ERR_PTR(error); |
2430 | } else { | 2445 | else |
2431 | nd.flags &= ~LOOKUP_PARENT; | 2446 | filp = do_last(&nd, &path, &op, pathname); |
2432 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | ||
2433 | } | ||
2434 | if (!IS_ERR(cookie) && linki->i_op->put_link) | 2447 | if (!IS_ERR(cookie) && linki->i_op->put_link) |
2435 | linki->i_op->put_link(link.dentry, &nd, cookie); | 2448 | linki->i_op->put_link(link.dentry, &nd, cookie); |
2436 | path_put(&link); | 2449 | path_put(&link); |