Il 29/01/2013 05:51, Wenchao Xia ha scritto: > In this example, first it will create some qcow2 images, then try get > information including backing file relationship, then it will do sync IO on > the image. > > Signed-off-by: Wenchao Xia <xiaw...@linux.vnet.ibm.com>
Patch 8 alone won't compile. This line: +check-libqblock-$(CONFIG_LIBQBLOCK) = tests/check-libqblock-qcow2$(EXESUF) has to be moved to this patch. Please do this instead: # in patch 9 check-libqblock-y = tests/check-libqblock-qcow2$(EXESUF) ... # in patch 8 check-unit-$(CONFIG_LIBQBLOCK) += $(check-libqblock-y) Paolo > --- > tests/check-libqblock-qcow2.c | 392 > +++++++++++++++++++++++++++++++++++++++++ > 1 files changed, 392 insertions(+), 0 deletions(-) > create mode 100644 tests/check-libqblock-qcow2.c > > diff --git a/tests/check-libqblock-qcow2.c b/tests/check-libqblock-qcow2.c > new file mode 100644 > index 0000000..0cbe8da > --- /dev/null > +++ b/tests/check-libqblock-qcow2.c > @@ -0,0 +1,392 @@ > +/* > + * QEMU block layer library test > + * > + * Copyright IBM, Corp. 2013 > + * > + * Authors: > + * Wenchao Xia <xiaw...@linux.vnet.ibm.com> > + * > + * This work is licensed under the terms of the GNU LGPL, version 2 or later. > + * See the COPYING.LIB file in the top-level directory. > + * > + * Limitation: > + * 1 filename do not support relative path, to save trouble in creating > + * backing files. > + */ > + > +#include <glib.h> > +#include <stdarg.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <inttypes.h> > +#include <string.h> > +#include <stdlib.h> > +#include <sys/stat.h> > +#include <sys/types.h> > + > + > +#include "libqblock.h" > +#include "libqtest.h" > + > +#define LIBQB_TEST_ENV_DIR "LIBQBLOCK_TEST_DIR" > +#define LIBQB_TEST_DEFAULT_DIR "/tmp" > +#define LIBQB_TEST_DEFAULT_FILENAME "libqblock_qcow2_test_img" > + > +typedef struct LibqbTestSettings { > + const char *image_filename; > + uint64_t image_size; > + unsigned int num_backings; > + unsigned int io_buf_size; > + uint64_t io_offset; > + int print_flag; > +} LibqbTestSettings; > + > +LibqbTestSettings libqb_test_settings; > + > +static void print_loc(const QBlockLocationInfo *loc) > +{ > + if (loc == NULL) { > + printf("loc is NULL."); > + return; > + } > + switch (loc->prot_type) { > + case QB_PROTO_NONE: > + printf("protocol type [none]."); > + break; > + case QB_PROTO_FILE: > + printf("protocol type [file], filename [%s].", > + loc->o_file.filename); > + break; > + default: > + printf("protocol type not supported."); > + break; > + } > +} > + > +static void print_info_image_static(QBlockStaticInfo *info) > +{ > + const uint64_t *virt_size = qb_get_virt_size(info); > + const QBlockLocationInfo *backing_loc = qb_get_backing_loc(info); > + g_assert(virt_size != NULL); > + > + printf("=======image location:\n"); > + print_loc(&info->loc); > + printf("\nvirtual_size %" PRId64 ", format type %d [%s]", > + *(virt_size), > + info->fmt.fmt_type, qb_fmttype2str(info->fmt.fmt_type)); > + printf("\nbacking image location:\n"); > + print_loc(backing_loc); > + printf("\n"); > +} > + > +static char *generate_backing_filename(const char *filename, int index) > +{ > + char *backing_filename = NULL; > + > + backing_filename = g_strdup_printf("%s_backing_%d", filename, index); > + return backing_filename; > +} > + > +/* get filename in a full path */ > +static const char *get_filename(const char *path) > +{ > + const char *filename; > + filename = strrchr(path, '/'); > + if (filename == NULL) { > + filename = path; > + } else { > + filename++; > + } > + return filename; > +} > + > +/* create a chain of files, num_backings must >= 0. */ > +static void files_create_qcow2(const char *filename, > + int num_backings, > + uint64_t virt_size) > +{ > + QBlockContext *context = NULL; > + QBlockImage *qbi = NULL; > + QBlockLocationInfo *loc_info = NULL; > + QBlockFormatInfo *fmt_info = NULL; > + int ret; > + int index; > + int flag; > + char *backing_filename = NULL, *new_filename = NULL; > + const char *relative_filename = NULL; > + > + ret = qb_context_new(&context); > + g_assert(ret == 0); > + > + ret = qb_image_new(context, &qbi); > + g_assert(ret == 0); > + > + ret = qb_loc_info_new(context, &loc_info); > + g_assert(ret == 0); > + > + ret = qb_fmt_info_new(context, &fmt_info); > + g_assert(ret == 0); > + > + loc_info->prot_type = QB_PROTO_FILE; > + fmt_info->fmt_type = QB_FMT_QCOW2; > + fmt_info->virt_size = virt_size; > + flag = 0; > + > + index = 0; > + while (index < num_backings) { > + new_filename = generate_backing_filename(filename, index); > + loc_info->o_file.filename = new_filename; > + if (backing_filename != NULL) { > + fmt_info->o_qcow2.backing_loc.prot_type = QB_PROTO_FILE; > + relative_filename = get_filename(backing_filename); > + fmt_info->o_qcow2.backing_loc.o_file.filename = > + > relative_filename; > + } > + ret = qb_create(context, qbi, loc_info, fmt_info, flag); > + g_assert(ret == 0); > + free(backing_filename); > + backing_filename = new_filename; > + new_filename = NULL; > + index++; > + } > + > + loc_info->o_file.filename = filename; > + if (backing_filename != NULL) { > + fmt_info->o_qcow2.backing_loc.prot_type = QB_PROTO_FILE; > + relative_filename = get_filename(backing_filename); > + fmt_info->o_qcow2.backing_loc.o_file.filename = > + relative_filename; > + } > + ret = qb_create(context, qbi, loc_info, fmt_info, flag); > + g_assert(ret == 0); > + free(backing_filename); > + > + qb_fmt_info_delete(context, &fmt_info); > + qb_loc_info_delete(context, &loc_info); > + qb_image_unref(context, &qbi); > + qb_context_delete(&context); > + return; > +} > + > +static void files_delete(const char *filename, > + int num_backings, > + uint64_t virt_size) > +{ > + char *new_filename = NULL; > + int index = 0; > + while (index < num_backings) { > + new_filename = generate_backing_filename(filename, index); > + unlink(new_filename); > + free(new_filename); > + index++; > + } > + unlink(filename); > +} > + > +static void testcase_info_image_static(void) > +{ > + const char *filename = libqb_test_settings.image_filename; > + uint64_t image_size = libqb_test_settings.image_size; > + int num_backings = libqb_test_settings.num_backings; > + QBlockContext *context = NULL; > + QBlockImage *qbi = NULL; > + QBlockLocationInfo *loc_info = NULL; > + int ret, flag; > + QBlockStaticInfo *info_st = NULL; > + int i; > + char *backing_filename = NULL; > + const uint64_t *virt_size = NULL; > + const QBlockLocationInfo *backing_loc = NULL; > + > + ret = qb_context_new(&context); > + g_assert(ret == 0); > + > + ret = qb_image_new(context, &qbi); > + g_assert(ret == 0); > + > + ret = qb_loc_info_new(context, &loc_info); > + g_assert(ret == 0); > + > + loc_info->prot_type = QB_PROTO_FILE; > + loc_info->o_file.filename = filename; > + flag = LIBQBLOCK_O_NO_BACKING; > + ret = qb_open(context, qbi, loc_info, NULL, flag); > + g_assert(ret == 0); > + > + i = num_backings - 1; > + while (1) { > + ret = qb_info_image_static_get(context, qbi, &info_st); > + g_assert(ret == 0); > + if (libqb_test_settings.print_flag > 0) { > + print_info_image_static(info_st); > + } > + qb_close(context, qbi); > + > + /* checking the information */ > + g_assert(info_st->loc.prot_type == loc_info->prot_type); > + ret = strcmp(info_st->loc.o_file.filename, > + loc_info->o_file.filename); > + > + g_assert(ret == 0); > + g_assert(info_st->fmt.fmt_type == QB_FMT_QCOW2); > + virt_size = qb_get_virt_size(info_st); > + g_assert(virt_size != NULL); > + g_assert(*virt_size == image_size); > + backing_loc = qb_get_backing_loc(info_st); > + /* qcow2 have always backing file property */ > + g_assert(backing_loc != NULL); > + if (i >= 0) { > + /* it should have backing file */ > + g_assert(backing_loc->prot_type == QB_PROTO_FILE); > + backing_filename = generate_backing_filename(filename, i); > + ret = strcmp(backing_filename, backing_loc->o_file.filename); > + g_assert(ret == 0); > + g_free(backing_filename); > + } else { > + g_assert(backing_loc->prot_type == QB_FMT_NONE); > + } > + i--; > + /* see if there is backing file need to check. */ > + if (backing_loc->prot_type == QB_FMT_NONE) { > + g_assert(i < 0); > + break; > + } > + qb_loc_info_delete(context, &loc_info); > + loc_info = qb_loc_info_dup(backing_loc); > + ret = qb_open(context, qbi, loc_info, NULL, flag); > + g_assert(ret == 0); > + qb_info_image_static_delete(context, &info_st); > + } > + qb_info_image_static_delete(context, &info_st); > + > + qb_loc_info_delete(context, &loc_info); > + qb_image_unref(context, &qbi); > + qb_context_delete(&context); > + return; > +} > + > +/* assuming the image is new created */ > +static void testcase_sync_io(void) > +{ > + const char *filename = libqb_test_settings.image_filename; > + uint64_t io_buf_size = libqb_test_settings.io_buf_size; > + uint64_t io_offset = libqb_test_settings.io_offset;; > + unsigned char *buf_r, *buf_w; > + uint64_t i; > + unsigned int rand_value; > + > + buf_r = g_malloc0(io_buf_size); > + buf_w = g_malloc0(io_buf_size); > + for (i = 0; i < io_buf_size; i++) { > + rand_value = g_test_rand_int_range(0, 255); > + buf_w[i] = (unsigned char)rand_value; > + } > + > + QBlockContext *context = NULL; > + QBlockImage *qbi = NULL; > + QBlockLocationInfo *loc_info = NULL; > + int ret, flag; > + > + ret = qb_context_new(&context); > + g_assert(ret == 0); > + > + ret = qb_image_new(context, &qbi); > + g_assert(ret == 0); > + > + ret = qb_loc_info_new(context, &loc_info); > + g_assert(ret == 0); > + > + > + loc_info->prot_type = QB_PROTO_FILE; > + loc_info->o_file.filename = filename; > + flag = LIBQBLOCK_O_RDWR; > + ret = qb_open(context, qbi, loc_info, NULL, flag); > + g_assert(ret == 0); > + > + int status; > + int64_t len; > + ret = qb_check_allocation(context, qbi, io_offset, io_buf_size, > + &status, &len); > + g_assert(ret == 0); > + g_assert(status == 0); > + g_assert(len == io_buf_size); > + > + ret = qb_write(context, qbi, buf_w, io_buf_size, io_offset); > + g_assert(ret == io_buf_size); > + > + ret = qb_read(context, qbi, buf_r, io_buf_size, io_offset); > + g_assert(ret == io_buf_size); > + > + int cmp = memcmp(buf_r, buf_w, io_buf_size); > + g_assert(cmp == 0); > + > + ret = qb_check_allocation(context, qbi, io_offset, io_buf_size, > + &status, &len); > + g_assert(ret == 0); > + g_assert(status == 1); > + g_assert(len == io_buf_size); > + > + qb_close(context, qbi); > + > + qb_loc_info_delete(context, &loc_info); > + qb_image_unref(context, &qbi); > + qb_context_delete(&context); > + g_free(buf_r); > + g_free(buf_w); > + return; > +} > + > +int main(int argc, char **argv) > +{ > + const char *root_dir; > + const char *name = LIBQB_TEST_DEFAULT_FILENAME; > + int ret; > + int dir_created = 0; > + char *filename; > + > + root_dir = getenv(LIBQB_TEST_ENV_DIR); > + if (root_dir == NULL) { > + root_dir = LIBQB_TEST_DEFAULT_DIR; > + } > + > + ret = access(root_dir, F_OK); > + if (ret != 0) { > + /* try mkdir */ > + ret = mkdir(root_dir, 0755); > + g_assert(ret == 0); > + dir_created = 1; > + } > + > + filename = g_strdup_printf("%s/%s", root_dir, name); > + > + g_test_init(&argc, &argv, NULL); > + g_test_rand_int(); > + > + libqb_test_settings.image_filename = filename; > + libqb_test_settings.image_size = > + 1024 * 1024 * g_test_rand_int_range(1, 1024); > + libqb_test_settings.num_backings = g_test_rand_int_range(0, 10); > + libqb_test_settings.io_buf_size = g_test_rand_int_range(1, 1024 * 1024); > + libqb_test_settings.io_offset = g_test_rand_int_range(0, > + libqb_test_settings.image_size - > libqb_test_settings.io_buf_size); > + > + files_create_qcow2(libqb_test_settings.image_filename, > + libqb_test_settings.num_backings, > + libqb_test_settings.image_size); > + > + g_test_add_func("/libqblock/sync_info_image_static", > + testcase_info_image_static); > + g_test_add_func("/libqblock/sync_io", testcase_sync_io); > + > + ret = g_test_run(); > + files_delete(libqb_test_settings.image_filename, > + libqb_test_settings.num_backings, > + libqb_test_settings.image_size); > + > + g_free(filename); > + if (dir_created) { > + ret = rmdir(root_dir); > + g_assert(ret == 0); > + } > + return ret; > +} >