diff options
Diffstat (limited to 'fs/super.c')
| -rw-r--r-- | fs/super.c | 51 |
1 files changed, 36 insertions, 15 deletions
diff --git a/fs/super.c b/fs/super.c index 938119ab8dcb..9674ab2c8718 100644 --- a/fs/super.c +++ b/fs/super.c | |||
| @@ -305,8 +305,13 @@ retry: | |||
| 305 | if (s) { | 305 | if (s) { |
| 306 | up_write(&s->s_umount); | 306 | up_write(&s->s_umount); |
| 307 | destroy_super(s); | 307 | destroy_super(s); |
| 308 | s = NULL; | ||
| 308 | } | 309 | } |
| 309 | down_write(&old->s_umount); | 310 | down_write(&old->s_umount); |
| 311 | if (unlikely(!(old->s_flags & MS_BORN))) { | ||
| 312 | deactivate_locked_super(old); | ||
| 313 | goto retry; | ||
| 314 | } | ||
| 310 | return old; | 315 | return old; |
| 311 | } | 316 | } |
| 312 | } | 317 | } |
| @@ -358,10 +363,10 @@ EXPORT_SYMBOL(drop_super); | |||
| 358 | */ | 363 | */ |
| 359 | void sync_supers(void) | 364 | void sync_supers(void) |
| 360 | { | 365 | { |
| 361 | struct super_block *sb, *n; | 366 | struct super_block *sb, *p = NULL; |
| 362 | 367 | ||
| 363 | spin_lock(&sb_lock); | 368 | spin_lock(&sb_lock); |
| 364 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { | 369 | list_for_each_entry(sb, &super_blocks, s_list) { |
| 365 | if (list_empty(&sb->s_instances)) | 370 | if (list_empty(&sb->s_instances)) |
| 366 | continue; | 371 | continue; |
| 367 | if (sb->s_op->write_super && sb->s_dirt) { | 372 | if (sb->s_op->write_super && sb->s_dirt) { |
| @@ -374,11 +379,13 @@ void sync_supers(void) | |||
| 374 | up_read(&sb->s_umount); | 379 | up_read(&sb->s_umount); |
| 375 | 380 | ||
| 376 | spin_lock(&sb_lock); | 381 | spin_lock(&sb_lock); |
| 377 | /* lock was dropped, must reset next */ | 382 | if (p) |
| 378 | list_safe_reset_next(sb, n, s_list); | 383 | __put_super(p); |
| 379 | __put_super(sb); | 384 | p = sb; |
| 380 | } | 385 | } |
| 381 | } | 386 | } |
| 387 | if (p) | ||
| 388 | __put_super(p); | ||
| 382 | spin_unlock(&sb_lock); | 389 | spin_unlock(&sb_lock); |
| 383 | } | 390 | } |
| 384 | 391 | ||
| @@ -392,10 +399,10 @@ void sync_supers(void) | |||
| 392 | */ | 399 | */ |
| 393 | void iterate_supers(void (*f)(struct super_block *, void *), void *arg) | 400 | void iterate_supers(void (*f)(struct super_block *, void *), void *arg) |
| 394 | { | 401 | { |
| 395 | struct super_block *sb, *n; | 402 | struct super_block *sb, *p = NULL; |
| 396 | 403 | ||
| 397 | spin_lock(&sb_lock); | 404 | spin_lock(&sb_lock); |
| 398 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { | 405 | list_for_each_entry(sb, &super_blocks, s_list) { |
| 399 | if (list_empty(&sb->s_instances)) | 406 | if (list_empty(&sb->s_instances)) |
| 400 | continue; | 407 | continue; |
| 401 | sb->s_count++; | 408 | sb->s_count++; |
| @@ -407,10 +414,12 @@ void iterate_supers(void (*f)(struct super_block *, void *), void *arg) | |||
| 407 | up_read(&sb->s_umount); | 414 | up_read(&sb->s_umount); |
| 408 | 415 | ||
| 409 | spin_lock(&sb_lock); | 416 | spin_lock(&sb_lock); |
| 410 | /* lock was dropped, must reset next */ | 417 | if (p) |
| 411 | list_safe_reset_next(sb, n, s_list); | 418 | __put_super(p); |
| 412 | __put_super(sb); | 419 | p = sb; |
| 413 | } | 420 | } |
| 421 | if (p) | ||
| 422 | __put_super(p); | ||
| 414 | spin_unlock(&sb_lock); | 423 | spin_unlock(&sb_lock); |
| 415 | } | 424 | } |
| 416 | 425 | ||
| @@ -572,10 +581,10 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) | |||
| 572 | 581 | ||
| 573 | static void do_emergency_remount(struct work_struct *work) | 582 | static void do_emergency_remount(struct work_struct *work) |
| 574 | { | 583 | { |
| 575 | struct super_block *sb, *n; | 584 | struct super_block *sb, *p = NULL; |
| 576 | 585 | ||
| 577 | spin_lock(&sb_lock); | 586 | spin_lock(&sb_lock); |
| 578 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { | 587 | list_for_each_entry(sb, &super_blocks, s_list) { |
| 579 | if (list_empty(&sb->s_instances)) | 588 | if (list_empty(&sb->s_instances)) |
| 580 | continue; | 589 | continue; |
| 581 | sb->s_count++; | 590 | sb->s_count++; |
| @@ -589,10 +598,12 @@ static void do_emergency_remount(struct work_struct *work) | |||
| 589 | } | 598 | } |
| 590 | up_write(&sb->s_umount); | 599 | up_write(&sb->s_umount); |
| 591 | spin_lock(&sb_lock); | 600 | spin_lock(&sb_lock); |
| 592 | /* lock was dropped, must reset next */ | 601 | if (p) |
| 593 | list_safe_reset_next(sb, n, s_list); | 602 | __put_super(p); |
| 594 | __put_super(sb); | 603 | p = sb; |
| 595 | } | 604 | } |
| 605 | if (p) | ||
| 606 | __put_super(p); | ||
| 596 | spin_unlock(&sb_lock); | 607 | spin_unlock(&sb_lock); |
| 597 | kfree(work); | 608 | kfree(work); |
| 598 | printk("Emergency Remount complete\n"); | 609 | printk("Emergency Remount complete\n"); |
| @@ -773,7 +784,16 @@ int get_sb_bdev(struct file_system_type *fs_type, | |||
| 773 | goto error_bdev; | 784 | goto error_bdev; |
| 774 | } | 785 | } |
| 775 | 786 | ||
| 787 | /* | ||
| 788 | * s_umount nests inside bd_mutex during | ||
| 789 | * __invalidate_device(). close_bdev_exclusive() | ||
| 790 | * acquires bd_mutex and can't be called under | ||
| 791 | * s_umount. Drop s_umount temporarily. This is safe | ||
| 792 | * as we're holding an active reference. | ||
| 793 | */ | ||
| 794 | up_write(&s->s_umount); | ||
| 776 | close_bdev_exclusive(bdev, mode); | 795 | close_bdev_exclusive(bdev, mode); |
| 796 | down_write(&s->s_umount); | ||
| 777 | } else { | 797 | } else { |
| 778 | char b[BDEVNAME_SIZE]; | 798 | char b[BDEVNAME_SIZE]; |
| 779 | 799 | ||
| @@ -909,6 +929,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void | |||
| 909 | goto out_free_secdata; | 929 | goto out_free_secdata; |
| 910 | BUG_ON(!mnt->mnt_sb); | 930 | BUG_ON(!mnt->mnt_sb); |
| 911 | WARN_ON(!mnt->mnt_sb->s_bdi); | 931 | WARN_ON(!mnt->mnt_sb->s_bdi); |
| 932 | mnt->mnt_sb->s_flags |= MS_BORN; | ||
| 912 | 933 | ||
| 913 | error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata); | 934 | error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata); |
| 914 | if (error) | 935 | if (error) |
