Statistics
| Branch: | Revision:

root / block / blkverify.c @ a77cffe7

History | View | Annotate | Download (10.5 kB)

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

    
90
    raw = strdup(filename);
91
    raw[c - filename] = '\0';
92
    ret = bdrv_file_open(&bs->file, raw, flags);
93
    free(raw);
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 void blkverify_flush(BlockDriverState *bs)
120
{
121
    BDRVBlkverifyState *s = bs->opaque;
122

    
123
    /* Only flush test file, the raw file is not important */
124
    bdrv_flush(s->test_file);
125
}
126

    
127
static int64_t blkverify_getlength(BlockDriverState *bs)
128
{
129
    BDRVBlkverifyState *s = bs->opaque;
130

    
131
    return bdrv_getlength(s->test_file);
132
}
133

    
134
/**
135
 * Check that I/O vector contents are identical
136
 *
137
 * @a:          I/O vector
138
 * @b:          I/O vector
139
 * @ret:        Offset to first mismatching byte or -1 if match
140
 */
141
static ssize_t blkverify_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
142
{
143
    int i;
144
    ssize_t offset = 0;
145

    
146
    assert(a->niov == b->niov);
147
    for (i = 0; i < a->niov; i++) {
148
        size_t len = 0;
149
        uint8_t *p = (uint8_t *)a->iov[i].iov_base;
150
        uint8_t *q = (uint8_t *)b->iov[i].iov_base;
151

    
152
        assert(a->iov[i].iov_len == b->iov[i].iov_len);
153
        while (len < a->iov[i].iov_len && *p++ == *q++) {
154
            len++;
155
        }
156

    
157
        offset += len;
158

    
159
        if (len != a->iov[i].iov_len) {
160
            return offset;
161
        }
162
    }
163
    return -1;
164
}
165

    
166
typedef struct {
167
    int src_index;
168
    struct iovec *src_iov;
169
    void *dest_base;
170
} IOVectorSortElem;
171

    
172
static int sortelem_cmp_src_base(const void *a, const void *b)
173
{
174
    const IOVectorSortElem *elem_a = a;
175
    const IOVectorSortElem *elem_b = b;
176

    
177
    /* Don't overflow */
178
    if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) {
179
        return -1;
180
    } else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) {
181
        return 1;
182
    } else {
183
        return 0;
184
    }
185
}
186

    
187
static int sortelem_cmp_src_index(const void *a, const void *b)
188
{
189
    const IOVectorSortElem *elem_a = a;
190
    const IOVectorSortElem *elem_b = b;
191

    
192
    return elem_a->src_index - elem_b->src_index;
193
}
194

    
195
/**
196
 * Copy contents of I/O vector
197
 *
198
 * The relative relationships of overlapping iovecs are preserved.  This is
199
 * necessary to ensure identical semantics in the cloned I/O vector.
200
 */
201
static void blkverify_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src,
202
                                  void *buf)
203
{
204
    IOVectorSortElem sortelems[src->niov];
205
    void *last_end;
206
    int i;
207

    
208
    /* Sort by source iovecs by base address */
209
    for (i = 0; i < src->niov; i++) {
210
        sortelems[i].src_index = i;
211
        sortelems[i].src_iov = &src->iov[i];
212
    }
213
    qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_base);
214

    
215
    /* Allocate buffer space taking into account overlapping iovecs */
216
    last_end = NULL;
217
    for (i = 0; i < src->niov; i++) {
218
        struct iovec *cur = sortelems[i].src_iov;
219
        ptrdiff_t rewind = 0;
220

    
221
        /* Detect overlap */
222
        if (last_end && last_end > cur->iov_base) {
223
            rewind = last_end - cur->iov_base;
224
        }
225

    
226
        sortelems[i].dest_base = buf - rewind;
227
        buf += cur->iov_len - MIN(rewind, cur->iov_len);
228
        last_end = MAX(cur->iov_base + cur->iov_len, last_end);
229
    }
230

    
231
    /* Sort by source iovec index and build destination iovec */
232
    qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_index);
233
    for (i = 0; i < src->niov; i++) {
234
        qemu_iovec_add(dest, sortelems[i].dest_base, src->iov[i].iov_len);
235
    }
236
}
237

    
238
static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
239
                                         int64_t sector_num, QEMUIOVector *qiov,
240
                                         int nb_sectors,
241
                                         BlockDriverCompletionFunc *cb,
242
                                         void *opaque)
243
{
244
    BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aio_pool, bs, cb, opaque);
