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