diff options
| -rw-r--r-- | fs/namespace.c | 25 |
1 files changed, 17 insertions, 8 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 1a9232356ef9..d8924bfaa9db 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -2513,20 +2513,29 @@ void put_mnt_ns(struct mnt_namespace *ns) | |||
| 2513 | { | 2513 | { |
| 2514 | struct vfsmount *root; | 2514 | struct vfsmount *root; |
| 2515 | LIST_HEAD(umount_list); | 2515 | LIST_HEAD(umount_list); |
| 2516 | spinlock_t *lock; | ||
| 2517 | 2516 | ||
| 2518 | lock = &get_cpu_var(vfsmount_lock); | 2517 | /* |
| 2519 | if (!atomic_dec_and_lock(&ns->count, lock)) { | 2518 | * We open code this to avoid vfsmount_write_lock() in case of |
| 2520 | put_cpu_var(vfsmount_lock); | 2519 | * ns->count > 1 |
| 2520 | */ | ||
| 2521 | if (atomic_add_unless(&ns->count, -1, 1)) | ||
| 2522 | return; | ||
| 2523 | |||
| 2524 | /* | ||
| 2525 | * Do the full locking here as it's likely that ns->count will | ||
| 2526 | * drop to zero and we have to take namespace_sem and all vfs | ||
| 2527 | * mount locks anyway for umount_tree(). | ||
| 2528 | */ | ||
| 2529 | down_write(&namespace_sem); | ||
| 2530 | vfsmount_write_lock(); | ||
| 2531 | if (!atomic_dec_and_test(&ns->count)) { | ||
| 2532 | vfsmount_write_unlock(); | ||
| 2533 | up_write(&namespace_sem); | ||
| 2521 | return; | 2534 | return; |
| 2522 | } | 2535 | } |
| 2523 | root = ns->root; | 2536 | root = ns->root; |
| 2524 | ns->root = NULL; | 2537 | ns->root = NULL; |
| 2525 | spin_unlock(lock); | ||
| 2526 | put_cpu_var(vfsmount_lock); | ||
| 2527 | 2538 | ||
| 2528 | down_write(&namespace_sem); | ||
| 2529 | vfsmount_write_lock(); | ||
| 2530 | umount_tree(root, 0, &umount_list); | 2539 | umount_tree(root, 0, &umount_list); |
| 2531 | vfsmount_write_unlock(); | 2540 | vfsmount_write_unlock(); |
| 2532 | up_write(&namespace_sem); | 2541 | up_write(&namespace_sem); |
