aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/super.c
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-06-07 12:39:32 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2009-06-11 21:36:18 -0400
commite59399d0102c1813cec48db5cebe1750313f88a0 (patch)
treecd4fde6b5c442ede5d00b9640d3a545f847aeb8c /fs/nilfs2/super.c
parent6dd4740662405a68bb229ac2b9e0aeaaf2188bf2 (diff)
nilfs2: correct exclusion control in nilfs_remount function
nilfs_remount() changes mount state of a superblock instance. Even though nilfs accesses other superblock instances during mount or remount, the mount state was not properly protected in nilfs_remount(). Moreover, nilfs_remount() has a lock order reversal problem; nilfs_get_sb() holds: 1. bdev->bd_mount_sem 2. sb->s_umount (sget acquires) and nilfs_remount() holds: 1. sb->s_umount (locked by the caller in vfs) 2. bdev->bd_mount_sem To avoid these problems, this patch divides a semaphore protecting super block instances from nilfs->ns_sem, and applies it to the mount state protection in nilfs_remount(). With this change, bd_mount_sem use is removed from nilfs_remount() and the lock order reversal will be resolved. And the new rw-semaphore, nilfs->ns_super_sem will properly protect the mount state except the modification from nilfs_error function. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/nilfs2/super.c')
-rw-r--r--fs/nilfs2/super.c44
1 files changed, 20 insertions, 24 deletions
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 1d1b6e125159..f02762fa8ea0 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -327,10 +327,10 @@ static void nilfs_put_super(struct super_block *sb)
327 nilfs_commit_super(sbi, 1); 327 nilfs_commit_super(sbi, 1);
328 up_write(&nilfs->ns_sem); 328 up_write(&nilfs->ns_sem);
329 } 329 }
330 down_write(&nilfs->ns_sem); 330 down_write(&nilfs->ns_super_sem);
331 if (nilfs->ns_current == sbi) 331 if (nilfs->ns_current == sbi)
332 nilfs->ns_current = NULL; 332 nilfs->ns_current = NULL;
333 up_write(&nilfs->ns_sem); 333 up_write(&nilfs->ns_super_sem);
334 334
335 nilfs_detach_checkpoint(sbi); 335 nilfs_detach_checkpoint(sbi);
336 put_nilfs(sbi->s_nilfs); 336 put_nilfs(sbi->s_nilfs);
@@ -408,9 +408,9 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno)
408 struct buffer_head *bh_cp; 408 struct buffer_head *bh_cp;
409 int err; 409 int err;
410 410
411 down_write(&nilfs->ns_sem); 411 down_write(&nilfs->ns_super_sem);
412 list_add(&sbi->s_list, &nilfs->ns_supers); 412 list_add(&sbi->s_list, &nilfs->ns_supers);
413 up_write(&nilfs->ns_sem); 413 up_write(&nilfs->ns_super_sem);
414 414
415 sbi->s_ifile = nilfs_mdt_new( 415 sbi->s_ifile = nilfs_mdt_new(
416 nilfs, sbi->s_super, NILFS_IFILE_INO, NILFS_IFILE_GFP); 416 nilfs, sbi->s_super, NILFS_IFILE_INO, NILFS_IFILE_GFP);
@@ -448,9 +448,9 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno)
448 nilfs_mdt_destroy(sbi->s_ifile); 448 nilfs_mdt_destroy(sbi->s_ifile);
449 sbi->s_ifile = NULL; 449 sbi->s_ifile = NULL;
450 450
451 down_write(&nilfs->ns_sem); 451 down_write(&nilfs->ns_super_sem);
452 list_del_init(&sbi->s_list); 452 list_del_init(&sbi->s_list);
453 up_write(&nilfs->ns_sem); 453 up_write(&nilfs->ns_super_sem);
454 454
455 return err; 455 return err;
456} 456}
@@ -462,9 +462,9 @@ void nilfs_detach_checkpoint(struct nilfs_sb_info *sbi)
462 nilfs_mdt_clear(sbi->s_ifile); 462 nilfs_mdt_clear(sbi->s_ifile);
463 nilfs_mdt_destroy(sbi->s_ifile); 463 nilfs_mdt_destroy(sbi->s_ifile);
464 sbi->s_ifile = NULL; 464 sbi->s_ifile = NULL;
465 down_write(&nilfs->ns_sem); 465 down_write(&nilfs->ns_super_sem);
466 list_del_init(&sbi->s_list); 466 list_del_init(&sbi->s_list);
467 up_write(&nilfs->ns_sem); 467 up_write(&nilfs->ns_super_sem);
468} 468}
469 469
470static int nilfs_mark_recovery_complete(struct nilfs_sb_info *sbi) 470static int nilfs_mark_recovery_complete(struct nilfs_sb_info *sbi)
@@ -883,10 +883,10 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
883 goto failed_root; 883 goto failed_root;
884 } 884 }
885 885
886 down_write(&nilfs->ns_sem); 886 down_write(&nilfs->ns_super_sem);
887 if (!nilfs_test_opt(sbi, SNAPSHOT)) 887 if (!nilfs_test_opt(sbi, SNAPSHOT))
888 nilfs->ns_current = sbi; 888 nilfs->ns_current = sbi;
889 up_write(&nilfs->ns_sem); 889 up_write(&nilfs->ns_super_sem);
890 890
891 return 0; 891 return 0;
892 892
@@ -918,6 +918,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
918 918
919 lock_kernel(); 919 lock_kernel();
920 920
921 down_write(&nilfs->ns_super_sem);
921 old_sb_flags = sb->s_flags; 922 old_sb_flags = sb->s_flags;
922 old_opts.mount_opt = sbi->s_mount_opt; 923 old_opts.mount_opt = sbi->s_mount_opt;
923 old_opts.snapshot_cno = sbi->s_snapshot_cno; 924 old_opts.snapshot_cno = sbi->s_snapshot_cno;
@@ -965,24 +966,20 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
965 * store the current valid flag. (It may have been changed 966 * store the current valid flag. (It may have been changed
966 * by fsck since we originally mounted the partition.) 967 * by fsck since we originally mounted the partition.)
967 */ 968 */
968 down(&sb->s_bdev->bd_mount_sem);
969 down_read(&nilfs->ns_sem);
970 if (nilfs->ns_current && nilfs->ns_current != sbi) { 969 if (nilfs->ns_current && nilfs->ns_current != sbi) {
971 printk(KERN_WARNING "NILFS (device %s): couldn't " 970 printk(KERN_WARNING "NILFS (device %s): couldn't "
972 "remount because an RW-mount exists.\n", 971 "remount because an RW-mount exists.\n",
973 sb->s_id); 972 sb->s_id);
974 up_read(&nilfs->ns_sem);
975 err = -EBUSY; 973 err = -EBUSY;
976 goto rw_remount_failed; 974 goto restore_opts;
977 } 975 }
978 up_read(&nilfs->ns_sem);
979 if (sbi->s_snapshot_cno != nilfs_last_cno(nilfs)) { 976 if (sbi->s_snapshot_cno != nilfs_last_cno(nilfs)) {
980 printk(KERN_WARNING "NILFS (device %s): couldn't " 977 printk(KERN_WARNING "NILFS (device %s): couldn't "
981 "remount because the current RO-mount is not " 978 "remount because the current RO-mount is not "
982 "the latest one.\n", 979 "the latest one.\n",
983 sb->s_id); 980 sb->s_id);
984 err = -EINVAL; 981 err = -EINVAL;
985 goto rw_remount_failed; 982 goto restore_opts;
986 } 983 }
987 sb->s_flags &= ~MS_RDONLY; 984 sb->s_flags &= ~MS_RDONLY;
988 nilfs_clear_opt(sbi, SNAPSHOT); 985 nilfs_clear_opt(sbi, SNAPSHOT);
@@ -990,25 +987,24 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
990 987
991 err = nilfs_attach_segment_constructor(sbi); 988 err = nilfs_attach_segment_constructor(sbi);
992 if (err) 989 if (err)
993 goto rw_remount_failed; 990 goto restore_opts;
994 991
995 down_write(&nilfs->ns_sem); 992 down_write(&nilfs->ns_sem);
996 nilfs_setup_super(sbi); 993 nilfs_setup_super(sbi);
997 nilfs->ns_current = sbi;
998 up_write(&nilfs->ns_sem); 994 up_write(&nilfs->ns_sem);
999 995
1000 up(&sb->s_bdev->bd_mount_sem); 996 nilfs->ns_current = sbi;
1001 } 997 }
1002 out: 998 out:
999 up_write(&nilfs->ns_super_sem);
1003 unlock_kernel(); 1000 unlock_kernel();
1004 return 0; 1001 return 0;
1005 1002
1006 rw_remount_failed:
1007 up(&sb->s_bdev->bd_mount_sem);
1008 restore_opts: 1003 restore_opts:
1009 sb->s_flags = old_sb_flags; 1004 sb->s_flags = old_sb_flags;
1010 sbi->s_mount_opt = old_opts.mount_opt; 1005 sbi->s_mount_opt = old_opts.mount_opt;
1011 sbi->s_snapshot_cno = old_opts.snapshot_cno; 1006 sbi->s_snapshot_cno = old_opts.snapshot_cno;
1007 up_write(&nilfs->ns_super_sem);
1012 unlock_kernel(); 1008 unlock_kernel();
1013 return err; 1009 return err;
1014} 1010}
@@ -1118,15 +1114,15 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
1118 * (i.e. rw-mount or ro-mount), whereas rw-mount and 1114 * (i.e. rw-mount or ro-mount), whereas rw-mount and
1119 * ro-mount are mutually exclusive. 1115 * ro-mount are mutually exclusive.
1120 */ 1116 */
1121 down_read(&nilfs->ns_sem); 1117 down_read(&nilfs->ns_super_sem);
1122 if (nilfs->ns_current && 1118 if (nilfs->ns_current &&
1123 ((nilfs->ns_current->s_super->s_flags ^ flags) 1119 ((nilfs->ns_current->s_super->s_flags ^ flags)
1124 & MS_RDONLY)) { 1120 & MS_RDONLY)) {
1125 up_read(&nilfs->ns_sem); 1121 up_read(&nilfs->ns_super_sem);
1126 err = -EBUSY; 1122 err = -EBUSY;
1127 goto failed_unlock; 1123 goto failed_unlock;
1128 } 1124 }
1129 up_read(&nilfs->ns_sem); 1125 up_read(&nilfs->ns_super_sem);
1130 } 1126 }
1131 1127
1132 /* 1128 /*