btrfs-progs: use read_data_from_disk() to replace read_extent_from_disk() and replace read_extent_data()

The function read_extent_from_disk() is only a wrapper to read tree
block.

And read_extent_data() is just a while loop to eliminate short read
caused by stripe boundary.

In fact, a lot of call sites of read_extent_data() are either reading
metadata (thus no possible short read) or doing extra loop by
themselves.

This patch will replace those two functions with read_data_from_disk(),
making it the only entrance for data/metadata read.
And update read_data_from_disk() to return the read bytes, so caller can
do a simple while loop.

For the few callers of read_extent_data(), open-code a small while loop
for them.

This will allow later RAID56 read repair using P/Q much easier.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2022-04-05 20:48:27 +08:00 committed by David Sterba
parent 2a93728391
commit 3ff9d35257
13 changed files with 80 additions and 176 deletions

View File

@ -40,36 +40,18 @@ static int debug_corrupt_block(struct extent_buffer *eb,
struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 copy)
{
int ret;
u64 length;
struct btrfs_multi_bio *multi = NULL;
struct btrfs_device *device;
int num_copies;
int mirror_num = 1;
length = blocksize;
while (1) {
ret = btrfs_map_block(root->fs_info, READ, eb->start, &length,
&multi, mirror_num, NULL);
if (ret) {
error("cannot map block %llu length %llu mirror %d: %d",
(unsigned long long)eb->start,
(unsigned long long)length,
mirror_num, ret);
return ret;
}
device = multi->stripes[0].dev;
eb->fd = device->fd;
device->total_ios++;
eb->dev_bytenr = multi->stripes[0].physical;
fprintf(stdout,
"mirror %d logical %llu physical %llu device %s\n",
mirror_num, (unsigned long long)bytenr,
(unsigned long long)eb->dev_bytenr, device->name);
free(multi);
if (!copy || mirror_num == copy) {
ret = read_extent_from_disk(eb, 0, eb->len);
u64 read_len = eb->len;
ret = read_data_from_disk(eb->fs_info, eb->data,
eb->start, &read_len,
mirror_num);
if (read_len < eb->len)
ret = -EIO;
if (ret < 0) {
errno = -ret;
error("cannot read eb bytenr %llu: %m",

View File

@ -173,8 +173,9 @@ static int write_extent_content(struct btrfs_fs_info *fs_info, int out_fd,
while (cur_offset < length) {
cur_len = min_t(u64, length - cur_offset, BUFFER_SIZE);
ret = read_extent_data(fs_info, buffer,
logical + cur_offset, &cur_len, mirror);
ret = read_data_from_disk(fs_info, buffer,
logical + cur_offset, &cur_len,
mirror);
if (ret < 0) {
errno = -ret;
fprintf(stderr,

View File

@ -337,7 +337,8 @@ static int populate_csum(struct btrfs_trans_handle *trans,
while (offset < len) {
sectorsize = fs_info->sectorsize;
ret = read_extent_data(fs_info, buf, start + offset, &sectorsize, 0);
ret = read_data_from_disk(fs_info, buf, start + offset,
&sectorsize, 0);
if (ret)
break;
ret = btrfs_csum_file_block(trans, start + len, start + offset,

View File

@ -5840,7 +5840,7 @@ static int check_extent_csums(struct btrfs_root *root, u64 bytenr,
for (mirror = 1; mirror <= num_copies; mirror++) {
read_len = num_bytes - offset;
/* read as much space once a time */
ret = read_extent_data(gfs_info, (char *)data + offset,
ret = read_data_from_disk(gfs_info, (char *)data + offset,
bytenr + offset, &read_len, mirror);
if (ret)
goto out;

View File

@ -1203,8 +1203,8 @@ static int populate_csum(struct btrfs_trans_handle *trans,
while (offset < len) {
sectorsize = gfs_info->sectorsize;
ret = read_extent_data(gfs_info, buf, start + offset,
&sectorsize, 0);
ret = read_data_from_disk(gfs_info, buf, start + offset,
&sectorsize, 0);
if (ret)
break;
ret = btrfs_csum_file_block(trans, start + len, start + offset,

View File

@ -407,8 +407,8 @@ again:
cur = bytenr;
while (cur < bytenr + size_left) {
length = bytenr + size_left - cur;
ret = read_extent_data(root->fs_info, inbuf + cur - bytenr, cur,
&length, mirror_num);
ret = read_data_from_disk(root->fs_info, inbuf + cur - bytenr, cur,
&length, mirror_num);
if (ret < 0) {
mirror_num++;
if (mirror_num > num_copies) {

View File

@ -615,7 +615,7 @@ static int read_data_extent(struct metadump_struct *md,
for (cur_mirror = 1; cur_mirror <= num_copies; cur_mirror++) {
while (bytes_left) {
read_len = bytes_left;
ret = read_extent_data(fs_info,
ret = read_data_from_disk(fs_info,
(char *)(async->buffer + offset),
logical, &read_len, cur_mirror);
if (ret < 0)

View File

@ -319,45 +319,20 @@ static int read_on_restore(struct extent_buffer *eb)
int read_whole_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, int mirror)
{
unsigned long offset = 0;
struct btrfs_multi_bio *multi = NULL;
struct btrfs_device *device;
int ret = 0;
u64 read_len;
unsigned long bytes_left = eb->len;
while (bytes_left) {
read_len = bytes_left;
device = NULL;
u64 read_len = bytes_left;
if (info->on_restoring)
return read_on_restore(eb);
ret = btrfs_map_block(info, READ, eb->start + offset,
&read_len, &multi, mirror, NULL);
if (ret) {
printk("Couldn't map the block %llu\n", eb->start + offset);
kfree(multi);
return -EIO;
}
device = multi->stripes[0].dev;
if (device->fd <= 0) {
kfree(multi);
return -EIO;
}
eb->fd = device->fd;
device->total_ios++;
eb->dev_bytenr = multi->stripes[0].physical;
kfree(multi);
multi = NULL;
if (read_len > bytes_left)
read_len = bytes_left;
ret = read_extent_from_disk(eb, offset, read_len);
if (ret)
return -EIO;
ret = read_data_from_disk(info, eb->data + offset,
eb->start + offset, &read_len,
mirror);
if (ret < 0)
return ret;
offset += read_len;
bytes_left -= read_len;
}
@ -474,42 +449,6 @@ struct extent_buffer* read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
return ERR_PTR(ret);
}
int read_extent_data(struct btrfs_fs_info *fs_info, char *data, u64 logical,
u64 *len, int mirror)
{
u64 offset = 0;
struct btrfs_multi_bio *multi = NULL;
struct btrfs_device *device;
int ret = 0;
u64 max_len = *len;
ret = btrfs_map_block(fs_info, READ, logical, len, &multi, mirror,
NULL);
if (ret) {
fprintf(stderr, "Couldn't map the block %llu\n",
logical + offset);
goto err;
}
device = multi->stripes[0].dev;
if (*len > max_len)
*len = max_len;
if (device->fd < 0) {
ret = -EIO;
goto err;
}
ret = btrfs_pread(device->fd, data, *len, multi->stripes[0].physical,
fs_info->zoned);
if (ret != *len)
ret = -EIO;
else
ret = 0;
err:
kfree(multi);
return ret;
}
int write_and_map_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
{
int ret;

View File

@ -141,8 +141,6 @@ int read_whole_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, int mirr
struct extent_buffer* read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
u64 parent_transid);
int read_extent_data(struct btrfs_fs_info *fs_info, char *data, u64 logical,
u64 *len, int mirror);
void readahead_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
u64 parent_transid);
struct extent_buffer* btrfs_find_create_tree_block(

View File

@ -28,6 +28,7 @@
#include "kernel-lib/list.h"
#include "kernel-shared/ctree.h"
#include "kernel-shared/volumes.h"
#include "kernel-shared/disk-io.h"
#include "common/utils.h"
#include "common/device-utils.h"
#include "common/internal.h"
@ -789,69 +790,41 @@ struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
return ret;
}
int read_extent_from_disk(struct extent_buffer *eb,
unsigned long offset, unsigned long len)
{
int ret;
ret = btrfs_pread(eb->fd, eb->data + offset, len, eb->dev_bytenr,
eb->fs_info->zoned);
if (ret < 0) {
ret = -errno;
goto out;
}
if (ret != len) {
ret = -EIO;
goto out;
}
ret = 0;
out:
return ret;
}
int read_data_from_disk(struct btrfs_fs_info *info, void *buf, u64 offset,
u64 bytes, int mirror)
int read_data_from_disk(struct btrfs_fs_info *info, void *buf, u64 logical,
u64 *len, int mirror)
{
struct btrfs_multi_bio *multi = NULL;
struct btrfs_device *device;
u64 bytes_left = bytes;
u64 read_len;
u64 total_read = 0;
u64 read_len = *len;
int ret;
while (bytes_left) {
read_len = bytes_left;
ret = btrfs_map_block(info, READ, offset, &read_len, &multi,
mirror, NULL);
if (ret) {
fprintf(stderr, "Couldn't map the block %llu\n",
offset);
return -EIO;
}
device = multi->stripes[0].dev;
ret = btrfs_map_block(info, READ, logical, &read_len, &multi, mirror,
NULL);
if (ret) {
fprintf(stderr, "Couldn't map the block %llu\n", logical);
return -EIO;
}
device = multi->stripes[0].dev;
read_len = min(bytes_left, read_len);
if (device->fd <= 0) {
kfree(multi);
return -EIO;
}
ret = btrfs_pread(device->fd, buf + total_read, read_len,
multi->stripes[0].physical, info->zoned);
read_len = min(*len, read_len);
if (device->fd <= 0) {
kfree(multi);
if (ret < 0) {
fprintf(stderr, "Error reading %llu, %d\n", offset,
ret);
return ret;
}
if (ret != read_len) {
fprintf(stderr, "Short read for %llu, read %d, "
"read_len %llu\n", offset, ret, read_len);
return -EIO;
}
return -EIO;
}
bytes_left -= read_len;
offset += read_len;
total_read += read_len;
ret = btrfs_pread(device->fd, buf, read_len,
multi->stripes[0].physical, info->zoned);
kfree(multi);
if (ret < 0) {
fprintf(stderr, "Error reading %llu, %d\n", logical,
ret);
return ret;
}
if (ret != read_len) {
fprintf(stderr,
"Short read for %llu, read %d, read_len %llu\n",
logical, ret, read_len);
return -EIO;
}
return 0;

View File

@ -150,8 +150,6 @@ struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
u64 bytenr, u32 blocksize);
void free_extent_buffer(struct extent_buffer *eb);
void free_extent_buffer_nocache(struct extent_buffer *eb);
int read_extent_from_disk(struct extent_buffer *eb,
unsigned long offset, unsigned long len);
int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
unsigned long start, unsigned long len);
void read_extent_buffer(const struct extent_buffer *eb, void *dst,
@ -169,8 +167,8 @@ int extent_buffer_test_bit(struct extent_buffer *eb, unsigned long start,
unsigned long nr);
int set_extent_buffer_dirty(struct extent_buffer *eb);
int clear_extent_buffer_dirty(struct extent_buffer *eb);
int read_data_from_disk(struct btrfs_fs_info *info, void *buf, u64 offset,
u64 bytes, int mirror);
int read_data_from_disk(struct btrfs_fs_info *info, void *buf, u64 logical,
u64 *len, int mirror);
int write_data_to_disk(struct btrfs_fs_info *info, void *buf, u64 offset,
u64 bytes, int mirror);
void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start,

View File

@ -225,11 +225,11 @@ int btrfs_read_file(struct btrfs_root *root, u64 ino, u64 start, int len,
memset(dest, 0, len);
while (1) {
struct btrfs_file_extent_item *fi;
u64 offset = 0;
u64 extent_start;
u64 extent_len;
u64 read_start;
u64 read_len;
u64 read_len_ret;
u64 disk_bytenr;
leaf = path.nodes[0];
@ -282,14 +282,16 @@ int btrfs_read_file(struct btrfs_root *root, u64 ino, u64 start, int len,
disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi) +
btrfs_file_extent_offset(leaf, fi);
read_len_ret = read_len;
ret = read_extent_data(fs_info, dest + read_start - start, disk_bytenr,
&read_len_ret, 0);
if (ret < 0)
break;
/* Short read, something went wrong */
if (read_len_ret != read_len)
return -EIO;
while (offset < read_len) {
u64 read_len_ret = read_len - offset;
ret = read_data_from_disk(fs_info,
dest + read_start - start + offset,
disk_bytenr + offset, &read_len_ret, 0);
if (ret < 0)
goto out;
offset += read_len_ret;
}
read += read_len;
next:
ret = btrfs_next_item(root, &path);

View File

@ -118,6 +118,8 @@ static int io_ctl_prepare_pages(struct io_ctl *io_ctl, struct btrfs_root *root,
}
while (total_read < io_ctl->total_size) {
u64 offset = 0;
if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
ret = btrfs_next_leaf(root, path);
if (ret) {
@ -150,11 +152,19 @@ static int io_ctl_prepare_pages(struct io_ctl *io_ctl, struct btrfs_root *root,
bytenr = btrfs_file_extent_disk_bytenr(leaf, fi) +
btrfs_file_extent_offset(leaf, fi);
len = btrfs_file_extent_num_bytes(leaf, fi);
ret = read_data_from_disk(root->fs_info,
io_ctl->buffer + key.offset, bytenr,
len, 0);
if (ret)
break;
while (offset < len) {
u64 read_len = len - offset;
ret = read_data_from_disk(root->fs_info,
io_ctl->buffer + key.offset + offset,
bytenr + offset,
&read_len, 0);
if (ret < 0) {
btrfs_release_path(path);
return ret;
}
offset += read_len;
}
total_read += len;
path->slots[0]++;
}