Commit 7dfb8be1 authored by Nikolay Borisov's avatar Nikolay Borisov Committed by David Sterba

btrfs: Round down values which are written for total_bytes_size

We got an internal report about a file system not wanting to mount
following 99e3ecfc ("Btrfs: add more validation checks for
superblock").

BTRFS error (device sdb1): super_total_bytes 1000203816960 mismatch with
fs_devices total_rw_bytes 1000203820544

Subtracting the numbers we get a difference of less than a 4kb. Upon
closer inspection it became apparent that mkfs actually rounds down the
size of the device to a multiple of sector size. However, the same
cannot be said for various functions which modify the total size and are
called from btrfs_balance as well as when adding a new device. So this
patch ensures that values being saved into on-disk data structures are
always rounded down to a multiple of sectorsize.
Signed-off-by: default avatarNikolay Borisov <nborisov@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent eca152ed
...@@ -1556,6 +1556,7 @@ static inline void btrfs_set_device_total_bytes(struct extent_buffer *eb, ...@@ -1556,6 +1556,7 @@ static inline void btrfs_set_device_total_bytes(struct extent_buffer *eb,
{ {
BUILD_BUG_ON(sizeof(u64) != BUILD_BUG_ON(sizeof(u64) !=
sizeof(((struct btrfs_dev_item *)0))->total_bytes); sizeof(((struct btrfs_dev_item *)0))->total_bytes);
WARN_ON(!IS_ALIGNED(val, eb->fs_info->sectorsize));
btrfs_set_64(eb, s, offsetof(struct btrfs_dev_item, total_bytes), val); btrfs_set_64(eb, s, offsetof(struct btrfs_dev_item, total_bytes), val);
} }
......
...@@ -2385,7 +2385,8 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path ...@@ -2385,7 +2385,8 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
device->io_width = fs_info->sectorsize; device->io_width = fs_info->sectorsize;
device->io_align = fs_info->sectorsize; device->io_align = fs_info->sectorsize;
device->sector_size = fs_info->sectorsize; device->sector_size = fs_info->sectorsize;
device->total_bytes = i_size_read(bdev->bd_inode); device->total_bytes = round_down(i_size_read(bdev->bd_inode),
fs_info->sectorsize);
device->disk_total_bytes = device->total_bytes; device->disk_total_bytes = device->total_bytes;
device->commit_total_bytes = device->total_bytes; device->commit_total_bytes = device->total_bytes;
device->fs_info = fs_info; device->fs_info = fs_info;
...@@ -2422,7 +2423,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path ...@@ -2422,7 +2423,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
tmp = btrfs_super_total_bytes(fs_info->super_copy); tmp = btrfs_super_total_bytes(fs_info->super_copy);
btrfs_set_super_total_bytes(fs_info->super_copy, btrfs_set_super_total_bytes(fs_info->super_copy,
tmp + device->total_bytes); round_down(tmp + device->total_bytes, fs_info->sectorsize));
tmp = btrfs_super_num_devices(fs_info->super_copy); tmp = btrfs_super_num_devices(fs_info->super_copy);
btrfs_set_super_num_devices(fs_info->super_copy, tmp + 1); btrfs_set_super_num_devices(fs_info->super_copy, tmp + 1);
...@@ -2685,6 +2686,8 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans, ...@@ -2685,6 +2686,8 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
if (!device->writeable) if (!device->writeable)
return -EACCES; return -EACCES;
new_size = round_down(new_size, fs_info->sectorsize);
mutex_lock(&fs_info->chunk_mutex); mutex_lock(&fs_info->chunk_mutex);
old_total = btrfs_super_total_bytes(super_copy); old_total = btrfs_super_total_bytes(super_copy);
diff = new_size - device->total_bytes; diff = new_size - device->total_bytes;
...@@ -2697,7 +2700,8 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans, ...@@ -2697,7 +2700,8 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
fs_devices = fs_info->fs_devices; fs_devices = fs_info->fs_devices;
btrfs_set_super_total_bytes(super_copy, old_total + diff); btrfs_set_super_total_bytes(super_copy,
round_down(old_total + diff, fs_info->sectorsize));
device->fs_devices->total_rw_bytes += diff; device->fs_devices->total_rw_bytes += diff;
btrfs_device_set_total_bytes(device, new_size); btrfs_device_set_total_bytes(device, new_size);
...@@ -4387,7 +4391,10 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) ...@@ -4387,7 +4391,10 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
struct btrfs_super_block *super_copy = fs_info->super_copy; struct btrfs_super_block *super_copy = fs_info->super_copy;
u64 old_total = btrfs_super_total_bytes(super_copy); u64 old_total = btrfs_super_total_bytes(super_copy);
u64 old_size = btrfs_device_get_total_bytes(device); u64 old_size = btrfs_device_get_total_bytes(device);
u64 diff = old_size - new_size; u64 diff;
new_size = round_down(new_size, fs_info->sectorsize);
diff = old_size - new_size;
if (device->is_tgtdev_for_dev_replace) if (device->is_tgtdev_for_dev_replace)
return -EINVAL; return -EINVAL;
...@@ -4514,7 +4521,8 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) ...@@ -4514,7 +4521,8 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
&fs_info->fs_devices->resized_devices); &fs_info->fs_devices->resized_devices);
WARN_ON(diff > old_total); WARN_ON(diff > old_total);
btrfs_set_super_total_bytes(super_copy, old_total - diff); btrfs_set_super_total_bytes(super_copy,
round_down(old_total - diff, fs_info->sectorsize));
mutex_unlock(&fs_info->chunk_mutex); mutex_unlock(&fs_info->chunk_mutex);
/* Now btrfs_update_device() will change the on-disk size. */ /* Now btrfs_update_device() will change the on-disk size. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment