diff options
Diffstat (limited to 'fs/super.c')
-rw-r--r-- | fs/super.c | 69 |
1 files changed, 54 insertions, 15 deletions
diff --git a/fs/super.c b/fs/super.c index 938119ab8dcb..8819e3a7ff20 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -54,7 +54,22 @@ static struct super_block *alloc_super(struct file_system_type *type) | |||
54 | s = NULL; | 54 | s = NULL; |
55 | goto out; | 55 | goto out; |
56 | } | 56 | } |
57 | #ifdef CONFIG_SMP | ||
58 | s->s_files = alloc_percpu(struct list_head); | ||
59 | if (!s->s_files) { | ||
60 | security_sb_free(s); | ||
61 | kfree(s); | ||
62 | s = NULL; | ||
63 | goto out; | ||
64 | } else { | ||
65 | int i; | ||
66 | |||
67 | for_each_possible_cpu(i) | ||
68 | INIT_LIST_HEAD(per_cpu_ptr(s->s_files, i)); | ||
69 | } | ||
70 | #else | ||
57 | INIT_LIST_HEAD(&s->s_files); | 71 | INIT_LIST_HEAD(&s->s_files); |
72 | #endif | ||
58 | INIT_LIST_HEAD(&s->s_instances); | 73 | INIT_LIST_HEAD(&s->s_instances); |
59 | INIT_HLIST_HEAD(&s->s_anon); | 74 | INIT_HLIST_HEAD(&s->s_anon); |
60 | INIT_LIST_HEAD(&s->s_inodes); | 75 | INIT_LIST_HEAD(&s->s_inodes); |
@@ -108,6 +123,9 @@ out: | |||
108 | */ | 123 | */ |
109 | static inline void destroy_super(struct super_block *s) | 124 | static inline void destroy_super(struct super_block *s) |
110 | { | 125 | { |
126 | #ifdef CONFIG_SMP | ||
127 | free_percpu(s->s_files); | ||
128 | #endif | ||
111 | security_sb_free(s); | 129 | security_sb_free(s); |
112 | kfree(s->s_subtype); | 130 | kfree(s->s_subtype); |
113 | kfree(s->s_options); | 131 | kfree(s->s_options); |
@@ -305,8 +323,13 @@ retry: | |||
305 | if (s) { | 323 | if (s) { |
306 | up_write(&s->s_umount); | 324 | up_write(&s->s_umount); |
307 | destroy_super(s); | 325 | destroy_super(s); |
326 | s = NULL; | ||
308 | } | 327 | } |
309 | down_write(&old->s_umount); | 328 | down_write(&old->s_umount); |
329 | if (unlikely(!(old->s_flags & MS_BORN))) { | ||
330 | deactivate_locked_super(old); | ||
331 | goto retry; | ||
332 | } | ||
310 | return old; | 333 | return old; |
311 | } | 334 | } |
312 | } | 335 | } |
@@ -358,10 +381,10 @@ EXPORT_SYMBOL(drop_super); | |||
358 | */ | 381 | */ |
359 | void sync_supers(void) | 382 | void sync_supers(void) |
360 | { | 383 | { |
361 | struct super_block *sb, *n; | 384 | struct super_block *sb, *p = NULL; |
362 | 385 | ||
363 | spin_lock(&sb_lock); | 386 | spin_lock(&sb_lock); |
364 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { | 387 | list_for_each_entry(sb, &super_blocks, s_list) { |
365 | if (list_empty(&sb->s_instances)) | 388 | if (list_empty(&sb->s_instances)) |
366 | continue; | 389 | continue; |
367 | if (sb->s_op->write_super && sb->s_dirt) { | 390 | if (sb->s_op->write_super && sb->s_dirt) { |
@@ -374,11 +397,13 @@ void sync_supers(void) | |||
374 | up_read(&sb->s_umount); | 397 | up_read(&sb->s_umount); |
375 | 398 | ||
376 | spin_lock(&sb_lock); | 399 | spin_lock(&sb_lock); |
377 | /* lock was dropped, must reset next */ | 400 | if (p) |
378 | list_safe_reset_next(sb, n, s_list); | 401 | __put_super(p); |
379 | __put_super(sb); | 402 | p = sb; |
380 | } | 403 | } |
381 | } | 404 | } |
405 | if (p) | ||
406 | __put_super(p); | ||
382 | spin_unlock(&sb_lock); | 407 | spin_unlock(&sb_lock); |
383 | } | 408 | } |
384 | 409 | ||
@@ -392,10 +417,10 @@ void sync_supers(void) | |||
392 | */ | 417 | */ |
393 | void iterate_supers(void (*f)(struct super_block *, void *), void *arg) | 418 | void iterate_supers(void (*f)(struct super_block *, void *), void *arg) |
394 | { | 419 | { |
395 | struct super_block *sb, *n; | 420 | struct super_block *sb, *p = NULL; |
396 | 421 | ||
397 | spin_lock(&sb_lock); | 422 | spin_lock(&sb_lock); |
398 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { | 423 | list_for_each_entry(sb, &super_blocks, s_list) { |
399 | if (list_empty(&sb->s_instances)) | 424 | if (list_empty(&sb->s_instances)) |
400 | continue; | 425 | continue; |
401 | sb->s_count++; | 426 | sb->s_count++; |
@@ -407,10 +432,12 @@ void iterate_supers(void (*f)(struct super_block *, void *), void *arg) | |||
407 | up_read(&sb->s_umount); | 432 | up_read(&sb->s_umount); |
408 | 433 | ||
409 | spin_lock(&sb_lock); | 434 | spin_lock(&sb_lock); |
410 | /* lock was dropped, must reset next */ | 435 | if (p) |
411 | list_safe_reset_next(sb, n, s_list); | 436 | __put_super(p); |
412 | __put_super(sb); | 437 | p = sb; |
413 | } | 438 | } |
439 | if (p) | ||
440 | __put_super(p); | ||
414 | spin_unlock(&sb_lock); | 441 | spin_unlock(&sb_lock); |
415 | } | 442 | } |
416 | 443 | ||
@@ -572,10 +599,10 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) | |||
572 | 599 | ||
573 | static void do_emergency_remount(struct work_struct *work) | 600 | static void do_emergency_remount(struct work_struct *work) |
574 | { | 601 | { |
575 | struct super_block *sb, *n; | 602 | struct super_block *sb, *p = NULL; |
576 | 603 | ||
577 | spin_lock(&sb_lock); | 604 | spin_lock(&sb_lock); |
578 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { | 605 | list_for_each_entry(sb, &super_blocks, s_list) { |
579 | if (list_empty(&sb->s_instances)) | 606 | if (list_empty(&sb->s_instances)) |
580 | continue; | 607 | continue; |
581 | sb->s_count++; | 608 | sb->s_count++; |
@@ -589,10 +616,12 @@ static void do_emergency_remount(struct work_struct *work) | |||
589 | } | 616 | } |
590 | up_write(&sb->s_umount); | 617 | up_write(&sb->s_umount); |
591 | spin_lock(&sb_lock); | 618 | spin_lock(&sb_lock); |
592 | /* lock was dropped, must reset next */ | 619 | if (p) |
593 | list_safe_reset_next(sb, n, s_list); | 620 | __put_super(p); |
594 | __put_super(sb); | 621 | p = sb; |
595 | } | 622 | } |
623 | if (p) | ||
624 | __put_super(p); | ||
596 | spin_unlock(&sb_lock); | 625 | spin_unlock(&sb_lock); |
597 | kfree(work); | 626 | kfree(work); |
598 | printk("Emergency Remount complete\n"); | 627 | printk("Emergency Remount complete\n"); |
@@ -773,7 +802,16 @@ int get_sb_bdev(struct file_system_type *fs_type, | |||
773 | goto error_bdev; | 802 | goto error_bdev; |
774 | } | 803 | } |
775 | 804 | ||
805 | /* | ||
806 | * s_umount nests inside bd_mutex during | ||
807 | * __invalidate_device(). close_bdev_exclusive() | ||
808 | * acquires bd_mutex and can't be called under | ||
809 | * s_umount. Drop s_umount temporarily. This is safe | ||
810 | * as we're holding an active reference. | ||
811 | */ | ||
812 | up_write(&s->s_umount); | ||
776 | close_bdev_exclusive(bdev, mode); | 813 | close_bdev_exclusive(bdev, mode); |
814 | down_write(&s->s_umount); | ||
777 | } else { | 815 | } else { |
778 | char b[BDEVNAME_SIZE]; | 816 | char b[BDEVNAME_SIZE]; |
779 | 817 | ||
@@ -909,6 +947,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void | |||
909 | goto out_free_secdata; | 947 | goto out_free_secdata; |
910 | BUG_ON(!mnt->mnt_sb); | 948 | BUG_ON(!mnt->mnt_sb); |
911 | WARN_ON(!mnt->mnt_sb->s_bdi); | 949 | WARN_ON(!mnt->mnt_sb->s_bdi); |
950 | mnt->mnt_sb->s_flags |= MS_BORN; | ||
912 | 951 | ||
913 | error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata); | 952 | error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata); |
914 | if (error) | 953 | if (error) |