245

    
246
    acb->bh = NULL;
247
    acb->is_write = is_write;
248
    acb->sector_num = sector_num;
249
    acb->nb_sectors = nb_sectors;
250
    acb->ret = -EINPROGRESS;
251
    acb->done = 0;
252
    acb->qiov = qiov;
253
    acb->buf = NULL;
254
    acb->verify = NULL;
255
    acb->finished = NULL;
256
    return acb;
257
}
258

    
259
static void blkverify_aio_bh(void *opaque)
260
{
261
    BlkverifyAIOCB *acb = opaque;
262

    
263
    qemu_bh_delete(acb->bh);
264
    if (acb->buf) {
265
        qemu_iovec_destroy(&acb->raw_qiov);
266
        qemu_vfree(acb->buf);
267
    }
268
    acb->common.cb(acb->common.opaque, acb->ret);
269
    if (acb->finished) {
270
        *acb->finished = true;
271
    }
272
    qemu_aio_release(acb);
273
}
274

    
275
static void blkverify_aio_cb(void *opaque, int ret)
276
{
277
    BlkverifyAIOCB *acb = opaque;
278

    
279
    switch (++acb->done) {
280
    case 1:
281
        acb->ret = ret;
282
        break;
283

    
284
    case 2:
285
        if (acb->ret != ret) {
286
            blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret);
287
        }
288

    
289
        if (acb->verify) {
290
            acb->verify(acb);
291
        }
292

    
293
        acb->bh = qemu_bh_new(blkverify_aio_bh, acb);
294
        qemu_bh_schedule(acb->bh);
295
        break;
296
    }
297
}
298

    
299
static void blkverify_verify_readv(BlkverifyAIOCB *acb)
300
{
301
    ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov);
302
    if (offset != -1) {
303
        blkverify_err(acb, "contents mismatch in sector %lld",
304
                      acb->sector_num + (offset / BDRV_SECTOR_SIZE));
305
    }
306
}
307

    
308
static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs,
309
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
310
        BlockDriverCompletionFunc *cb, void *opaque)
311
{
312
    BDRVBlkverifyState *s = bs->opaque;
313
    BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov,
314
                                            nb_sectors, cb, opaque);
315

    
316
    acb->verify = blkverify_verify_readv;
317
    acb->buf = qemu_blockalign(bs->file, qiov->size);
318
    qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
319
    blkverify_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
320

    
321
    if (!bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
322
                        blkverify_aio_cb, acb)) {
323
        blkverify_aio_cb(acb, -EIO);
324
    }
325
    if (!bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
326
                        blkverify_aio_cb, acb)) {
327
        blkverify_aio_cb(acb, -EIO);
328
    }
329
    return &acb->common;
330
}
331

    
332
static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs,
333
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
334
        BlockDriverCompletionFunc *cb, void *opaque)
335
{
336
    BDRVBlkverifyState *s = bs->opaque;
337
    BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
338
                                            nb_sectors, cb, opaque);
339

    
340
    if (!bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors,
341
                         blkverify_aio_cb, acb)) {
342
        blkverify_aio_cb(acb, -EIO);
343
    }
344
    if (!bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
345
                         blkverify_aio_cb, acb)) {
346
        blkverify_aio_cb(acb, -EIO);
347
    }
348
    return &acb->common;
349
}
350

    
351
static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs,
352
                                             BlockDriverCompletionFunc *cb,
353
                                             void *opaque)
354
{
355
    BDRVBlkverifyState *s = bs->opaque;
356

    
357
    /* Only flush test file, the raw file is not important */
358
    return bdrv_aio_flush(s->test_file, cb, opaque);
359
}
360

    
361
static BlockDriver bdrv_blkverify = {
362
    .format_name        = "blkverify",
363
    .protocol_name      = "blkverify",
364

    
365
    .instance_size      = sizeof(BDRVBlkverifyState),
366

    
367
    .bdrv_getlength     = blkverify_getlength,
368

    
369
    .bdrv_file_open     = blkverify_open,
370
    .bdrv_close         = blkverify_close,
371
    .bdrv_flush         = blkverify_flush,
372

    
373
    .bdrv_aio_readv     = blkverify_aio_readv,
374
    .bdrv_aio_writev    = blkverify_aio_writev,
375
    .bdrv_aio_flush     = blkverify_aio_flush,
376
};
377

    
378
static void bdrv_blkverify_init(void)
379
{
380
    bdrv_register(&bdrv_blkverify);
381
}
382

    
383
block_init(bdrv_blkverify_init);