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