mirror of
https://github.com/torvalds/linux
synced 2024-10-04 02:10:58 +00:00
btrfs: fix ->free_chunk_space math in btrfs_shrink_device
There are two bugs in how we adjust ->free_chunk_space in btrfs_shrink_device. First we're removing the entire diff between new_size and old_size from ->free_chunk_space. This only works if we're reducing the free area, which we could potentially not be. So adjust the math to only subtract the diff in the free space from ->free_chunk_space. Additionally in the error case we're unconditionally adding the diff back into ->free_chunk_space, which we need to only do if this device is writeable. Signed-off-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
efba145449
commit
e9fd2c0523
|
@ -4722,6 +4722,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
|
||||||
u64 old_size = btrfs_device_get_total_bytes(device);
|
u64 old_size = btrfs_device_get_total_bytes(device);
|
||||||
u64 diff;
|
u64 diff;
|
||||||
u64 start;
|
u64 start;
|
||||||
|
u64 free_diff = 0;
|
||||||
|
|
||||||
new_size = round_down(new_size, fs_info->sectorsize);
|
new_size = round_down(new_size, fs_info->sectorsize);
|
||||||
start = new_size;
|
start = new_size;
|
||||||
|
@ -4747,7 +4748,19 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
|
||||||
btrfs_device_set_total_bytes(device, new_size);
|
btrfs_device_set_total_bytes(device, new_size);
|
||||||
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
|
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
|
||||||
device->fs_devices->total_rw_bytes -= diff;
|
device->fs_devices->total_rw_bytes -= diff;
|
||||||
atomic64_sub(diff, &fs_info->free_chunk_space);
|
|
||||||
|
/*
|
||||||
|
* The new free_chunk_space is new_size - used, so we have to
|
||||||
|
* subtract the delta of the old free_chunk_space which included
|
||||||
|
* old_size - used. If used > new_size then just subtract this
|
||||||
|
* entire device's free space.
|
||||||
|
*/
|
||||||
|
if (device->bytes_used < new_size)
|
||||||
|
free_diff = (old_size - device->bytes_used) -
|
||||||
|
(new_size - device->bytes_used);
|
||||||
|
else
|
||||||
|
free_diff = old_size - device->bytes_used;
|
||||||
|
atomic64_sub(free_diff, &fs_info->free_chunk_space);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4882,9 +4895,10 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
|
||||||
if (ret) {
|
if (ret) {
|
||||||
mutex_lock(&fs_info->chunk_mutex);
|
mutex_lock(&fs_info->chunk_mutex);
|
||||||
btrfs_device_set_total_bytes(device, old_size);
|
btrfs_device_set_total_bytes(device, old_size);
|
||||||
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state))
|
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
|
||||||
device->fs_devices->total_rw_bytes += diff;
|
device->fs_devices->total_rw_bytes += diff;
|
||||||
atomic64_add(diff, &fs_info->free_chunk_space);
|
atomic64_add(free_diff, &fs_info->free_chunk_space);
|
||||||
|
}
|
||||||
mutex_unlock(&fs_info->chunk_mutex);
|
mutex_unlock(&fs_info->chunk_mutex);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in a new issue