aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2013-04-11 06:30:16 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-05-06 15:54:46 -0400
commitceda08642459e31673d24d7968d864390d2ce5fa (patch)
tree57d1a9be32a9a2653011b5fedf6615731af48b7f
parentf42a34b2f10c411ef45f247f3000ed03ba4e80c0 (diff)
Btrfs: use a lock to protect incompat/compat flag of the super block
The following case will make the incompat/compat flag of the super block be recovered. Task1 |Task2 flags = btrfs_super_incompat_flags(); | |flags = btrfs_super_incompat_flags(); flags |= new_flag1; | |flags |= new_flag2; btrfs_set_super_incompat_flags(flags); | |btrfs_set_super_incompat_flags(flags); the new_flag1 is recovered. In order to avoid this problem, we introduce a lock named super_lock into the btrfs_fs_info structure. If we want to update incompat/compat flags of the super block, we must hold it. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
-rw-r--r--fs/btrfs/ctree.h22
-rw-r--r--fs/btrfs/disk-io.c5
-rw-r--r--fs/btrfs/volumes.c10
3 files changed, 26 insertions, 11 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 1a850402937d..c3b15f8dca00 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1362,6 +1362,17 @@ struct btrfs_fs_info {
1362 wait_queue_head_t transaction_blocked_wait; 1362 wait_queue_head_t transaction_blocked_wait;
1363 wait_queue_head_t async_submit_wait; 1363 wait_queue_head_t async_submit_wait;
1364 1364
1365 /*
1366 * Used to protect the incompat_flags, compat_flags, compat_ro_flags
1367 * when they are updated.
1368 *
1369 * Because we do not clear the flags for ever, so we needn't use
1370 * the lock on the read side.
1371 *
1372 * We also needn't use the lock when we mount the fs, because
1373 * there is no other task which will update the flag.
1374 */
1375 spinlock_t super_lock;
1365 struct btrfs_super_block *super_copy; 1376 struct btrfs_super_block *super_copy;
1366 struct btrfs_super_block *super_for_commit; 1377 struct btrfs_super_block *super_for_commit;
1367 struct block_device *__bdev; 1378 struct block_device *__bdev;
@@ -3688,8 +3699,15 @@ static inline void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info,
3688 disk_super = fs_info->super_copy; 3699 disk_super = fs_info->super_copy;
3689 features = btrfs_super_incompat_flags(disk_super); 3700 features = btrfs_super_incompat_flags(disk_super);
3690 if (!(features & flag)) { 3701 if (!(features & flag)) {
3691 features |= flag; 3702 spin_lock(&fs_info->super_lock);
3692 btrfs_set_super_incompat_flags(disk_super, features); 3703 features = btrfs_super_incompat_flags(disk_super);
3704 if (!(features & flag)) {
3705 features |= flag;
3706 btrfs_set_super_incompat_flags(disk_super, features);
3707 printk(KERN_INFO "btrfs: setting %llu feature flag\n",
3708 flag);
3709 }
3710 spin_unlock(&fs_info->super_lock);
3693 } 3711 }
3694} 3712}
3695 3713
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 9f83e5b870d2..8a7a366267ec 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2086,6 +2086,7 @@ int open_ctree(struct super_block *sb,
2086 spin_lock_init(&fs_info->defrag_inodes_lock); 2086 spin_lock_init(&fs_info->defrag_inodes_lock);
2087 spin_lock_init(&fs_info->free_chunk_lock); 2087 spin_lock_init(&fs_info->free_chunk_lock);
2088 spin_lock_init(&fs_info->tree_mod_seq_lock); 2088 spin_lock_init(&fs_info->tree_mod_seq_lock);
2089 spin_lock_init(&fs_info->super_lock);
2089 rwlock_init(&fs_info->tree_mod_log_lock); 2090 rwlock_init(&fs_info->tree_mod_log_lock);
2090 mutex_init(&fs_info->reloc_mutex); 2091 mutex_init(&fs_info->reloc_mutex);
2091 seqlock_init(&fs_info->profiles_lock); 2092 seqlock_init(&fs_info->profiles_lock);
@@ -2349,6 +2350,10 @@ int open_ctree(struct super_block *sb,
2349 goto fail_alloc; 2350 goto fail_alloc;
2350 } 2351 }
2351 2352
2353 /*
2354 * Needn't use the lock because there is no other task which will
2355 * update the flag.
2356 */
2352 btrfs_set_super_incompat_flags(disk_super, features); 2357 btrfs_set_super_incompat_flags(disk_super, features);
2353 2358
2354 features = btrfs_super_compat_ro_flags(disk_super) & 2359 features = btrfs_super_compat_ro_flags(disk_super) &
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 5aa52ee5c25e..76ded9eb77a7 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3674,18 +3674,10 @@ static u32 find_raid56_stripe_len(u32 data_devices, u32 dev_stripe_target)
3674 3674
3675static void check_raid56_incompat_flag(struct btrfs_fs_info *info, u64 type) 3675static void check_raid56_incompat_flag(struct btrfs_fs_info *info, u64 type)
3676{ 3676{
3677 u64 features;
3678
3679 if (!(type & (BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6))) 3677 if (!(type & (BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6)))
3680 return; 3678 return;
3681 3679
3682 features = btrfs_super_incompat_flags(info->super_copy); 3680 btrfs_set_fs_incompat(info, RAID56);
3683 if (features & BTRFS_FEATURE_INCOMPAT_RAID56)
3684 return;
3685
3686 features |= BTRFS_FEATURE_INCOMPAT_RAID56;
3687 btrfs_set_super_incompat_flags(info->super_copy, features);
3688 printk(KERN_INFO "btrfs: setting RAID5/6 feature flag\n");
3689} 3681}
3690 3682
3691static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, 3683static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,