Commit 2f697dc6 authored by Liu Bo's avatar Liu Bo Committed by Josef Bacik

Btrfs: extend the checksum item as much as possible

For write, we also reserve some space for COW blocks during updating
the checksum tree, and we calculate the number of blocks by checking
if the number of bytes outstanding that are going to need csums needs
one more block for csum.

When we add these checksum into the checksum tree, we use ordered sums
list.
Every ordered sum contains csums for each sector, and we'll first try
to look up an existing csum item,
a) if we don't yet have a proper csum item, then we need to insert one,
b) or if we find one but the csum item is not big enough, then we need
to extend it.

The point is we'll unlock the whole path and then insert or extend.
So others can hack in and update the tree.

Each insert or extend needs update the tree with COW on, and we may need
to insert/extend for many times.

That means what we've reserved for updating checksum tree is NOT enough
indeed.

The case is even more serious with having several write threads at the
same time, it can end up eating our reserved space quickly and starting
eating globle reserve pool instead.

I don't yet come up with a way to calculate the worse case for updating
csum, but extending the checksum item as much as possible can be helpful
in my test.

The idea behind is that it can reduce the times we insert/extend so that
it saves us precious reserved space.
Signed-off-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
parent de78b51a
...@@ -684,6 +684,24 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, ...@@ -684,6 +684,24 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
static u64 btrfs_sector_sum_left(struct btrfs_ordered_sum *sums,
struct btrfs_sector_sum *sector_sum,
u64 total_bytes, u64 sectorsize)
{
u64 tmp = sectorsize;
u64 next_sector = sector_sum->bytenr;
struct btrfs_sector_sum *next = sector_sum + 1;
while ((tmp + total_bytes) < sums->len) {
if (next_sector + sectorsize != next->bytenr)
break;
tmp += sectorsize;
next_sector = next->bytenr;
next++;
}
return tmp;
}
int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_ordered_sum *sums) struct btrfs_ordered_sum *sums)
...@@ -789,20 +807,32 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, ...@@ -789,20 +807,32 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
goto insert; goto insert;
} }
if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) / if (csum_offset == btrfs_item_size_nr(leaf, path->slots[0]) /
csum_size) { csum_size) {
u32 diff = (csum_offset + 1) * csum_size; int extend_nr;
u64 tmp;
u32 diff;
u32 free_space;
/* if (btrfs_leaf_free_space(root, leaf) <
* is the item big enough already? we dropped our lock sizeof(struct btrfs_item) + csum_size * 2)
* before and need to recheck goto insert;
*/
if (diff < btrfs_item_size_nr(leaf, path->slots[0])) free_space = btrfs_leaf_free_space(root, leaf) -
goto csum; sizeof(struct btrfs_item) - csum_size;
tmp = btrfs_sector_sum_left(sums, sector_sum, total_bytes,
root->sectorsize);
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 = diff - btrfs_item_size_nr(leaf, path->slots[0]);
if (diff != csum_size) diff = min(free_space, diff);
goto insert; diff /= csum_size;
diff *= csum_size;
btrfs_extend_item(trans, root, path, diff); btrfs_extend_item(trans, root, path, diff);
goto csum; goto csum;
...@@ -812,19 +842,14 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, ...@@ -812,19 +842,14 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
btrfs_release_path(path); btrfs_release_path(path);
csum_offset = 0; csum_offset = 0;
if (found_next) { if (found_next) {
u64 tmp = total_bytes + root->sectorsize; u64 tmp;
u64 next_sector = sector_sum->bytenr;
struct btrfs_sector_sum *next = sector_sum + 1;
while (tmp < sums->len) { tmp = btrfs_sector_sum_left(sums, sector_sum, total_bytes,
if (next_sector + root->sectorsize != next->bytenr) root->sectorsize);
break;
tmp += root->sectorsize;
next_sector = next->bytenr;
next++;
}
tmp = min(tmp, next_offset - file_key.offset);
tmp >>= root->fs_info->sb->s_blocksize_bits; tmp >>= root->fs_info->sb->s_blocksize_bits;
tmp = min(tmp, (next_offset - file_key.offset) >>
root->fs_info->sb->s_blocksize_bits);
tmp = max((u64)1, tmp); tmp = max((u64)1, tmp);
tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size)); tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size));
ins_size = csum_size * tmp; ins_size = csum_size * tmp;
......
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