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