提交 b7a9f29f 编写于 作者: C Chris Mason

Btrfs: sort references by byte number during btrfs_inc_ref

When a block goes through cow, we update the reference counts of
everything that block points to.  The internal pointers of the block
can be in just about any order, and it is likely to have clusters of
things that are close together and clusters of things that are not.

To help reduce the seeks that come with updating all of these reference
counts, sort them by byte number before actual updates are done.
Signed-off-by: NChris Mason <chris.mason@oracle.com>
上级 b51912c9
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/sort.h>
#include "compat.h" #include "compat.h"
#include "hash.h" #include "hash.h"
#include "crc32c.h" #include "crc32c.h"
...@@ -1521,15 +1522,50 @@ int btrfs_cache_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -1521,15 +1522,50 @@ int btrfs_cache_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
return ret; return ret;
} }
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, /* when a block goes through cow, we update the reference counts of
struct extent_buffer *orig_buf, struct extent_buffer *buf, * everything that block points to. The internal pointers of the block
u32 *nr_extents) * can be in just about any order, and it is likely to have clusters of
* things that are close together and clusters of things that are not.
*
* To help reduce the seeks that come with updating all of these reference
* counts, sort them by byte number before actual updates are done.
*
* struct refsort is used to match byte number to slot in the btree block.
* we sort based on the byte number and then use the slot to actually
* find the item.
*/
struct refsort {
u64 bytenr;
u32 slot;
};
/*
* for passing into sort()
*/
static int refsort_cmp(const void *a_void, const void *b_void)
{
const struct refsort *a = a_void;
const struct refsort *b = b_void;
if (a->bytenr < b->bytenr)
return -1;
if (a->bytenr > b->bytenr)
return 1;
return 0;
}
noinline int btrfs_inc_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *orig_buf,
struct extent_buffer *buf, u32 *nr_extents)
{ {
u64 bytenr; u64 bytenr;
u64 ref_root; u64 ref_root;
u64 orig_root; u64 orig_root;
u64 ref_generation; u64 ref_generation;
u64 orig_generation; u64 orig_generation;
struct refsort *sorted;
u32 nritems; u32 nritems;
u32 nr_file_extents = 0; u32 nr_file_extents = 0;
struct btrfs_key key; struct btrfs_key key;
...@@ -1538,6 +1574,8 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -1538,6 +1574,8 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
int level; int level;
int ret = 0; int ret = 0;
int faili = 0; int faili = 0;
int refi = 0;
int slot;
int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *, int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *,
u64, u64, u64, u64, u64, u64, u64, u64); u64, u64, u64, u64, u64, u64, u64, u64);
...@@ -1549,6 +1587,9 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -1549,6 +1587,9 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
nritems = btrfs_header_nritems(buf); nritems = btrfs_header_nritems(buf);
level = btrfs_header_level(buf); level = btrfs_header_level(buf);
sorted = kmalloc(sizeof(struct refsort) * nritems, GFP_NOFS);
BUG_ON(!sorted);
if (root->ref_cows) { if (root->ref_cows) {
process_func = __btrfs_inc_extent_ref; process_func = __btrfs_inc_extent_ref;
} else { } else {
...@@ -1561,6 +1602,11 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -1561,6 +1602,11 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
process_func = __btrfs_update_extent_ref; process_func = __btrfs_update_extent_ref;
} }
/*
* we make two passes through the items. In the first pass we
* only record the byte number and slot. Then we sort based on
* byte number and do the actual work based on the sorted results
*/
for (i = 0; i < nritems; i++) { for (i = 0; i < nritems; i++) {
cond_resched(); cond_resched();
if (level == 0) { if (level == 0) {
...@@ -1577,6 +1623,32 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -1577,6 +1623,32 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
continue; continue;
nr_file_extents++; nr_file_extents++;
sorted[refi].bytenr = bytenr;
sorted[refi].slot = i;
refi++;
} else {
bytenr = btrfs_node_blockptr(buf, i);
sorted[refi].bytenr = bytenr;
sorted[refi].slot = i;
refi++;
}
}
/*
* if refi == 0, we didn't actually put anything into the sorted
* array and we're done
*/
if (refi == 0)
goto out;
sort(sorted, refi, sizeof(struct refsort), refsort_cmp, NULL);
for (i = 0; i < refi; i++) {
cond_resched();
slot = sorted[i].slot;
bytenr = sorted[i].bytenr;
if (level == 0) {
btrfs_item_key_to_cpu(buf, &key, slot);
ret = process_func(trans, root, bytenr, ret = process_func(trans, root, bytenr,
orig_buf->start, buf->start, orig_buf->start, buf->start,
...@@ -1585,25 +1657,25 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -1585,25 +1657,25 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
key.objectid); key.objectid);
if (ret) { if (ret) {
faili = i; faili = slot;
WARN_ON(1); WARN_ON(1);
goto fail; goto fail;
} }
} else { } else {
bytenr = btrfs_node_blockptr(buf, i);
ret = process_func(trans, root, bytenr, ret = process_func(trans, root, bytenr,
orig_buf->start, buf->start, orig_buf->start, buf->start,
orig_root, ref_root, orig_root, ref_root,
orig_generation, ref_generation, orig_generation, ref_generation,
level - 1); level - 1);
if (ret) { if (ret) {
faili = i; faili = slot;
WARN_ON(1); WARN_ON(1);
goto fail; goto fail;
} }
} }
} }
out: out:
kfree(sorted);
if (nr_extents) { if (nr_extents) {
if (level == 0) if (level == 0)
*nr_extents = nr_file_extents; *nr_extents = nr_file_extents;
...@@ -1612,6 +1684,7 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -1612,6 +1684,7 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
} }
return 0; return 0;
fail: fail:
kfree(sorted);
WARN_ON(1); WARN_ON(1);
return ret; return ret;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册