[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 3/4] Test cases for block-queue
From: |
Kevin Wolf |
Subject: |
[Qemu-devel] [PATCH 3/4] Test cases for block-queue |
Date: |
Mon, 13 Dec 2010 17:29:06 +0100 |
Add some unit tests especially for the ordering and request merging in
block-queue.
Signed-off-by: Kevin Wolf <address@hidden>
---
Makefile | 1 +
check-block-queue.c | 402 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 403 insertions(+), 0 deletions(-)
create mode 100644 check-block-queue.c
diff --git a/Makefile b/Makefile
index c80566c..3e60d7e 100644
--- a/Makefile
+++ b/Makefile
@@ -172,6 +172,7 @@ check-qdict: check-qdict.o qdict.o qfloat.o qint.o
qstring.o qbool.o qlist.o $(C
check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o
qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS)
+check-block-queue: check-block-queue.o qemu-tool.o qemu-error.o $(oslib-obj-y)
$(filter-out block-queue.o,$(block-obj-y)) $(qobject-obj-y) qemu-timer-common.o
clean:
# avoid old build problems by removing potentially incorrect old files
diff --git a/check-block-queue.c b/check-block-queue.c
new file mode 100644
index 0000000..b2d4444
--- /dev/null
+++ b/check-block-queue.c
@@ -0,0 +1,402 @@
+/*
+ * block-queue.c unit tests
+ *
+ * Copyright (c) 2010 Kevin Wolf <address@hidden>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* We want to test some static functions, so just include the source file */
+#define RUN_TESTS
+#include "block-queue.c"
+
+#define CHECK_WRITE(req, _bq, _offset, _size, _buf, _section) \
+ do { \
+ assert(req != NULL); \
+ assert(req->type == REQ_TYPE_WRITE); \
+ assert(req->bq == _bq); \
+ assert(req->offset == _offset); \
+ assert(req->size == _size); \
+ assert(req->section == _section); \
+ assert(!memcmp(req->buf, _buf, _size)); \
+ } while(0)
+
+#define CHECK_BARRIER(req, _bq, _section) \
+ do { \
+ assert(req != NULL); \
+ assert(req->type == REQ_TYPE_BARRIER); \
+ assert(req->bq == _bq); \
+ assert(req->section == _section); \
+ } while(0)
+
+#define CHECK_READ(_context, _offset, _buf, _size, _cmpbuf) \
+ do { \
+ int ret; \
+ memset(buf, 0, 512); \
+ ret = blkqueue_pread(_context, _offset, _buf, _size); \
+ assert(ret == 0); \
+ assert(!memcmp(_cmpbuf, _buf, _size)); \
+ } while(0)
+
+#define QUEUE_WRITE(_context, _offset, _buf, _size, _pattern) \
+ do { \
+ int ret; \
+ memset(_buf, _pattern, _size); \
+ ret = blkqueue_pwrite(_context, _offset, _buf, _size); \
+ assert(ret == 0); \
+ } while(0)
+#define QUEUE_BARRIER(_context) \
+ do { \
+ int ret; \
+ ret = blkqueue_barrier(_context); \
+ assert(ret == 0); \
+ } while(0)
+
+#define POP_CHECK_WRITE(_bq, _offset, _buf, _size, _pattern, _section) \
+ do { \
+ BlockQueueRequest *req; \
+ memset(_buf, _pattern, _size); \
+ req = blkqueue_pop(_bq); \
+ CHECK_WRITE(req, _bq, _offset, _size, _buf, _section); \
+ blkqueue_free_request(req); \
+ } while(0)
+#define POP_CHECK_BARRIER(_bq, _section) \
+ do { \
+ BlockQueueRequest *req; \
+ req = blkqueue_pop(_bq); \
+ CHECK_BARRIER(req, _bq, _section); \
+ blkqueue_free_request(req); \
+ } while(0)
+
+static void __attribute__((used)) dump_queue(BlockQueue *bq)
+{
+ BlockQueueRequest *req;
+
+ fprintf(stderr, "--- Queue dump ---\n");
+ QTAILQ_FOREACH(req, &bq->queue, link) {
+ fprintf(stderr, "[%d] ", req->section);
+ if (req->type == REQ_TYPE_WRITE) {
+ fprintf(stderr, "Write off=%5"PRId64", len=%5"PRId64", buf=%p\n",
+ req->offset, req->size, req->buf);
+ } else if (req->type == REQ_TYPE_BARRIER) {
+ fprintf(stderr, "Barrier\n");
+ } else {
+ fprintf(stderr, "Unknown type %d\n", req->type);
+ }
+ }
+}
+
+static void test_basic(BlockDriverState *bs)
+{
+ uint8_t buf[512];
+ BlockQueue *bq;
+ BlockQueueContext context;
+
+ bq = blkqueue_create(bs, NULL, NULL);
+ blkqueue_init_context(&context, bq);
+
+ /* Queue requests */
+ QUEUE_WRITE(&context, 0, buf, 512, 0x12);
+ QUEUE_WRITE(&context, 512, buf, 42, 0x34);
+ QUEUE_BARRIER(&context);
+ QUEUE_WRITE(&context, 678, buf, 42, 0x56);
+
+ /* Verify queue contents */
+ POP_CHECK_WRITE(bq, 0, buf, 512, 0x12, 1);
+ POP_CHECK_WRITE(bq, 512, buf, 42, 0x34, 1);
+ POP_CHECK_BARRIER(bq, 1);
+ POP_CHECK_WRITE(bq, 678, buf, 42, 0x56, 2);
+
+ blkqueue_destroy(bq);
+}
+
+static void test_merge(BlockDriverState *bs)
+{
+ uint8_t buf[512];
+ BlockQueue *bq;
+ BlockQueueContext ctx1, ctx2;
+
+ bq = blkqueue_create(bs, NULL, NULL);
+ blkqueue_init_context(&ctx1, bq);
+ blkqueue_init_context(&ctx2, bq);
+
+ /* Queue requests */
+ QUEUE_WRITE(&ctx1, 0, buf, 512, 0x12);
+ QUEUE_BARRIER(&ctx1);
+ QUEUE_WRITE(&ctx2, 512, buf, 42, 0x34);
+ QUEUE_WRITE(&ctx1, 1024, buf, 512, 0x12);
+ QUEUE_BARRIER(&ctx2);
+ QUEUE_WRITE(&ctx2, 1536, buf, 42, 0x34);
+
+ /* Verify queue contents */
+ POP_CHECK_WRITE(bq, 0, buf, 512, 0x12, 1);
+ POP_CHECK_WRITE(bq, 512, buf, 42, 0x34, 1);
+ POP_CHECK_BARRIER(bq, 1);
+ POP_CHECK_WRITE(bq, 1024, buf, 512, 0x12, 2);
+ POP_CHECK_WRITE(bq, 1536, buf, 42, 0x34, 2);
+
+ /* Same queue, new contexts */
+ blkqueue_init_context(&ctx1, bq);
+ blkqueue_init_context(&ctx2, bq);
+
+ /* Queue requests */
+ QUEUE_BARRIER(&ctx2);
+ QUEUE_WRITE(&ctx2, 512, buf, 42, 0x34);
+ QUEUE_WRITE(&ctx2, 12, buf, 20, 0x45);
+ QUEUE_BARRIER(&ctx2);
+ QUEUE_WRITE(&ctx2, 2892, buf, 142, 0x56);
+
+ QUEUE_WRITE(&ctx1, 0, buf, 8, 0x12);
+ QUEUE_BARRIER(&ctx1);
+ QUEUE_WRITE(&ctx1, 1024, buf, 512, 0x12);
+ QUEUE_BARRIER(&ctx1);
+ QUEUE_WRITE(&ctx1, 2512, buf, 42, 0x34);
+ QUEUE_BARRIER(&ctx1);
+
+ /* Verify queue contents */
+ POP_CHECK_WRITE(bq, 0, buf, 8, 0x12, 1);
+ POP_CHECK_BARRIER(bq, 1);
+ POP_CHECK_WRITE(bq, 512, buf, 42, 0x34, 2);
+ POP_CHECK_WRITE(bq, 12, buf, 20, 0x45, 2);
+ POP_CHECK_WRITE(bq, 1024, buf, 512, 0x12, 2);
+ POP_CHECK_BARRIER(bq, 2);
+ POP_CHECK_WRITE(bq, 2892, buf, 142, 0x56, 3);
+ POP_CHECK_WRITE(bq, 2512, buf, 42, 0x34, 3);
+ POP_CHECK_BARRIER(bq, 3);
+
+ blkqueue_destroy(bq);
+}
+
+static void test_read(BlockDriverState *bs)
+{
+ uint8_t buf[512], buf2[512];
+ BlockQueue *bq;
+ BlockQueueContext ctx1;
+
+ bq = blkqueue_create(bs, NULL, NULL);
+ blkqueue_init_context(&ctx1, bq);
+
+ /* Queue requests and do some test reads */
+ memset(buf2, 0xa5, 512);
+ CHECK_READ(&ctx1, 0, buf, 32, buf2);
+
+ QUEUE_WRITE(&ctx1, 5, buf, 5, 0x12);
+ memset(buf2, 0x12, 5);
+ CHECK_READ(&ctx1, 5, buf, 5, buf2);
+ CHECK_READ(&ctx1, 7, buf, 2, buf2);
+ memset(buf2, 0xa5, 512);
+ memset(buf2 + 5, 0x12, 5);
+ CHECK_READ(&ctx1, 0, buf, 8, buf2);
+ CHECK_READ(&ctx1, 0, buf, 10, buf2);
+ CHECK_READ(&ctx1, 0, buf, 32, buf2);
+ memset(buf2, 0xa5, 512);
+ memset(buf2, 0x12, 5);
+ CHECK_READ(&ctx1, 5, buf, 16, buf2);
+ memset(buf2, 0xa5, 512);
+ CHECK_READ(&ctx1, 0, buf, 2, buf2);
+ CHECK_READ(&ctx1, 10, buf, 16, buf2);
+
+ QUEUE_WRITE(&ctx1, 0, buf, 2, 0x12);
+ memset(&buf2[5], 0x12, 5);
+ memset(buf2, 0x12, 2);
+ CHECK_READ(&ctx1, 0, buf, 32, buf2);
+
+ /* Verify queue contents */
+ POP_CHECK_WRITE(bq, 5, buf, 5, 0x12, 1);
+ POP_CHECK_WRITE(bq, 0, buf, 2, 0x12, 1);
+
+ blkqueue_destroy(bq);
+}
+
+static void test_read_order(BlockDriverState *bs)
+{
+ uint8_t buf[512], buf2[512];
+ BlockQueue *bq;
+ BlockQueueContext ctx1, ctx2;
+
+ bq = blkqueue_create(bs, NULL, NULL);
+ blkqueue_init_context(&ctx1, bq);
+ blkqueue_init_context(&ctx2, bq);
+
+ /* Queue requests and do some test reads */
+ QUEUE_WRITE(&ctx1, 25, buf, 5, 0x44);
+ QUEUE_BARRIER(&ctx1);
+ QUEUE_WRITE(&ctx1, 5, buf, 5, 0x12);
+ QUEUE_BARRIER(&ctx1);
+ QUEUE_WRITE(&ctx2, 10, buf, 5, 0x34);
+
+ memset(buf2, 0xa5, 512);
+ memset(buf2 + 5, 0x12, 5);
+ memset(buf2 + 10, 0x34, 5);
+ CHECK_READ(&ctx2, 0, buf, 20, buf2);
+ QUEUE_WRITE(&ctx2, 0, buf, 10, 0x34);
+ QUEUE_BARRIER(&ctx2);
+
+ /* Verify queue contents */
+ POP_CHECK_WRITE(bq, 25, buf, 5, 0x44, 1);
+ POP_CHECK_WRITE(bq, 10, buf, 5, 0x34, 1);
+ POP_CHECK_BARRIER(bq, 1);
+ POP_CHECK_WRITE(bq, 5, buf, 5, 0x34, 2);
+ POP_CHECK_WRITE(bq, 0, buf, 5, 0x34, 2);
+ POP_CHECK_BARRIER(bq, 2);
+
+ blkqueue_destroy(bq);
+}
+
+static void test_write_order(BlockDriverState *bs)
+{
+ uint8_t buf[512], buf2[512];
+ BlockQueue *bq;
+ BlockQueueContext context;
+
+ bq = blkqueue_create(bs, NULL, NULL);
+
+ /* Merging two writes */
+ /* Queue requests */
+ blkqueue_init_context(&context, bq);
+ QUEUE_WRITE(&context, 0, buf, 512, 0x12);
+ QUEUE_BARRIER(&context);
+ QUEUE_WRITE(&context, 512, buf, 512, 0x56);
+
+ blkqueue_init_context(&context, bq);
+ QUEUE_WRITE(&context, 512, buf, 512, 0x34);
+
+ /* Verify queue contents */
+ POP_CHECK_WRITE(bq, 0, buf, 512, 0x12, 1);
+ POP_CHECK_BARRIER(bq, 1);
+ POP_CHECK_WRITE(bq, 512, buf, 512, 0x34, 2);
+
+ /* Queue requests once again */
+ blkqueue_init_context(&context, bq);
+ QUEUE_WRITE(&context, 0, buf, 512, 0x12);
+ QUEUE_BARRIER(&context);
+ QUEUE_WRITE(&context, 512, buf, 512, 0x56);
+
+ blkqueue_init_context(&context, bq);
+ QUEUE_WRITE(&context, 512, buf, 512, 0x34);
+
+ /* Check if the right values are read back */
+ memset(buf2, 0x34, 512);
+ CHECK_READ(&context, 512, buf, 512, buf2);
+ blkqueue_process_request(bq);
+ qemu_aio_flush();
+ memset(buf2, 0x34, 512);
+ CHECK_READ(&context, 512, buf, 512, buf2);
+
+ blkqueue_flush(bq);
+
+ /* Must not merge with write in earlier section */
+ /* Queue requests */
+ blkqueue_init_context(&context, bq);
+ QUEUE_WRITE(&context, 0, buf, 512, 0x12);
+
+ blkqueue_init_context(&context, bq);
+ QUEUE_WRITE(&context, 512, buf, 512, 0x34);
+ QUEUE_BARRIER(&context);
+ QUEUE_WRITE(&context, 0, buf, 512, 0x56);
+
+ /* Verify queue contents */
+ POP_CHECK_WRITE(bq, 0, buf, 512, 0x12, 1);
+ POP_CHECK_WRITE(bq, 512, buf, 512, 0x34, 1);
+ POP_CHECK_BARRIER(bq, 1);
+ POP_CHECK_WRITE(bq, 0, buf, 512, 0x56, 2);
+
+ blkqueue_destroy(bq);
+}
+
+static void test_process_request(BlockDriverState *bs)
+{
+ uint8_t buf[512], buf2[512];
+ BlockQueue *bq;
+ BlockQueueContext ctx1;
+
+ bq = blkqueue_create(bs, NULL, NULL);
+ blkqueue_init_context(&ctx1, bq);
+
+ /* Queue requests and do a test read */
+ QUEUE_WRITE(&ctx1, 25, buf, 5, 0x44);
+ QUEUE_BARRIER(&ctx1);
+
+ memset(buf2, 0xa5, 512);
+ memset(buf2 + 25, 0x44, 5);
+ CHECK_READ(&ctx1, 0, buf, 64, buf2);
+
+ /* Process the requests */
+ blkqueue_process_request(bq);
+
+ /* Check if we still read the same */
+ CHECK_READ(&ctx1, 0, buf, 64, buf2);
+
+ /* Process the AIO requests and check again */
+ qemu_aio_flush();
+ assert(bq->barriers_submitted == 1);
+ assert(bq->in_flight_num == 0);
+ CHECK_READ(&ctx1, 0, buf, 64, buf2);
+
+ /* Run the barrier */
+ blkqueue_flush(bq);
+
+ /* Verify the queue is empty */
+ assert(blkqueue_pop(bq) == NULL);
+
+ /* Check that processing an empty queue works */
+ blkqueue_process_request(bq);
+
+ blkqueue_destroy(bq);
+}
+
+static void run_test(void (*testfn)(BlockDriverState*), BlockDriverState *bs)
+{
+ void* buf;
+ int ret;
+
+ buf = qemu_malloc(1024 * 1024);
+ memset(buf, 0xa5, 1024 * 1024);
+ ret = bdrv_write(bs, 0, buf, 2048);
+ assert(ret >= 0);
+ qemu_free(buf);
+
+ testfn(bs);
+}
+
+int main(void)
+{
+ BlockDriverState *bs;
+ int ret;
+
+ bdrv_init();
+ bs = bdrv_new("");
+ ret = bdrv_open(bs, "block-queue.img", BDRV_O_RDWR | BDRV_O_CACHE_WB,
NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Couldn't open block-queue.img: %s\n",
+ strerror(-ret));
+ exit(1);
+ }
+
+ run_test(&test_basic, bs);
+ run_test(&test_merge, bs);
+ run_test(&test_read, bs);
+ run_test(&test_read_order, bs);
+ run_test(&test_write_order, bs);
+ run_test(&test_process_request, bs);
+
+ bdrv_delete(bs);
+
+ return 0;
+}
--
1.7.2.3