mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 08:02:07 +00:00
btrfs: backref: introduce the skeleton of btrfs_backref_iter
Due to the complex nature of btrfs extent tree, when we want to iterate all backrefs of one extent, this involves quite a lot of work, like searching the EXTENT_ITEM/METADATA_ITEM, iteration through inline and keyed backrefs. Normally this would result in a complex code, something like: btrfs_search_slot() /* Ensure we are at EXTENT_ITEM/METADATA_ITEM */ while (1) { /* Loop for extent tree items */ while (ptr < end) { /* Loop for inlined items */ /* Real work here */ } next: ret = btrfs_next_item() /* Ensure we're still at keyed item for specified bytenr */ } The idea of btrfs_backref_iter is to avoid such complex and hard to read code structure, but something like the following: iter = btrfs_backref_iter_alloc(); ret = btrfs_backref_iter_start(iter, bytenr); if (ret < 0) goto out; for (; ; ret = btrfs_backref_iter_next(iter)) { /* Real work here */ } out: btrfs_backref_iter_free(iter); This patch is just the skeleton + btrfs_backref_iter_start() code. Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Reviewed-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
78d933c79c
commit
a37f232b7b
@ -2295,3 +2295,113 @@ void free_ipath(struct inode_fs_paths *ipath)
|
|||||||
kvfree(ipath->fspath);
|
kvfree(ipath->fspath);
|
||||||
kfree(ipath);
|
kfree(ipath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct btrfs_backref_iter *btrfs_backref_iter_alloc(
|
||||||
|
struct btrfs_fs_info *fs_info, gfp_t gfp_flag)
|
||||||
|
{
|
||||||
|
struct btrfs_backref_iter *ret;
|
||||||
|
|
||||||
|
ret = kzalloc(sizeof(*ret), gfp_flag);
|
||||||
|
if (!ret)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret->path = btrfs_alloc_path();
|
||||||
|
if (!ret) {
|
||||||
|
kfree(ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Current backref iterator only supports iteration in commit root */
|
||||||
|
ret->path->search_commit_root = 1;
|
||||||
|
ret->path->skip_locking = 1;
|
||||||
|
ret->fs_info = fs_info;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
|
||||||
|
{
|
||||||
|
struct btrfs_fs_info *fs_info = iter->fs_info;
|
||||||
|
struct btrfs_path *path = iter->path;
|
||||||
|
struct btrfs_extent_item *ei;
|
||||||
|
struct btrfs_key key;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
key.objectid = bytenr;
|
||||||
|
key.type = BTRFS_METADATA_ITEM_KEY;
|
||||||
|
key.offset = (u64)-1;
|
||||||
|
iter->bytenr = bytenr;
|
||||||
|
|
||||||
|
ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = -EUCLEAN;
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
if (path->slots[0] == 0) {
|
||||||
|
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
|
||||||
|
ret = -EUCLEAN;
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
path->slots[0]--;
|
||||||
|
|
||||||
|
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
|
||||||
|
if ((key.type != BTRFS_EXTENT_ITEM_KEY &&
|
||||||
|
key.type != BTRFS_METADATA_ITEM_KEY) || key.objectid != bytenr) {
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
memcpy(&iter->cur_key, &key, sizeof(key));
|
||||||
|
iter->item_ptr = (u32)btrfs_item_ptr_offset(path->nodes[0],
|
||||||
|
path->slots[0]);
|
||||||
|
iter->end_ptr = (u32)(iter->item_ptr +
|
||||||
|
btrfs_item_size_nr(path->nodes[0], path->slots[0]));
|
||||||
|
ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
|
||||||
|
struct btrfs_extent_item);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only support iteration on tree backref yet.
|
||||||
|
*
|
||||||
|
* This is an extra precaution for non skinny-metadata, where
|
||||||
|
* EXTENT_ITEM is also used for tree blocks, that we can only use
|
||||||
|
* extent flags to determine if it's a tree block.
|
||||||
|
*/
|
||||||
|
if (btrfs_extent_flags(path->nodes[0], ei) & BTRFS_EXTENT_FLAG_DATA) {
|
||||||
|
ret = -ENOTSUPP;
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
iter->cur_ptr = (u32)(iter->item_ptr + sizeof(*ei));
|
||||||
|
|
||||||
|
/* If there is no inline backref, go search for keyed backref */
|
||||||
|
if (iter->cur_ptr >= iter->end_ptr) {
|
||||||
|
ret = btrfs_next_item(fs_info->extent_root, path);
|
||||||
|
|
||||||
|
/* No inline nor keyed ref */
|
||||||
|
if (ret > 0) {
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
if (ret < 0)
|
||||||
|
goto release;
|
||||||
|
|
||||||
|
btrfs_item_key_to_cpu(path->nodes[0], &iter->cur_key,
|
||||||
|
path->slots[0]);
|
||||||
|
if (iter->cur_key.objectid != bytenr ||
|
||||||
|
(iter->cur_key.type != BTRFS_SHARED_BLOCK_REF_KEY &&
|
||||||
|
iter->cur_key.type != BTRFS_TREE_BLOCK_REF_KEY)) {
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
iter->cur_ptr = (u32)btrfs_item_ptr_offset(path->nodes[0],
|
||||||
|
path->slots[0]);
|
||||||
|
iter->item_ptr = iter->cur_ptr;
|
||||||
|
iter->end_ptr = (u32)(iter->item_ptr + btrfs_item_size_nr(
|
||||||
|
path->nodes[0], path->slots[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
release:
|
||||||
|
btrfs_backref_iter_release(iter);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -78,4 +78,42 @@ struct prelim_ref {
|
|||||||
u64 wanted_disk_byte;
|
u64 wanted_disk_byte;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iterate backrefs of one extent.
|
||||||
|
*
|
||||||
|
* Now it only supports iteration of tree block in commit root.
|
||||||
|
*/
|
||||||
|
struct btrfs_backref_iter {
|
||||||
|
u64 bytenr;
|
||||||
|
struct btrfs_path *path;
|
||||||
|
struct btrfs_fs_info *fs_info;
|
||||||
|
struct btrfs_key cur_key;
|
||||||
|
u32 item_ptr;
|
||||||
|
u32 cur_ptr;
|
||||||
|
u32 end_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct btrfs_backref_iter *btrfs_backref_iter_alloc(
|
||||||
|
struct btrfs_fs_info *fs_info, gfp_t gfp_flag);
|
||||||
|
|
||||||
|
static inline void btrfs_backref_iter_free(struct btrfs_backref_iter *iter)
|
||||||
|
{
|
||||||
|
if (!iter)
|
||||||
|
return;
|
||||||
|
btrfs_free_path(iter->path);
|
||||||
|
kfree(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr);
|
||||||
|
|
||||||
|
static inline void btrfs_backref_iter_release(struct btrfs_backref_iter *iter)
|
||||||
|
{
|
||||||
|
iter->bytenr = 0;
|
||||||
|
iter->item_ptr = 0;
|
||||||
|
iter->cur_ptr = 0;
|
||||||
|
iter->end_ptr = 0;
|
||||||
|
btrfs_release_path(iter->path);
|
||||||
|
memset(&iter->cur_key, 0, sizeof(iter->cur_key));
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user