Patchwork [V5,5/5] libqblock test example

login
register
mail settings
Submitter Wayne Xia
Date Sept. 29, 2012, 8:13 a.m.
Message ID <1348906418-16471-6-git-send-email-xiawenc@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/188021/
State New
Headers show

Comments

Wayne Xia - Sept. 29, 2012, 8:13 a.m.
In this example, at first it will create some qcow2 images, then get
information including backing file relationship. Then it will do sync IO on
the image.

Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
---
 tests/libqblock/libqblock-qcow2.c |  392 ++++++++++++++++++++++++++++++++++++-
 1 files changed, 390 insertions(+), 2 deletions(-)
wenchao xia - Oct. 3, 2012, 11:31 a.m.
>> +const uint64_t *qb_get_virt_size(const QBlockStaticInfo *info)
>> +{
>> +    return info->member_addr->virt_size;
>
>Please change this to:
>
>     QBlockStaticInfoAddr addrs;
>     qb_setup_info_addr(info, &addrs);
>     return *addrs->virt_size;
>
>and similarly for the others.
>
>QBlockStaticInfoAddr should not be a public struct.  I'm sorry if this
>wasn't clear.
>
>I'll review the rest on Monday.
>
>Paolo
>
  Hi, QBlockStaticInfoAddr was declared as a pointer, user can't see
what it really is. It is actually defined in internal header files.
Paolo Bonzini - Oct. 3, 2012, 12:21 p.m.
Il 03/10/2012 13:31, wenchao xia ha scritto:
>>> +const uint64_t *qb_get_virt_size(const QBlockStaticInfo *info)
>>> +{
>>> +    return info->member_addr->virt_size;
>>
>> Please change this to:
>>
>>     QBlockStaticInfoAddr addrs;
>>     qb_setup_info_addr(info, &addrs);
>>     return *addrs->virt_size;
>>
>> and similarly for the others.
>>
>> QBlockStaticInfoAddr should not be a public struct.  I'm sorry if this
>> wasn't clear.
>>
>> I'll review the rest on Monday.
>>
>> Paolo
>>
>   Hi, QBlockStaticInfoAddr was declared as a pointer, user can't see
> what it really is. It is actually defined in internal header files.

Yes, but even the type should be hidden.  It should be purely an
implementation detail, at least for now, to hide the switch in a single
function.

Paolo
wenchao xia - Oct. 5, 2012, 11:20 a.m.
于 2012-10-3 20:21, Paolo Bonzini 写道:
> Il 03/10/2012 13:31, wenchao xia ha scritto:
>>>> +const uint64_t *qb_get_virt_size(const QBlockStaticInfo *info)
>>>> +{
>>>> +    return info->member_addr->virt_size;
>>>
>>> Please change this to:
>>>
>>>      QBlockStaticInfoAddr addrs;
>>>      qb_setup_info_addr(info, &addrs);
>>>      return *addrs->virt_size;
>>>
>>> and similarly for the others.
>>>
>>> QBlockStaticInfoAddr should not be a public struct.  I'm sorry if this
>>> wasn't clear.
>>>
>>> I'll review the rest on Monday.
>>>
>>> Paolo
>>>
>>    Hi, QBlockStaticInfoAddr was declared as a pointer, user can't see
>> what it really is. It is actually defined in internal header files.
> 
> Yes, but even the type should be hidden.  It should be purely an
> implementation detail, at least for now, to hide the switch in a single
> function.
> 
> Paolo
> 
  OK, then I'll remove it. Do you think there is other things need to
be modified?
Paolo Bonzini - Oct. 5, 2012, 11:32 a.m.
Il 05/10/2012 13:20, wenchao xia ha scritto:
> > >    Hi, QBlockStaticInfoAddr was declared as a pointer, user can't see
> > > what it really is. It is actually defined in internal header files.
> > 
> > Yes, but even the type should be hidden.  It should be purely an
> > implementation detail, at least for now, to hide the switch in a single
> > function.
> 
> OK, then I'll remove it. Do you think there is other things need to
> be modified?

I don't recall anything.

Paolo

Patch

diff --git a/tests/libqblock/libqblock-qcow2.c b/tests/libqblock/libqblock-qcow2.c
index 58fe692..15e81b8 100644
--- a/tests/libqblock/libqblock-qcow2.c
+++ b/tests/libqblock/libqblock-qcow2.c
@@ -1,4 +1,392 @@ 
-int main(void)
+/*
+ * QEMU block layer library test
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Wenchao Xia   <xiawenc@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)
 {
-    return 0;
+    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;
+    QBlockState *qbs = 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_state_new(context, &qbs);
+    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->o_qcow2.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, qbs, 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, qbs, 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_state_delete(context, &qbs);
+    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;
+    QBlockState *qbs = 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_state_new(context, &qbs);
+    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, qbs, loc_info, NULL, flag);
+    g_assert(ret == 0);
+
+    i = num_backings - 1;
+    while (1) {
+        ret = qb_info_image_static_get(context, qbs, &info_st);
+        g_assert(ret == 0);
+        if (libqb_test_settings.print_flag > 0) {
+            print_info_image_static(info_st);
+        }
+        qb_close(context, qbs);
+
+        /* 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, qbs, 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_state_delete(context, &qbs);
+    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;
+    QBlockState *qbs = NULL;
+    QBlockLocationInfo *loc_info = NULL;
+    int ret, flag;
+
+    ret = qb_context_new(&context);
+    g_assert(ret == 0);
+
+    ret = qb_state_new(context, &qbs);
+    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, qbs, loc_info, NULL, flag);
+    g_assert(ret == 0);
+
+    int status;
+    int64_t len;
+    ret = qb_check_allocation(context, qbs, 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, qbs, buf_w, io_buf_size, io_offset);
+    g_assert(ret == io_buf_size);
+
+    ret = qb_read(context, qbs, 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, qbs, io_offset, io_buf_size,
+                                       &status, &len);
+    g_assert(ret == 0);
+    g_assert(status == 1);
+    g_assert(len == io_buf_size);
+
+    qb_close(context, qbs);
+
+    qb_loc_info_delete(context, &loc_info);
+    qb_state_delete(context, &qbs);
+    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;
 }