diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2009-06-07 12:39:32 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2009-06-11 21:36:18 -0400 |
commit | e59399d0102c1813cec48db5cebe1750313f88a0 (patch) | |
tree | cd4fde6b5c442ede5d00b9640d3a545f847aeb8c /fs/nilfs2/the_nilfs.c | |
parent | 6dd4740662405a68bb229ac2b9e0aeaaf2188bf2 (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/the_nilfs.c')
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 13 |
1 files changed, 7 insertions, 6 deletions
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 221953bfc859..06e8dfd538d6 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -72,6 +72,7 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev) | |||
72 | atomic_set(&nilfs->ns_writer_refcount, -1); | 72 | atomic_set(&nilfs->ns_writer_refcount, -1); |
73 | atomic_set(&nilfs->ns_ndirtyblks, 0); | 73 | atomic_set(&nilfs->ns_ndirtyblks, 0); |
74 | init_rwsem(&nilfs->ns_sem); | 74 | init_rwsem(&nilfs->ns_sem); |
75 | init_rwsem(&nilfs->ns_super_sem); | ||
75 | mutex_init(&nilfs->ns_writer_mutex); | 76 | mutex_init(&nilfs->ns_writer_mutex); |
76 | INIT_LIST_HEAD(&nilfs->ns_list); | 77 | INIT_LIST_HEAD(&nilfs->ns_list); |
77 | INIT_LIST_HEAD(&nilfs->ns_supers); | 78 | INIT_LIST_HEAD(&nilfs->ns_supers); |
@@ -681,10 +682,10 @@ struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *nilfs, | |||
681 | { | 682 | { |
682 | struct nilfs_sb_info *sbi; | 683 | struct nilfs_sb_info *sbi; |
683 | 684 | ||
684 | down_read(&nilfs->ns_sem); | 685 | down_read(&nilfs->ns_super_sem); |
685 | /* | 686 | /* |
686 | * The SNAPSHOT flag and sb->s_flags are supposed to be | 687 | * The SNAPSHOT flag and sb->s_flags are supposed to be |
687 | * protected with nilfs->ns_sem. | 688 | * protected with nilfs->ns_super_sem. |
688 | */ | 689 | */ |
689 | sbi = nilfs->ns_current; | 690 | sbi = nilfs->ns_current; |
690 | if (rw_mount) { | 691 | if (rw_mount) { |
@@ -705,12 +706,12 @@ struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *nilfs, | |||
705 | goto found; /* snapshot mount */ | 706 | goto found; /* snapshot mount */ |
706 | } | 707 | } |
707 | out: | 708 | out: |
708 | up_read(&nilfs->ns_sem); | 709 | up_read(&nilfs->ns_super_sem); |
709 | return NULL; | 710 | return NULL; |
710 | 711 | ||
711 | found: | 712 | found: |
712 | atomic_inc(&sbi->s_count); | 713 | atomic_inc(&sbi->s_count); |
713 | up_read(&nilfs->ns_sem); | 714 | up_read(&nilfs->ns_super_sem); |
714 | return sbi; | 715 | return sbi; |
715 | } | 716 | } |
716 | 717 | ||
@@ -720,7 +721,7 @@ int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, | |||
720 | struct nilfs_sb_info *sbi; | 721 | struct nilfs_sb_info *sbi; |
721 | int ret = 0; | 722 | int ret = 0; |
722 | 723 | ||
723 | down_read(&nilfs->ns_sem); | 724 | down_read(&nilfs->ns_super_sem); |
724 | if (cno == 0 || cno > nilfs->ns_cno) | 725 | if (cno == 0 || cno > nilfs->ns_cno) |
725 | goto out_unlock; | 726 | goto out_unlock; |
726 | 727 | ||
@@ -737,6 +738,6 @@ int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, | |||
737 | ret++; | 738 | ret++; |
738 | 739 | ||
739 | out_unlock: | 740 | out_unlock: |
740 | up_read(&nilfs->ns_sem); | 741 | up_read(&nilfs->ns_super_sem); |
741 | return ret; | 742 | return ret; |
742 | } | 743 | } |