btrfs: don't reserve space for checksums when writing to nocow files

commit feefe1f49d26bad9d8997096e3a200280fa7b1c5 upstream.

Currently when doing a write to a file we always reserve metadata space
for inserting data checksums. However we don't need to do it if we have
a nodatacow file (-o nodatacow mount option or chattr +C) or if checksums
are disabled (-o nodatasum mount option), as in that case we are only
adding unnecessary pressure to metadata reservations.

For example on x86_64, with the default node size of 16K, a 4K buffered
write into a nodatacow file is reserving 655360 bytes of metadata space,
as it's accounting for checksums. After this change, which stops reserving
space for checksums if we have a nodatacow file or checksums are disabled,
we only need to reserve 393216 bytes of metadata.

CC: stable@vger.kernel.org # 6.1+
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Filipe Manana 2024-01-31 17:18:04 +00:00 committed by Greg Kroah-Hartman
parent dfd1f44e49
commit 4d6b2e17b5
1 changed files with 19 additions and 10 deletions

View File

@ -243,7 +243,6 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
struct btrfs_block_rsv *block_rsv = &inode->block_rsv; struct btrfs_block_rsv *block_rsv = &inode->block_rsv;
u64 reserve_size = 0; u64 reserve_size = 0;
u64 qgroup_rsv_size = 0; u64 qgroup_rsv_size = 0;
u64 csum_leaves;
unsigned outstanding_extents; unsigned outstanding_extents;
lockdep_assert_held(&inode->lock); lockdep_assert_held(&inode->lock);
@ -258,10 +257,12 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
outstanding_extents); outstanding_extents);
reserve_size += btrfs_calc_metadata_size(fs_info, 1); reserve_size += btrfs_calc_metadata_size(fs_info, 1);
} }
csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, if (!(inode->flags & BTRFS_INODE_NODATASUM)) {
inode->csum_bytes); u64 csum_leaves;
reserve_size += btrfs_calc_insert_metadata_size(fs_info,
csum_leaves); csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, inode->csum_bytes);
reserve_size += btrfs_calc_insert_metadata_size(fs_info, csum_leaves);
}
/* /*
* For qgroup rsv, the calculation is very simple: * For qgroup rsv, the calculation is very simple:
* account one nodesize for each outstanding extent * account one nodesize for each outstanding extent
@ -276,14 +277,20 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
spin_unlock(&block_rsv->lock); spin_unlock(&block_rsv->lock);
} }
static void calc_inode_reservations(struct btrfs_fs_info *fs_info, static void calc_inode_reservations(struct btrfs_inode *inode,
u64 num_bytes, u64 disk_num_bytes, u64 num_bytes, u64 disk_num_bytes,
u64 *meta_reserve, u64 *qgroup_reserve) u64 *meta_reserve, u64 *qgroup_reserve)
{ {
struct btrfs_fs_info *fs_info = inode->root->fs_info;
u64 nr_extents = count_max_extents(fs_info, num_bytes); u64 nr_extents = count_max_extents(fs_info, num_bytes);
u64 csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, disk_num_bytes); u64 csum_leaves;
u64 inode_update = btrfs_calc_metadata_size(fs_info, 1); u64 inode_update = btrfs_calc_metadata_size(fs_info, 1);
if (inode->flags & BTRFS_INODE_NODATASUM)
csum_leaves = 0;
else
csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, disk_num_bytes);
*meta_reserve = btrfs_calc_insert_metadata_size(fs_info, *meta_reserve = btrfs_calc_insert_metadata_size(fs_info,
nr_extents + csum_leaves); nr_extents + csum_leaves);
@ -335,7 +342,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes,
* everything out and try again, which is bad. This way we just * everything out and try again, which is bad. This way we just
* over-reserve slightly, and clean up the mess when we are done. * over-reserve slightly, and clean up the mess when we are done.
*/ */
calc_inode_reservations(fs_info, num_bytes, disk_num_bytes, calc_inode_reservations(inode, num_bytes, disk_num_bytes,
&meta_reserve, &qgroup_reserve); &meta_reserve, &qgroup_reserve);
ret = btrfs_qgroup_reserve_meta_prealloc(root, qgroup_reserve, true, ret = btrfs_qgroup_reserve_meta_prealloc(root, qgroup_reserve, true,
noflush); noflush);
@ -356,6 +363,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes,
spin_lock(&inode->lock); spin_lock(&inode->lock);
nr_extents = count_max_extents(fs_info, num_bytes); nr_extents = count_max_extents(fs_info, num_bytes);
btrfs_mod_outstanding_extents(inode, nr_extents); btrfs_mod_outstanding_extents(inode, nr_extents);
if (!(inode->flags & BTRFS_INODE_NODATASUM))
inode->csum_bytes += disk_num_bytes; inode->csum_bytes += disk_num_bytes;
btrfs_calculate_inode_block_rsv_size(fs_info, inode); btrfs_calculate_inode_block_rsv_size(fs_info, inode);
spin_unlock(&inode->lock); spin_unlock(&inode->lock);
@ -390,6 +398,7 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
num_bytes = ALIGN(num_bytes, fs_info->sectorsize); num_bytes = ALIGN(num_bytes, fs_info->sectorsize);
spin_lock(&inode->lock); spin_lock(&inode->lock);
if (!(inode->flags & BTRFS_INODE_NODATASUM))
inode->csum_bytes -= num_bytes; inode->csum_bytes -= num_bytes;
btrfs_calculate_inode_block_rsv_size(fs_info, inode); btrfs_calculate_inode_block_rsv_size(fs_info, inode);
spin_unlock(&inode->lock); spin_unlock(&inode->lock);