Commit 637e3b48 authored by Josef Bacik's avatar Josef Bacik Committed by David Sterba

btrfs: add helpers for manipulating leaf items and data

We have some gnarly memmove and copy_extent_buffer calls for leaf
manipulation.  This is because our item offsets aren't absolute, they're
based on 0 being where the items start in the leaf, which is after the
btrfs_header.  This means any manipulation of the data requires adding
sizeof(struct btrfs_header) to the offsets we pull from the items.
Moving the items themselves is easier as the helpers are absolute
offsets, however we of course have to call the helpers to get the
offsets for the item numbers.  This makes for
copy_extent_buffer/memmove_extent_buffer calls that are kind of hard to
reason about what's happening.

Fix this by pushing this logic into helpers.  For data we'll only use
the item provided offsets, and the helpers will use the
BTRFS_LEAF_DATA_OFFSET addition for the offsets.  Additionally for the
item manipulation simply pass in the item numbers, and then the helpers
will call the offset helper to get the actual offset into the leaf.

The diffstat makes this look like more code, but that's simply because I
added comments for the helpers, it's net negative for the amount of
code, and is easier to reason.
Signed-off-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent e23efd8e
......@@ -65,6 +65,91 @@ static unsigned int leaf_data_end(const struct extent_buffer *leaf)
return btrfs_item_offset(leaf, nr - 1);
}
/*
* Move data in a @leaf (using memmove, safe for overlapping ranges).
*
* @leaf: leaf that we're doing a memmove on
* @dst_offset: item data offset we're moving to
* @src_offset: item data offset were' moving from
* @len: length of the data we're moving
*
* Wrapper around memmove_extent_buffer() that takes into account the header on
* the leaf. The btrfs_item offset's start directly after the header, so we
* have to adjust any offsets to account for the header in the leaf. This
* handles that math to simplify the callers.
*/
static inline void memmove_leaf_data(const struct extent_buffer *leaf,
unsigned long dst_offset,
unsigned long src_offset,
unsigned long len)
{
memmove_extent_buffer(leaf, BTRFS_LEAF_DATA_OFFSET + dst_offset,
BTRFS_LEAF_DATA_OFFSET + src_offset, len);
}
/*
* Copy item data from @src into @dst at the given @offset.
*
* @dst: destination leaf that we're copying into
* @src: source leaf that we're copying from
* @dst_offset: item data offset we're copying to
* @src_offset: item data offset were' copying from
* @len: length of the data we're copying
*
* Wrapper around copy_extent_buffer() that takes into account the header on
* the leaf. The btrfs_item offset's start directly after the header, so we
* have to adjust any offsets to account for the header in the leaf. This
* handles that math to simplify the callers.
*/
static inline void copy_leaf_data(const struct extent_buffer *dst,
const struct extent_buffer *src,
unsigned long dst_offset,
unsigned long src_offset, unsigned long len)
{
copy_extent_buffer(dst, src, BTRFS_LEAF_DATA_OFFSET + dst_offset,
BTRFS_LEAF_DATA_OFFSET + src_offset, len);
}
/*
* Move items in a @leaf (using memmove).
*
* @dst: destination leaf for the items
* @dst_item: the item nr we're copying into
* @src_item: the item nr we're copying from
* @nr_items: the number of items to copy
*
* Wrapper around memmove_extent_buffer() that does the math to get the
* appropriate offsets into the leaf from the item numbers.
*/
static inline void memmove_leaf_items(const struct extent_buffer *leaf,
int dst_item, int src_item, int nr_items)
{
memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, dst_item),
btrfs_item_nr_offset(leaf, src_item),
nr_items * sizeof(struct btrfs_item));
}
/*
* Copy items from @src into @dst at the given @offset.
*
* @dst: destination leaf for the items
* @src: source leaf for the items
* @dst_item: the item nr we're copying into
* @src_item: the item nr we're copying from
* @nr_items: the number of items to copy
*
* Wrapper around copy_extent_buffer() that does the math to get the
* appropriate offsets into the leaf from the item numbers.
*/
static inline void copy_leaf_items(const struct extent_buffer *dst,
const struct extent_buffer *src,
int dst_item, int src_item, int nr_items)
{
copy_extent_buffer(dst, src, btrfs_item_nr_offset(dst, dst_item),
btrfs_item_nr_offset(src, src_item),
nr_items * sizeof(struct btrfs_item));
}
int btrfs_super_csum_size(const struct btrfs_super_block *s)
{
u16 t = btrfs_super_csum_type(s);
......@@ -3022,25 +3107,17 @@ static noinline int __push_leaf_right(struct btrfs_path *path,
/* make room in the right data area */
data_end = leaf_data_end(right);
memmove_extent_buffer(right,
BTRFS_LEAF_DATA_OFFSET + data_end - push_space,
BTRFS_LEAF_DATA_OFFSET + data_end,
BTRFS_LEAF_DATA_SIZE(fs_info) - data_end);
memmove_leaf_data(right, data_end - push_space, data_end,
BTRFS_LEAF_DATA_SIZE(fs_info) - data_end);
/* copy from the left data area */
copy_extent_buffer(right, left, BTRFS_LEAF_DATA_OFFSET +
BTRFS_LEAF_DATA_SIZE(fs_info) - push_space,
BTRFS_LEAF_DATA_OFFSET + leaf_data_end(left),
push_space);
copy_leaf_data(right, left, BTRFS_LEAF_DATA_SIZE(fs_info) - push_space,
leaf_data_end(left), push_space);
memmove_extent_buffer(right, btrfs_item_nr_offset(right, push_items),
btrfs_item_nr_offset(right, 0),
right_nritems * sizeof(struct btrfs_item));
memmove_leaf_items(right, push_items, 0, right_nritems);
/* copy the items from left to right */
copy_extent_buffer(right, left, btrfs_item_nr_offset(right, 0),
btrfs_item_nr_offset(left, left_nritems - push_items),
push_items * sizeof(struct btrfs_item));
copy_leaf_items(right, left, 0, left_nritems - push_items, push_items);
/* update the item pointers */
btrfs_init_map_token(&token, right);
......@@ -3232,19 +3309,13 @@ static noinline int __push_leaf_left(struct btrfs_path *path, int data_size,
WARN_ON(!empty && push_items == btrfs_header_nritems(right));
/* push data from right to left */
copy_extent_buffer(left, right,
btrfs_item_nr_offset(left, btrfs_header_nritems(left)),
btrfs_item_nr_offset(right, 0),
push_items * sizeof(struct btrfs_item));
copy_leaf_items(left, right, btrfs_header_nritems(left), 0, push_items);
push_space = BTRFS_LEAF_DATA_SIZE(fs_info) -
btrfs_item_offset(right, push_items - 1);
copy_extent_buffer(left, right, BTRFS_LEAF_DATA_OFFSET +
leaf_data_end(left) - push_space,
BTRFS_LEAF_DATA_OFFSET +
btrfs_item_offset(right, push_items - 1),
push_space);
copy_leaf_data(left, right, leaf_data_end(left) - push_space,
btrfs_item_offset(right, push_items - 1), push_space);
old_left_nritems = btrfs_header_nritems(left);
BUG_ON(old_left_nritems <= 0);
......@@ -3267,15 +3338,12 @@ static noinline int __push_leaf_left(struct btrfs_path *path, int data_size,
if (push_items < right_nritems) {
push_space = btrfs_item_offset(right, push_items - 1) -
leaf_data_end(right);
memmove_extent_buffer(right, BTRFS_LEAF_DATA_OFFSET +
BTRFS_LEAF_DATA_SIZE(fs_info) - push_space,
BTRFS_LEAF_DATA_OFFSET +
leaf_data_end(right), push_space);
memmove_leaf_data(right,
BTRFS_LEAF_DATA_SIZE(fs_info) - push_space,
leaf_data_end(right), push_space);
memmove_extent_buffer(right, btrfs_item_nr_offset(right, 0),
btrfs_item_nr_offset(left, push_items),
(btrfs_header_nritems(right) - push_items) *
sizeof(struct btrfs_item));
memmove_leaf_items(right, 0, push_items,
btrfs_header_nritems(right) - push_items);
}
btrfs_init_map_token(&token, right);
......@@ -3407,14 +3475,10 @@ static noinline void copy_for_split(struct btrfs_trans_handle *trans,
btrfs_set_header_nritems(right, nritems);
data_copy_size = btrfs_item_data_end(l, mid) - leaf_data_end(l);
copy_extent_buffer(right, l, btrfs_item_nr_offset(right, 0),
btrfs_item_nr_offset(l, mid),
nritems * sizeof(struct btrfs_item));
copy_leaf_items(right, l, 0, mid, nritems);
copy_extent_buffer(right, l,
BTRFS_LEAF_DATA_OFFSET + BTRFS_LEAF_DATA_SIZE(fs_info) -
data_copy_size, BTRFS_LEAF_DATA_OFFSET +
leaf_data_end(l), data_copy_size);
copy_leaf_data(right, l, BTRFS_LEAF_DATA_SIZE(fs_info) - data_copy_size,
leaf_data_end(l), data_copy_size);
rt_data_off = BTRFS_LEAF_DATA_SIZE(fs_info) - btrfs_item_data_end(l, mid);
......@@ -3784,9 +3848,7 @@ static noinline int split_item(struct btrfs_path *path,
nritems = btrfs_header_nritems(leaf);
if (slot != nritems) {
/* shift the items */
memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, slot + 1),
btrfs_item_nr_offset(leaf, slot),
(nritems - slot) * sizeof(struct btrfs_item));
memmove_leaf_items(leaf, slot + 1, slot, nritems - slot);
}
btrfs_cpu_key_to_disk(&disk_key, new_key);
......@@ -3897,9 +3959,8 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
/* shift the data */
if (from_end) {
memmove_extent_buffer(leaf, BTRFS_LEAF_DATA_OFFSET +
data_end + size_diff, BTRFS_LEAF_DATA_OFFSET +
data_end, old_data_start + new_size - data_end);
memmove_leaf_data(leaf, data_end + size_diff, data_end,
old_data_start + new_size - data_end);
} else {
struct btrfs_disk_key disk_key;
u64 offset;
......@@ -3924,9 +3985,8 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)
}
}
memmove_extent_buffer(leaf, BTRFS_LEAF_DATA_OFFSET +
data_end + size_diff, BTRFS_LEAF_DATA_OFFSET +
data_end, old_data_start - data_end);
memmove_leaf_data(leaf, data_end + size_diff, data_end,
old_data_start - data_end);
offset = btrfs_disk_key_offset(&disk_key);
btrfs_set_disk_key_offset(&disk_key, offset + size_diff);
......@@ -3991,9 +4051,8 @@ void btrfs_extend_item(struct btrfs_path *path, u32 data_size)
}
/* shift the data */
memmove_extent_buffer(leaf, BTRFS_LEAF_DATA_OFFSET +
data_end - data_size, BTRFS_LEAF_DATA_OFFSET +
data_end, old_data - data_end);
memmove_leaf_data(leaf, data_end - data_size, data_end,
old_data - data_end);
data_end = old_data;
old_size = btrfs_item_size(leaf, slot);
......@@ -4077,16 +4136,11 @@ static void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *p
ioff - batch->total_data_size);
}
/* shift the items */
memmove_extent_buffer(leaf,
btrfs_item_nr_offset(leaf, slot + batch->nr),
btrfs_item_nr_offset(leaf, slot),
(nritems - slot) * sizeof(struct btrfs_item));
memmove_leaf_items(leaf, slot + batch->nr, slot, nritems - slot);
/* shift the data */
memmove_extent_buffer(leaf, BTRFS_LEAF_DATA_OFFSET +
data_end - batch->total_data_size,
BTRFS_LEAF_DATA_OFFSET + data_end,
old_data - data_end);
memmove_leaf_data(leaf, data_end - batch->total_data_size,
data_end, old_data - data_end);
data_end = old_data;
}
......@@ -4321,10 +4375,8 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
for (i = 0; i < nr; i++)
dsize += btrfs_item_size(leaf, slot + i);
memmove_extent_buffer(leaf, BTRFS_LEAF_DATA_OFFSET +
data_end + dsize,
BTRFS_LEAF_DATA_OFFSET + data_end,
last_off - data_end);
memmove_leaf_data(leaf, data_end + dsize, data_end,
last_off - data_end);
btrfs_init_map_token(&token, leaf);
for (i = slot + nr; i < nritems; i++) {
......@@ -4334,10 +4386,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
btrfs_set_token_item_offset(&token, i, ioff + dsize);
}
memmove_extent_buffer(leaf, btrfs_item_nr_offset(leaf, slot),
btrfs_item_nr_offset(leaf, slot + nr),
sizeof(struct btrfs_item) *
(nritems - slot - nr));
memmove_leaf_items(leaf, slot, slot + nr, nritems - slot - nr);
}
btrfs_set_header_nritems(leaf, nritems - nr);
nritems -= nr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment