aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2013-01-29 05:13:12 -0500
committerJosef Bacik <jbacik@fusionio.com>2013-02-20 12:59:08 -0500
commitde98ced9e743656d108de41841797def0f5cb951 (patch)
tree52314be4abe2cd2510712e8b629d58d8d01d5e0a /fs
parentdf0af1a57f72c74d53a9377c60ff20095afab97d (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.h2
-rw-r--r--fs/btrfs/disk-io.c1
-rw-r--r--fs/btrfs/extent-tree.c22
-rw-r--r--fs/btrfs/volumes.c56
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
3325static u64 get_alloc_profile(struct btrfs_root *root, u64 flags) 3327static 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
7978int btrfs_remove_block_group(struct btrfs_trans_handle *trans, 7988int 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);