Skip to content

Commit 0ce46f4

Browse files
raeburnMikulas Patocka
authored andcommitted
dm vdo slab-depot: read refcount blocks in large chunks at load time
At startup, vdo loads all the reference count data before the device reports that it is ready. Using a pool of large metadata vios can improve the startup speed of vdo. The pool of large vios is released after the device is ready. During normal operation, reference counts are updated 4kB at a time, as before. Signed-off-by: Ken Raeburn <raeburn@redhat.com> Signed-off-by: Matthew Sakai <msakai@redhat.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
1 parent f979da5 commit 0ce46f4

File tree

2 files changed

+59
-17
lines changed

2 files changed

+59
-17
lines changed

drivers/md/dm-vdo/slab-depot.c

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,7 +1170,7 @@ static void handle_io_error(struct vdo_completion *completion)
11701170

11711171
vio_record_metadata_io_error(vio);
11721172
return_vio_to_pool(vio_as_pooled_vio(vio));
1173-
slab->active_count--;
1173+
slab->active_count -= vio->io_size / VDO_BLOCK_SIZE;
11741174
vdo_enter_read_only_mode(slab->allocator->depot->vdo, result);
11751175
check_if_slab_drained(slab);
11761176
}
@@ -2239,13 +2239,20 @@ static void finish_reference_block_load(struct vdo_completion *completion)
22392239
struct pooled_vio *pooled = vio_as_pooled_vio(vio);
22402240
struct reference_block *block = completion->parent;
22412241
struct vdo_slab *slab = block->slab;
2242+
unsigned int block_count = vio->io_size / VDO_BLOCK_SIZE;
2243+
unsigned int i;
2244+
char *data = vio->data;
2245+
2246+
for (i = 0; i < block_count; i++, block++, data += VDO_BLOCK_SIZE) {
2247+
struct packed_reference_block *packed = (struct packed_reference_block *) data;
22422248

2243-
unpack_reference_block((struct packed_reference_block *) vio->data, block);
2249+
unpack_reference_block(packed, block);
2250+
clear_provisional_references(block);
2251+
slab->free_blocks -= block->allocated_count;
2252+
}
22442253
return_vio_to_pool(pooled);
2245-
slab->active_count--;
2246-
clear_provisional_references(block);
2254+
slab->active_count -= block_count;
22472255

2248-
slab->free_blocks -= block->allocated_count;
22492256
check_if_slab_drained(slab);
22502257
}
22512258

@@ -2259,23 +2266,25 @@ static void load_reference_block_endio(struct bio *bio)
22592266
}
22602267

22612268
/**
2262-
* load_reference_block() - After a block waiter has gotten a VIO from the VIO pool, load the
2263-
* block.
2264-
* @waiter: The waiter of the block to load.
2269+
* load_reference_block_group() - After a block waiter has gotten a VIO from the VIO pool, load
2270+
* a set of blocks.
2271+
* @waiter: The waiter of the first block to load.
22652272
* @context: The VIO returned by the pool.
22662273
*/
2267-
static void load_reference_block(struct vdo_waiter *waiter, void *context)
2274+
static void load_reference_block_group(struct vdo_waiter *waiter, void *context)
22682275
{
22692276
struct pooled_vio *pooled = context;
22702277
struct vio *vio = &pooled->vio;
22712278
struct reference_block *block =
22722279
container_of(waiter, struct reference_block, waiter);
2273-
size_t block_offset = (block - block->slab->reference_blocks);
2280+
u32 block_offset = block - block->slab->reference_blocks;
2281+
u32 max_block_count = block->slab->reference_block_count - block_offset;
2282+
u32 block_count = min_t(int, vio->block_count, max_block_count);
22742283

22752284
vio->completion.parent = block;
2276-
vdo_submit_metadata_vio(vio, block->slab->ref_counts_origin + block_offset,
2277-
load_reference_block_endio, handle_io_error,
2278-
REQ_OP_READ);
2285+
vdo_submit_metadata_vio_with_size(vio, block->slab->ref_counts_origin + block_offset,
2286+
load_reference_block_endio, handle_io_error,
2287+
REQ_OP_READ, block_count * VDO_BLOCK_SIZE);
22792288
}
22802289

