Any comments?
Thanks
Miao
On thu, 13 Jun 2013 20:22:17 +0800, Miao Xie wrote:> Before applying this patch, we search the csum item at first, and If the
> new csums is adjoining to the existed csum item, we call
btrfs_search_slot()
> to grow this item. It is unnecessary because we can re-use the first search
> result, if so, we can reduce the time of the csum insertion.
>
> And Without this patch, in order to avoid the overlap of the csum items,
> we had to search the tree to get the next csum item if it was in the next
> leaf. It was also inefficient, we can get the information of the next csum
> item while we look up the csum item.
>
> This patch improved these problems.
>
> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
> ---
> fs/btrfs/ctree.c | 25 ++++++
> fs/btrfs/ctree.h | 2 +
> fs/btrfs/file-item.c | 249
++++++++++++++++++++++-----------------------------
> 3 files changed, 133 insertions(+), 143 deletions(-)
>
> diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> index 02fae7f..d2f69d8 100644
> --- a/fs/btrfs/ctree.c
> +++ b/fs/btrfs/ctree.c
> @@ -144,6 +144,9 @@ noinline void btrfs_release_path(struct btrfs_path *p)
> free_extent_buffer(p->nodes[i]);
> p->nodes[i] = NULL;
> }
> +
> + if (p->search_next_key)
> + memset(&p->next_key, 0, sizeof(struct btrfs_key));
> }
>
> /*
> @@ -2499,6 +2502,26 @@ done:
> return ret;
> }
>
> +static void __cache_next_key(struct btrfs_path *p, struct extent_buffer
*eb,
> + int level, int slot, int bin_search_result)
> +{
> + int nitems = btrfs_header_nritems(eb);
> +
> + if (!nitems)
> + return;
> +
> + if (!bin_search_result)
> + slot++;
> +
> + if (slot >= nitems)
> + return;
> +
> + if (level)
> + btrfs_node_key_to_cpu(eb, &p->next_key, slot);
> + else
> + btrfs_item_key_to_cpu(eb, &p->next_key, slot);
> +}
> +
> /*
> * look for key in the tree. path is filled in with nodes along the way
> * if key is found, we return zero and you can find the item in the leaf
> @@ -2658,6 +2681,8 @@ cow_done:
> btrfs_unlock_up_safe(p, level + 1);
>
> ret = bin_search(b, key, level, &slot);
> + if (p->search_next_key)
> + __cache_next_key(p, b, level, slot, ret);
>
> if (level != 0) {
> int dec = 0;
> diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
> index d6dd49b..4cec301 100644
> --- a/fs/btrfs/ctree.h
> +++ b/fs/btrfs/ctree.h
> @@ -573,6 +573,7 @@ struct btrfs_path {
> int slots[BTRFS_MAX_LEVEL];
> /* if there is real range locking, this locks field will change */
> int locks[BTRFS_MAX_LEVEL];
> + struct btrfs_key next_key;
> int reada;
> /* keep some upper locks as we walk down */
> int lowest_level;
> @@ -586,6 +587,7 @@ struct btrfs_path {
> unsigned int skip_locking:1;
> unsigned int leave_spinning:1;
> unsigned int search_commit_root:1;
> + unsigned int search_next_key:1;
> };
>
> /*
> diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
> index a7bfc95..892f1ce 100644
> --- a/fs/btrfs/file-item.c
> +++ b/fs/btrfs/file-item.c
> @@ -25,12 +25,12 @@
> #include "transaction.h"
> #include "print-tree.h"
>
> -#define __MAX_CSUM_ITEMS(r, size) ((unsigned
long)(((BTRFS_LEAF_DATA_SIZE(r) - \
> - sizeof(struct btrfs_item) * 2) / \
> - size) - 1))
> -
> -#define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \
> - PAGE_CACHE_SIZE))
> +#define __BTRFS_MAX_CSUM_ITEMS(r, size) ( \
> + (int)((BTRFS_LEAF_DATA_SIZE(r) - sizeof(struct btrfs_item) * 2) / size \
> + - 1) \
> +)
> +#define BTRFS_MAX_CSUM_ITEM_SIZE(r, size) \
> + (min_t(int, __BTRFS_MAX_CSUM_ITEMS(r, size), PAGE_CACHE_SIZE) * size)
>
> #define MAX_ORDERED_SUM_BYTES(r) ((PAGE_SIZE - \
> sizeof(struct btrfs_ordered_sum)) / \
> @@ -661,183 +661,149 @@ out:
> return ret;
> }
>
> +static inline u64 __calc_csum_size(struct btrfs_root *root, u64
extent_size,
> + u16 csum_size)
> +{
> + return (extent_size >>
root->fs_info->sb->s_blocksize_bits) * csum_size;
> +}
> +
> +static u32 btrfs_calc_csum_size(struct btrfs_root *root, u64 bytenr,
> + u64 extent_size, u16 csum_size,
> + struct btrfs_key *next_item_key)
> +{
> + u64 next_offset;
> + u64 ins_size;
> +
> + ins_size = __calc_csum_size(root, extent_size, csum_size);
> + if (next_item_key->objectid == BTRFS_EXTENT_CSUM_OBJECTID &&
> + next_item_key->type == BTRFS_EXTENT_CSUM_KEY) {
> + next_offset = next_item_key->offset - bytenr;
> + ins_size = min(ins_size,
> + __calc_csum_size(root, next_offset, csum_size));
> + }
> +
> + return (u32)ins_size;
> +}
> +
> +static struct btrfs_csum_item *
> +btrfs_tune_csum_item(struct btrfs_root *root, struct btrfs_path *path,
> + struct btrfs_csum_item *item, u32 *ins_size,
> + u16 csum_size)
> +{
> + struct btrfs_csum_item *orig_item;
> + struct extent_buffer *leaf = path->nodes[0];
> + int slot = path->slots[0];
> + u32 extend_size;
> + u64 csum_offset;
> + u32 item_size;
> +
> + orig_item = btrfs_item_ptr(leaf, slot, struct btrfs_csum_item);
> + csum_offset = (char *)item - (char *)orig_item;
> + item_size = (u32)(btrfs_item_size_nr(leaf, slot) - csum_offset);
> + if (*ins_size <= item_size) {
> + return item;
> + } else if (btrfs_leaf_free_space(root, leaf) < csum_size) {
> + *ins_size = item_size;
> + return item;
> + }
> +
> + extend_size = btrfs_leaf_free_space(root, leaf);
> + extend_size = extend_size / csum_size;
> + extend_size *= csum_size;
> +
> + *ins_size -= item_size;
> + extend_size = min(extend_size, *ins_size);
> +
> + btrfs_extend_item(root, path, extend_size);
> + *ins_size = item_size + extend_size;
> +
> + item = btrfs_item_ptr(leaf, slot, struct btrfs_csum_item);
> + item = (struct btrfs_csum_item *)((unsigned char *)item + csum_offset);
> + return item;
> +}
> +
> int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
> struct btrfs_root *root,
> struct btrfs_ordered_sum *sums)
> {
> struct btrfs_key file_key;
> - struct btrfs_key found_key;
> struct btrfs_path *path;
> struct btrfs_csum_item *item;
> - struct btrfs_csum_item *item_end;
> struct extent_buffer *leaf = NULL;
> - u64 next_offset;
> u64 total_bytes = 0;
> u64 csum_offset;
> u64 bytenr;
> - u32 nritems;
> u32 ins_size;
> int index = 0;
> - int found_next;
> - int ret;
> + int ret = 0;
> u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
> + u32 item_size;
> + bool might_overlap = !trans->adding_csums;
>
> path = btrfs_alloc_path();
> if (!path)
> return -ENOMEM;
> + path->search_next_key = might_overlap;
> again:
> - next_offset = (u64)-1;
> - found_next = 0;
> + csum_offset = 0;
> bytenr = sums->bytenr + total_bytes;
> - file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
> - file_key.offset = bytenr;
> - btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY);
>
> item = btrfs_lookup_csum(trans, root, path, bytenr, 1);
> if (!IS_ERR(item)) {
> - ret = 0;
> + BUG_ON(!might_overlap);
> + ins_size = btrfs_calc_csum_size(root, bytenr,
> + sums->len - total_bytes,
> + csum_size, &path->next_key);
> +
> leaf = path->nodes[0];
> - item_end = btrfs_item_ptr(leaf, path->slots[0],
> - struct btrfs_csum_item);
> - item_end = (struct btrfs_csum_item *)((char *)item_end +
> - btrfs_item_size_nr(leaf, path->slots[0]));
> + item = btrfs_tune_csum_item(root, path, item, &ins_size,
> + csum_size);
> goto found;
> }
> - ret = PTR_ERR(item);
> - if (ret != -EFBIG && ret != -ENOENT)
> - goto fail_unlock;
>
> - if (ret == -EFBIG) {
> - u32 item_size;
> + if (PTR_ERR(item) == -EFBIG) {
> /* we found one, but it isn''t big enough yet */
> leaf = path->nodes[0];
> - item_size = btrfs_item_size_nr(leaf, path->slots[0]);
> - if ((item_size / csum_size) >> - MAX_CSUM_ITEMS(root,
csum_size)) {
> - /* already at max size, make a new one */
> - goto insert;
> - }
> - } else {
> - int slot = path->slots[0] + 1;
> - /* we didn''t find a csum item, insert one */
> - nritems = btrfs_header_nritems(path->nodes[0]);
> - if (path->slots[0] >= nritems - 1) {
> - ret = btrfs_next_leaf(root, path);
> - if (ret == 1)
> - found_next = 1;
> - if (ret != 0)
> - goto insert;
> - slot = 0;
> - }
> - btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
> - if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
> - found_key.type != BTRFS_EXTENT_CSUM_KEY) {
> - found_next = 1;
> - goto insert;
> - }
> - next_offset = found_key.offset;
> - found_next = 1;
> - goto insert;
> - }
> -
> - /*
> - * at this point, we know the tree has an item, but it isn''t big
> - * enough yet to put our csum in. Grow it
> - */
> - btrfs_release_path(path);
> - ret = btrfs_search_slot(trans, root, &file_key, path,
> - csum_size, 1);
> - if (ret < 0)
> - goto fail_unlock;
> -
> - if (ret > 0) {
> - if (path->slots[0] == 0)
> - goto insert;
> - path->slots[0]--;
> - }
> -
> - leaf = path->nodes[0];
> - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
> - csum_offset = (bytenr - found_key.offset) >>
> - root->fs_info->sb->s_blocksize_bits;
> -
> - if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY ||
> - found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
> - csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) {
> - goto insert;
> - }
> -
> - if (csum_offset == btrfs_item_size_nr(leaf, path->slots[0]) /
> - csum_size) {
> - int extend_nr;
> - u64 tmp;
> - u32 diff;
> - u32 free_space;
> -
> if (btrfs_leaf_free_space(root, leaf) <
> - sizeof(struct btrfs_item) + csum_size * 2)
> + sizeof(struct btrfs_item) + csum_size)
> goto insert;
>
> - free_space = btrfs_leaf_free_space(root, leaf) -
> - sizeof(struct btrfs_item) - csum_size;
> - tmp = sums->len - total_bytes;
> - tmp >>= root->fs_info->sb->s_blocksize_bits;
> - WARN_ON(tmp < 1);
> -
> - extend_nr = max_t(int, 1, (int)tmp);
> - diff = (csum_offset + extend_nr) * csum_size;
> - diff = min(diff, MAX_CSUM_ITEMS(root, csum_size) * csum_size);
> -
> - diff = diff - btrfs_item_size_nr(leaf, path->slots[0]);
> - diff = min(free_space, diff);
> - diff /= csum_size;
> - diff *= csum_size;
> -
> - btrfs_extend_item(root, path, diff);
> - ret = 0;
> + ins_size = btrfs_calc_csum_size(root, bytenr,
> + sums->len - total_bytes,
> + csum_size, &path->next_key);
> + csum_offset = btrfs_item_size_nr(leaf, path->slots[0]);
> + item_size = btrfs_leaf_free_space(root, leaf);
> + if (ins_size > item_size) {
> + ins_size = item_size / csum_size;
> + ins_size *= csum_size;
> + }
> + btrfs_extend_item(root, path, ins_size);
> goto csum;
> + } else if (PTR_ERR(item) != -ENOENT) {
> + goto out;
> }
> -
> insert:
> btrfs_release_path(path);
> - csum_offset = 0;
> - if (found_next) {
> - u64 tmp;
>
> - tmp = sums->len - total_bytes;
> - tmp >>= root->fs_info->sb->s_blocksize_bits;
> - tmp = min(tmp, (next_offset - file_key.offset) >>
> - root->fs_info->sb->s_blocksize_bits);
> + ins_size = btrfs_calc_csum_size(root, bytenr,
> + sums->len - total_bytes,
> + csum_size, &path->next_key);
> + ins_size = min_t(u32, ins_size,
> + BTRFS_MAX_CSUM_ITEM_SIZE(root, csum_size));
> + file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
> + file_key.offset = bytenr;
> + btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY);
>
> - tmp = max((u64)1, tmp);
> - tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size));
> - ins_size = csum_size * tmp;
> - } else {
> - ins_size = csum_size;
> - }
> path->leave_spinning = 1;
> - ret = btrfs_insert_empty_item(trans, root, path, &file_key,
> - ins_size);
> + ret = btrfs_insert_empty_item(trans, root, path, &file_key,
ins_size);
> path->leave_spinning = 0;
> - if (ret < 0)
> - goto fail_unlock;
> - if (ret != 0) {
> - WARN_ON(1);
> - goto fail_unlock;
> - }
> - leaf = path->nodes[0];
> + if (ret)
> + goto out;
> csum:
> + leaf = path->nodes[0];
> item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
> - item_end = (struct btrfs_csum_item *)((unsigned char *)item +
> - btrfs_item_size_nr(leaf, path->slots[0]));
> - item = (struct btrfs_csum_item *)((unsigned char *)item +
> - csum_offset * csum_size);
> + item = (struct btrfs_csum_item *)((unsigned char *)item + csum_offset);
> found:
> - ins_size = (u32)(sums->len - total_bytes) >>
> - root->fs_info->sb->s_blocksize_bits;
> - ins_size *= csum_size;
> - ins_size = min_t(u32, (unsigned long)item_end - (unsigned long)item,
> - ins_size);
> write_extent_buffer(leaf, sums->sums + index, (unsigned long)item,
> ins_size);
>
> @@ -854,7 +820,4 @@ found:
> out:
> btrfs_free_path(path);
> return ret;
> -
> -fail_unlock:
> - goto out;
> }
>
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs"
in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html