diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-06-20 13:41:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-06-20 13:41:51 -0400 |
commit | 67016f6cdfd079e632bbc49e33178b2d558c120a (patch) | |
tree | 086f6dc06468a9b565b0f6dad6b218e2ecc1956b /fs | |
parent | f780f00d723d991353b2a97a8a844ffefbc40505 (diff) | |
parent | e7d6ef9790bc281f5c29d0132b68031248523fe8 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro:
"A couple more of d_walk()/d_subdirs reordering fixes (stable fodder;
ought to solve that crap for good) and a fix for a brown paperbag bug
in d_alloc_parallel() (this cycle)"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
fix idiotic braino in d_alloc_parallel()
autofs races
much milder d_walk() race
Diffstat (limited to 'fs')
-rw-r--r-- | fs/autofs4/autofs_i.h | 8 | ||||
-rw-r--r-- | fs/autofs4/expire.c | 27 | ||||
-rw-r--r-- | fs/autofs4/root.c | 2 | ||||
-rw-r--r-- | fs/dcache.c | 75 | ||||
-rw-r--r-- | fs/internal.h | 1 | ||||
-rw-r--r-- | fs/libfs.c | 4 |
6 files changed, 81 insertions, 36 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index f0d268b97d19..a439548de785 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -70,9 +70,13 @@ struct autofs_info { | |||
70 | }; | 70 | }; |
71 | 71 | ||
72 | #define AUTOFS_INF_EXPIRING (1<<0) /* dentry in the process of expiring */ | 72 | #define AUTOFS_INF_EXPIRING (1<<0) /* dentry in the process of expiring */ |
73 | #define AUTOFS_INF_NO_RCU (1<<1) /* the dentry is being considered | 73 | #define AUTOFS_INF_WANT_EXPIRE (1<<1) /* the dentry is being considered |
74 | * for expiry, so RCU_walk is | 74 | * for expiry, so RCU_walk is |
75 | * not permitted | 75 | * not permitted. If it progresses to |
76 | * actual expiry attempt, the flag is | ||
77 | * not cleared when EXPIRING is set - | ||
78 | * in that case it gets cleared only | ||
79 | * when it comes to clearing EXPIRING. | ||
76 | */ | 80 | */ |
77 | #define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */ | 81 | #define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */ |
78 | 82 | ||
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 9510d8d2e9cd..b493909e7492 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -316,19 +316,17 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
316 | if (ino->flags & AUTOFS_INF_PENDING) | 316 | if (ino->flags & AUTOFS_INF_PENDING) |
317 | goto out; | 317 | goto out; |
318 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { | 318 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { |
319 | ino->flags |= AUTOFS_INF_NO_RCU; | 319 | ino->flags |= AUTOFS_INF_WANT_EXPIRE; |
320 | spin_unlock(&sbi->fs_lock); | 320 | spin_unlock(&sbi->fs_lock); |
321 | synchronize_rcu(); | 321 | synchronize_rcu(); |
322 | spin_lock(&sbi->fs_lock); | 322 | spin_lock(&sbi->fs_lock); |
323 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { | 323 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { |
324 | ino->flags |= AUTOFS_INF_EXPIRING; | 324 | ino->flags |= AUTOFS_INF_EXPIRING; |
325 | smp_mb(); | ||
326 | ino->flags &= ~AUTOFS_INF_NO_RCU; | ||
327 | init_completion(&ino->expire_complete); | 325 | init_completion(&ino->expire_complete); |
328 | spin_unlock(&sbi->fs_lock); | 326 | spin_unlock(&sbi->fs_lock); |
329 | return root; | 327 | return root; |
330 | } | 328 | } |
331 | ino->flags &= ~AUTOFS_INF_NO_RCU; | 329 | ino->flags &= ~AUTOFS_INF_WANT_EXPIRE; |
332 | } | 330 | } |
333 | out: | 331 | out: |
334 | spin_unlock(&sbi->fs_lock); | 332 | spin_unlock(&sbi->fs_lock); |
@@ -446,7 +444,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
446 | while ((dentry = get_next_positive_subdir(dentry, root))) { | 444 | while ((dentry = get_next_positive_subdir(dentry, root))) { |
447 | spin_lock(&sbi->fs_lock); | 445 | spin_lock(&sbi->fs_lock); |
448 | ino = autofs4_dentry_ino(dentry); | 446 | ino = autofs4_dentry_ino(dentry); |
449 | if (ino->flags & AUTOFS_INF_NO_RCU) | 447 | if (ino->flags & AUTOFS_INF_WANT_EXPIRE) |
450 | expired = NULL; | 448 | expired = NULL; |
451 | else | 449 | else |
452 | expired = should_expire(dentry, mnt, timeout, how); | 450 | expired = should_expire(dentry, mnt, timeout, how); |
@@ -455,7 +453,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
455 | continue; | 453 | continue; |
456 | } | 454 | } |
457 | ino = autofs4_dentry_ino(expired); | 455 | ino = autofs4_dentry_ino(expired); |
458 | ino->flags |= AUTOFS_INF_NO_RCU; | 456 | ino->flags |= AUTOFS_INF_WANT_EXPIRE; |
459 | spin_unlock(&sbi->fs_lock); | 457 | spin_unlock(&sbi->fs_lock); |
460 | synchronize_rcu(); | 458 | synchronize_rcu(); |
461 | spin_lock(&sbi->fs_lock); | 459 | spin_lock(&sbi->fs_lock); |
@@ -465,7 +463,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
465 | goto found; | 463 | goto found; |
466 | } | 464 | } |
467 | 465 | ||
468 | ino->flags &= ~AUTOFS_INF_NO_RCU; | 466 | ino->flags &= ~AUTOFS_INF_WANT_EXPIRE; |
469 | if (expired != dentry) | 467 | if (expired != dentry) |
470 | dput(expired); | 468 | dput(expired); |
471 | spin_unlock(&sbi->fs_lock); | 469 | spin_unlock(&sbi->fs_lock); |
@@ -475,17 +473,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
475 | found: | 473 | found: |
476 | pr_debug("returning %p %pd\n", expired, expired); | 474 | pr_debug("returning %p %pd\n", expired, expired); |
477 | ino->flags |= AUTOFS_INF_EXPIRING; | 475 | ino->flags |= AUTOFS_INF_EXPIRING; |
478 | smp_mb(); | ||
479 | ino->flags &= ~AUTOFS_INF_NO_RCU; | ||
480 | init_completion(&ino->expire_complete); | 476 | init_completion(&ino->expire_complete); |
481 | spin_unlock(&sbi->fs_lock); | 477 | spin_unlock(&sbi->fs_lock); |
482 | spin_lock(&sbi->lookup_lock); | ||
483 | spin_lock(&expired->d_parent->d_lock); | ||
484 | spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED); | ||
485 | list_move(&expired->d_parent->d_subdirs, &expired->d_child); | ||
486 | spin_unlock(&expired->d_lock); | ||
487 | spin_unlock(&expired->d_parent->d_lock); | ||
488 | spin_unlock(&sbi->lookup_lock); | ||
489 | return expired; | 478 | return expired; |
490 | } | 479 | } |
491 | 480 | ||
@@ -496,7 +485,7 @@ int autofs4_expire_wait(struct dentry *dentry, int rcu_walk) | |||
496 | int status; | 485 | int status; |
497 | 486 | ||
498 | /* Block on any pending expire */ | 487 | /* Block on any pending expire */ |
499 | if (!(ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU))) | 488 | if (!(ino->flags & AUTOFS_INF_WANT_EXPIRE)) |
500 | return 0; | 489 | return 0; |
501 | if (rcu_walk) | 490 | if (rcu_walk) |
502 | return -ECHILD; | 491 | return -ECHILD; |
@@ -554,7 +543,7 @@ int autofs4_expire_run(struct super_block *sb, | |||
554 | ino = autofs4_dentry_ino(dentry); | 543 | ino = autofs4_dentry_ino(dentry); |
555 | /* avoid rapid-fire expire attempts if expiry fails */ | 544 | /* avoid rapid-fire expire attempts if expiry fails */ |
556 | ino->last_used = now; | 545 | ino->last_used = now; |
557 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 546 | ino->flags &= ~(AUTOFS_INF_EXPIRING|AUTOFS_INF_WANT_EXPIRE); |
558 | complete_all(&ino->expire_complete); | 547 | complete_all(&ino->expire_complete); |
559 | spin_unlock(&sbi->fs_lock); | 548 | spin_unlock(&sbi->fs_lock); |
560 | 549 | ||
@@ -583,7 +572,7 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, | |||
583 | spin_lock(&sbi->fs_lock); | 572 | spin_lock(&sbi->fs_lock); |
584 | /* avoid rapid-fire expire attempts if expiry fails */ | 573 | /* avoid rapid-fire expire attempts if expiry fails */ |
585 | ino->last_used = now; | 574 | ino->last_used = now; |
586 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 575 | ino->flags &= ~(AUTOFS_INF_EXPIRING|AUTOFS_INF_WANT_EXPIRE); |
587 | complete_all(&ino->expire_complete); | 576 | complete_all(&ino->expire_complete); |
588 | spin_unlock(&sbi->fs_lock); | 577 | spin_unlock(&sbi->fs_lock); |
589 | dput(dentry); | 578 | dput(dentry); |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 78bd80298528..3767f6641af1 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -458,7 +458,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk) | |||
458 | */ | 458 | */ |
459 | struct inode *inode; | 459 | struct inode *inode; |
460 | 460 | ||
461 | if (ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU)) | 461 | if (ino->flags & AUTOFS_INF_WANT_EXPIRE) |
462 | return 0; | 462 | return 0; |
463 | if (d_mountpoint(dentry)) | 463 | if (d_mountpoint(dentry)) |
464 | return 0; | 464 | return 0; |
diff --git a/fs/dcache.c b/fs/dcache.c index 817c243c1ff1..d6847d7b123d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -507,6 +507,44 @@ void d_drop(struct dentry *dentry) | |||
507 | } | 507 | } |
508 | EXPORT_SYMBOL(d_drop); | 508 | EXPORT_SYMBOL(d_drop); |
509 | 509 | ||
510 | static inline void dentry_unlist(struct dentry *dentry, struct dentry *parent) | ||
511 | { | ||
512 | struct dentry *next; | ||
513 | /* | ||
514 | * Inform d_walk() and shrink_dentry_list() that we are no longer | ||
515 | * attached to the dentry tree | ||
516 | */ | ||
517 | dentry->d_flags |= DCACHE_DENTRY_KILLED; | ||
518 | if (unlikely(list_empty(&dentry->d_child))) | ||
519 | return; | ||
520 | __list_del_entry(&dentry->d_child); | ||
521 | /* | ||
522 | * Cursors can move around the list of children. While we'd been | ||
523 | * a normal list member, it didn't matter - ->d_child.next would've | ||
524 | * been updated. However, from now on it won't be and for the | ||
525 | * things like d_walk() it might end up with a nasty surprise. | ||
526 | * Normally d_walk() doesn't care about cursors moving around - | ||
527 | * ->d_lock on parent prevents that and since a cursor has no children | ||
528 | * of its own, we get through it without ever unlocking the parent. | ||
529 | * There is one exception, though - if we ascend from a child that | ||
530 | * gets killed as soon as we unlock it, the next sibling is found | ||
531 | * using the value left in its ->d_child.next. And if _that_ | ||
532 | * pointed to a cursor, and cursor got moved (e.g. by lseek()) | ||
533 | * before d_walk() regains parent->d_lock, we'll end up skipping | ||
534 | * everything the cursor had been moved past. | ||
535 | * | ||
536 | * Solution: make sure that the pointer left behind in ->d_child.next | ||
537 | * points to something that won't be moving around. I.e. skip the | ||
538 | * cursors. | ||
539 | */ | ||
540 | while (dentry->d_child.next != &parent->d_subdirs) { | ||
541 | next = list_entry(dentry->d_child.next, struct dentry, d_child); | ||
542 | if (likely(!(next->d_flags & DCACHE_DENTRY_CURSOR))) | ||
543 | break; | ||
544 | dentry->d_child.next = next->d_child.next; | ||
545 | } | ||
546 | } | ||
547 | |||
510 | static void __dentry_kill(struct dentry *dentry) | 548 | static void __dentry_kill(struct dentry *dentry) |
511 | { | 549 | { |
512 | struct dentry *parent = NULL; | 550 | struct dentry *parent = NULL; |
@@ -532,12 +570,7 @@ static void __dentry_kill(struct dentry *dentry) | |||
532 | } | 570 | } |
533 | /* if it was on the hash then remove it */ | 571 | /* if it was on the hash then remove it */ |
534 | __d_drop(dentry); | 572 | __d_drop(dentry); |
535 | __list_del_entry(&dentry->d_child); | 573 | dentry_unlist(dentry, parent); |
536 | /* | ||
537 | * Inform d_walk() that we are no longer attached to the | ||
538 | * dentry tree | ||
539 | */ | ||
540 | dentry->d_flags |= DCACHE_DENTRY_KILLED; | ||
541 | if (parent) | 574 | if (parent) |
542 | spin_unlock(&parent->d_lock); | 575 | spin_unlock(&parent->d_lock); |
543 | dentry_iput(dentry); | 576 | dentry_iput(dentry); |
@@ -1203,6 +1236,9 @@ resume: | |||
1203 | struct dentry *dentry = list_entry(tmp, struct dentry, d_child); | 1236 | struct dentry *dentry = list_entry(tmp, struct dentry, d_child); |
1204 | next = tmp->next; | 1237 | next = tmp->next; |
1205 | 1238 | ||
1239 | if (unlikely(dentry->d_flags & DCACHE_DENTRY_CURSOR)) | ||
1240 | continue; | ||
1241 | |||
1206 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | 1242 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); |
1207 | 1243 | ||
1208 | ret = enter(data, dentry); | 1244 | ret = enter(data, dentry); |
@@ -1651,6 +1687,16 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | |||
1651 | } | 1687 | } |
1652 | EXPORT_SYMBOL(d_alloc); | 1688 | EXPORT_SYMBOL(d_alloc); |
1653 | 1689 | ||
1690 | struct dentry *d_alloc_cursor(struct dentry * parent) | ||
1691 | { | ||
1692 | struct dentry *dentry = __d_alloc(parent->d_sb, NULL); | ||
1693 | if (dentry) { | ||
1694 | dentry->d_flags |= DCACHE_RCUACCESS | DCACHE_DENTRY_CURSOR; | ||
1695 | dentry->d_parent = dget(parent); | ||
1696 | } | ||
1697 | return dentry; | ||
1698 | } | ||
1699 | |||
1654 | /** | 1700 | /** |
1655 | * d_alloc_pseudo - allocate a dentry (for lookup-less filesystems) | 1701 | * d_alloc_pseudo - allocate a dentry (for lookup-less filesystems) |
1656 | * @sb: the superblock | 1702 | * @sb: the superblock |
@@ -2457,7 +2503,6 @@ retry: | |||
2457 | rcu_read_unlock(); | 2503 | rcu_read_unlock(); |
2458 | goto retry; | 2504 | goto retry; |
2459 | } | 2505 | } |
2460 | rcu_read_unlock(); | ||
2461 | /* | 2506 | /* |
2462 | * No changes for the parent since the beginning of d_lookup(). | 2507 | * No changes for the parent since the beginning of d_lookup(). |
2463 | * Since all removals from the chain happen with hlist_bl_lock(), | 2508 | * Since all removals from the chain happen with hlist_bl_lock(), |
@@ -2470,8 +2515,6 @@ retry: | |||
2470 | continue; | 2515 | continue; |
2471 | if (dentry->d_parent != parent) | 2516 | if (dentry->d_parent != parent) |
2472 | continue; | 2517 | continue; |
2473 | if (d_unhashed(dentry)) | ||
2474 | continue; | ||
2475 | if (parent->d_flags & DCACHE_OP_COMPARE) { | 2518 | if (parent->d_flags & DCACHE_OP_COMPARE) { |
2476 | int tlen = dentry->d_name.len; | 2519 | int tlen = dentry->d_name.len; |
2477 | const char *tname = dentry->d_name.name; | 2520 | const char *tname = dentry->d_name.name; |
@@ -2483,9 +2526,18 @@ retry: | |||
2483 | if (dentry_cmp(dentry, str, len)) | 2526 | if (dentry_cmp(dentry, str, len)) |
2484 | continue; | 2527 | continue; |
2485 | } | 2528 | } |
2486 | dget(dentry); | ||
2487 | hlist_bl_unlock(b); | 2529 | hlist_bl_unlock(b); |
2488 | /* somebody is doing lookup for it right now; wait for it */ | 2530 | /* now we can try to grab a reference */ |
2531 | if (!lockref_get_not_dead(&dentry->d_lockref)) { | ||
2532 | rcu_read_unlock(); | ||
2533 | goto retry; | ||
2534 | } | ||
2535 | |||
2536 | rcu_read_unlock(); | ||
2537 | /* | ||
2538 | * somebody is likely to be still doing lookup for it; | ||
2539 | * wait for them to finish | ||
2540 | */ | ||
2489 | spin_lock(&dentry->d_lock); | 2541 | spin_lock(&dentry->d_lock); |
2490 | d_wait_lookup(dentry); | 2542 | d_wait_lookup(dentry); |
2491 | /* | 2543 | /* |
@@ -2516,6 +2568,7 @@ retry: | |||
2516 | dput(new); | 2568 | dput(new); |
2517 | return dentry; | 2569 | return dentry; |
2518 | } | 2570 | } |
2571 | rcu_read_unlock(); | ||
2519 | /* we can't take ->d_lock here; it's OK, though. */ | 2572 | /* we can't take ->d_lock here; it's OK, though. */ |
2520 | new->d_flags |= DCACHE_PAR_LOOKUP; | 2573 | new->d_flags |= DCACHE_PAR_LOOKUP; |
2521 | new->d_wait = wq; | 2574 | new->d_wait = wq; |
diff --git a/fs/internal.h b/fs/internal.h index b71deeecea17..f57ced528cde 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -130,6 +130,7 @@ extern int invalidate_inodes(struct super_block *, bool); | |||
130 | extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); | 130 | extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); |
131 | extern int d_set_mounted(struct dentry *dentry); | 131 | extern int d_set_mounted(struct dentry *dentry); |
132 | extern long prune_dcache_sb(struct super_block *sb, struct shrink_control *sc); | 132 | extern long prune_dcache_sb(struct super_block *sb, struct shrink_control *sc); |
133 | extern struct dentry *d_alloc_cursor(struct dentry *); | ||
133 | 134 | ||
134 | /* | 135 | /* |
135 | * read_write.c | 136 | * read_write.c |
diff --git a/fs/libfs.c b/fs/libfs.c index 3db2721144c2..cedeacbae303 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -71,9 +71,7 @@ EXPORT_SYMBOL(simple_lookup); | |||
71 | 71 | ||
72 | int dcache_dir_open(struct inode *inode, struct file *file) | 72 | int dcache_dir_open(struct inode *inode, struct file *file) |
73 | { | 73 | { |
74 | static struct qstr cursor_name = QSTR_INIT(".", 1); | 74 | file->private_data = d_alloc_cursor(file->f_path.dentry); |
75 | |||
76 | file->private_data = d_alloc(file->f_path.dentry, &cursor_name); | ||
77 | 75 | ||
78 | return file->private_data ? 0 : -ENOMEM; | 76 | return file->private_data ? 0 : -ENOMEM; |
79 | } | 77 | } |