]> git.proxmox.com Git - pve-qemu-kvm.git/blob - debian/patches/0005-add-regression-tests-for-backup.patch
341a815546b9e2f56052dc4ce2af88195852b8be
[pve-qemu-kvm.git] / debian / patches / 0005-add-regression-tests-for-backup.patch
1 From 2a7c5bdf32295a97fdfe63783fcdc846c92e50a9 Mon Sep 17 00:00:00 2001
2 From: Dietmar Maurer <dietmar@proxmox.com>
3 Date: Wed, 14 Nov 2012 09:57:04 +0100
4 Subject: [PATCH v3 5/6] add regression tests for backup
5
6 Simple regression tests using vma-reader and vma-writer.
7
8 Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
9 ---
10 tests/Makefile | 11 +-
11 tests/backup-test.c | 511 +++++++++++++++++++++++++++++++++++++++++++++++++++
12 2 files changed, 520 insertions(+), 2 deletions(-)
13 create mode 100644 tests/backup-test.c
14
15 diff --git a/tests/Makefile b/tests/Makefile
16 index b60f0fb..cffbd22 100644
17 --- a/tests/Makefile
18 +++ b/tests/Makefile
19 @@ -20,6 +20,8 @@ check-unit-y += tests/test-thread-pool$(EXESUF)
20
21 check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
22
23 +check-backup-y = tests/backup-test$(EXESUF)
24 +
25 # All QTests for now are POSIX-only, but the dependencies are
26 # really in libqtest, not in the testcases themselves.
27 check-qtest-i386-y = tests/fdc-test$(EXESUF)
28 @@ -54,6 +56,7 @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools
29 tests/test-aio$(EXESUF): tests/test-aio.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) libqemustub.a
30 tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) libqemustub.a
31 tests/test-iov$(EXESUF): tests/test-iov.o iov.o
32 +tests/backup-test$(EXESUF): tests/backup-test.o vma-reader.o $(tools-obj-y) $(block-obj-y) libqemustub.a
33
34 tests/test-qapi-types.c tests/test-qapi-types.h :\
35 $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
36 @@ -146,10 +149,14 @@ check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF)
37
38 # Consolidated targets
39
40 -.PHONY: check-qtest check-unit check
41 +.PHONY: check-backup check-qtest check-unit check
42 check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS))
43 check-unit: $(patsubst %,check-%, $(check-unit-y))
44 check-block: $(patsubst %,check-%, $(check-block-y))
45 -check: check-unit check-qtest
46 +
47 +check-backup: tests/backup-test$(EXESUF)
48 + $<
49 +
50 +check: check-unit check-qtest check-backup
51
52 -include $(wildcard tests/*.d)
53 diff --git a/tests/backup-test.c b/tests/backup-test.c
54 new file mode 100644
55 index 0000000..c434c5f
56 --- /dev/null
57 +++ b/tests/backup-test.c
58 @@ -0,0 +1,511 @@
59 +/*
60 + * QEMU backup test suit
61 + *
62 + * Copyright (C) Proxmox Server Solutions
63 + *
64 + * Authors:
65 + * Dietmar Maurer (dietmar@proxmox.com)
66 + *
67 + * This work is licensed under the terms of the GNU GPL, version 2. See
68 + * the COPYING file in the top-level directory.
69 + *
70 + * Fixme: running 'backup-test -l' trigger a bug in g_slice_alloc()
71 + * Note: 'G_SLICE=always-malloc ./tests/backup-test -l' works
72 + *
73 + */
74 +
75 +#include <sys/time.h>
76 +#include <sys/types.h>
77 +#include <stdarg.h>
78 +#include <stdio.h>
79 +#include <getopt.h>
80 +#include <libgen.h>
81 +
82 +#include "qemu-common.h"
83 +#include "main-loop.h"
84 +#include "block_int.h"
85 +
86 +#include "vma.h"
87 +
88 +static int opt_debug;
89 +static int opt_loop;
90 +
91 +#define DPRINTF(fmt, ...) \
92 + do { if (opt_debug) { printf(fmt, ## __VA_ARGS__); } } while (0)
93 +
94 +#define CLUSTER(x) (x*BACKUP_CLUSTER_SIZE)
95 +
96 +#define RUN_TEST(testfunc, speed) \
97 + backup_test(#testfunc " speed " #speed, speed, testfunc);
98 +
99 +
100 +static unsigned char buf_sec_pattern_cd[BDRV_SECTOR_SIZE];
101 +static unsigned char buf_sec_pattern_32[BDRV_SECTOR_SIZE];
102 +
103 +#define TEST_IMG_SIZE (6*1024*1024+BDRV_SECTOR_SIZE)
104 +#define TEST_IMG_NAME "backuptest.raw"
105 +#define TEST_IMG_RESTORE_NAME "backuptest.raw.restore"
106 +#define TEST_VMA_NAME "backuptest.vma"
107 +
108 +typedef struct BackupCB {
109 + VmaWriter *vmaw;
110 + uint8_t dev_id;
111 +} BackupCB;
112 +
113 +static int backup_dump_cb(void *opaque, BlockDriverState *bs,
114 + int64_t cluster_num, unsigned char *buf)
115 +{
116 + BackupCB *bcb = opaque;
117 +
118 + DPRINTF("backup_dump_cb C%zd %d\n", cluster_num, bcb->dev_id);
119 +
120 + size_t zb = 0;
121 + if (vma_writer_write(bcb->vmaw, bcb->dev_id, cluster_num, buf, &zb) < 0) {
122 + printf("backup_dump_cb vma_writer_write failed\n");
123 + return -1;
124 + }
125 +
126 + return 0;
127 +}
128 +
129 +static void backup_complete_cb(void *opaque, int ret)
130 +{
131 + BackupCB *bcb = opaque;
132 +
133 + DPRINTF("backup_complete_cb %d %d\n", bcb->dev_id, ret);
134 +
135 + if (ret < 0) {
136 + vma_writer_set_error(bcb->vmaw, "backup_complete_cb %d", ret);
137 + }
138 +
139 + if (vma_writer_close_stream(bcb->vmaw, bcb->dev_id) <= 0) {
140 + Error *err = NULL;
141 + if (vma_writer_close(bcb->vmaw, &err) != 0) {
142 + g_error("vma_writer_close failed %s", error_get_pretty(err));
143 + }
144 + }
145 + DPRINTF("backup_complete_cb finish\n");
146 +}
147 +
148 +static void write_sec_pattern_cd(BlockDriverState *bs, int64_t offset)
149 +{
150 + int ret;
151 +
152 + DPRINTF("write_sec_pattern_cd %zd\n", offset);
153 +
154 + if (offset & 0x1ff) {
155 + g_error("write_sec_pattern_cd offset %zd is not sector aligned\n",
156 + offset);
157 + }
158 +
159 + ret = bdrv_write(bs, offset >> 9, buf_sec_pattern_cd, 1);
160 + if (ret < 0) {
161 + g_error("write_sec_pattern_cd %zd failed", offset);
162 + }
163 +
164 +}
165 +
166 +static void read_sec(BlockDriverState *bs, int64_t offset, unsigned char *buf)
167 +{
168 + DPRINTF("read_sec C%zd start %zd\n", offset>>VMA_CLUSTER_BITS, offset);
169 +
170 + if (offset & 0x1ff) {
171 + g_error("read_sec offset %zd is not sector aligned\n", offset);
172 + }
173 +
174 + if (bdrv_read(bs, offset >> 9, buf, 1) < 0) {
175 + g_error("bdrv_read failed");
176 + }
177 +}
178 +
179 +static bool request_term;
180 +
181 +typedef struct TestCB {
182 + Coroutine *co;
183 + BlockDriverState *bs;
184 + bool finished;
185 +} TestCB;
186 +
187 +static TestCB *enter_test_co(BlockDriverState *bs, CoroutineEntry *entry)
188 +{
189 + TestCB *cb = g_new0(TestCB, 1);
190 + cb->bs = bs;
191 + cb->co = qemu_coroutine_create(entry);
192 + qemu_coroutine_enter(cb->co, cb);
193 + return cb;
194 +}
195 +
196 +static void test_co_sleep(double sec)
197 +{
198 + co_sleep_ns(rt_clock, (int64_t)(sec*1000000000));
199 +};
200 +
201 +static void test_co_yield(void)
202 +{
203 + co_sleep_ns(rt_clock, (int64_t)(1000));
204 +};
205 +
206 +static void coroutine_fn run_co_test1(void *opaque)
207 +{
208 + assert(opaque);
209 + TestCB *cb = (TestCB *)opaque;
210 +
211 + test_co_sleep(0.2);
212 + write_sec_pattern_cd(cb->bs, 5*BACKUP_CLUSTER_SIZE);
213 + test_co_sleep(0.2);
214 + write_sec_pattern_cd(cb->bs, 10*BACKUP_CLUSTER_SIZE);
215 + test_co_sleep(0.2);
216 + write_sec_pattern_cd(cb->bs, 10*BACKUP_CLUSTER_SIZE);
217 +
218 + cb->finished = true;
219 +}
220 +
221 +static void coroutine_fn run_co_test2(void *opaque)
222 +{
223 + assert(opaque);
224 + TestCB *cb = (TestCB *)opaque;
225 + unsigned char buf[512];
226 +
227 + test_co_sleep(0.2);
228 + read_sec(cb->bs, 5*BACKUP_CLUSTER_SIZE, buf);
229 + write_sec_pattern_cd(cb->bs, 6*BACKUP_CLUSTER_SIZE);
230 +
231 + cb->finished = true;
232 +}
233 +
234 +static void coroutine_fn run_co_random_read(void *opaque)
235 +{
236 + assert(opaque);
237 + TestCB *cb = (TestCB *)opaque;
238 + int64_t sectors = bdrv_getlength(cb->bs)/BDRV_SECTOR_SIZE - 1;
239 + unsigned char buf[512];
240 +
241 + while (1) {
242 + test_co_yield();
243 + if (request_term) {
244 + DPRINTF("finish run_co_random_read\n");
245 + break;
246 + }
247 + int64_t s = (rand()*sectors)/RAND_MAX;
248 + read_sec(cb->bs, s*BDRV_SECTOR_SIZE, buf);
249 + }
250 +
251 + cb->finished = true;
252 +}
253 +
254 +static void coroutine_fn run_co_random_write(void *opaque)
255 +{
256 + assert(opaque);
257 + TestCB *cb = (TestCB *)opaque;
258 + int64_t sectors = bdrv_getlength(cb->bs)/BDRV_SECTOR_SIZE;
259 +
260 + while (1) {
261 + test_co_yield();
262 + if (request_term) {
263 + DPRINTF("finish run_co_random_write\n");
264 + break;
265 + }
266 + int64_t s = (rand()*sectors)/RAND_MAX;
267 + write_sec_pattern_cd(cb->bs, s*BDRV_SECTOR_SIZE);
268 + }
269 +
270 + cb->finished = true;
271 +}
272 +
273 +static void fill_test_sector(void *buf, size_t sector_num)
274 +{
275 + int64_t *i64buf = (int64_t *)buf;
276 + int i;
277 +
278 + int data = sector_num;
279 + if (sector_num >= 8 && sector_num < 8*(2*16+2)) {
280 + data = 0; /* add zero region for testing */
281 + }
282 +
283 + for (i = 0; i < (512/sizeof(int64_t)); i++) {
284 + i64buf[i] = data;
285 + }
286 +}
287 +
288 +static void verify_archive(const char *archive, size_t size)
289 +{
290 + Error *errp = NULL;
291 +
292 + VmaReader *vmar = vma_reader_create(archive, &errp);
293 +
294 + if (!vmar) {
295 + g_error("%s", error_get_pretty(errp));
296 + }
297 +
298 + VmaDeviceInfo *di = vma_reader_get_device_info(vmar, 1);
299 + if (!di || strcmp((char *)di->devname, "hda") || di->size != size) {
300 + g_error("got wrong device info");
301 + }
302 +
303 + unlink(TEST_IMG_RESTORE_NAME);
304 +
305 + int flags = BDRV_O_NATIVE_AIO|BDRV_O_RDWR|BDRV_O_CACHE_WB;
306 +
307 + if (bdrv_img_create(TEST_IMG_RESTORE_NAME, "raw", NULL, NULL, NULL,
308 + size, flags)) {
309 + g_error("can't create file %s", TEST_IMG_RESTORE_NAME);
310 + }
311 +
312 + BlockDriverState *bs = NULL;
313 + if (bdrv_file_open(&bs, TEST_IMG_RESTORE_NAME, flags)) {
314 + g_error("can't open file %s", TEST_IMG_RESTORE_NAME);
315 + }
316 + if (vma_reader_register_bs(vmar, 1, bs, false, &errp) < 0) {
317 + g_error("%s", error_get_pretty(errp));
318 + }
319 +
320 + if (vma_reader_restore(vmar, -1, &errp) < 0) {
321 + g_error("restore failed - %s", error_get_pretty(errp));
322 + }
323 +
324 + size_t i;
325 + size_t sectors = size/BDRV_SECTOR_SIZE;
326 + int64_t buf[512/sizeof(int64_t)];
327 + int64_t buf2[512/sizeof(int64_t)];
328 +
329 + for (i = 0; i < sectors; i++) {
330 + if (bdrv_read(bs, i, (uint8_t *)buf, 1) != 0) {
331 + g_error("bdrv_read failed");
332 + }
333 + fill_test_sector(buf2, i);
334 + if (bcmp(buf, buf2, sizeof(buf))) {
335 + g_error("data is different at sector %zd", i);
336 + }
337 + }
338 +
339 + vma_reader_destroy(vmar);
340 +
341 + unlink(TEST_IMG_RESTORE_NAME);
342 +}
343 +
344 +static void prepare_vm_image(const char *filename, size_t sectors)
345 +{
346 + int fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644);
347 + if (fd < 0) {
348 + g_error("can't open file %s\n", filename);
349 + }
350 +
351 + size_t i;
352 + int64_t buf[512/sizeof(int64_t)];
353 +
354 + for (i = 0; i < sectors; i++) {
355 + fill_test_sector(buf, i);
356 +
357 + int res = 0;
358 + while (1) {
359 + res = write(fd, buf, sizeof(buf));
360 + if (!(res < 0 && errno == EINTR)) {
361 + break;
362 + }
363 + }
364 + if (res != sizeof(buf)) {
365 + g_error("can't initialize file %s - %s %d\n",
366 + filename, strerror(errno), res);
367 + }
368 + }
369 +
370 + if (close(fd) != 0) {
371 + g_error("close failed");
372 + }
373 +}
374 +
375 +static GList *simple_test(BlockDriverState *bs)
376 +{
377 + GList *cb_list = NULL;
378 +
379 + cb_list = g_list_append(cb_list, enter_test_co(bs, run_co_test1));
380 + cb_list = g_list_append(cb_list, enter_test_co(bs, run_co_test2));
381 +
382 + return cb_list;
383 +}
384 +
385 +static GList *random_read_write_test(BlockDriverState *bs)
386 +{
387 + GList *cb_list = NULL;
388 +
389 + cb_list = g_list_append(cb_list, enter_test_co(bs, run_co_random_read));
390 + cb_list = g_list_append(cb_list, enter_test_co(bs, run_co_random_read));
391 + cb_list = g_list_append(cb_list, enter_test_co(bs, run_co_random_write));
392 + cb_list = g_list_append(cb_list, enter_test_co(bs, run_co_random_write));
393 +
394 + return cb_list;
395 +}
396 +
397 +static void backup_test(const char *testname, int64_t speed,
398 + GList *(*start_test_cb)(BlockDriverState *bs))
399 +{
400 + BlockDriverState *bs = bdrv_new("hda");
401 +
402 + static int test_counter;
403 +
404 + test_counter++;
405 +
406 + printf("starting test #%d '%s'\n", test_counter, testname);
407 +
408 + const char *filename = TEST_IMG_NAME;
409 +
410 + prepare_vm_image(TEST_IMG_NAME, TEST_IMG_SIZE/BDRV_SECTOR_SIZE);
411 +
412 + int flags = BDRV_O_NATIVE_AIO|BDRV_O_RDWR|BDRV_O_CACHE_WB;
413 +
414 + if (bdrv_open(bs, filename, flags, NULL) < 0) {
415 + g_error("can't open device %s\n", filename);
416 + }
417 +
418 + Error *err = NULL;
419 + uuid_t uuid;
420 + uuid_generate(uuid);
421 +
422 + unlink(TEST_VMA_NAME);
423 +
424 + VmaWriter *vmaw = vma_writer_create(TEST_VMA_NAME, uuid, speed, &err);
425 + if (!vmaw) {
426 + g_error("%s", error_get_pretty(err));
427 + }
428 +
429 + BackupCB bcb;
430 + bcb.vmaw = vmaw;
431 + bcb.dev_id = vma_writer_register_stream(vmaw, bdrv_get_device_name(bs),
432 + bdrv_getlength(bs));
433 + if (backup_job_start(bs, backup_dump_cb, backup_complete_cb, &bcb) < 0) {
434 + g_error("backup_job_start failed");
435 + }
436 +
437 + request_term = false;
438 +
439 + GList *cb_list = start_test_cb(bs);
440 +
441 + while (1) {
442 + main_loop_wait(false);
443 +
444 + VmaStatus vmastat;
445 + vma_writer_get_status(vmaw, &vmastat);
446 + if (vmastat.closed) {
447 + break;
448 + }
449 + }
450 +
451 + request_term = true;
452 +
453 + while (1) {
454 + GList *l = cb_list;
455 + bool active = 0;
456 + while (l && l->data) {
457 + TestCB *cb = (TestCB *)l->data;
458 + l = g_list_next(l);
459 + if (!cb->finished) {
460 + active = true;
461 + break;
462 + }
463 + }
464 + if (!active) {
465 + DPRINTF("All test coroutines finished\n");
466 + break;
467 + }
468 + main_loop_wait(false);
469 + }
470 +
471 + /* Make sure all outstanding requests complete */
472 + bdrv_drain_all();
473 +
474 + VmaStatus vmastat;
475 + vma_writer_get_status(vmaw, &vmastat);
476 + DPRINTF("statistic %zd %zd\n", vmastat.stream_info[1].size,
477 + vmastat.stream_info[1].transferred);
478 + assert(vmastat.stream_info[1].size == vmastat.stream_info[1].transferred);
479 +
480 + vma_writer_destroy(vmaw);
481 +
482 + bdrv_delete(bs);
483 +
484 + /* start verification */
485 + verify_archive(TEST_VMA_NAME, TEST_IMG_SIZE);
486 +
487 + bdrv_close_all();
488 +
489 + unlink(TEST_IMG_NAME);
490 + unlink(TEST_VMA_NAME);
491 +
492 + printf("finish test #%d '%s' OK\n", test_counter, testname);
493 +}
494 +
495 +static void help(void)
496 +{
497 + const char *help_msg =
498 + "usage: backup-test [options]\n"
499 + "\n"
500 + "backup-test run default regression test (fast)\n"
501 + "backup-test -l run long running test loop (endless)\n"
502 + "\n"
503 + "use option -d to turn on verbose debug output\n"
504 + ;
505 +
506 + printf("%s", help_msg);
507 + exit(1);
508 +}
509 +
510 +int main(int argc, char **argv)
511 +{
512 + int c;
513 +
514 + for (;;) {
515 + c = getopt(argc, argv, "hdl");
516 + if (c == -1) {
517 + break;
518 + }
519 + switch (c) {
520 + case '?':
521 + case 'h':
522 + help();
523 + break;
524 + case 'd':
525 + opt_debug = 1;
526 + break;
527 + case 'l':
528 + opt_loop = 1;
529 + break;
530 + default:
531 + g_assert_not_reached();
532 + }
533 + }
534 +
535 + memset(buf_sec_pattern_cd, 0xcd, sizeof(buf_sec_pattern_cd));
536 + memset(buf_sec_pattern_32, 0x32, sizeof(buf_sec_pattern_32));
537 +
538 + srand(1234);
539 +
540 + /* ignore SIGPIPE */
541 + struct sigaction act;
542 + sigfillset(&act.sa_mask);
543 + act.sa_flags = 0;
544 + act.sa_handler = SIG_IGN;
545 + sigaction(SIGPIPE, &act, NULL);
546 +
547 + qemu_init_main_loop();
548 +
549 + bdrv_init();
550 +
551 + if (opt_loop) { /* endless test loop */
552 + while (1) {
553 + RUN_TEST(random_read_write_test, 0);
554 + }
555 + return 0;
556 + }
557 +
558 + if (opt_debug) { /* run simple test (rate limited) */
559 + RUN_TEST(simple_test, 1024*1024);
560 + return 0;
561 + }
562 +
563 + /* run default regression tests at full speed */
564 +
565 + RUN_TEST(simple_test, 0);
566 + RUN_TEST(random_read_write_test, 0);
567 +
568 + return 0;
569 +}
570 --
571 1.7.2.5
572