btrfs-progs: tune: add the ability to generate new data checksums

This patch would modify btrfs_csum_file_block() to handle csum type
other than the one used in the current fs.

The new data checksum would use a different objectid (-13) to
distinguish with the existing one (-10).
This needs to change tree-checker to skip the item size checks,
since new csum can be larger than the original csum.

After this stage, the resulted csum tree would look like this:

	item 0 key (CSUM_CHANGE EXTENT_CSUM 13631488) itemoff 8091 itemsize 8192
		range start 13631488 end 22020096 length 8388608
	item 1 key (EXTENT_CSUM EXTENT_CSUM 13631488) itemoff 7067 itemsize 1024
		range start 13631488 end 14680064 length 1048576

Note the itemsize is 8 times the original one, as the original csum is
CRC32, while target csum is SHA256, which is 8 times the size.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2023-05-18 10:10:42 +08:00 committed by David Sterba
parent 2c02b799b1
commit 08a3bd7694
7 changed files with 52 additions and 35 deletions

View File

@ -1209,18 +1209,19 @@ static int populate_csum(struct btrfs_trans_handle *trans,
struct btrfs_root *csum_root, char *buf, u64 start, struct btrfs_root *csum_root, char *buf, u64 start,
u64 len) u64 len)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info;
u64 offset = 0; u64 offset = 0;
u64 sectorsize; u64 sectorsize = fs_info->sectorsize;
int ret = 0; int ret = 0;
while (offset < len) { while (offset < len) {
sectorsize = gfs_info->sectorsize; ret = read_data_from_disk(fs_info, buf, start + offset,
ret = read_data_from_disk(gfs_info, buf, start + offset,
&sectorsize, 0); &sectorsize, 0);
if (ret) if (ret)
break; break;
ret = btrfs_csum_file_block(trans, start + len, start + offset, ret = btrfs_csum_file_block(trans, start + offset,
buf, sectorsize); BTRFS_EXTENT_CSUM_OBJECTID,
fs_info->csum_type, buf);
if (ret) if (ret)
break; break;
offset += sectorsize; offset += sectorsize;

View File

@ -182,7 +182,8 @@ static int csum_disk_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
u64 disk_bytenr, u64 num_bytes) u64 disk_bytenr, u64 num_bytes)
{ {
u32 blocksize = root->fs_info->sectorsize; struct btrfs_fs_info *fs_info = trans->fs_info;
u32 blocksize = fs_info->sectorsize;
u64 offset; u64 offset;
char *buffer; char *buffer;
int ret = 0; int ret = 0;
@ -193,7 +194,7 @@ static int csum_disk_extent(struct btrfs_trans_handle *trans,
for (offset = 0; offset < num_bytes; offset += blocksize) { for (offset = 0; offset < num_bytes; offset += blocksize) {
u64 read_len = blocksize; u64 read_len = blocksize;
ret = read_data_from_disk(root->fs_info, buffer, ret = read_data_from_disk(fs_info, buffer,
disk_bytenr + offset, &read_len, 0); disk_bytenr + offset, &read_len, 0);
if (ret) if (ret)
break; break;
@ -203,10 +204,9 @@ static int csum_disk_extent(struct btrfs_trans_handle *trans,
ret = -EIO; ret = -EIO;
break; break;
} }
ret = btrfs_csum_file_block(trans, ret = btrfs_csum_file_block(trans, disk_bytenr + offset,
disk_bytenr + num_bytes, BTRFS_EXTENT_CSUM_OBJECTID,
disk_bytenr + offset, fs_info->csum_type, buffer);
buffer, blocksize);
if (ret) if (ret)
break; break;
} }

View File

@ -134,7 +134,7 @@ static struct btrfs_csum_item *
btrfs_lookup_csum(struct btrfs_trans_handle *trans, btrfs_lookup_csum(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_path *path, struct btrfs_path *path,
u64 bytenr, int cow) u64 bytenr, u64 csum_objectid, u16 csum_type, int cow)
{ {
int ret; int ret;
struct btrfs_key file_key; struct btrfs_key file_key;
@ -142,10 +142,10 @@ btrfs_lookup_csum(struct btrfs_trans_handle *trans,
struct btrfs_csum_item *item; struct btrfs_csum_item *item;
struct extent_buffer *leaf; struct extent_buffer *leaf;
u64 csum_offset = 0; u64 csum_offset = 0;
u16 csum_size = root->fs_info->csum_size; u16 csum_size = btrfs_csum_type_size(csum_type);
int csums_in_item; int csums_in_item;
file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; file_key.objectid = csum_objectid;
file_key.offset = bytenr; file_key.offset = bytenr;
file_key.type = BTRFS_EXTENT_CSUM_KEY; file_key.type = BTRFS_EXTENT_CSUM_KEY;
ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
@ -159,7 +159,8 @@ btrfs_lookup_csum(struct btrfs_trans_handle *trans,
goto fail; goto fail;
path->slots[0]--; path->slots[0]--;
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
if (found_key.type != BTRFS_EXTENT_CSUM_KEY) if (found_key.type != BTRFS_EXTENT_CSUM_KEY ||
found_key.objectid != csum_objectid)
goto fail; goto fail;
csum_offset = (bytenr - found_key.offset) / csum_offset = (bytenr - found_key.offset) /
@ -182,10 +183,10 @@ fail:
return ERR_PTR(ret); return ERR_PTR(ret);
} }
int btrfs_csum_file_block(struct btrfs_trans_handle *trans, int btrfs_csum_file_block(struct btrfs_trans_handle *trans, u64 logical,
u64 alloc_end, u64 bytenr, char *data, size_t len) u64 csum_objectid, u32 csum_type, const char *data)
{ {
struct btrfs_root *root = btrfs_csum_root(trans->fs_info, bytenr); struct btrfs_root *root = btrfs_csum_root(trans->fs_info, logical);
int ret = 0; int ret = 0;
struct btrfs_key file_key; struct btrfs_key file_key;
struct btrfs_key found_key; struct btrfs_key found_key;
@ -199,18 +200,18 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
u32 sectorsize = root->fs_info->sectorsize; u32 sectorsize = root->fs_info->sectorsize;
u32 nritems; u32 nritems;
u32 ins_size; u32 ins_size;
u16 csum_size = root->fs_info->csum_size; u16 csum_size = btrfs_csum_type_size(csum_type);
u16 csum_type = root->fs_info->csum_type;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; file_key.objectid = csum_objectid;
file_key.offset = bytenr; file_key.offset = logical;
file_key.type = BTRFS_EXTENT_CSUM_KEY; file_key.type = BTRFS_EXTENT_CSUM_KEY;
item = btrfs_lookup_csum(trans, root, path, bytenr, 1); item = btrfs_lookup_csum(trans, root, path, logical, csum_objectid,
csum_type, 1);
if (!IS_ERR(item)) { if (!IS_ERR(item)) {
leaf = path->nodes[0]; leaf = path->nodes[0];
ret = 0; ret = 0;
@ -241,7 +242,7 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
slot = 0; slot = 0;
} }
btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || if (found_key.objectid != csum_objectid ||
found_key.type != BTRFS_EXTENT_CSUM_KEY) { found_key.type != BTRFS_EXTENT_CSUM_KEY) {
found_next = 1; found_next = 1;
goto insert; goto insert;
@ -270,7 +271,7 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
leaf = path->nodes[0]; leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
csum_offset = (file_key.offset - found_key.offset) / sectorsize; csum_offset = (file_key.offset - found_key.offset) / sectorsize;
if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || if (found_key.objectid != csum_objectid ||
found_key.type != BTRFS_EXTENT_CSUM_KEY || found_key.type != BTRFS_EXTENT_CSUM_KEY ||
csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) {
goto insert; goto insert;
@ -290,7 +291,7 @@ insert:
btrfs_release_path(path); btrfs_release_path(path);
csum_offset = 0; csum_offset = 0;
if (found_next) { if (found_next) {
u64 tmp = min(alloc_end, next_offset); u64 tmp = min(logical + sectorsize, next_offset);
tmp -= file_key.offset; tmp -= file_key.offset;
tmp /= sectorsize; tmp /= sectorsize;
tmp = max((u64)1, tmp); tmp = max((u64)1, tmp);
@ -314,7 +315,8 @@ csum:
item = (struct btrfs_csum_item *)((unsigned char *)item + item = (struct btrfs_csum_item *)((unsigned char *)item +
csum_offset * csum_size); csum_offset * csum_size);
found: found:
btrfs_csum_data(root->fs_info, csum_type, (u8 *)data, csum_result, len); btrfs_csum_data(root->fs_info, csum_type, (u8 *)data, csum_result,
sectorsize);
write_extent_buffer(leaf, csum_result, (unsigned long)item, write_extent_buffer(leaf, csum_result, (unsigned long)item,
csum_size); csum_size);
btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_mark_buffer_dirty(path->nodes[0]);

View File

@ -80,8 +80,8 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
u64 objectid, u64 pos, u64 offset, u64 objectid, u64 pos, u64 offset,
u64 disk_num_bytes, u64 num_bytes); u64 disk_num_bytes, u64 num_bytes);
int btrfs_csum_file_block(struct btrfs_trans_handle *trans, int btrfs_csum_file_block(struct btrfs_trans_handle *trans, u64 logical,
u64 alloc_end, u64 bytenr, char *data, size_t len); u64 csum_objectid, u32 csum_type, const char *data);
int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans, int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 objectid, struct btrfs_root *root, u64 objectid,
u64 offset, const char *buffer, size_t size); u64 offset, const char *buffer, size_t size);

View File

@ -367,6 +367,11 @@ static int check_csum_item(struct extent_buffer *leaf, struct btrfs_key *key,
u32 sectorsize = fs_info->sectorsize; u32 sectorsize = fs_info->sectorsize;
const u32 csumsize = fs_info->csum_size; const u32 csumsize = fs_info->csum_size;
/* For fs under csum change, we should not check the regular csum items. */
if (unlikely(btrfs_super_flags(fs_info->super_copy) &
(BTRFS_SUPER_FLAG_CHANGING_DATA_CSUM |
BTRFS_SUPER_FLAG_CHANGING_META_CSUM)))
return 0;
if (unlikely(key->objectid != BTRFS_EXTENT_CSUM_OBJECTID)) { if (unlikely(key->objectid != BTRFS_EXTENT_CSUM_OBJECTID)) {
generic_err(leaf, slot, generic_err(leaf, slot,
"invalid key objectid for csum item, have %llu expect %llu", "invalid key objectid for csum item, have %llu expect %llu",

View File

@ -306,12 +306,13 @@ static int add_file_items(struct btrfs_trans_handle *trans,
struct btrfs_inode_item *btrfs_inode, u64 objectid, struct btrfs_inode_item *btrfs_inode, u64 objectid,
struct stat *st, const char *path_name) struct stat *st, const char *path_name)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info;
int ret = -1; int ret = -1;
ssize_t ret_read; ssize_t ret_read;
u64 bytes_read = 0; u64 bytes_read = 0;
struct btrfs_key key; struct btrfs_key key;
int blocks; int blocks;
u32 sectorsize = root->fs_info->sectorsize; u32 sectorsize = fs_info->sectorsize;
u64 first_block = 0; u64 first_block = 0;
u64 file_pos = 0; u64 file_pos = 0;
u64 cur_bytes; u64 cur_bytes;
@ -332,7 +333,7 @@ static int add_file_items(struct btrfs_trans_handle *trans,
if (st->st_size % sectorsize) if (st->st_size % sectorsize)
blocks += 1; blocks += 1;
if (st->st_size <= BTRFS_MAX_INLINE_DATA_SIZE(root->fs_info) && if (st->st_size <= BTRFS_MAX_INLINE_DATA_SIZE(fs_info) &&
st->st_size < sectorsize) { st->st_size < sectorsize) {
char *buffer = malloc(st->st_size); char *buffer = malloc(st->st_size);
@ -397,9 +398,9 @@ again:
goto end; goto end;
} }
ret = btrfs_csum_file_block(trans, ret = btrfs_csum_file_block(trans, first_block + bytes_read,
first_block + bytes_read + sectorsize, BTRFS_EXTENT_CSUM_OBJECTID,
first_block + bytes_read, buf, sectorsize); fs_info->csum_type, buf);
if (ret) if (ret)
goto end; goto end;

View File

@ -21,6 +21,7 @@
#include "kernel-shared/ctree.h" #include "kernel-shared/ctree.h"
#include "kernel-shared/disk-io.h" #include "kernel-shared/disk-io.h"
#include "kernel-shared/volumes.h" #include "kernel-shared/volumes.h"
#include "kernel-shared/file-item.h"
#include "kernel-shared/extent_io.h" #include "kernel-shared/extent_io.h"
#include "kernel-shared/transaction.h" #include "kernel-shared/transaction.h"
#include "common/messages.h" #include "common/messages.h"
@ -180,7 +181,14 @@ static int generate_new_csum_range(struct btrfs_trans_handle *trans,
goto out; goto out;
} }
/* Calculate new csum and insert it into the csum tree. */ /* Calculate new csum and insert it into the csum tree. */
ret = -EOPNOTSUPP; ret = btrfs_csum_file_block(trans, cur,
BTRFS_CSUM_CHANGE_OBJECTID, new_csum_type, buf);
if (ret < 0) {
errno = -ret;
error("failed to insert new csum for data at logical %llu: %m",
cur);
goto out;
}
} }
out: out:
free(buf); free(buf);