1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

bcache: Add sync io engine

Something to fall back to when testing.
This commit is contained in:
Joe Thornber 2018-05-10 14:29:26 +01:00
parent 67b80e2d9d
commit ae50374811
3 changed files with 150 additions and 10 deletions

View File

@ -129,7 +129,6 @@ static struct control_block *_iocb_to_cb(struct iocb *icb)
//---------------------------------------------------------------- //----------------------------------------------------------------
// FIXME: write a sync engine too
struct async_engine { struct async_engine {
struct io_engine e; struct io_engine e;
io_context_t aio_context; io_context_t aio_context;
@ -281,6 +280,97 @@ struct io_engine *create_async_io_engine(void)
//---------------------------------------------------------------- //----------------------------------------------------------------
struct sync_io {
struct dm_list list;
void *context;
int err;
};
struct sync_engine {
struct io_engine e;
struct dm_list complete;
};
static struct sync_engine *_to_sync(struct io_engine *e)
{
return container_of(e, struct sync_engine, e);
}
static void _sync_destroy(struct io_engine *ioe)
{
struct sync_engine *e = _to_sync(ioe);
dm_free(e);
}
static bool _sync_issue(struct io_engine *ioe, enum dir d, int fd,
sector_t sb, sector_t se, void *data, void *context)
{
int r;
uint64_t len = (se - sb) * 512;
struct sync_engine *e = _to_sync(ioe);
struct sync_io *io = malloc(sizeof(*io));
if (!io)
return false;
r = lseek(fd, sb * 512, SEEK_SET);
if (r < 0)
return false;
do {
if (d == DIR_READ)
r = read(fd, data, len);
else
r = write(fd, data, len);
} while (r == EINTR || r == EAGAIN);
if (r != len)
r = -EIO;
dm_list_add(&e->complete, &io->list);
io->context = context;
io->err = r < 0 ? r : 0;
return true;
}
static bool _sync_wait(struct io_engine *ioe, io_complete_fn fn)
{
struct sync_io *io, *tmp;
struct sync_engine *e = _to_sync(ioe);
dm_list_iterate_items_safe(io, tmp, &e->complete) {
fn(io->context, io->err);
dm_list_del(&io->list);
dm_free(io);
}
return true;
}
static unsigned _sync_max_io(struct io_engine *e)
{
return 1;
}
struct io_engine *create_sync_io_engine(void)
{
struct sync_engine *e = dm_malloc(sizeof(*e));
if (!e)
return NULL;
e->e.destroy = _sync_destroy;
e->e.issue = _sync_issue;
e->e.wait = _sync_wait;
e->e.max_io = _sync_max_io;
dm_list_init(&e->complete);
return &e->e;
}
//----------------------------------------------------------------
#define MIN_BLOCKS 16 #define MIN_BLOCKS 16
#define WRITEBACK_LOW_THRESHOLD_PERCENT 33 #define WRITEBACK_LOW_THRESHOLD_PERCENT 33
#define WRITEBACK_HIGH_THRESHOLD_PERCENT 66 #define WRITEBACK_HIGH_THRESHOLD_PERCENT 66

View File

@ -48,6 +48,7 @@ struct io_engine {
}; };
struct io_engine *create_async_io_engine(void); struct io_engine *create_async_io_engine(void);
struct io_engine *create_sync_io_engine(void);
/*----------------------------------------------------------------*/ /*----------------------------------------------------------------*/

View File

@ -48,10 +48,9 @@ static uint64_t byte(block_address b, uint64_t offset)
return b * T_BLOCK_SIZE + offset; return b * T_BLOCK_SIZE + offset;
} }
static void *_fix_init(void) static void *_fix_init(struct io_engine *engine)
{ {
uint8_t buffer[T_BLOCK_SIZE]; uint8_t buffer[T_BLOCK_SIZE];
struct io_engine *engine;
struct fixture *f = malloc(sizeof(*f)); struct fixture *f = malloc(sizeof(*f));
unsigned b, i; unsigned b, i;
@ -72,15 +71,26 @@ static void *_fix_init(void)
f->fd = open(f->fname, O_RDWR | O_DIRECT); f->fd = open(f->fname, O_RDWR | O_DIRECT);
T_ASSERT(f->fd >= 0); T_ASSERT(f->fd >= 0);
engine = create_async_io_engine();
T_ASSERT(engine);
f->cache = bcache_create(T_BLOCK_SIZE / 512, NR_BLOCKS, engine); f->cache = bcache_create(T_BLOCK_SIZE / 512, NR_BLOCKS, engine);
T_ASSERT(f->cache); T_ASSERT(f->cache);
return f; return f;
} }
static void *_async_init(void)
{
struct io_engine *e = create_async_io_engine();
T_ASSERT(e);
return _fix_init(e);
}
static void *_sync_init(void)
{
struct io_engine *e = create_sync_io_engine();
T_ASSERT(e);
return _fix_init(e);
}
static void _fix_exit(void *fixture) static void _fix_exit(void *fixture)
{ {
struct fixture *f = fixture; struct fixture *f = fixture;
@ -123,6 +133,7 @@ static void _verify(struct fixture *f, uint64_t byte_b, uint64_t byte_e, uint8_t
T_ASSERT(bcache_read_bytes(f->cache, f->fd, byte_b, len2, buffer)); T_ASSERT(bcache_read_bytes(f->cache, f->fd, byte_b, len2, buffer));
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
T_ASSERT_EQUAL(buffer[i], _pattern_at(pat, byte_b + i)); T_ASSERT_EQUAL(buffer[i], _pattern_at(pat, byte_b + i));
free(buffer);
} }
// Verify again, driving bcache directly // Verify again, driving bcache directly
@ -349,16 +360,17 @@ static void _test_set_many_boundaries(void *fixture)
//---------------------------------------------------------------- //----------------------------------------------------------------
#define T(path, desc, fn) register_test(ts, "/base/device/bcache/utils/" path, desc, fn) #define T(path, desc, fn) register_test(ts, "/base/device/bcache/utils/async/" path, desc, fn)
static struct test_suite *_tests(void) static struct test_suite *_async_tests(void)
{ {
struct test_suite *ts = test_suite_create(_fix_init, _fix_exit); struct test_suite *ts = test_suite_create(_async_init, _fix_exit);
if (!ts) { if (!ts) {
fprintf(stderr, "out of memory\n"); fprintf(stderr, "out of memory\n");
exit(1); exit(1);
} }
#define T(path, desc, fn) register_test(ts, "/base/device/bcache/utils/async/" path, desc, fn)
T("rw-first-block", "read/write/verify the first block", _test_rw_first_block); T("rw-first-block", "read/write/verify the first block", _test_rw_first_block);
T("rw-last-block", "read/write/verify the last block", _test_rw_last_block); T("rw-last-block", "read/write/verify the last block", _test_rw_last_block);
T("rw-several-blocks", "read/write/verify several whole blocks", _test_rw_several_whole_blocks); T("rw-several-blocks", "read/write/verify several whole blocks", _test_rw_several_whole_blocks);
@ -379,12 +391,49 @@ static struct test_suite *_tests(void)
T("set-within-single-block", "set within single block", _test_set_within_single_block); T("set-within-single-block", "set within single block", _test_set_within_single_block);
T("set-cross-one-boundary", "set across one boundary", _test_set_cross_one_boundary); T("set-cross-one-boundary", "set across one boundary", _test_set_cross_one_boundary);
T("set-many-boundaries", "set many boundaries", _test_set_many_boundaries); T("set-many-boundaries", "set many boundaries", _test_set_many_boundaries);
#undef T
return ts;
}
static struct test_suite *_sync_tests(void)
{
struct test_suite *ts = test_suite_create(_sync_init, _fix_exit);
if (!ts) {
fprintf(stderr, "out of memory\n");
exit(1);
}
#define T(path, desc, fn) register_test(ts, "/base/device/bcache/utils/sync/" path, desc, fn)
T("rw-first-block", "read/write/verify the first block", _test_rw_first_block);
T("rw-last-block", "read/write/verify the last block", _test_rw_last_block);
T("rw-several-blocks", "read/write/verify several whole blocks", _test_rw_several_whole_blocks);
T("rw-within-single-block", "read/write/verify within single block", _test_rw_within_single_block);
T("rw-cross-one-boundary", "read/write/verify across one boundary", _test_rw_cross_one_boundary);
T("rw-many-boundaries", "read/write/verify many boundaries", _test_rw_many_boundaries);
T("zero-first-block", "zero the first block", _test_zero_first_block);
T("zero-last-block", "zero the last block", _test_zero_last_block);
T("zero-several-blocks", "zero several whole blocks", _test_zero_several_whole_blocks);
T("zero-within-single-block", "zero within single block", _test_zero_within_single_block);
T("zero-cross-one-boundary", "zero across one boundary", _test_zero_cross_one_boundary);
T("zero-many-boundaries", "zero many boundaries", _test_zero_many_boundaries);
T("set-first-block", "set the first block", _test_set_first_block);
T("set-last-block", "set the last block", _test_set_last_block);
T("set-several-blocks", "set several whole blocks", _test_set_several_whole_blocks);
T("set-within-single-block", "set within single block", _test_set_within_single_block);
T("set-cross-one-boundary", "set across one boundary", _test_set_cross_one_boundary);
T("set-many-boundaries", "set many boundaries", _test_set_many_boundaries);
#undef T
return ts; return ts;
} }
void bcache_utils_tests(struct dm_list *all_tests) void bcache_utils_tests(struct dm_list *all_tests)
{ {
dm_list_add(all_tests, &_tests()->list); dm_list_add(all_tests, &_async_tests()->list);
dm_list_add(all_tests, &_sync_tests()->list);
} }