aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2012-05-21 11:30:19 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-06-01 12:12:01 -0400
commit16b1c1cd71176ab0a76b26818fbf12db9183ed57 (patch)
treeda4ab8077cc3d9dce5b6ec2d003074cba3841446 /fs
parent50ee93afcaa970620d1fb5a9894109a2ab152868 (diff)
vfs: retry last component if opening stale dentry
NFS optimizes away d_revalidates for last component of open. This means that open itself can find the dentry stale. This patch allows the filesystem to return EOPENSTALE and the VFS will retry the lookup on just the last component if possible. If the lookup was done using RCU mode, including the last component, then this is not possible since the parent dentry is lost. In this case fall back to non-RCU lookup. Currently this is not used since NFS will always leave RCU mode. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
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: