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 <mi...@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 majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html