]> git.proxmox.com Git - pve-qemu-kvm.git/blame - 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
CommitLineData
309874bd 1From 37ec0e0badcbf3cc6d3959f1867b8a1d6db3be13 Mon Sep 17 00:00:00 2001
5ad5891c
DM
2From: Dietmar Maurer <dietmar@proxmox.com>
3Date: Wed, 14 Nov 2012 09:57:04 +0100
309874bd 4Subject: [PATCH v3 5/7] 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 +-
309874bd
DM
13 tests/backup-test.c | 515 +++++++++++++++++++++++++++++++++++++++++++++++++++
14 2 files changed, 524 insertions(+), 2 deletions(-)
5ad5891c
DM
15 create mode 100644 tests/backup-test.c
16
5ad5891c
DM
17diff --git a/tests/Makefile b/tests/Makefile
18index 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)
55diff --git a/tests/backup-test.c b/tests/backup-test.c
56new file mode 100644
309874bd 57index 0000000..813590e
5ad5891c
DM
58--- /dev/null
59+++ b/tests/backup-test.c
309874bd 60@@ -0,0 +1,515 @@
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"
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+
4244016d 322+ if (vma_reader_restore(vmar, -1, false, &errp) < 0) {
5ad5891c
DM
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));
309874bd
DM
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);
5ad5891c
DM
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+
309874bd
DM
518+ g_thread_init(NULL);
519+
5ad5891c
DM
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--
5771.7.2.5
578