diff options
| -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; |
