[lvm-devel] master - bcache: Add sync io engine
Joe Thornber
thornber at sourceware.org
Thu May 10 13:33:50 UTC 2018
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=ae5037481172da84d414ca047408d9fb13955886
Commit: ae5037481172da84d414ca047408d9fb13955886
Parent: 67b80e2d9d9b437f18f909c9c09e4b286337b031
Author: Joe Thornber <ejt at redhat.com>
AuthorDate: Thu May 10 14:29:26 2018 +0100
Committer: Joe Thornber <ejt at redhat.com>
CommitterDate: Thu May 10 14:29:26 2018 +0100
bcache: Add sync io engine
Something to fall back to when testing.
---
lib/device/bcache.c | 92 +++++++++++++++++++++++++++++++++++++++++++-
lib/device/bcache.h | 1 +
test/unit/bcache_utils_t.c | 67 +++++++++++++++++++++++++++----
3 files changed, 150 insertions(+), 10 deletions(-)
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
index 62e99bd..7a221c5 100644
--- a/lib/device/bcache.c
+++ b/lib/device/bcache.c
@@ -129,7 +129,6 @@ static struct control_block *_iocb_to_cb(struct iocb *icb)
//----------------------------------------------------------------
-// FIXME: write a sync engine too
struct async_engine {
struct io_engine e;
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 WRITEBACK_LOW_THRESHOLD_PERCENT 33
#define WRITEBACK_HIGH_THRESHOLD_PERCENT 66
diff --git a/lib/device/bcache.h b/lib/device/bcache.h
index 3084fa7..b0aebb4 100644
--- a/lib/device/bcache.h
+++ b/lib/device/bcache.h
@@ -48,6 +48,7 @@ struct io_engine {
};
struct io_engine *create_async_io_engine(void);
+struct io_engine *create_sync_io_engine(void);
/*----------------------------------------------------------------*/
diff --git a/test/unit/bcache_utils_t.c b/test/unit/bcache_utils_t.c
index b784c6f..4f15591 100644
--- a/test/unit/bcache_utils_t.c
+++ b/test/unit/bcache_utils_t.c
@@ -48,10 +48,9 @@ static uint64_t byte(block_address b, uint64_t 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];
- struct io_engine *engine;
struct fixture *f = malloc(sizeof(*f));
unsigned b, i;
@@ -72,15 +71,26 @@ static void *_fix_init(void)
f->fd = open(f->fname, O_RDWR | O_DIRECT);
T_ASSERT(f->fd >= 0);
- engine = create_async_io_engine();
- T_ASSERT(engine);
-
f->cache = bcache_create(T_BLOCK_SIZE / 512, NR_BLOCKS, engine);
T_ASSERT(f->cache);
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)
{
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));
for (i = 0; i < len; i++)
T_ASSERT_EQUAL(buffer[i], _pattern_at(pat, byte_b + i));
+ free(buffer);
}
// Verify again, driving bcache directly
@@ -349,16 +360,52 @@ 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 *_async_tests(void)
+{
+ struct test_suite *ts = test_suite_create(_async_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/async/" 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;
+}
+
-static struct test_suite *_tests(void)
+static struct test_suite *_sync_tests(void)
{
- struct test_suite *ts = test_suite_create(_fix_init, _fix_exit);
+ 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);
@@ -379,12 +426,14 @@ static struct test_suite *_tests(void)
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;
}
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);
}
More information about the lvm-devel
mailing list