mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/
synced 2026-05-02 18:15:03 -04:00
dm space maps: improve performance with inc/dec on ranges of blocks
When we break sharing on btree nodes we typically need to increment the reference counts to every value held in the node. This can cause a lot of repeated calls to the space maps. Fix this by changing the interface to the space map inc/dec methods to take ranges of adjacent blocks to be operated on. For installations that are using a lot of snapshots this will reduce cpu overhead of fundamental operations such as provisioning a new block, or deleting a snapshot, by as much as 10 times. Signed-off-by: Joe Thornber <ejt@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
committed by
Mike Snitzer
parent
5faafc77f7
commit
be500ed721
@@ -311,28 +311,53 @@ static void unpack_block_time(uint64_t v, dm_block_t *b, uint32_t *t)
|
||||
*t = v & ((1 << 24) - 1);
|
||||
}
|
||||
|
||||
static void data_block_inc(void *context, const void *value_le)
|
||||
{
|
||||
struct dm_space_map *sm = context;
|
||||
__le64 v_le;
|
||||
uint64_t b;
|
||||
uint32_t t;
|
||||
/*
|
||||
* It's more efficient to call dm_sm_{inc,dec}_blocks as few times as
|
||||
* possible. 'with_runs' reads contiguous runs of blocks, and calls the
|
||||
* given sm function.
|
||||
*/
|
||||
typedef int (*run_fn)(struct dm_space_map *, dm_block_t, dm_block_t);
|
||||
|
||||
memcpy(&v_le, value_le, sizeof(v_le));
|
||||
unpack_block_time(le64_to_cpu(v_le), &b, &t);
|
||||
dm_sm_inc_block(sm, b);
|
||||
static void with_runs(struct dm_space_map *sm, const __le64 *value_le, unsigned count, run_fn fn)
|
||||
{
|
||||
uint64_t b, begin, end;
|
||||
uint32_t t;
|
||||
bool in_run = false;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < count; i++, value_le++) {
|
||||
/* We know value_le is 8 byte aligned */
|
||||
unpack_block_time(le64_to_cpu(*value_le), &b, &t);
|
||||
|
||||
if (in_run) {
|
||||
if (b == end) {
|
||||
end++;
|
||||
} else {
|
||||
fn(sm, begin, end);
|
||||
begin = b;
|
||||
end = b + 1;
|
||||
}
|
||||
} else {
|
||||
in_run = true;
|
||||
begin = b;
|
||||
end = b + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_run)
|
||||
fn(sm, begin, end);
|
||||
}
|
||||
|
||||
static void data_block_dec(void *context, const void *value_le)
|
||||
static void data_block_inc(void *context, const void *value_le, unsigned count)
|
||||
{
|
||||
struct dm_space_map *sm = context;
|
||||
__le64 v_le;
|
||||
uint64_t b;
|
||||
uint32_t t;
|
||||
with_runs((struct dm_space_map *) context,
|
||||
(const __le64 *) value_le, count, dm_sm_inc_blocks);
|
||||
}
|
||||
|
||||
memcpy(&v_le, value_le, sizeof(v_le));
|
||||
unpack_block_time(le64_to_cpu(v_le), &b, &t);
|
||||
dm_sm_dec_block(sm, b);
|
||||
static void data_block_dec(void *context, const void *value_le, unsigned count)
|
||||
{
|
||||
with_runs((struct dm_space_map *) context,
|
||||
(const __le64 *) value_le, count, dm_sm_dec_blocks);
|
||||
}
|
||||
|
||||
static int data_block_equal(void *context, const void *value1_le, const void *value2_le)
|
||||
@@ -349,27 +374,25 @@ static int data_block_equal(void *context, const void *value1_le, const void *va
|
||||
return b1 == b2;
|
||||
}
|
||||
|
||||
static void subtree_inc(void *context, const void *value)
|
||||
static void subtree_inc(void *context, const void *value, unsigned count)
|
||||
{
|
||||
struct dm_btree_info *info = context;
|
||||
__le64 root_le;
|
||||
uint64_t root;
|
||||
const __le64 *root_le = value;
|
||||
unsigned i;
|
||||
|
||||
memcpy(&root_le, value, sizeof(root_le));
|
||||
root = le64_to_cpu(root_le);
|
||||
dm_tm_inc(info->tm, root);
|
||||
for (i = 0; i < count; i++, root_le++)
|
||||
dm_tm_inc(info->tm, le64_to_cpu(*root_le));
|
||||
}
|
||||
|
||||
static void subtree_dec(void *context, const void *value)
|
||||
static void subtree_dec(void *context, const void *value, unsigned count)
|
||||
{
|
||||
struct dm_btree_info *info = context;
|
||||
__le64 root_le;
|
||||
uint64_t root;
|
||||
const __le64 *root_le = value;
|
||||
unsigned i;
|
||||
|
||||
memcpy(&root_le, value, sizeof(root_le));
|
||||
root = le64_to_cpu(root_le);
|
||||
if (dm_btree_del(info, root))
|
||||
DMERR("btree delete failed");
|
||||
for (i = 0; i < count; i++, root_le++)
|
||||
if (dm_btree_del(info, le64_to_cpu(*root_le)))
|
||||
DMERR("btree delete failed");
|
||||
}
|
||||
|
||||
static int subtree_equal(void *context, const void *value1_le, const void *value2_le)
|
||||
@@ -1761,11 +1784,7 @@ int dm_pool_inc_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_
|
||||
int r = 0;
|
||||
|
||||
pmd_write_lock(pmd);
|
||||
for (; b != e; b++) {
|
||||
r = dm_sm_inc_block(pmd->data_sm, b);
|
||||
if (r)
|
||||
break;
|
||||
}
|
||||
r = dm_sm_inc_blocks(pmd->data_sm, b, e);
|
||||
pmd_write_unlock(pmd);
|
||||
|
||||
return r;
|
||||
@@ -1776,11 +1795,7 @@ int dm_pool_dec_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_
|
||||
int r = 0;
|
||||
|
||||
pmd_write_lock(pmd);
|
||||
for (; b != e; b++) {
|
||||
r = dm_sm_dec_block(pmd->data_sm, b);
|
||||
if (r)
|
||||
break;
|
||||
}
|
||||
r = dm_sm_dec_blocks(pmd->data_sm, b, e);
|
||||
pmd_write_unlock(pmd);
|
||||
|
||||
return r;
|
||||
|
||||
Reference in New Issue
Block a user