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 diff;
|
||||
u64 start;
|
||||
u64 free_diff = 0;
|
||||
|
||||
new_size = round_down(new_size, fs_info->sectorsize);
|
||||
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);
|
||||
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
|
||||
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 @@ done:
|
||||
if (ret) {
|
||||
mutex_lock(&fs_info->chunk_mutex);
|
||||
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;
|
||||
atomic64_add(diff, &fs_info->free_chunk_space);
|
||||
atomic64_add(free_diff, &fs_info->free_chunk_space);
|
||||
}
|
||||
mutex_unlock(&fs_info->chunk_mutex);
|
||||
}
|
||||
return ret;
|
||||
|
Loading…
x
Reference in New Issue
Block a user