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