diff options
Diffstat (limited to 'fs/autofs4/waitq.c')
-rw-r--r-- | fs/autofs4/waitq.c | 40 |
1 files changed, 34 insertions, 6 deletions
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 2341375386f8..25435987d6ae 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -186,16 +186,26 @@ static int autofs4_getpath(struct autofs_sb_info *sbi, | |||
186 | { | 186 | { |
187 | struct dentry *root = sbi->sb->s_root; | 187 | struct dentry *root = sbi->sb->s_root; |
188 | struct dentry *tmp; | 188 | struct dentry *tmp; |
189 | char *buf = *name; | 189 | char *buf; |
190 | char *p; | 190 | char *p; |
191 | int len = 0; | 191 | int len; |
192 | unsigned seq; | ||
192 | 193 | ||
193 | spin_lock(&dcache_lock); | 194 | rename_retry: |
195 | buf = *name; | ||
196 | len = 0; | ||
197 | |||
198 | seq = read_seqbegin(&rename_lock); | ||
199 | rcu_read_lock(); | ||
200 | spin_lock(&sbi->fs_lock); | ||
194 | for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) | 201 | for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) |
195 | len += tmp->d_name.len + 1; | 202 | len += tmp->d_name.len + 1; |
196 | 203 | ||
197 | if (!len || --len > NAME_MAX) { | 204 | if (!len || --len > NAME_MAX) { |
198 | spin_unlock(&dcache_lock); | 205 | spin_unlock(&sbi->fs_lock); |
206 | rcu_read_unlock(); | ||
207 | if (read_seqretry(&rename_lock, seq)) | ||
208 | goto rename_retry; | ||
199 | return 0; | 209 | return 0; |
200 | } | 210 | } |
201 | 211 | ||
@@ -208,7 +218,10 @@ static int autofs4_getpath(struct autofs_sb_info *sbi, | |||
208 | p -= tmp->d_name.len; | 218 | p -= tmp->d_name.len; |
209 | strncpy(p, tmp->d_name.name, tmp->d_name.len); | 219 | strncpy(p, tmp->d_name.name, tmp->d_name.len); |
210 | } | 220 | } |
211 | spin_unlock(&dcache_lock); | 221 | spin_unlock(&sbi->fs_lock); |
222 | rcu_read_unlock(); | ||
223 | if (read_seqretry(&rename_lock, seq)) | ||
224 | goto rename_retry; | ||
212 | 225 | ||
213 | return len; | 226 | return len; |
214 | } | 227 | } |
@@ -296,6 +309,9 @@ static int validate_request(struct autofs_wait_queue **wait, | |||
296 | * completed while we waited on the mutex ... | 309 | * completed while we waited on the mutex ... |
297 | */ | 310 | */ |
298 | if (notify == NFY_MOUNT) { | 311 | if (notify == NFY_MOUNT) { |
312 | struct dentry *new = NULL; | ||
313 | int valid = 1; | ||
314 | |||
299 | /* | 315 | /* |
300 | * If the dentry was successfully mounted while we slept | 316 | * If the dentry was successfully mounted while we slept |
301 | * on the wait queue mutex we can return success. If it | 317 | * on the wait queue mutex we can return success. If it |
@@ -303,8 +319,20 @@ static int validate_request(struct autofs_wait_queue **wait, | |||
303 | * a multi-mount with no mount at it's base) we can | 319 | * a multi-mount with no mount at it's base) we can |
304 | * continue on and create a new request. | 320 | * continue on and create a new request. |
305 | */ | 321 | */ |
322 | if (!IS_ROOT(dentry)) { | ||
323 | if (dentry->d_inode && d_unhashed(dentry)) { | ||
324 | struct dentry *parent = dentry->d_parent; | ||
325 | new = d_lookup(parent, &dentry->d_name); | ||
326 | if (new) | ||
327 | dentry = new; | ||
328 | } | ||
329 | } | ||
306 | if (have_submounts(dentry)) | 330 | if (have_submounts(dentry)) |
307 | return 0; | 331 | valid = 0; |
332 | |||
333 | if (new) | ||
334 | dput(new); | ||
335 | return valid; | ||
308 | } | 336 | } |
309 | 337 | ||
310 | return 1; | 338 | return 1; |