diff options
author | Miao Xie <miaox@cn.fujitsu.com> | 2013-01-29 05:13:12 -0500 |
---|---|---|
committer | Josef Bacik <jbacik@fusionio.com> | 2013-02-20 12:59:08 -0500 |
commit | de98ced9e743656d108de41841797def0f5cb951 (patch) | |
tree | 52314be4abe2cd2510712e8b629d58d8d01d5e0a /fs | |
parent | df0af1a57f72c74d53a9377c60ff20095afab97d (diff) |
Btrfs: use seqlock to protect fs_info->avail_{data, metadata, system}_alloc_bits
There is no lock to protect
fs_info->avail_{data, metadata, system}_alloc_bits,
it may introduce some problem, such as the wrong profile
information, so we add a seqlock to protect them.
Signed-off-by: Zhao Lei <zhaolei@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 1 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 22 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 56 |
4 files changed, 49 insertions, 32 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 50def99f5379..5f5c30aaef36 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1483,6 +1483,8 @@ struct btrfs_fs_info { | |||
1483 | struct rb_root defrag_inodes; | 1483 | struct rb_root defrag_inodes; |
1484 | atomic_t defrag_running; | 1484 | atomic_t defrag_running; |
1485 | 1485 | ||
1486 | /* Used to protect avail_{data, metadata, system}_alloc_bits */ | ||
1487 | seqlock_t profiles_lock; | ||
1486 | /* | 1488 | /* |
1487 | * these three are in extended format (availability of single | 1489 | * these three are in extended format (availability of single |
1488 | * chunks is denoted by BTRFS_AVAIL_ALLOC_BIT_SINGLE bit, other | 1490 | * chunks is denoted by BTRFS_AVAIL_ALLOC_BIT_SINGLE bit, other |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 11f6dbcb1191..00b6742fdde7 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -2040,6 +2040,7 @@ int open_ctree(struct super_block *sb, | |||
2040 | spin_lock_init(&fs_info->tree_mod_seq_lock); | 2040 | spin_lock_init(&fs_info->tree_mod_seq_lock); |
2041 | rwlock_init(&fs_info->tree_mod_log_lock); | 2041 | rwlock_init(&fs_info->tree_mod_log_lock); |
2042 | mutex_init(&fs_info->reloc_mutex); | 2042 | mutex_init(&fs_info->reloc_mutex); |
2043 | seqlock_init(&fs_info->profiles_lock); | ||
2043 | 2044 | ||
2044 | init_completion(&fs_info->kobj_unregister); | 2045 | init_completion(&fs_info->kobj_unregister); |
2045 | INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); | 2046 | INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 115d1646bf50..faff98f720de 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -3227,12 +3227,14 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) | |||
3227 | u64 extra_flags = chunk_to_extended(flags) & | 3227 | u64 extra_flags = chunk_to_extended(flags) & |
3228 | BTRFS_EXTENDED_PROFILE_MASK; | 3228 | BTRFS_EXTENDED_PROFILE_MASK; |
3229 | 3229 | ||
3230 | write_seqlock(&fs_info->profiles_lock); | ||
3230 | if (flags & BTRFS_BLOCK_GROUP_DATA) | 3231 | if (flags & BTRFS_BLOCK_GROUP_DATA) |
3231 | fs_info->avail_data_alloc_bits |= extra_flags; | 3232 | fs_info->avail_data_alloc_bits |= extra_flags; |
3232 | if (flags & BTRFS_BLOCK_GROUP_METADATA) | 3233 | if (flags & BTRFS_BLOCK_GROUP_METADATA) |
3233 | fs_info->avail_metadata_alloc_bits |= extra_flags; | 3234 | fs_info->avail_metadata_alloc_bits |= extra_flags; |
3234 | if (flags & BTRFS_BLOCK_GROUP_SYSTEM) | 3235 | if (flags & BTRFS_BLOCK_GROUP_SYSTEM) |
3235 | fs_info->avail_system_alloc_bits |= extra_flags; | 3236 | fs_info->avail_system_alloc_bits |= extra_flags; |
3237 | write_sequnlock(&fs_info->profiles_lock); | ||
3236 | } | 3238 | } |
3237 | 3239 | ||
3238 | /* | 3240 | /* |
@@ -3324,12 +3326,18 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) | |||
3324 | 3326 | ||
3325 | static u64 get_alloc_profile(struct btrfs_root *root, u64 flags) | 3327 | static u64 get_alloc_profile(struct btrfs_root *root, u64 flags) |
3326 | { | 3328 | { |
3327 | if (flags & BTRFS_BLOCK_GROUP_DATA) | 3329 | unsigned seq; |
3328 | flags |= root->fs_info->avail_data_alloc_bits; | 3330 | |
3329 | else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) | 3331 | do { |
3330 | flags |= root->fs_info->avail_system_alloc_bits; | 3332 | seq = read_seqbegin(&root->fs_info->profiles_lock); |
3331 | else if (flags & BTRFS_BLOCK_GROUP_METADATA) | 3333 | |
3332 | flags |= root->fs_info->avail_metadata_alloc_bits; | 3334 | if (flags & BTRFS_BLOCK_GROUP_DATA) |
3335 | flags |= root->fs_info->avail_data_alloc_bits; | ||
3336 | else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) | ||
3337 | flags |= root->fs_info->avail_system_alloc_bits; | ||
3338 | else if (flags & BTRFS_BLOCK_GROUP_METADATA) | ||
3339 | flags |= root->fs_info->avail_metadata_alloc_bits; | ||
3340 | } while (read_seqretry(&root->fs_info->profiles_lock, seq)); | ||
3333 | 3341 | ||
3334 | return btrfs_reduce_alloc_profile(root, flags); | 3342 | return btrfs_reduce_alloc_profile(root, flags); |
3335 | } | 3343 | } |
@@ -7967,12 +7975,14 @@ static void clear_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) | |||
7967 | u64 extra_flags = chunk_to_extended(flags) & | 7975 | u64 extra_flags = chunk_to_extended(flags) & |
7968 | BTRFS_EXTENDED_PROFILE_MASK; | 7976 | BTRFS_EXTENDED_PROFILE_MASK; |
7969 | 7977 | ||
7978 | write_seqlock(&fs_info->profiles_lock); | ||
7970 | if (flags & BTRFS_BLOCK_GROUP_DATA) | 7979 | if (flags & BTRFS_BLOCK_GROUP_DATA) |
7971 | fs_info->avail_data_alloc_bits &= ~extra_flags; | 7980 | fs_info->avail_data_alloc_bits &= ~extra_flags; |
7972 | if (flags & BTRFS_BLOCK_GROUP_METADATA) | 7981 | if (flags & BTRFS_BLOCK_GROUP_METADATA) |
7973 | fs_info->avail_metadata_alloc_bits &= ~extra_flags; | 7982 | fs_info->avail_metadata_alloc_bits &= ~extra_flags; |
7974 | if (flags & BTRFS_BLOCK_GROUP_SYSTEM) | 7983 | if (flags & BTRFS_BLOCK_GROUP_SYSTEM) |
7975 | fs_info->avail_system_alloc_bits &= ~extra_flags; | 7984 | fs_info->avail_system_alloc_bits &= ~extra_flags; |
7985 | write_sequnlock(&fs_info->profiles_lock); | ||
7976 | } | 7986 | } |
7977 | 7987 | ||
7978 | int btrfs_remove_block_group(struct btrfs_trans_handle *trans, | 7988 | int btrfs_remove_block_group(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 1ce581d58d87..8c9ea4cd66bb 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -1430,14 +1430,19 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
1430 | u64 devid; | 1430 | u64 devid; |
1431 | u64 num_devices; | 1431 | u64 num_devices; |
1432 | u8 *dev_uuid; | 1432 | u8 *dev_uuid; |
1433 | unsigned seq; | ||
1433 | int ret = 0; | 1434 | int ret = 0; |
1434 | bool clear_super = false; | 1435 | bool clear_super = false; |
1435 | 1436 | ||
1436 | mutex_lock(&uuid_mutex); | 1437 | mutex_lock(&uuid_mutex); |
1437 | 1438 | ||
1438 | all_avail = root->fs_info->avail_data_alloc_bits | | 1439 | do { |
1439 | root->fs_info->avail_system_alloc_bits | | 1440 | seq = read_seqbegin(&root->fs_info->profiles_lock); |
1440 | root->fs_info->avail_metadata_alloc_bits; | 1441 | |
1442 | all_avail = root->fs_info->avail_data_alloc_bits | | ||
1443 | root->fs_info->avail_system_alloc_bits | | ||
1444 | root->fs_info->avail_metadata_alloc_bits; | ||
1445 | } while (read_seqretry(&root->fs_info->profiles_lock, seq)); | ||
1441 | 1446 | ||
1442 | num_devices = root->fs_info->fs_devices->num_devices; | 1447 | num_devices = root->fs_info->fs_devices->num_devices; |
1443 | btrfs_dev_replace_lock(&root->fs_info->dev_replace); | 1448 | btrfs_dev_replace_lock(&root->fs_info->dev_replace); |
@@ -3043,6 +3048,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl, | |||
3043 | int mixed = 0; | 3048 | int mixed = 0; |
3044 | int ret; | 3049 | int ret; |
3045 | u64 num_devices; | 3050 | u64 num_devices; |
3051 | unsigned seq; | ||
3046 | 3052 | ||
3047 | if (btrfs_fs_closing(fs_info) || | 3053 | if (btrfs_fs_closing(fs_info) || |
3048 | atomic_read(&fs_info->balance_pause_req) || | 3054 | atomic_read(&fs_info->balance_pause_req) || |
@@ -3126,22 +3132,26 @@ int btrfs_balance(struct btrfs_balance_control *bctl, | |||
3126 | /* allow to reduce meta or sys integrity only if force set */ | 3132 | /* allow to reduce meta or sys integrity only if force set */ |
3127 | allowed = BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 | | 3133 | allowed = BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 | |
3128 | BTRFS_BLOCK_GROUP_RAID10; | 3134 | BTRFS_BLOCK_GROUP_RAID10; |
3129 | if (((bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) && | 3135 | do { |
3130 | (fs_info->avail_system_alloc_bits & allowed) && | 3136 | seq = read_seqbegin(&fs_info->profiles_lock); |
3131 | !(bctl->sys.target & allowed)) || | 3137 | |
3132 | ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) && | 3138 | if (((bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) && |
3133 | (fs_info->avail_metadata_alloc_bits & allowed) && | 3139 | (fs_info->avail_system_alloc_bits & allowed) && |
3134 | !(bctl->meta.target & allowed))) { | 3140 | !(bctl->sys.target & allowed)) || |
3135 | if (bctl->flags & BTRFS_BALANCE_FORCE) { | 3141 | ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) && |
3136 | printk(KERN_INFO "btrfs: force reducing metadata " | 3142 | (fs_info->avail_metadata_alloc_bits & allowed) && |
3137 | "integrity\n"); | 3143 | !(bctl->meta.target & allowed))) { |
3138 | } else { | 3144 | if (bctl->flags & BTRFS_BALANCE_FORCE) { |
3139 | printk(KERN_ERR "btrfs: balance will reduce metadata " | 3145 | printk(KERN_INFO "btrfs: force reducing metadata " |
3140 | "integrity, use force if you want this\n"); | 3146 | "integrity\n"); |
3141 | ret = -EINVAL; | 3147 | } else { |
3142 | goto out; | 3148 | printk(KERN_ERR "btrfs: balance will reduce metadata " |
3149 | "integrity, use force if you want this\n"); | ||
3150 | ret = -EINVAL; | ||
3151 | goto out; | ||
3152 | } | ||
3143 | } | 3153 | } |
3144 | } | 3154 | } while (read_seqretry(&fs_info->profiles_lock, seq)); |
3145 | 3155 | ||
3146 | if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) { | 3156 | if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) { |
3147 | int num_tolerated_disk_barrier_failures; | 3157 | int num_tolerated_disk_barrier_failures; |
@@ -3980,10 +3990,7 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans, | |||
3980 | if (ret) | 3990 | if (ret) |
3981 | return ret; | 3991 | return ret; |
3982 | 3992 | ||
3983 | alloc_profile = BTRFS_BLOCK_GROUP_METADATA | | 3993 | alloc_profile = btrfs_get_alloc_profile(extent_root, 0); |
3984 | fs_info->avail_metadata_alloc_bits; | ||
3985 | alloc_profile = btrfs_reduce_alloc_profile(root, alloc_profile); | ||
3986 | |||
3987 | ret = __btrfs_alloc_chunk(trans, extent_root, &map, &chunk_size, | 3994 | ret = __btrfs_alloc_chunk(trans, extent_root, &map, &chunk_size, |
3988 | &stripe_size, chunk_offset, alloc_profile); | 3995 | &stripe_size, chunk_offset, alloc_profile); |
3989 | if (ret) | 3996 | if (ret) |
@@ -3991,10 +3998,7 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans, | |||
3991 | 3998 | ||
3992 | sys_chunk_offset = chunk_offset + chunk_size; | 3999 | sys_chunk_offset = chunk_offset + chunk_size; |
3993 | 4000 | ||
3994 | alloc_profile = BTRFS_BLOCK_GROUP_SYSTEM | | 4001 | alloc_profile = btrfs_get_alloc_profile(fs_info->chunk_root, 0); |
3995 | fs_info->avail_system_alloc_bits; | ||
3996 | alloc_profile = btrfs_reduce_alloc_profile(root, alloc_profile); | ||
3997 | |||
3998 | ret = __btrfs_alloc_chunk(trans, extent_root, &sys_map, | 4002 | ret = __btrfs_alloc_chunk(trans, extent_root, &sys_map, |
3999 | &sys_chunk_size, &sys_stripe_size, | 4003 | &sys_chunk_size, &sys_stripe_size, |
4000 | sys_chunk_offset, alloc_profile); | 4004 | sys_chunk_offset, alloc_profile); |