diff options
author | Miao Xie <miaox@cn.fujitsu.com> | 2014-09-03 09:35:38 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-09-17 16:38:38 -0400 |
commit | 7cc8e58d53cd2295c3c1cee7b503bd1790ea4486 (patch) | |
tree | 1befd9a2bea8e1808f0fe1b12406c05b3f7dbe2d /fs/btrfs/volumes.c | |
parent | 1c1161870c8bcb0d966ebbf1aec05a87a79a4175 (diff) |
Btrfs: fix unprotected device's variants on 32bits machine
->total_bytes,->disk_total_bytes,->bytes_used is protected by chunk
lock when we change them, but sometimes we read them without any lock,
and we might get unexpected value. We fix this problem like inode's
i_size.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 48 |
1 files changed, 28 insertions, 20 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index d8e4a3d1ad89..41da102cdcc0 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -1308,7 +1308,7 @@ again: | |||
1308 | 1308 | ||
1309 | if (device->bytes_used > 0) { | 1309 | if (device->bytes_used > 0) { |
1310 | u64 len = btrfs_dev_extent_length(leaf, extent); | 1310 | u64 len = btrfs_dev_extent_length(leaf, extent); |
1311 | device->bytes_used -= len; | 1311 | btrfs_device_set_bytes_used(device, device->bytes_used - len); |
1312 | spin_lock(&root->fs_info->free_chunk_lock); | 1312 | spin_lock(&root->fs_info->free_chunk_lock); |
1313 | root->fs_info->free_chunk_space += len; | 1313 | root->fs_info->free_chunk_space += len; |
1314 | spin_unlock(&root->fs_info->free_chunk_lock); | 1314 | spin_unlock(&root->fs_info->free_chunk_lock); |
@@ -1462,8 +1462,10 @@ static int btrfs_add_device(struct btrfs_trans_handle *trans, | |||
1462 | btrfs_set_device_io_align(leaf, dev_item, device->io_align); | 1462 | btrfs_set_device_io_align(leaf, dev_item, device->io_align); |
1463 | btrfs_set_device_io_width(leaf, dev_item, device->io_width); | 1463 | btrfs_set_device_io_width(leaf, dev_item, device->io_width); |
1464 | btrfs_set_device_sector_size(leaf, dev_item, device->sector_size); | 1464 | btrfs_set_device_sector_size(leaf, dev_item, device->sector_size); |
1465 | btrfs_set_device_total_bytes(leaf, dev_item, device->disk_total_bytes); | 1465 | btrfs_set_device_total_bytes(leaf, dev_item, |
1466 | btrfs_set_device_bytes_used(leaf, dev_item, device->bytes_used); | 1466 | btrfs_device_get_disk_total_bytes(device)); |
1467 | btrfs_set_device_bytes_used(leaf, dev_item, | ||
1468 | btrfs_device_get_bytes_used(device)); | ||
1467 | btrfs_set_device_group(leaf, dev_item, 0); | 1469 | btrfs_set_device_group(leaf, dev_item, 0); |
1468 | btrfs_set_device_seek_speed(leaf, dev_item, 0); | 1470 | btrfs_set_device_seek_speed(leaf, dev_item, 0); |
1469 | btrfs_set_device_bandwidth(leaf, dev_item, 0); | 1471 | btrfs_set_device_bandwidth(leaf, dev_item, 0); |
@@ -2330,7 +2332,8 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path, | |||
2330 | } | 2332 | } |
2331 | 2333 | ||
2332 | 2334 | ||
2333 | if (i_size_read(bdev->bd_inode) < srcdev->total_bytes) { | 2335 | if (i_size_read(bdev->bd_inode) < |
2336 | btrfs_device_get_total_bytes(srcdev)) { | ||
2334 | btrfs_err(fs_info, "target device is smaller than source device!"); | 2337 | btrfs_err(fs_info, "target device is smaller than source device!"); |
2335 | ret = -EINVAL; | 2338 | ret = -EINVAL; |
2336 | goto error; | 2339 | goto error; |
@@ -2360,11 +2363,11 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path, | |||
2360 | device->io_width = root->sectorsize; | 2363 | device->io_width = root->sectorsize; |
2361 | device->io_align = root->sectorsize; | 2364 | device->io_align = root->sectorsize; |
2362 | device->sector_size = root->sectorsize; | 2365 | device->sector_size = root->sectorsize; |
2363 | device->total_bytes = srcdev->total_bytes; | 2366 | device->total_bytes = btrfs_device_get_total_bytes(srcdev); |
2364 | device->disk_total_bytes = srcdev->disk_total_bytes; | 2367 | device->disk_total_bytes = btrfs_device_get_disk_total_bytes(srcdev); |
2368 | device->bytes_used = btrfs_device_get_bytes_used(srcdev); | ||
2365 | ASSERT(list_empty(&srcdev->resized_list)); | 2369 | ASSERT(list_empty(&srcdev->resized_list)); |
2366 | device->commit_total_bytes = srcdev->commit_total_bytes; | 2370 | device->commit_total_bytes = srcdev->commit_total_bytes; |
2367 | device->bytes_used = srcdev->bytes_used; | ||
2368 | device->commit_bytes_used = device->bytes_used; | 2371 | device->commit_bytes_used = device->bytes_used; |
2369 | device->dev_root = fs_info->dev_root; | 2372 | device->dev_root = fs_info->dev_root; |
2370 | device->bdev = bdev; | 2373 | device->bdev = bdev; |
@@ -2435,8 +2438,10 @@ static noinline int btrfs_update_device(struct btrfs_trans_handle *trans, | |||
2435 | btrfs_set_device_io_align(leaf, dev_item, device->io_align); | 2438 | btrfs_set_device_io_align(leaf, dev_item, device->io_align); |
2436 | btrfs_set_device_io_width(leaf, dev_item, device->io_width); | 2439 | btrfs_set_device_io_width(leaf, dev_item, device->io_width); |
2437 | btrfs_set_device_sector_size(leaf, dev_item, device->sector_size); | 2440 | btrfs_set_device_sector_size(leaf, dev_item, device->sector_size); |
2438 | btrfs_set_device_total_bytes(leaf, dev_item, device->disk_total_bytes); | 2441 | btrfs_set_device_total_bytes(leaf, dev_item, |
2439 | btrfs_set_device_bytes_used(leaf, dev_item, device->bytes_used); | 2442 | btrfs_device_get_disk_total_bytes(device)); |
2443 | btrfs_set_device_bytes_used(leaf, dev_item, | ||
2444 | btrfs_device_get_bytes_used(device)); | ||
2440 | btrfs_mark_buffer_dirty(leaf); | 2445 | btrfs_mark_buffer_dirty(leaf); |
2441 | 2446 | ||
2442 | out: | 2447 | out: |
@@ -2464,8 +2469,8 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans, | |||
2464 | btrfs_set_super_total_bytes(super_copy, old_total + diff); | 2469 | btrfs_set_super_total_bytes(super_copy, old_total + diff); |
2465 | device->fs_devices->total_rw_bytes += diff; | 2470 | device->fs_devices->total_rw_bytes += diff; |
2466 | 2471 | ||
2467 | device->total_bytes = new_size; | 2472 | btrfs_device_set_total_bytes(device, new_size); |
2468 | device->disk_total_bytes = new_size; | 2473 | btrfs_device_set_disk_total_bytes(device, new_size); |
2469 | btrfs_clear_space_info_full(device->dev_root->fs_info); | 2474 | btrfs_clear_space_info_full(device->dev_root->fs_info); |
2470 | if (list_empty(&device->resized_list)) | 2475 | if (list_empty(&device->resized_list)) |
2471 | list_add_tail(&device->resized_list, | 2476 | list_add_tail(&device->resized_list, |
@@ -3110,11 +3115,12 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info) | |||
3110 | /* step one make some room on all the devices */ | 3115 | /* step one make some room on all the devices */ |
3111 | devices = &fs_info->fs_devices->devices; | 3116 | devices = &fs_info->fs_devices->devices; |
3112 | list_for_each_entry(device, devices, dev_list) { | 3117 | list_for_each_entry(device, devices, dev_list) { |
3113 | old_size = device->total_bytes; | 3118 | old_size = btrfs_device_get_total_bytes(device); |
3114 | size_to_free = div_factor(old_size, 1); | 3119 | size_to_free = div_factor(old_size, 1); |
3115 | size_to_free = min(size_to_free, (u64)1 * 1024 * 1024); | 3120 | size_to_free = min(size_to_free, (u64)1 * 1024 * 1024); |
3116 | if (!device->writeable || | 3121 | if (!device->writeable || |
3117 | device->total_bytes - device->bytes_used > size_to_free || | 3122 | btrfs_device_get_total_bytes(device) - |
3123 | btrfs_device_get_bytes_used(device) > size_to_free || | ||
3118 | device->is_tgtdev_for_dev_replace) | 3124 | device->is_tgtdev_for_dev_replace) |
3119 | continue; | 3125 | continue; |
3120 | 3126 | ||
@@ -3920,8 +3926,8 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) | |||
3920 | struct btrfs_key key; | 3926 | struct btrfs_key key; |
3921 | struct btrfs_super_block *super_copy = root->fs_info->super_copy; | 3927 | struct btrfs_super_block *super_copy = root->fs_info->super_copy; |
3922 | u64 old_total = btrfs_super_total_bytes(super_copy); | 3928 | u64 old_total = btrfs_super_total_bytes(super_copy); |
3923 | u64 old_size = device->total_bytes; | 3929 | u64 old_size = btrfs_device_get_total_bytes(device); |
3924 | u64 diff = device->total_bytes - new_size; | 3930 | u64 diff = old_size - new_size; |
3925 | 3931 | ||
3926 | if (device->is_tgtdev_for_dev_replace) | 3932 | if (device->is_tgtdev_for_dev_replace) |
3927 | return -EINVAL; | 3933 | return -EINVAL; |
@@ -3934,7 +3940,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) | |||
3934 | 3940 | ||
3935 | lock_chunks(root); | 3941 | lock_chunks(root); |
3936 | 3942 | ||
3937 | device->total_bytes = new_size; | 3943 | btrfs_device_set_total_bytes(device, new_size); |
3938 | if (device->writeable) { | 3944 | if (device->writeable) { |
3939 | device->fs_devices->total_rw_bytes -= diff; | 3945 | device->fs_devices->total_rw_bytes -= diff; |
3940 | spin_lock(&root->fs_info->free_chunk_lock); | 3946 | spin_lock(&root->fs_info->free_chunk_lock); |
@@ -4000,7 +4006,7 @@ again: | |||
4000 | ret = -ENOSPC; | 4006 | ret = -ENOSPC; |
4001 | lock_chunks(root); | 4007 | lock_chunks(root); |
4002 | 4008 | ||
4003 | device->total_bytes = old_size; | 4009 | btrfs_device_set_total_bytes(device, old_size); |
4004 | if (device->writeable) | 4010 | if (device->writeable) |
4005 | device->fs_devices->total_rw_bytes += diff; | 4011 | device->fs_devices->total_rw_bytes += diff; |
4006 | spin_lock(&root->fs_info->free_chunk_lock); | 4012 | spin_lock(&root->fs_info->free_chunk_lock); |
@@ -4018,7 +4024,7 @@ again: | |||
4018 | } | 4024 | } |
4019 | 4025 | ||
4020 | lock_chunks(root); | 4026 | lock_chunks(root); |
4021 | device->disk_total_bytes = new_size; | 4027 | btrfs_device_set_disk_total_bytes(device, new_size); |
4022 | if (list_empty(&device->resized_list)) | 4028 | if (list_empty(&device->resized_list)) |
4023 | list_add_tail(&device->resized_list, | 4029 | list_add_tail(&device->resized_list, |
4024 | &root->fs_info->fs_devices->resized_devices); | 4030 | &root->fs_info->fs_devices->resized_devices); |
@@ -4429,8 +4435,10 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
4429 | if (ret) | 4435 | if (ret) |
4430 | goto error_del_extent; | 4436 | goto error_del_extent; |
4431 | 4437 | ||
4432 | for (i = 0; i < map->num_stripes; i++) | 4438 | for (i = 0; i < map->num_stripes; i++) { |
4433 | map->stripes[i].dev->bytes_used += stripe_size; | 4439 | num_bytes = map->stripes[i].dev->bytes_used + stripe_size; |
4440 | btrfs_device_set_bytes_used(map->stripes[i].dev, num_bytes); | ||
4441 | } | ||
4434 | 4442 | ||
4435 | spin_lock(&extent_root->fs_info->free_chunk_lock); | 4443 | spin_lock(&extent_root->fs_info->free_chunk_lock); |
4436 | extent_root->fs_info->free_chunk_space -= (stripe_size * | 4444 | extent_root->fs_info->free_chunk_space -= (stripe_size * |