diff options
-rw-r--r-- | fs/namei.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/fs/namei.c b/fs/namei.c index fe47e6d8e85f..d07bc1b206c3 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1142,6 +1142,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, | |||
1142 | 1142 | ||
1143 | static int follow_dotdot_rcu(struct nameidata *nd) | 1143 | static int follow_dotdot_rcu(struct nameidata *nd) |
1144 | { | 1144 | { |
1145 | struct inode *inode = nd->inode; | ||
1145 | if (!nd->root.mnt) | 1146 | if (!nd->root.mnt) |
1146 | set_root_rcu(nd); | 1147 | set_root_rcu(nd); |
1147 | 1148 | ||
@@ -1155,6 +1156,7 @@ static int follow_dotdot_rcu(struct nameidata *nd) | |||
1155 | struct dentry *parent = old->d_parent; | 1156 | struct dentry *parent = old->d_parent; |
1156 | unsigned seq; | 1157 | unsigned seq; |
1157 | 1158 | ||
1159 | inode = parent->d_inode; | ||
1158 | seq = read_seqcount_begin(&parent->d_seq); | 1160 | seq = read_seqcount_begin(&parent->d_seq); |
1159 | if (read_seqcount_retry(&old->d_seq, nd->seq)) | 1161 | if (read_seqcount_retry(&old->d_seq, nd->seq)) |
1160 | goto failed; | 1162 | goto failed; |
@@ -1164,6 +1166,7 @@ static int follow_dotdot_rcu(struct nameidata *nd) | |||
1164 | } | 1166 | } |
1165 | if (!follow_up_rcu(&nd->path)) | 1167 | if (!follow_up_rcu(&nd->path)) |
1166 | break; | 1168 | break; |
1169 | inode = nd->path.dentry->d_inode; | ||
1167 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); | 1170 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); |
1168 | } | 1171 | } |
1169 | while (d_mountpoint(nd->path.dentry)) { | 1172 | while (d_mountpoint(nd->path.dentry)) { |
@@ -1173,11 +1176,12 @@ static int follow_dotdot_rcu(struct nameidata *nd) | |||
1173 | break; | 1176 | break; |
1174 | nd->path.mnt = &mounted->mnt; | 1177 | nd->path.mnt = &mounted->mnt; |
1175 | nd->path.dentry = mounted->mnt.mnt_root; | 1178 | nd->path.dentry = mounted->mnt.mnt_root; |
1179 | inode = nd->path.dentry->d_inode; | ||
1176 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); | 1180 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); |
1177 | if (read_seqretry(&mount_lock, nd->m_seq)) | 1181 | if (read_seqretry(&mount_lock, nd->m_seq)) |
1178 | goto failed; | 1182 | goto failed; |
1179 | } | 1183 | } |
1180 | nd->inode = nd->path.dentry->d_inode; | 1184 | nd->inode = inode; |
1181 | return 0; | 1185 | return 0; |
1182 | 1186 | ||
1183 | failed: | 1187 | failed: |
@@ -1904,7 +1908,14 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1904 | } | 1908 | } |
1905 | 1909 | ||
1906 | nd->inode = nd->path.dentry->d_inode; | 1910 | nd->inode = nd->path.dentry->d_inode; |
1907 | return 0; | 1911 | if (!(flags & LOOKUP_RCU)) |
1912 | return 0; | ||
1913 | if (likely(!read_seqcount_retry(&nd->path.dentry->d_seq, nd->seq))) | ||
1914 | return 0; | ||
1915 | if (!(nd->flags & LOOKUP_ROOT)) | ||
1916 | nd->root.mnt = NULL; | ||
1917 | rcu_read_unlock(); | ||
1918 | return -ECHILD; | ||
1908 | } | 1919 | } |
1909 | 1920 | ||
1910 | static inline int lookup_last(struct nameidata *nd, struct path *path) | 1921 | static inline int lookup_last(struct nameidata *nd, struct path *path) |