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