diff options
Diffstat (limited to 'fs/namei.c')
| -rw-r--r-- | fs/namei.c | 23 |
1 files changed, 11 insertions, 12 deletions
diff --git a/fs/namei.c b/fs/namei.c index b55440baf7ab..94a5e60779f9 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -561,6 +561,7 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata | |||
| 561 | dget(dentry); | 561 | dget(dentry); |
| 562 | } | 562 | } |
| 563 | mntget(path->mnt); | 563 | mntget(path->mnt); |
| 564 | nd->last_type = LAST_BIND; | ||
| 564 | cookie = dentry->d_inode->i_op->follow_link(dentry, nd); | 565 | cookie = dentry->d_inode->i_op->follow_link(dentry, nd); |
| 565 | error = PTR_ERR(cookie); | 566 | error = PTR_ERR(cookie); |
| 566 | if (!IS_ERR(cookie)) { | 567 | if (!IS_ERR(cookie)) { |
| @@ -1603,11 +1604,12 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
| 1603 | struct file *filp; | 1604 | struct file *filp; |
| 1604 | struct nameidata nd; | 1605 | struct nameidata nd; |
| 1605 | int error; | 1606 | int error; |
| 1606 | struct path path, save; | 1607 | struct path path; |
| 1607 | struct dentry *dir; | 1608 | struct dentry *dir; |
| 1608 | int count = 0; | 1609 | int count = 0; |
| 1609 | int will_truncate; | 1610 | int will_truncate; |
| 1610 | int flag = open_to_namei_flags(open_flag); | 1611 | int flag = open_to_namei_flags(open_flag); |
| 1612 | int force_reval = 0; | ||
| 1611 | 1613 | ||
| 1612 | /* | 1614 | /* |
| 1613 | * 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 |
| @@ -1619,7 +1621,7 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
| 1619 | open_flag |= O_DSYNC; | 1621 | open_flag |= O_DSYNC; |
| 1620 | 1622 | ||
| 1621 | if (!acc_mode) | 1623 | if (!acc_mode) |
| 1622 | acc_mode = MAY_OPEN | ACC_MODE(flag); | 1624 | acc_mode = MAY_OPEN | ACC_MODE(open_flag); |
| 1623 | 1625 | ||
| 1624 | /* O_TRUNC implies we need access checks for write permissions */ | 1626 | /* O_TRUNC implies we need access checks for write permissions */ |
| 1625 | if (flag & O_TRUNC) | 1627 | if (flag & O_TRUNC) |
| @@ -1659,9 +1661,12 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
| 1659 | /* | 1661 | /* |
| 1660 | * Create - we need to know the parent. | 1662 | * Create - we need to know the parent. |
| 1661 | */ | 1663 | */ |
| 1664 | reval: | ||
| 1662 | error = path_init(dfd, pathname, LOOKUP_PARENT, &nd); | 1665 | error = path_init(dfd, pathname, LOOKUP_PARENT, &nd); |
| 1663 | if (error) | 1666 | if (error) |
| 1664 | return ERR_PTR(error); | 1667 | return ERR_PTR(error); |
| 1668 | if (force_reval) | ||
| 1669 | nd.flags |= LOOKUP_REVAL; | ||
| 1665 | error = path_walk(pathname, &nd); | 1670 | error = path_walk(pathname, &nd); |
| 1666 | if (error) { | 1671 | if (error) { |
| 1667 | if (nd.root.mnt) | 1672 | if (nd.root.mnt) |
| @@ -1853,17 +1858,7 @@ do_link: | |||
| 1853 | error = security_inode_follow_link(path.dentry, &nd); | 1858 | error = security_inode_follow_link(path.dentry, &nd); |
| 1854 | if (error) | 1859 | if (error) |
| 1855 | goto exit_dput; | 1860 | goto exit_dput; |
| 1856 | save = nd.path; | ||
| 1857 | path_get(&save); | ||
| 1858 | error = __do_follow_link(&path, &nd); | 1861 | error = __do_follow_link(&path, &nd); |
| 1859 | if (error == -ESTALE) { | ||
| 1860 | /* nd.path had been dropped */ | ||
| 1861 | nd.path = save; | ||
| 1862 | path_get(&nd.path); | ||
| 1863 | nd.flags |= LOOKUP_REVAL; | ||
| 1864 | error = __do_follow_link(&path, &nd); | ||
| 1865 | } | ||
| 1866 | path_put(&save); | ||
| 1867 | path_put(&path); | 1862 | path_put(&path); |
| 1868 | if (error) { | 1863 | if (error) { |
| 1869 | /* Does someone understand code flow here? Or it is only | 1864 | /* Does someone understand code flow here? Or it is only |
| @@ -1873,6 +1868,10 @@ do_link: | |||
| 1873 | release_open_intent(&nd); | 1868 | release_open_intent(&nd); |
| 1874 | if (nd.root.mnt) | 1869 | if (nd.root.mnt) |
| 1875 | path_put(&nd.root); | 1870 | path_put(&nd.root); |
| 1871 | if (error == -ESTALE && !force_reval) { | ||
| 1872 | force_reval = 1; | ||
| 1873 | goto reval; | ||
| 1874 | } | ||
| 1876 | return ERR_PTR(error); | 1875 | return ERR_PTR(error); |
| 1877 | } | 1876 | } |
| 1878 | nd.flags &= ~LOOKUP_PARENT; | 1877 | nd.flags &= ~LOOKUP_PARENT; |
