diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-12-05 20:25:06 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-12-06 21:18:16 -0500 |
commit | ef55d91700d54f29b9ac301658b5b8f377ef3206 (patch) | |
tree | bc40a635ac5368b450197b540502a558a8a9efe8 /fs/namei.c | |
parent | 9e6697e26f9888cdb6088664d31c3772b0dff0a4 (diff) |
path_init(): set nd->inode earlier in cwd-relative case
that allows to kill the recheck of nd->seq on the way out in
this case, and this check on the way out is left only for
absolute pathnames.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 22 |
1 files changed, 12 insertions, 10 deletions
diff --git a/fs/namei.c b/fs/namei.c index f89fe5f7eac3..a08018b1485c 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2028,6 +2028,15 @@ static const char *path_init(struct nameidata *nd, unsigned flags) | |||
2028 | path_get(&nd->root); | 2028 | path_get(&nd->root); |
2029 | nd->path = nd->root; | 2029 | nd->path = nd->root; |
2030 | } | 2030 | } |
2031 | nd->inode = nd->path.dentry->d_inode; | ||
2032 | if (!(flags & LOOKUP_RCU)) | ||
2033 | return s; | ||
2034 | if (likely(!read_seqcount_retry(&nd->path.dentry->d_seq, nd->seq))) | ||
2035 | return s; | ||
2036 | if (!(nd->flags & LOOKUP_ROOT)) | ||
2037 | nd->root.mnt = NULL; | ||
2038 | rcu_read_unlock(); | ||
2039 | return ERR_PTR(-ECHILD); | ||
2031 | } else if (nd->dfd == AT_FDCWD) { | 2040 | } else if (nd->dfd == AT_FDCWD) { |
2032 | if (flags & LOOKUP_RCU) { | 2041 | if (flags & LOOKUP_RCU) { |
2033 | struct fs_struct *fs = current->fs; | 2042 | struct fs_struct *fs = current->fs; |
@@ -2038,11 +2047,14 @@ static const char *path_init(struct nameidata *nd, unsigned flags) | |||
2038 | do { | 2047 | do { |
2039 | seq = read_seqcount_begin(&fs->seq); | 2048 | seq = read_seqcount_begin(&fs->seq); |
2040 | nd->path = fs->pwd; | 2049 | nd->path = fs->pwd; |
2050 | nd->inode = nd->path.dentry->d_inode; | ||
2041 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); | 2051 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); |
2042 | } while (read_seqcount_retry(&fs->seq, seq)); | 2052 | } while (read_seqcount_retry(&fs->seq, seq)); |
2043 | } else { | 2053 | } else { |
2044 | get_fs_pwd(current->fs, &nd->path); | 2054 | get_fs_pwd(current->fs, &nd->path); |
2055 | nd->inode = nd->path.dentry->d_inode; | ||
2045 | } | 2056 | } |
2057 | return s; | ||
2046 | } else { | 2058 | } else { |
2047 | /* Caller must check execute permissions on the starting path component */ | 2059 | /* Caller must check execute permissions on the starting path component */ |
2048 | struct fd f = fdget_raw(nd->dfd); | 2060 | struct fd f = fdget_raw(nd->dfd); |
@@ -2072,16 +2084,6 @@ static const char *path_init(struct nameidata *nd, unsigned flags) | |||
2072 | fdput(f); | 2084 | fdput(f); |
2073 | return s; | 2085 | return s; |
2074 | } | 2086 | } |
2075 | |||
2076 | nd->inode = nd->path.dentry->d_inode; | ||
2077 | if (!(flags & LOOKUP_RCU)) | ||
2078 | return s; | ||
2079 | if (likely(!read_seqcount_retry(&nd->path.dentry->d_seq, nd->seq))) | ||
2080 | return s; | ||
2081 | if (!(nd->flags & LOOKUP_ROOT)) | ||
2082 | nd->root.mnt = NULL; | ||
2083 | rcu_read_unlock(); | ||
2084 | return ERR_PTR(-ECHILD); | ||
2085 | } | 2087 | } |
2086 | 2088 | ||
2087 | static const char *trailing_symlink(struct nameidata *nd) | 2089 | static const char *trailing_symlink(struct nameidata *nd) |