]> git.proxmox.com Git - pve-qemu-kvm.git/blame - debian/patches/0005-add-regression-tests-for-backup.patch
update to qemu 1.3 final
[pve-qemu-kvm.git] / debian / patches / 0005-add-regression-tests-for-backup.patch
CommitLineData
efa8e5de 1From e6cbe1cf67c6fd7b6fdce689c17cb40a4c644e13 Mon Sep 17 00:00:00 2001
5ad5891c
DM
2From: Dietmar Maurer <dietmar@proxmox.com>
3Date: Wed, 14 Nov 2012 09:57:04 +0100
4Subject: [PATCH v3 5/6] add regression tests for backup
5
16aecab6 6Simple regression tests using vma-reader and vma-writer.
5ad5891c
DM
7
8Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
9---
16aecab6
DM
10 tests/Makefile | 11 +-
11 tests/backup-test.c | 511 +++++++++++++++++++++++++++++++++++++++++++++++++++
12 2 files changed, 520 insertions(+), 2 deletions(-)
5ad5891c
DM
13 create mode 100644 tests/backup-test.c
14
5ad5891c
DM
15diff --git a/tests/Makefile b/tests/Makefile
16index 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)
53diff --git a/tests/backup-test.c b/tests/backup-test.c
54new file mode 100644
55index 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--
5711.7.2.5
572