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:
parent
a26a6bedaf
commit
01347f64d5
101
fs/btrfs/inode.c
101
fs/btrfs/inode.c
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user