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