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:
parent
67b80e2d9d
commit
ae50374811
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
/*----------------------------------------------------------------*/
|
/*----------------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user