提交 44b67892 编写于 作者: K Kevin Wolf

blkverify: Implement bdrv_co_preadv/pwritev/flush

This enables byte granularity requests for blkverify, and at the same
time gets us rid of another user of the BDS-level AIO emulation.

The reference output of a test case must be changed because the
verification failure message reports byte offsets instead of sectors
now.
Signed-off-by: NKevin Wolf <kwolf@redhat.com>
Reviewed-by: NEric Blake <eblake@redhat.com>
上级 7c3a9985
...@@ -19,38 +19,36 @@ typedef struct { ...@@ -19,38 +19,36 @@ typedef struct {
BdrvChild *test_file; BdrvChild *test_file;
} BDRVBlkverifyState; } BDRVBlkverifyState;
typedef struct BlkverifyAIOCB BlkverifyAIOCB; typedef struct BlkverifyRequest {
struct BlkverifyAIOCB { Coroutine *co;
BlockAIOCB common; BlockDriverState *bs;
/* Request metadata */ /* Request metadata */
bool is_write; bool is_write;
int64_t sector_num; uint64_t offset;
int nb_sectors; uint64_t bytes;
int flags;
int ret; /* first completed request's result */ int (*request_fn)(BdrvChild *, int64_t, unsigned int, QEMUIOVector *,
unsigned int done; /* completion counter */ BdrvRequestFlags);
QEMUIOVector *qiov; /* user I/O vector */ int ret; /* test image result */
QEMUIOVector raw_qiov; /* cloned I/O vector for raw file */ int raw_ret; /* raw image result */
void *buf; /* buffer for raw file I/O */
void (*verify)(BlkverifyAIOCB *acb); unsigned int done; /* completion counter */
};
static const AIOCBInfo blkverify_aiocb_info = { QEMUIOVector *qiov; /* user I/O vector */
.aiocb_size = sizeof(BlkverifyAIOCB), QEMUIOVector *raw_qiov; /* cloned I/O vector for raw file */
}; } BlkverifyRequest;
static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb, static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyRequest *r,
const char *fmt, ...) const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
fprintf(stderr, "blkverify: %s sector_num=%" PRId64 " nb_sectors=%d ", fprintf(stderr, "blkverify: %s offset=%" PRId64 " bytes=%" PRId64 " ",
acb->is_write ? "write" : "read", acb->sector_num, r->is_write ? "write" : "read", r->offset, r->bytes);
acb->nb_sectors);
vfprintf(stderr, fmt, ap); vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
va_end(ap); va_end(ap);
...@@ -166,113 +164,106 @@ static int64_t blkverify_getlength(BlockDriverState *bs) ...@@ -166,113 +164,106 @@ static int64_t blkverify_getlength(BlockDriverState *bs)
return bdrv_getlength(s->test_file->bs); return bdrv_getlength(s->test_file->bs);
} }
static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write, static void coroutine_fn blkverify_do_test_req(void *opaque)
int64_t sector_num, QEMUIOVector *qiov,
int nb_sectors,
BlockCompletionFunc *cb,
void *opaque)
{ {
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque); BlkverifyRequest *r = opaque;
BDRVBlkverifyState *s = r->bs->opaque;
acb->is_write = is_write;
acb->sector_num = sector_num; r->ret = r->request_fn(s->test_file, r->offset, r->bytes, r->qiov,
acb->nb_sectors = nb_sectors; r->flags);
acb->ret = -EINPROGRESS; r->done++;
acb->done = 0; qemu_coroutine_enter_if_inactive(r->co);
acb->qiov = qiov;
acb->buf = NULL;
acb->verify = NULL;
return acb;
} }
static void blkverify_aio_bh(void *opaque) static void coroutine_fn blkverify_do_raw_req(void *opaque)
{ {
BlkverifyAIOCB *acb = opaque; BlkverifyRequest *r = opaque;
if (acb->buf) { r->raw_ret = r->request_fn(r->bs->file, r->offset, r->bytes, r->raw_qiov,
qemu_iovec_destroy(&acb->raw_qiov); r->flags);
qemu_vfree(acb->buf); r->done++;
} qemu_coroutine_enter_if_inactive(r->co);
acb->common.cb(acb->common.opaque, acb->ret);
qemu_aio_unref(acb);
} }
static void blkverify_aio_cb(void *opaque, int ret) static int coroutine_fn
blkverify_co_prwv(BlockDriverState *bs, BlkverifyRequest *r, uint64_t offset,
uint64_t bytes, QEMUIOVector *qiov, QEMUIOVector *raw_qiov,
int flags, bool is_write)
{ {
BlkverifyAIOCB *acb = opaque; Coroutine *co_a, *co_b;
switch (++acb->done) { *r = (BlkverifyRequest) {
case 1: .co = qemu_coroutine_self(),
acb->ret = ret; .bs = bs,
break; .offset = offset,
.bytes = bytes,
case 2: .qiov = qiov,
if (acb->ret != ret) { .raw_qiov = raw_qiov,
blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret); .flags = flags,
} .is_write = is_write,
.request_fn = is_write ? bdrv_co_pwritev : bdrv_co_preadv,
if (acb->verify) { };
acb->verify(acb);
} co_a = qemu_coroutine_create(blkverify_do_test_req, r);
co_b = qemu_coroutine_create(blkverify_do_raw_req, r);
qemu_coroutine_enter(co_a);
qemu_coroutine_enter(co_b);
while (r->done < 2) {
qemu_coroutine_yield();
}
aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs), if (r->ret != r->raw_ret) {
blkverify_aio_bh, acb); blkverify_err(r, "return value mismatch %d != %d", r->ret, r->raw_ret);
break;
} }
return r->ret;
} }
static void blkverify_verify_readv(BlkverifyAIOCB *acb) static int coroutine_fn
blkverify_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{ {
ssize_t offset = qemu_iovec_compare(acb->qiov, &acb->raw_qiov); BlkverifyRequest r;
if (offset != -1) { QEMUIOVector raw_qiov;
blkverify_err(acb, "contents mismatch in sector %" PRId64, void *buf;
acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE)); ssize_t cmp_offset;
int ret;
buf = qemu_blockalign(bs->file->bs, qiov->size);
qemu_iovec_init(&raw_qiov, qiov->niov);
qemu_iovec_clone(&raw_qiov, qiov, buf);
ret = blkverify_co_prwv(bs, &r, offset, bytes, qiov, &raw_qiov, flags,
false);
cmp_offset = qemu_iovec_compare(qiov, &raw_qiov);
if (cmp_offset != -1) {
blkverify_err(&r, "contents mismatch at offset %" PRId64,
offset + cmp_offset);
} }
}
static BlockAIOCB *blkverify_aio_readv(BlockDriverState *bs, qemu_iovec_destroy(&raw_qiov);
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, qemu_vfree(buf);
BlockCompletionFunc *cb, void *opaque)
{ return ret;
BDRVBlkverifyState *s = bs->opaque;
BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov,
nb_sectors, cb, opaque);
acb->verify = blkverify_verify_readv;
acb->buf = qemu_blockalign(bs->file->bs, qiov->size);
qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
blkverify_aio_cb, acb);
bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
blkverify_aio_cb, acb);
return &acb->common;
} }
static BlockAIOCB *blkverify_aio_writev(BlockDriverState *bs, static int coroutine_fn
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, blkverify_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
BlockCompletionFunc *cb, void *opaque) QEMUIOVector *qiov, int flags)
{ {
BDRVBlkverifyState *s = bs->opaque; BlkverifyRequest r;
BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov, return blkverify_co_prwv(bs, &r, offset, bytes, qiov, qiov, flags, true);
nb_sectors, cb, opaque);
bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors,
blkverify_aio_cb, acb);
bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
blkverify_aio_cb, acb);
return &acb->common;
} }
static BlockAIOCB *blkverify_aio_flush(BlockDriverState *bs, static int blkverify_co_flush(BlockDriverState *bs)
BlockCompletionFunc *cb,
void *opaque)
{ {
BDRVBlkverifyState *s = bs->opaque; BDRVBlkverifyState *s = bs->opaque;
/* Only flush test file, the raw file is not important */ /* Only flush test file, the raw file is not important */
return bdrv_aio_flush(s->test_file->bs, cb, opaque); return bdrv_co_flush(s->test_file->bs);
} }
static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs, static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
...@@ -332,9 +323,9 @@ static BlockDriver bdrv_blkverify = { ...@@ -332,9 +323,9 @@ static BlockDriver bdrv_blkverify = {
.bdrv_getlength = blkverify_getlength, .bdrv_getlength = blkverify_getlength,
.bdrv_refresh_filename = blkverify_refresh_filename, .bdrv_refresh_filename = blkverify_refresh_filename,
.bdrv_aio_readv = blkverify_aio_readv, .bdrv_co_preadv = blkverify_co_preadv,
.bdrv_aio_writev = blkverify_aio_writev, .bdrv_co_pwritev = blkverify_co_pwritev,
.bdrv_aio_flush = blkverify_aio_flush, .bdrv_co_flush = blkverify_co_flush,
.is_filter = true, .is_filter = true,
.bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter, .bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter,
......
...@@ -12,7 +12,7 @@ read 512/512 bytes at offset 229376 ...@@ -12,7 +12,7 @@ read 512/512 bytes at offset 229376
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 blkverify: read offset=0 bytes=512 contents mismatch at offset 0
=== Testing blkverify through file blockref === === Testing blkverify through file blockref ===
...@@ -26,7 +26,7 @@ read 512/512 bytes at offset 229376 ...@@ -26,7 +26,7 @@ read 512/512 bytes at offset 229376
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 512/512 bytes at offset 0 wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 blkverify: read offset=0 bytes=512 contents mismatch at offset 0
=== Testing blkdebug through filename === === Testing blkdebug through filename ===
...@@ -56,7 +56,7 @@ QMP_VERSION ...@@ -56,7 +56,7 @@ QMP_VERSION
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 blkverify: read offset=0 bytes=512 contents mismatch at offset 0
=== Testing blkverify on existing raw block device === === Testing blkverify on existing raw block device ===
...@@ -66,7 +66,7 @@ QMP_VERSION ...@@ -66,7 +66,7 @@ QMP_VERSION
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
{"return": {}} {"return": {}}
blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 blkverify: read offset=0 bytes=512 contents mismatch at offset 0
=== Testing blkdebug's set-state through QMP === === Testing blkdebug's set-state through QMP ===
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册