diff options
| -rw-r--r-- | fs/namei.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/fs/namei.c b/fs/namei.c index ac6d214da827..5008f01787f5 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -852,7 +852,7 @@ static int follow_managed(struct path *path, unsigned flags) | |||
| 852 | mntput(path->mnt); | 852 | mntput(path->mnt); |
| 853 | if (ret == -EISDIR) | 853 | if (ret == -EISDIR) |
| 854 | ret = 0; | 854 | ret = 0; |
| 855 | return ret; | 855 | return ret < 0 ? ret : need_mntput; |
| 856 | } | 856 | } |
| 857 | 857 | ||
| 858 | int follow_down_one(struct path *path) | 858 | int follow_down_one(struct path *path) |
| @@ -900,6 +900,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, | |||
| 900 | break; | 900 | break; |
| 901 | path->mnt = mounted; | 901 | path->mnt = mounted; |
| 902 | path->dentry = mounted->mnt_root; | 902 | path->dentry = mounted->mnt_root; |
| 903 | nd->flags |= LOOKUP_JUMPED; | ||
| 903 | nd->seq = read_seqcount_begin(&path->dentry->d_seq); | 904 | nd->seq = read_seqcount_begin(&path->dentry->d_seq); |
| 904 | /* | 905 | /* |
| 905 | * Update the inode too. We don't need to re-check the | 906 | * Update the inode too. We don't need to re-check the |
| @@ -1213,6 +1214,8 @@ retry: | |||
| 1213 | path_put_conditional(path, nd); | 1214 | path_put_conditional(path, nd); |
| 1214 | return err; | 1215 | return err; |
| 1215 | } | 1216 | } |
| 1217 | if (err) | ||
| 1218 | nd->flags |= LOOKUP_JUMPED; | ||
| 1216 | *inode = path->dentry->d_inode; | 1219 | *inode = path->dentry->d_inode; |
| 1217 | return 0; | 1220 | return 0; |
| 1218 | } | 1221 | } |
| @@ -2146,6 +2149,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
| 2146 | } | 2149 | } |
| 2147 | 2150 | ||
| 2148 | /* create side of things */ | 2151 | /* create side of things */ |
| 2152 | /* | ||
| 2153 | * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED has been | ||
| 2154 | * cleared when we got to the last component we are about to look up | ||
| 2155 | */ | ||
| 2149 | error = complete_walk(nd); | 2156 | error = complete_walk(nd); |
| 2150 | if (error) | 2157 | if (error) |
| 2151 | return ERR_PTR(error); | 2158 | return ERR_PTR(error); |
| @@ -2214,6 +2221,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
| 2214 | if (error < 0) | 2221 | if (error < 0) |
| 2215 | goto exit_dput; | 2222 | goto exit_dput; |
| 2216 | 2223 | ||
| 2224 | if (error) | ||
| 2225 | nd->flags |= LOOKUP_JUMPED; | ||
| 2226 | |||
| 2217 | error = -ENOENT; | 2227 | error = -ENOENT; |
| 2218 | if (!path->dentry->d_inode) | 2228 | if (!path->dentry->d_inode) |
| 2219 | goto exit_dput; | 2229 | goto exit_dput; |
| @@ -2223,6 +2233,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
| 2223 | 2233 | ||
| 2224 | path_to_nameidata(path, nd); | 2234 | path_to_nameidata(path, nd); |
| 2225 | nd->inode = path->dentry->d_inode; | 2235 | nd->inode = path->dentry->d_inode; |
| 2236 | /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ | ||
| 2237 | error = complete_walk(nd); | ||
| 2238 | if (error) | ||
| 2239 | goto exit; | ||
| 2226 | error = -EISDIR; | 2240 | error = -EISDIR; |
| 2227 | if (S_ISDIR(nd->inode->i_mode)) | 2241 | if (S_ISDIR(nd->inode->i_mode)) |
| 2228 | goto exit; | 2242 | goto exit; |
