diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2010-01-13 15:01:15 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-01-14 09:05:26 -0500 |
commit | 9850c056559f3633a32d810aaf00ced39437b364 (patch) | |
tree | 30e80de94e12ae758736cfb586db39cfa77d69df /fs/namei.c | |
parent | 806892e9e12e731a0ca76c8f62ad95cf8eea9614 (diff) |
Fix the -ESTALE handling in do_filp_open()
Instead of playing sick games with path saving, cleanups, just retry
the entire thing once with LOOKUP_REVAL added. Post-.34 we'll convert
all -ESTALE handling in there to that style, rather than playing with
many retry loops deep in the call chain.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 20 |
1 files changed, 9 insertions, 11 deletions
diff --git a/fs/namei.c b/fs/namei.c index d930f1856ed2..94a5e60779f9 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1604,11 +1604,12 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1604 | struct file *filp; | 1604 | struct file *filp; |
1605 | struct nameidata nd; | 1605 | struct nameidata nd; |
1606 | int error; | 1606 | int error; |
1607 | struct path path, save; | 1607 | struct path path; |
1608 | struct dentry *dir; | 1608 | struct dentry *dir; |
1609 | int count = 0; | 1609 | int count = 0; |
1610 | int will_truncate; | 1610 | int will_truncate; |
1611 | int flag = open_to_namei_flags(open_flag); | 1611 | int flag = open_to_namei_flags(open_flag); |
1612 | int force_reval = 0; | ||
1612 | 1613 | ||
1613 | /* | 1614 | /* |
1614 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only | 1615 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only |
@@ -1660,9 +1661,12 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1660 | /* | 1661 | /* |
1661 | * Create - we need to know the parent. | 1662 | * Create - we need to know the parent. |
1662 | */ | 1663 | */ |
1664 | reval: | ||
1663 | error = path_init(dfd, pathname, LOOKUP_PARENT, &nd); | 1665 | error = path_init(dfd, pathname, LOOKUP_PARENT, &nd); |
1664 | if (error) | 1666 | if (error) |
1665 | return ERR_PTR(error); | 1667 | return ERR_PTR(error); |
1668 | if (force_reval) | ||
1669 | nd.flags |= LOOKUP_REVAL; | ||
1666 | error = path_walk(pathname, &nd); | 1670 | error = path_walk(pathname, &nd); |
1667 | if (error) { | 1671 | if (error) { |
1668 | if (nd.root.mnt) | 1672 | if (nd.root.mnt) |
@@ -1854,17 +1858,7 @@ do_link: | |||
1854 | error = security_inode_follow_link(path.dentry, &nd); | 1858 | error = security_inode_follow_link(path.dentry, &nd); |
1855 | if (error) | 1859 | if (error) |
1856 | goto exit_dput; | 1860 | goto exit_dput; |
1857 | save = nd.path; | ||
1858 | path_get(&save); | ||
1859 | error = __do_follow_link(&path, &nd); | 1861 | error = __do_follow_link(&path, &nd); |
1860 | if (error == -ESTALE) { | ||
1861 | /* nd.path had been dropped */ | ||
1862 | nd.path = save; | ||
1863 | path_get(&nd.path); | ||
1864 | nd.flags |= LOOKUP_REVAL; | ||
1865 | error = __do_follow_link(&path, &nd); | ||
1866 | } | ||
1867 | path_put(&save); | ||
1868 | path_put(&path); | 1862 | path_put(&path); |
1869 | if (error) { | 1863 | if (error) { |
1870 | /* Does someone understand code flow here? Or it is only | 1864 | /* Does someone understand code flow here? Or it is only |
@@ -1874,6 +1868,10 @@ do_link: | |||
1874 | release_open_intent(&nd); | 1868 | release_open_intent(&nd); |
1875 | if (nd.root.mnt) | 1869 | if (nd.root.mnt) |
1876 | path_put(&nd.root); | 1870 | path_put(&nd.root); |
1871 | if (error == -ESTALE && !force_reval) { | ||
1872 | force_reval = 1; | ||
1873 | goto reval; | ||
1874 | } | ||
1877 | return ERR_PTR(error); | 1875 | return ERR_PTR(error); |
1878 | } | 1876 | } |
1879 | nd.flags &= ~LOOKUP_PARENT; | 1877 | nd.flags &= ~LOOKUP_PARENT; |