22812290
/**
@@ -2285,14 +2294,21 @@ static void load_reference_block(struct vdo_waiter *waiter, void *context)
22852294
static void load_reference_blocks(struct vdo_slab *slab)
22862295
{
22872296
block_count_t i;
2297+
u64 blocks_per_vio = slab->allocator->refcount_blocks_per_big_vio;
2298+
struct vio_pool *pool = slab->allocator->refcount_big_vio_pool;
2299+
2300+
if (!pool) {
2301+
pool = slab->allocator->vio_pool;
2302+
blocks_per_vio = 1;
2303+
}
22882304

22892305
slab->free_blocks = slab->block_count;
22902306
slab->active_count = slab->reference_block_count;
2291-
for (i = 0; i < slab->reference_block_count; i++) {
2307+
for (i = 0; i < slab->reference_block_count; i += blocks_per_vio) {
22922308
struct vdo_waiter *waiter = &slab->reference_blocks[i].waiter;
22932309

2294-
waiter->callback = load_reference_block;
2295-
acquire_vio_from_pool(slab->allocator->vio_pool, waiter);
2310+
waiter->callback = load_reference_block_group;
2311+
acquire_vio_from_pool(pool, waiter);
22962312
}
22972313
}
22982314

@@ -2699,6 +2715,7 @@ static void finish_scrubbing(struct slab_scrubber *scrubber, int result)
26992715
vdo_log_info("VDO commencing normal operation");
27002716
else if (prior_state == VDO_RECOVERING)
27012717
vdo_log_info("Exiting recovery mode");
2718+
free_vio_pool(vdo_forget(allocator->refcount_big_vio_pool));
27022719
}
27032720

27042721
/*
@@ -3982,6 +3999,7 @@ static int __must_check initialize_block_allocator(struct slab_depot *depot,
39823999
struct vdo *vdo = depot->vdo;
39834000
block_count_t max_free_blocks = depot->slab_config.data_blocks;
39844001
unsigned int max_priority = (2 + ilog2(max_free_blocks));
4002+
u32 reference_block_count, refcount_reads_needed, refcount_blocks_per_vio;
39854003

39864004
*allocator = (struct block_allocator) {
39874005
.depot = depot,
@@ -4005,6 +4023,18 @@ static int __must_check initialize_block_allocator(struct slab_depot *depot,
40054023
if (result != VDO_SUCCESS)
40064024
return result;
40074025

4026+
/* Initialize the refcount-reading vio pool. */
4027+
reference_block_count = vdo_get_saved_reference_count_size(depot->slab_config.slab_blocks);
4028+
refcount_reads_needed = DIV_ROUND_UP(reference_block_count, MAX_BLOCKS_PER_VIO);
4029+
refcount_blocks_per_vio = DIV_ROUND_UP(reference_block_count, refcount_reads_needed);
4030+
allocator->refcount_blocks_per_big_vio = refcount_blocks_per_vio;
4031+
result = make_vio_pool(vdo, BLOCK_ALLOCATOR_REFCOUNT_VIO_POOL_SIZE,
4032+
allocator->refcount_blocks_per_big_vio, allocator->thread_id,
4033+
VIO_TYPE_SLAB_JOURNAL, VIO_PRIORITY_METADATA,
4034+
NULL, &allocator->refcount_big_vio_pool);
4035+
if (result != VDO_SUCCESS)
4036+
return result;
4037+
40084038
result = initialize_slab_scrubber(allocator);
40094039
if (result != VDO_SUCCESS)
40104040
return result;
@@ -4222,6 +4252,7 @@ void vdo_free_slab_depot(struct slab_depot *depot)
42224252
uninitialize_allocator_summary(allocator);
42234253
uninitialize_scrubber_vio(&allocator->scrubber);
42244254
free_vio_pool(vdo_forget(allocator->vio_pool));
4255+
free_vio_pool(vdo_forget(allocator->refcount_big_vio_pool));
42254256
vdo_free_priority_table(vdo_forget(allocator->prioritized_slabs));
42264257
}
42274258

drivers/md/dm-vdo/slab-depot.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@
4545
enum {
4646
/* The number of vios in the vio pool is proportional to the throughput of the VDO. */
4747
BLOCK_ALLOCATOR_VIO_POOL_SIZE = 128,
48+
49+
/*
50+
* The number of vios in the vio pool used for loading reference count data. A slab's
51+
* refcounts is capped at ~8MB, and we process one at a time in a zone, so 9 should be
52+
* plenty.
53+
*/
54+
BLOCK_ALLOCATOR_REFCOUNT_VIO_POOL_SIZE = 9,
4855
};
4956

5057
/*
@@ -248,7 +255,7 @@ struct vdo_slab {
248255

249256
/* A list of the dirty blocks waiting to be written out */
250257
struct vdo_wait_queue dirty_blocks;
251-
/* The number of blocks which are currently writing */
258+
/* The number of blocks which are currently reading or writing */
252259
size_t active_count;
253260

254261
/* A waiter object for updating the slab summary */
@@ -425,6 +432,10 @@ struct block_allocator {
425432

426433
/* The vio pool for reading and writing block allocator metadata */
427434
struct vio_pool *vio_pool;
435+
/* The vio pool for large initial reads of ref count areas */
436+
struct vio_pool *refcount_big_vio_pool;
437+
/* How many ref count blocks are read per vio at initial load */
438+
u32 refcount_blocks_per_big_vio;
428439
/* The dm_kcopyd client for erasing slab journals */
429440
struct dm_kcopyd_client *eraser;
430441
/* Iterator over the slabs to be erased */

0 commit comments

Comments
 (0)