aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2013-01-29 05:07:33 -0500
committerJosef Bacik <jbacik@fusionio.com>2013-02-20 12:59:02 -0500
commitc018daecead7a46a575e2a1397fea850b83396c8 (patch)
treef6a68357fbc230b8894a6f19b0ecfae40c1de6d3
parent8c6a3ee6dbd564d05019d396ecb5dc5b35cbc273 (diff)
Btrfs: protect fs_info->alloc_start
fs_info->alloc_start is a 64bits variant, can be accessed by multi-task, but it is not protected strictly, it can be changed while we are accessing it. On 32bit machine, we will get wrong value because we access it by two instructions.(In fact, it is also possible that the same problem happens on the 64bit machine, because the compiler may split the 64bit operation into two 32bit operation.) For example: Assuming -> alloc_start is 0x0000 0000 0001 0000 at the beginning, then we remount and set ->alloc_start to 0x0000 0100 0000 0000. Task0 Task1 load high 32 bits set high 32 bits set low 32 bits load low 32 bits Task1 will get 0. This patch fixes this problem by using two locks to protect it fs_info->chunk_mutex sb->s_umount On the read side, we just need get one of these two locks, and on the write side, we must lock all of them. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
-rw-r--r--fs/btrfs/ctree.h10
-rw-r--r--fs/btrfs/super.c4
2 files changed, 14 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 169baa817d96..d8e539fe5544 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1304,6 +1304,16 @@ struct btrfs_fs_info {
1304 * so it is also safe. 1304 * so it is also safe.
1305 */ 1305 */
1306 u64 max_inline; 1306 u64 max_inline;
1307 /*
1308 * Protected by ->chunk_mutex and sb->s_umount.
1309 *
1310 * The reason that we use two lock to protect it is because only
1311 * remount and mount operations can change it and these two operations
1312 * are under sb->s_umount, but the read side (chunk allocation) can not
1313 * acquire sb->s_umount or the deadlock would happen. So we use two
1314 * locks to protect it. On the write side, we must acquire two locks,
1315 * and on the read side, we just need acquire one of them.
1316 */
1307 u64 alloc_start; 1317 u64 alloc_start;
1308 struct btrfs_transaction *running_transaction; 1318 struct btrfs_transaction *running_transaction;
1309 wait_queue_head_t transaction_throttle; 1319 wait_queue_head_t transaction_throttle;
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 6846ededfe95..eda330df45a4 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -519,7 +519,9 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
519 case Opt_alloc_start: 519 case Opt_alloc_start:
520 num = match_strdup(&args[0]); 520 num = match_strdup(&args[0]);
521 if (num) { 521 if (num) {
522 mutex_lock(&info->chunk_mutex);
522 info->alloc_start = memparse(num, NULL); 523 info->alloc_start = memparse(num, NULL);
524 mutex_unlock(&info->chunk_mutex);
523 kfree(num); 525 kfree(num);
524 printk(KERN_INFO 526 printk(KERN_INFO
525 "btrfs: allocations start at %llu\n", 527 "btrfs: allocations start at %llu\n",
@@ -1289,7 +1291,9 @@ restore:
1289 fs_info->mount_opt = old_opts; 1291 fs_info->mount_opt = old_opts;
1290 fs_info->compress_type = old_compress_type; 1292 fs_info->compress_type = old_compress_type;
1291 fs_info->max_inline = old_max_inline; 1293 fs_info->max_inline = old_max_inline;
1294 mutex_lock(&fs_info->chunk_mutex);
1292 fs_info->alloc_start = old_alloc_start; 1295 fs_info->alloc_start = old_alloc_start;
1296 mutex_unlock(&fs_info->chunk_mutex);
1293 btrfs_resize_thread_pool(fs_info, 1297 btrfs_resize_thread_pool(fs_info,
1294 old_thread_pool_size, fs_info->thread_pool_size); 1298 old_thread_pool_size, fs_info->thread_pool_size);
1295 fs_info->metadata_ratio = old_metadata_ratio; 1299 fs_info->metadata_ratio = old_metadata_ratio;