Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Block protocol for block driver correctness testing |
| 3 | * |
| 4 | * Copyright (C) 2010 IBM, Corp. |
| 5 | * |
| 6 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
| 7 | * See the COPYING file in the top-level directory. |
| 8 | */ |
| 9 | |
| 10 | #include <stdarg.h> |
Paolo Bonzini | 1de7afc | 2012-12-17 18:20:00 +0100 | [diff] [blame] | 11 | #include "qemu/sockets.h" /* for EINPROGRESS on Windows */ |
Paolo Bonzini | 737e150 | 2012-12-17 18:19:44 +0100 | [diff] [blame] | 12 | #include "block/block_int.h" |
Max Reitz | 74b36b2 | 2014-07-18 20:24:58 +0200 | [diff] [blame] | 13 | #include "qapi/qmp/qdict.h" |
| 14 | #include "qapi/qmp/qstring.h" |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 15 | |
| 16 | typedef struct { |
| 17 | BlockDriverState *test_file; |
| 18 | } BDRVBlkverifyState; |
| 19 | |
| 20 | typedef struct BlkverifyAIOCB BlkverifyAIOCB; |
| 21 | struct BlkverifyAIOCB { |
| 22 | BlockDriverAIOCB common; |
| 23 | QEMUBH *bh; |
| 24 | |
| 25 | /* Request metadata */ |
| 26 | bool is_write; |
| 27 | int64_t sector_num; |
| 28 | int nb_sectors; |
| 29 | |
| 30 | int ret; /* first completed request's result */ |
| 31 | unsigned int done; /* completion counter */ |
| 32 | bool *finished; /* completion signal for cancel */ |
| 33 | |
| 34 | QEMUIOVector *qiov; /* user I/O vector */ |
| 35 | QEMUIOVector raw_qiov; /* cloned I/O vector for raw file */ |
| 36 | void *buf; /* buffer for raw file I/O */ |
| 37 | |
| 38 | void (*verify)(BlkverifyAIOCB *acb); |
| 39 | }; |
| 40 | |
| 41 | static void blkverify_aio_cancel(BlockDriverAIOCB *blockacb) |
| 42 | { |
| 43 | BlkverifyAIOCB *acb = (BlkverifyAIOCB *)blockacb; |
Stefan Hajnoczi | 9d94020 | 2014-05-08 16:34:39 +0200 | [diff] [blame] | 44 | AioContext *aio_context = bdrv_get_aio_context(blockacb->bs); |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 45 | bool finished = false; |
| 46 | |
| 47 | /* Wait until request completes, invokes its callback, and frees itself */ |
| 48 | acb->finished = &finished; |
| 49 | while (!finished) { |
Stefan Hajnoczi | 9d94020 | 2014-05-08 16:34:39 +0200 | [diff] [blame] | 50 | aio_poll(aio_context, true); |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 51 | } |
| 52 | } |
| 53 | |
Stefan Hajnoczi | d7331be | 2012-10-31 16:34:37 +0100 | [diff] [blame] | 54 | static const AIOCBInfo blkverify_aiocb_info = { |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 55 | .aiocb_size = sizeof(BlkverifyAIOCB), |
| 56 | .cancel = blkverify_aio_cancel, |
| 57 | }; |
| 58 | |
Stefan Weil | a77cffe | 2010-09-24 21:02:05 +0200 | [diff] [blame] | 59 | static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb, |
| 60 | const char *fmt, ...) |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 61 | { |
| 62 | va_list ap; |
| 63 | |
| 64 | va_start(ap, fmt); |
Anthony Liguori | 687db4e | 2010-09-22 14:46:33 -0500 | [diff] [blame] | 65 | fprintf(stderr, "blkverify: %s sector_num=%" PRId64 " nb_sectors=%d ", |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 66 | acb->is_write ? "write" : "read", acb->sector_num, |
| 67 | acb->nb_sectors); |
| 68 | vfprintf(stderr, fmt, ap); |
| 69 | fprintf(stderr, "\n"); |
| 70 | va_end(ap); |
| 71 | exit(1); |
| 72 | } |
| 73 | |
| 74 | /* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */ |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 75 | static void blkverify_parse_filename(const char *filename, QDict *options, |
| 76 | Error **errp) |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 77 | { |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 78 | const char *c; |
| 79 | QString *raw_path; |
| 80 | |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 81 | |
| 82 | /* Parse the blkverify: prefix */ |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 83 | if (!strstart(filename, "blkverify:", &filename)) { |
Max Reitz | 22511ad | 2013-12-20 19:28:17 +0100 | [diff] [blame] | 84 | /* There was no prefix; therefore, all options have to be already |
| 85 | present in the QDict (except for the filename) */ |
| 86 | qdict_put(options, "x-image", qstring_from_str(filename)); |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 87 | return; |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 88 | } |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 89 | |
| 90 | /* Parse the raw image filename */ |
| 91 | c = strchr(filename, ':'); |
| 92 | if (c == NULL) { |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 93 | error_setg(errp, "blkverify requires raw copy and original image path"); |
| 94 | return; |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 95 | } |
| 96 | |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 97 | /* TODO Implement option pass-through and set raw.filename here */ |
| 98 | raw_path = qstring_from_substr(filename, 0, c - filename - 1); |
| 99 | qdict_put(options, "x-raw", raw_path); |
| 100 | |
| 101 | /* TODO Allow multi-level nesting and set file.filename here */ |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 102 | filename = c + 1; |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 103 | qdict_put(options, "x-image", qstring_from_str(filename)); |
| 104 | } |
| 105 | |
| 106 | static QemuOptsList runtime_opts = { |
| 107 | .name = "blkverify", |
| 108 | .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), |
| 109 | .desc = { |
| 110 | { |
| 111 | .name = "x-raw", |
| 112 | .type = QEMU_OPT_STRING, |
| 113 | .help = "[internal use only, will be removed]", |
| 114 | }, |
| 115 | { |
| 116 | .name = "x-image", |
| 117 | .type = QEMU_OPT_STRING, |
| 118 | .help = "[internal use only, will be removed]", |
| 119 | }, |
| 120 | { /* end of list */ } |
| 121 | }, |
| 122 | }; |
| 123 | |
Max Reitz | 015a103 | 2013-09-05 14:22:29 +0200 | [diff] [blame] | 124 | static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, |
| 125 | Error **errp) |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 126 | { |
| 127 | BDRVBlkverifyState *s = bs->opaque; |
| 128 | QemuOpts *opts; |
| 129 | Error *local_err = NULL; |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 130 | int ret; |
| 131 | |
Peter Crosthwaite | 87ea75d | 2014-01-01 18:49:17 -0800 | [diff] [blame] | 132 | opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 133 | qemu_opts_absorb_qdict(opts, options, &local_err); |
Markus Armbruster | 84d18f0 | 2014-01-30 15:07:28 +0100 | [diff] [blame] | 134 | if (local_err) { |
Max Reitz | ca28840 | 2013-10-10 15:44:04 +0200 | [diff] [blame] | 135 | error_propagate(errp, local_err); |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 136 | ret = -EINVAL; |
| 137 | goto fail; |
| 138 | } |
| 139 | |
Max Reitz | 70b6198 | 2013-12-20 19:28:16 +0100 | [diff] [blame] | 140 | /* Open the raw file */ |
Max Reitz | f67503e | 2014-02-18 18:33:05 +0100 | [diff] [blame] | 141 | assert(bs->file == NULL); |
Max Reitz | 70b6198 | 2013-12-20 19:28:16 +0100 | [diff] [blame] | 142 | ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-raw"), options, |
Max Reitz | f7d9fd8 | 2014-02-18 18:33:12 +0100 | [diff] [blame] | 143 | "raw", flags | BDRV_O_PROTOCOL, false, &local_err); |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 144 | if (ret < 0) { |
Max Reitz | ca28840 | 2013-10-10 15:44:04 +0200 | [diff] [blame] | 145 | error_propagate(errp, local_err); |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 146 | goto fail; |
| 147 | } |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 148 | |
| 149 | /* Open the test file */ |
Max Reitz | f67503e | 2014-02-18 18:33:05 +0100 | [diff] [blame] | 150 | assert(s->test_file == NULL); |
Max Reitz | 70b6198 | 2013-12-20 19:28:16 +0100 | [diff] [blame] | 151 | ret = bdrv_open_image(&s->test_file, qemu_opt_get(opts, "x-image"), options, |
Max Reitz | f7d9fd8 | 2014-02-18 18:33:12 +0100 | [diff] [blame] | 152 | "test", flags, false, &local_err); |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 153 | if (ret < 0) { |
Max Reitz | ca28840 | 2013-10-10 15:44:04 +0200 | [diff] [blame] | 154 | error_propagate(errp, local_err); |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 155 | s->test_file = NULL; |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 156 | goto fail; |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 157 | } |
| 158 | |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 159 | ret = 0; |
| 160 | fail: |
Fam Zheng | 3158593 | 2014-08-28 13:56:11 +0800 | [diff] [blame] | 161 | qemu_opts_del(opts); |
Kevin Wolf | 16c7909 | 2013-04-10 14:40:28 +0200 | [diff] [blame] | 162 | return ret; |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | static void blkverify_close(BlockDriverState *bs) |
| 166 | { |
| 167 | BDRVBlkverifyState *s = bs->opaque; |
| 168 | |
Fam Zheng | 4f6fd34 | 2013-08-23 09:14:47 +0800 | [diff] [blame] | 169 | bdrv_unref(s->test_file); |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 170 | s->test_file = NULL; |
| 171 | } |
| 172 | |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 173 | static int64_t blkverify_getlength(BlockDriverState *bs) |
| 174 | { |
| 175 | BDRVBlkverifyState *s = bs->opaque; |
| 176 | |
| 177 | return bdrv_getlength(s->test_file); |
| 178 | } |
| 179 | |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 180 | static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write, |
| 181 | int64_t sector_num, QEMUIOVector *qiov, |
| 182 | int nb_sectors, |
| 183 | BlockDriverCompletionFunc *cb, |
| 184 | void *opaque) |
| 185 | { |
Stefan Hajnoczi | d7331be | 2012-10-31 16:34:37 +0100 | [diff] [blame] | 186 | BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque); |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 187 | |
| 188 | acb->bh = NULL; |
| 189 | acb->is_write = is_write; |
| 190 | acb->sector_num = sector_num; |
| 191 | acb->nb_sectors = nb_sectors; |
| 192 | acb->ret = -EINPROGRESS; |
| 193 | acb->done = 0; |
| 194 | acb->qiov = qiov; |
| 195 | acb->buf = NULL; |
| 196 | acb->verify = NULL; |
| 197 | acb->finished = NULL; |
| 198 | return acb; |
| 199 | } |
| 200 | |
| 201 | static void blkverify_aio_bh(void *opaque) |
| 202 | { |
| 203 | BlkverifyAIOCB *acb = opaque; |
| 204 | |
| 205 | qemu_bh_delete(acb->bh); |
| 206 | if (acb->buf) { |
| 207 | qemu_iovec_destroy(&acb->raw_qiov); |
| 208 | qemu_vfree(acb->buf); |
| 209 | } |
| 210 | acb->common.cb(acb->common.opaque, acb->ret); |
| 211 | if (acb->finished) { |
| 212 | *acb->finished = true; |
| 213 | } |
| 214 | qemu_aio_release(acb); |
| 215 | } |
| 216 | |
| 217 | static void blkverify_aio_cb(void *opaque, int ret) |
| 218 | { |
| 219 | BlkverifyAIOCB *acb = opaque; |
| 220 | |
| 221 | switch (++acb->done) { |
| 222 | case 1: |
| 223 | acb->ret = ret; |
| 224 | break; |
| 225 | |
| 226 | case 2: |
| 227 | if (acb->ret != ret) { |
| 228 | blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret); |
| 229 | } |
| 230 | |
| 231 | if (acb->verify) { |
| 232 | acb->verify(acb); |
| 233 | } |
| 234 | |
Stefan Hajnoczi | 9d94020 | 2014-05-08 16:34:39 +0200 | [diff] [blame] | 235 | acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs), |
| 236 | blkverify_aio_bh, acb); |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 237 | qemu_bh_schedule(acb->bh); |
| 238 | break; |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | static void blkverify_verify_readv(BlkverifyAIOCB *acb) |
| 243 | { |
Benoît Canet | f70d7f7 | 2014-02-21 22:21:13 +0100 | [diff] [blame] | 244 | ssize_t offset = qemu_iovec_compare(acb->qiov, &acb->raw_qiov); |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 245 | if (offset != -1) { |
Blue Swirl | a313358 | 2010-10-30 16:46:27 +0000 | [diff] [blame] | 246 | blkverify_err(acb, "contents mismatch in sector %" PRId64, |
| 247 | acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE)); |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 248 | } |
| 249 | } |
| 250 | |
| 251 | static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs, |
| 252 | int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, |
| 253 | BlockDriverCompletionFunc *cb, void *opaque) |
| 254 | { |
| 255 | BDRVBlkverifyState *s = bs->opaque; |
| 256 | BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov, |
| 257 | nb_sectors, cb, opaque); |
| 258 | |
| 259 | acb->verify = blkverify_verify_readv; |
| 260 | acb->buf = qemu_blockalign(bs->file, qiov->size); |
| 261 | qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov); |
Benoît Canet | f70d7f7 | 2014-02-21 22:21:13 +0100 | [diff] [blame] | 262 | qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf); |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 263 | |
Paolo Bonzini | ad54ae8 | 2011-11-30 09:12:30 +0100 | [diff] [blame] | 264 | bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors, |
| 265 | blkverify_aio_cb, acb); |
| 266 | bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors, |
| 267 | blkverify_aio_cb, acb); |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 268 | return &acb->common; |
| 269 | } |
| 270 | |
| 271 | static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs, |
| 272 | int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, |
| 273 | BlockDriverCompletionFunc *cb, void *opaque) |
| 274 | { |
| 275 | BDRVBlkverifyState *s = bs->opaque; |
| 276 | BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov, |
| 277 | nb_sectors, cb, opaque); |
| 278 | |
Paolo Bonzini | ad54ae8 | 2011-11-30 09:12:30 +0100 | [diff] [blame] | 279 | bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors, |
| 280 | blkverify_aio_cb, acb); |
| 281 | bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, |
| 282 | blkverify_aio_cb, acb); |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 283 | return &acb->common; |
| 284 | } |
| 285 | |
| 286 | static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs, |
| 287 | BlockDriverCompletionFunc *cb, |
| 288 | void *opaque) |
| 289 | { |
| 290 | BDRVBlkverifyState *s = bs->opaque; |
| 291 | |
| 292 | /* Only flush test file, the raw file is not important */ |
| 293 | return bdrv_aio_flush(s->test_file, cb, opaque); |
| 294 | } |
| 295 | |
Benoît Canet | b5042a3 | 2014-03-03 19:11:34 +0100 | [diff] [blame] | 296 | static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs, |
| 297 | BlockDriverState *candidate) |
| 298 | { |
| 299 | BDRVBlkverifyState *s = bs->opaque; |
| 300 | |
| 301 | bool perm = bdrv_recurse_is_first_non_filter(bs->file, candidate); |
| 302 | |
| 303 | if (perm) { |
| 304 | return true; |
| 305 | } |
| 306 | |
| 307 | return bdrv_recurse_is_first_non_filter(s->test_file, candidate); |
| 308 | } |
| 309 | |
Stefan Hajnoczi | 9d94020 | 2014-05-08 16:34:39 +0200 | [diff] [blame] | 310 | /* Propagate AioContext changes to ->test_file */ |
| 311 | static void blkverify_detach_aio_context(BlockDriverState *bs) |
| 312 | { |
| 313 | BDRVBlkverifyState *s = bs->opaque; |
| 314 | |
| 315 | bdrv_detach_aio_context(s->test_file); |
| 316 | } |
| 317 | |
| 318 | static void blkverify_attach_aio_context(BlockDriverState *bs, |
| 319 | AioContext *new_context) |
| 320 | { |
| 321 | BDRVBlkverifyState *s = bs->opaque; |
| 322 | |
| 323 | bdrv_attach_aio_context(s->test_file, new_context); |
| 324 | } |
| 325 | |
Max Reitz | 74b36b2 | 2014-07-18 20:24:58 +0200 | [diff] [blame] | 326 | static void blkverify_refresh_filename(BlockDriverState *bs) |
| 327 | { |
| 328 | BDRVBlkverifyState *s = bs->opaque; |
| 329 | |
| 330 | /* bs->file has already been refreshed */ |
| 331 | bdrv_refresh_filename(s->test_file); |
| 332 | |
| 333 | if (bs->file->full_open_options && s->test_file->full_open_options) { |
| 334 | QDict *opts = qdict_new(); |
| 335 | qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkverify"))); |
| 336 | |
| 337 | QINCREF(bs->file->full_open_options); |
| 338 | qdict_put_obj(opts, "raw", QOBJECT(bs->file->full_open_options)); |
| 339 | QINCREF(s->test_file->full_open_options); |
| 340 | qdict_put_obj(opts, "test", QOBJECT(s->test_file->full_open_options)); |
| 341 | |
| 342 | bs->full_open_options = opts; |
| 343 | } |
| 344 | |
| 345 | if (bs->file->exact_filename[0] && s->test_file->exact_filename[0]) { |
| 346 | snprintf(bs->exact_filename, sizeof(bs->exact_filename), |
| 347 | "blkverify:%s:%s", |
| 348 | bs->file->exact_filename, s->test_file->exact_filename); |
| 349 | } |
| 350 | } |
| 351 | |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 352 | static BlockDriver bdrv_blkverify = { |
Stefan Hajnoczi | 9d94020 | 2014-05-08 16:34:39 +0200 | [diff] [blame] | 353 | .format_name = "blkverify", |
| 354 | .protocol_name = "blkverify", |
| 355 | .instance_size = sizeof(BDRVBlkverifyState), |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 356 | |
Stefan Hajnoczi | 9d94020 | 2014-05-08 16:34:39 +0200 | [diff] [blame] | 357 | .bdrv_parse_filename = blkverify_parse_filename, |
| 358 | .bdrv_file_open = blkverify_open, |
| 359 | .bdrv_close = blkverify_close, |
| 360 | .bdrv_getlength = blkverify_getlength, |
Max Reitz | 74b36b2 | 2014-07-18 20:24:58 +0200 | [diff] [blame] | 361 | .bdrv_refresh_filename = blkverify_refresh_filename, |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 362 | |
Stefan Hajnoczi | 9d94020 | 2014-05-08 16:34:39 +0200 | [diff] [blame] | 363 | .bdrv_aio_readv = blkverify_aio_readv, |
| 364 | .bdrv_aio_writev = blkverify_aio_writev, |
| 365 | .bdrv_aio_flush = blkverify_aio_flush, |
Benoît Canet | f6186f4 | 2013-10-02 14:33:48 +0200 | [diff] [blame] | 366 | |
Stefan Hajnoczi | 9d94020 | 2014-05-08 16:34:39 +0200 | [diff] [blame] | 367 | .bdrv_attach_aio_context = blkverify_attach_aio_context, |
| 368 | .bdrv_detach_aio_context = blkverify_detach_aio_context, |
| 369 | |
| 370 | .is_filter = true, |
Benoît Canet | b5042a3 | 2014-03-03 19:11:34 +0100 | [diff] [blame] | 371 | .bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter, |
Stefan Hajnoczi | d9d3341 | 2010-09-21 15:43:03 +0100 | [diff] [blame] | 372 | }; |
| 373 | |
| 374 | static void bdrv_blkverify_init(void) |
| 375 | { |
| 376 | bdrv_register(&bdrv_blkverify); |
| 377 | } |
| 378 | |
| 379 | block_init(bdrv_blkverify_init); |