aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/namei.c37
1 files changed, 35 insertions, 2 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 998d5316921a..7d694194024a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2202,6 +2202,8 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
2202 struct file *filp; 2202 struct file *filp;
2203 struct inode *inode; 2203 struct inode *inode;
2204 int symlink_ok = 0; 2204 int symlink_ok = 0;
2205 struct path save_parent = { .dentry = NULL, .mnt = NULL };
2206 bool retried = false;
2205 int error; 2207 int error;
2206 2208
2207 nd->flags &= ~LOOKUP_PARENT; 2209 nd->flags &= ~LOOKUP_PARENT;
@@ -2267,6 +2269,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
2267 if (nd->last.name[nd->last.len]) 2269 if (nd->last.name[nd->last.len])
2268 goto exit; 2270 goto exit;
2269 2271
2272retry_lookup:
2270 mutex_lock(&dir->d_inode->i_mutex); 2273 mutex_lock(&dir->d_inode->i_mutex);
2271 2274
2272 dentry = lookup_hash(nd); 2275 dentry = lookup_hash(nd);
@@ -2349,12 +2352,21 @@ finish_lookup:
2349 return NULL; 2352 return NULL;
2350 } 2353 }
2351 2354
2352 path_to_nameidata(path, nd); 2355 if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path->mnt) {
2356 path_to_nameidata(path, nd);
2357 } else {
2358 save_parent.dentry = nd->path.dentry;
2359 save_parent.mnt = mntget(path->mnt);
2360 nd->path.dentry = path->dentry;
2361
2362 }
2353 nd->inode = inode; 2363 nd->inode = inode;
2354 /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ 2364 /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */
2355 error = complete_walk(nd); 2365 error = complete_walk(nd);
2356 if (error) 2366 if (error) {
2367 path_put(&save_parent);
2357 return ERR_PTR(error); 2368 return ERR_PTR(error);
2369 }
2358 error = -EISDIR; 2370 error = -EISDIR;
2359 if ((open_flag & O_CREAT) && S_ISDIR(nd->inode->i_mode)) 2371 if ((open_flag & O_CREAT) && S_ISDIR(nd->inode->i_mode))
2360 goto exit; 2372 goto exit;
@@ -2377,6 +2389,20 @@ common:
2377 if (error) 2389 if (error)
2378 goto exit; 2390 goto exit;
2379 filp = nameidata_to_filp(nd); 2391 filp = nameidata_to_filp(nd);
2392 if (filp == ERR_PTR(-EOPENSTALE) && save_parent.dentry && !retried) {
2393 BUG_ON(save_parent.dentry != dir);
2394 path_put(&nd->path);
2395 nd->path = save_parent;
2396 nd->inode = dir->d_inode;
2397 save_parent.mnt = NULL;
2398 save_parent.dentry = NULL;
2399 if (want_write) {
2400 mnt_drop_write(nd->path.mnt);
2401 want_write = 0;
2402 }
2403 retried = true;
2404 goto retry_lookup;
2405 }
2380 if (!IS_ERR(filp)) { 2406 if (!IS_ERR(filp)) {
2381 error = ima_file_check(filp, op->acc_mode); 2407 error = ima_file_check(filp, op->acc_mode);
2382 if (error) { 2408 if (error) {
@@ -2396,6 +2422,7 @@ common:
2396out: 2422out:
2397 if (want_write) 2423 if (want_write)
2398 mnt_drop_write(nd->path.mnt); 2424 mnt_drop_write(nd->path.mnt);
2425 path_put(&save_parent);
2399 terminate_walk(nd); 2426 terminate_walk(nd);
2400 return filp; 2427 return filp;
2401 2428
@@ -2459,6 +2486,12 @@ out:
2459 if (base) 2486 if (base)
2460 fput(base); 2487 fput(base);
2461 release_open_intent(nd); 2488 release_open_intent(nd);
2489 if (filp == ERR_PTR(-EOPENSTALE)) {
2490 if (flags & LOOKUP_RCU)
2491 filp = ERR_PTR(-ECHILD);
2492 else
2493 filp = ERR_PTR(-ESTALE);
2494 }
2462 return filp; 2495 return filp;
2463 2496
2464out_filp: 2497out_filp: