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