Skip to content

Commit ef53fbd

Browse files
adam900710kdave
authored andcommitted
btrfs-progs: change-csum: fix the wrong metadata space reservation
[BUG] 'btrfstune --csum' would always fail for a newly created btrfs: # truncate -s 1G test.img # ./mkfs.btrfs -f test.img # ./btrsftune --csum xxhash test.img WARNING: Experimental build with unstable or unfinished features WARNING: Switching checksums is experimental, do not use for valuable data! Proceed to switch checksums ERROR: failed to start transaction: Unknown error -28 ERROR: failed to start transaction: No space left on device ERROR: failed to generate new data csums: No space left on device ERROR: btrfstune failed [CAUSE] After commit e79f18a ("btrfs-progs: introduce a basic metadata free space reservation check"), btrfs_start_transaction() would check the metadata space. But at the time of introduction of csum conversion, the parameter for btrfs_start_transaction() was incorrect. The 2nd parameter is the *number* of items to be added (if we're deleting items, just pass 1). However commit 08a3bd7 ("btrfs-progs: tune: add the ability to generate new data checksums") is using the item size, not the number of items to be added. This means we're passing a number 8 * nodesize times larger than the original size, no wonder we would error out with -ENOSPC. [FIX] Use proper calcuation to convert the new csum item size to number of leaves needed, and double it just in case. Pull-request: #820 Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 29f3820 commit ef53fbd

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

tune/change-csum.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -224,14 +224,25 @@ static int generate_new_csum_range(struct btrfs_trans_handle *trans,
224224
* item.
225225
*/
226226
#define CSUM_CHANGE_BYTES_THRESHOLD (SZ_2M)
227+
228+
static unsigned int calc_csum_change_nr_items(struct btrfs_fs_info *fs_info,
229+
u16 new_csum_type)
230+
{
231+
const u32 new_csum_size = btrfs_csum_type_size(new_csum_type);
232+
const u32 csum_item_size = CSUM_CHANGE_BYTES_THRESHOLD /
233+
fs_info->sectorsize * new_csum_size;
234+
235+
return round_up(csum_item_size, fs_info->nodesize) / fs_info->nodesize * 2;
236+
}
237+
227238
static int generate_new_data_csums_range(struct btrfs_fs_info *fs_info, u64 start,
228239
u16 new_csum_type)
229240
{
241+
const unsigned int nr_items = calc_csum_change_nr_items(fs_info, new_csum_type);
230242
struct btrfs_root *csum_root = btrfs_csum_root(fs_info, 0);
231243
struct btrfs_trans_handle *trans;
232244
struct btrfs_path path = { 0 };
233245
struct btrfs_key key;
234-
const u32 new_csum_size = btrfs_csum_type_size(new_csum_type);
235246
void *csum_buffer;
236247
u64 converted_bytes = 0;
237248
u64 last_csum;
@@ -248,9 +259,7 @@ static int generate_new_data_csums_range(struct btrfs_fs_info *fs_info, u64 star
248259
if (!csum_buffer)
249260
return -ENOMEM;
250261

251-
trans = btrfs_start_transaction(csum_root,
252-
CSUM_CHANGE_BYTES_THRESHOLD / fs_info->sectorsize *
253-
new_csum_size);
262+
trans = btrfs_start_transaction(csum_root, nr_items);
254263
if (IS_ERR(trans)) {
255264
ret = PTR_ERR(trans);
256265
errno = -ret;
@@ -306,9 +315,7 @@ static int generate_new_data_csums_range(struct btrfs_fs_info *fs_info, u64 star
306315
return -EUCLEAN;
307316
if (ret < 0)
308317
goto out;
309-
trans = btrfs_start_transaction(csum_root,
310-
CSUM_CHANGE_BYTES_THRESHOLD /
311-
fs_info->sectorsize * new_csum_size);
318+
trans = btrfs_start_transaction(csum_root, nr_items);
312319
if (IS_ERR(trans)) {
313320
ret = PTR_ERR(trans);
314321
goto out;

0 commit comments

Comments
 (0)