fs: btrfs: Introduce lookup_data_extent() for later use

This implements lookup_data_extent() function for the incoming
new implementation of btrfs_file_read().

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: Marek Behún <marek.behun@nic.cz>
This commit is contained in:
Qu Wenruo 2020-06-24 18:03:10 +02:00 committed by Tom Rini
parent a26a6bedaf
commit 01347f64d5

View File

@ -825,3 +825,104 @@ out:
free(dbuf);
return ret;
}
/*
* Get the first file extent that covers bytenr @file_offset.
*
* @file_offset must be aligned to sectorsize.
*
* return 0 for found, and path points to the file extent.
* return >0 for not found, and fill @next_offset.
* @next_offset can be 0 if there is no next file extent.
* return <0 for error.
*/
static int lookup_data_extent(struct btrfs_root *root, struct btrfs_path *path,
u64 ino, u64 file_offset, u64 *next_offset)
{
struct btrfs_key key;
struct btrfs_file_extent_item *fi;
u8 extent_type;
int ret = 0;
ASSERT(IS_ALIGNED(file_offset, root->fs_info->sectorsize));
key.objectid = ino;
key.type = BTRFS_EXTENT_DATA_KEY;
key.offset = file_offset;
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
/* Error or we're already at the file extent */
if (ret <= 0)
return ret;
if (ret > 0) {
/* Check previous file extent */
ret = btrfs_previous_item(root, path, ino,
BTRFS_EXTENT_DATA_KEY);
if (ret < 0)
return ret;
if (ret > 0)
goto check_next;
}
/* Now the key.offset must be smaller than @file_offset */
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
if (key.objectid != ino ||
key.type != BTRFS_EXTENT_DATA_KEY)
goto check_next;
fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_file_extent_item);
extent_type = btrfs_file_extent_type(path->nodes[0], fi);
if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
if (file_offset == 0)
return 0;
/* Inline extent should be the only extent, no next extent. */
*next_offset = 0;
return 1;
}
/* This file extent covers @file_offset */
if (key.offset <= file_offset && key.offset +
btrfs_file_extent_num_bytes(path->nodes[0], fi) > file_offset)
return 0;
check_next:
ret = btrfs_next_item(root, path);
if (ret < 0)
return ret;
if (ret > 0) {
*next_offset = 0;
return 1;
}
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_file_extent_item);
/* Next next data extent */
if (key.objectid != ino ||
key.type != BTRFS_EXTENT_DATA_KEY) {
*next_offset = 0;
return 1;
}
/* Current file extent already beyond @file_offset */
if (key.offset > file_offset) {
*next_offset = key.offset;
return 1;
}
/* This file extent covers @file_offset */
if (key.offset <= file_offset && key.offset +
btrfs_file_extent_num_bytes(path->nodes[0], fi) > file_offset)
return 0;
/* This file extent ends before @file_offset, check next */
ret = btrfs_next_item(root, path);
if (ret < 0)
return ret;
if (ret > 0) {
*next_offset = 0;
return 1;
}
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
if (key.type != BTRFS_EXTENT_DATA_KEY || key.objectid != ino) {
*next_offset = 0;
return 1;
}
*next_offset = key.offset;
return 1;
}