|
|
1.1 root 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_socket.h" /* for EINPROGRESS on Windows */
12: #include "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: bool finished = false;
43:
44: /* Wait until request completes, invokes its callback, and frees itself */
45: acb->finished = &finished;
46: while (!finished) {
47: qemu_aio_wait();
48: }
49: }
50:
51: static AIOPool blkverify_aio_pool = {
52: .aiocb_size = sizeof(BlkverifyAIOCB),
53: .cancel = blkverify_aio_cancel,
54: };
55:
56: static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb,
57: const char *fmt, ...)
58: {
59: va_list ap;
60:
61: va_start(ap, fmt);
62: fprintf(stderr, "blkverify: %s sector_num=%" PRId64 " nb_sectors=%d ",
63: acb->is_write ? "write" : "read", acb->sector_num,
64: acb->nb_sectors);
65: vfprintf(stderr, fmt, ap);
66: fprintf(stderr, "\n");
67: va_end(ap);
68: exit(1);
69: }
70:
71: /* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */
72: static int blkverify_open(BlockDriverState *bs, const char *filename, int flags)
73: {
74: BDRVBlkverifyState *s = bs->opaque;
75: int ret;
76: char *raw, *c;
77:
78: /* Parse the blkverify: prefix */
79: if (strncmp(filename, "blkverify:", strlen("blkverify:"))) {
80: return -EINVAL;
81: }
82: filename += strlen("blkverify:");
83:
84: /* Parse the raw image filename */
85: c = strchr(filename, ':');
86: if (c == NULL) {
87: return -EINVAL;
88: }
89:
1.1.1.3 ! root 90: raw = g_strdup(filename);
1.1 root 91: raw[c - filename] = '\0';
92: ret = bdrv_file_open(&bs->file, raw, flags);
1.1.1.3 ! root 93: g_free(raw);
1.1 root 94: if (ret < 0) {
95: return ret;
96: }
97: filename = c + 1;
98:
99: /* Open the test file */
100: s->test_file = bdrv_new("");
101: ret = bdrv_open(s->test_file, filename, flags, NULL);
102: if (ret < 0) {
103: bdrv_delete(s->test_file);
104: s->test_file = NULL;
105: return ret;
106: }
107:
108: return 0;
109: }
110:
111: static void blkverify_close(BlockDriverState *bs)
112: {
113: BDRVBlkverifyState *s = bs->opaque;
114:
115: bdrv_delete(s->test_file);
116: s->test_file = NULL;
117: }
118:
119: static int64_t blkverify_getlength(BlockDriverState *bs)
120: {
121: BDRVBlkverifyState *s = bs->opaque;
122:
123: return bdrv_getlength(s->test_file);
124: }
125:
126: /**
127: * Check that I/O vector contents are identical
128: *
129: * @a: I/O vector
130: * @b: I/O vector
131: * @ret: Offset to first mismatching byte or -1 if match
132: */
133: static ssize_t blkverify_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
134: {
135: int i;
136: ssize_t offset = 0;
137:
138: assert(a->niov == b->niov);
139: for (i = 0; i < a->niov; i++) {
140: size_t len = 0;
141: uint8_t *p = (uint8_t *)a->iov[i].iov_base;
142: uint8_t *q = (uint8_t *)b->iov[i].iov_base;
143:
144: assert(a->iov[i].iov_len == b->iov[i].iov_len);
145: while (len < a->iov[i].iov_len && *p++ == *q++) {
146: len++;
147: }
148:
149: offset += len;
150:
151: if (len != a->iov[i].iov_len) {
152: return offset;
153: }
154: }
155: return -1;
156: }
157:
158: typedef struct {
159: int src_index;
160: struct iovec *src_iov;
161: void *dest_base;
162: } IOVectorSortElem;
163:
164: static int sortelem_cmp_src_base(const void *a, const void *b)
165: {
166: const IOVectorSortElem *elem_a = a;
167: const IOVectorSortElem *elem_b = b;
168:
169: /* Don't overflow */
170: if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) {
171: return -1;
172: } else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) {
173: return 1;
174: } else {
175: return 0;
176: }
177: }
178:
179: static int sortelem_cmp_src_index(const void *a, const void *b)
180: {
181: const IOVectorSortElem *elem_a = a;
182: const IOVectorSortElem *elem_b = b;
183:
184: return elem_a->src_index - elem_b->src_index;
185: }
186:
187: /**
188: * Copy contents of I/O vector
189: *
190: * The relative relationships of overlapping iovecs are preserved. This is
191: * necessary to ensure identical semantics in the cloned I/O vector.
192: */
193: static void blkverify_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src,
194: void *buf)
195: {
196: IOVectorSortElem sortelems[src->niov];
197: void *last_end;
198: int i;
199:
200: /* Sort by source iovecs by base address */
201: for (i = 0; i < src->niov; i++) {
202: sortelems[i].src_index = i;
203: sortelems[i].src_iov = &src->iov[i];
204: }
205: qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_base);
206:
207: /* Allocate buffer space taking into account overlapping iovecs */
208: last_end = NULL;
209: for (i = 0; i < src->niov; i++) {
210: struct iovec *cur = sortelems[i].src_iov;
211: ptrdiff_t rewind = 0;
212:
213: /* Detect overlap */
214: if (last_end && last_end > cur->iov_base) {
215: rewind = last_end - cur->iov_base;
216: }
217:
218: sortelems[i].dest_base = buf - rewind;
219: buf += cur->iov_len - MIN(rewind, cur->iov_len);
220: last_end = MAX(cur->iov_base + cur->iov_len, last_end);
221: }
222:
223: /* Sort by source iovec index and build destination iovec */
224: qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_index);
225: for (i = 0; i < src->niov; i++) {
226: qemu_iovec_add(dest, sortelems[i].dest_base, src->iov[i].iov_len);
227: }
228: }
229:
230: static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
231: int64_t sector_num, QEMUIOVector *qiov,
232: int nb_sectors,
233: BlockDriverCompletionFunc *cb,
234: void *opaque)
235: {
236: BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aio_pool, bs, cb, opaque);
237:
238: acb->bh = NULL;
239: acb->is_write = is_write;
240: acb->sector_num = sector_num;
241: acb->nb_sectors = nb_sectors;
242: acb->ret = -EINPROGRESS;
243: acb->done = 0;
244: acb->qiov = qiov;
245: acb->buf = NULL;
246: acb->verify = NULL;
247: acb->finished = NULL;
248: return acb;
249: }
250:
251: static void blkverify_aio_bh(void *opaque)
252: {
253: BlkverifyAIOCB *acb = opaque;
254:
255: qemu_bh_delete(acb->bh);
256: if (acb->buf) {
257: qemu_iovec_destroy(&acb->raw_qiov);
258: qemu_vfree(acb->buf);
259: }
260: acb->common.cb(acb->common.opaque, acb->ret);
261: if (acb->finished) {
262: *acb->finished = true;
263: }
264: qemu_aio_release(acb);
265: }
266:
267: static void blkverify_aio_cb(void *opaque, int ret)
268: {
269: BlkverifyAIOCB *acb = opaque;
270:
271: switch (++acb->done) {
272: case 1:
273: acb->ret = ret;
274: break;
275:
276: case 2:
277: if (acb->ret != ret) {
278: blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret);
279: }
280:
281: if (acb->verify) {
282: acb->verify(acb);
283: }
284:
285: acb->bh = qemu_bh_new(blkverify_aio_bh, acb);
286: qemu_bh_schedule(acb->bh);
287: break;
288: }
289: }
290:
291: static void blkverify_verify_readv(BlkverifyAIOCB *acb)
292: {
293: ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov);
294: if (offset != -1) {
295: blkverify_err(acb, "contents mismatch in sector %" PRId64,
296: acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE));
297: }
298: }
299:
300: static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs,
301: int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
302: BlockDriverCompletionFunc *cb, void *opaque)
303: {
304: BDRVBlkverifyState *s = bs->opaque;
305: BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov,
306: nb_sectors, cb, opaque);
307:
308: acb->verify = blkverify_verify_readv;
309: acb->buf = qemu_blockalign(bs->file, qiov->size);
310: qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
311: blkverify_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
312:
1.1.1.3 ! root 313: bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
! 314: blkverify_aio_cb, acb);
! 315: bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
! 316: blkverify_aio_cb, acb);
1.1 root 317: return &acb->common;
318: }
319:
320: static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs,
321: int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
322: BlockDriverCompletionFunc *cb, void *opaque)
323: {
324: BDRVBlkverifyState *s = bs->opaque;
325: BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
326: nb_sectors, cb, opaque);
327:
1.1.1.3 ! root 328: bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors,
! 329: blkverify_aio_cb, acb);
! 330: bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
! 331: blkverify_aio_cb, acb);
1.1 root 332: return &acb->common;
333: }
334:
335: static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs,
336: BlockDriverCompletionFunc *cb,
337: void *opaque)
338: {
339: BDRVBlkverifyState *s = bs->opaque;
340:
341: /* Only flush test file, the raw file is not important */
342: return bdrv_aio_flush(s->test_file, cb, opaque);
343: }
344:
345: static BlockDriver bdrv_blkverify = {
346: .format_name = "blkverify",
347: .protocol_name = "blkverify",
348:
349: .instance_size = sizeof(BDRVBlkverifyState),
350:
351: .bdrv_getlength = blkverify_getlength,
352:
353: .bdrv_file_open = blkverify_open,
354: .bdrv_close = blkverify_close,
355:
356: .bdrv_aio_readv = blkverify_aio_readv,
357: .bdrv_aio_writev = blkverify_aio_writev,
358: .bdrv_aio_flush = blkverify_aio_flush,
359: };
360:
361: static void bdrv_blkverify_init(void)
362: {
363: bdrv_register(&bdrv_blkverify);
364: }
365:
366: block_init(bdrv_blkverify_init);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.