Patchwork [v3,2/5,RFC] libqblock, user example

login
register
mail settings
Submitter Wayne Xia
Date Aug. 29, 2012, 11:05 a.m.
Message ID <1346238308-24513-1-git-send-email-xiawenc@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/180682/
State New
Headers show

Comments

Wayne Xia - Aug. 29, 2012, 11:05 a.m.
In this example, user first create two qcow2 images, and then get the
backing file relationship information of them. Then does write and read
AIO on them.

Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
---
 libqblock/libqblock-test.c |  242 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 242 insertions(+), 0 deletions(-)
 create mode 100644 libqblock/libqblock-test.c
Paolo Bonzini - Aug. 29, 2012, 11:11 a.m.
Il 29/08/2012 13:05, Wenchao Xia ha scritto:
> +    printf("checking aio status for %d times.\n", check_times);
> +    while (true == qb_aio_check(broker)) {
> +        check_times++;
> +        usleep(1);
> +    }
> +

Busy waiting is not acceptable, and this is the reason why I had
suggested to keep AIO out of the design for now.

You need to provide an implementation of AIO for either glib or
something else, but this is best done within QEMU first (and only later
moved to libqblock).

Paolo
Wayne Xia - Aug. 30, 2012, 1:59 a.m.
于 2012-8-29 19:11, Paolo Bonzini 写道:
> Il 29/08/2012 13:05, Wenchao Xia ha scritto:
>> +    printf("checking aio status for %d times.\n", check_times);
>> +    while (true == qb_aio_check(broker)) {
>> +        check_times++;
>> +        usleep(1);
>> +    }
>> +
>
> Busy waiting is not acceptable, and this is the reason why I had
> suggested to keep AIO out of the design for now.
>
> You need to provide an implementation of AIO for either glib or
> something else, but this is best done within QEMU first (and only later
> moved to libqblock).
>
   It is similar to qemu's "select" type of AIO, while (true ==
qb_aio_check(broker) is not neccessary but an example here
to ensure write i/o is executed first.
   Do you mean qemu's aio should be improved to another type of
AIO API instead of select type? which kind of AIO api is preferred?

> Paolo
>
Paolo Bonzini - Aug. 30, 2012, 7:46 a.m.
Il 30/08/2012 03:59, Wenchao Xia ha scritto:
>>>
>>
>> Busy waiting is not acceptable, and this is the reason why I had
>> suggested to keep AIO out of the design for now.
>>
>> You need to provide an implementation of AIO for either glib or
>> something else, but this is best done within QEMU first (and only later
>> moved to libqblock).
>>
>   It is similar to qemu's "select" type of AIO, while (true ==
> qb_aio_check(broker) is not neccessary but an example here
> to ensure write i/o is executed first.
>   Do you mean qemu's aio should be improved to another type of
> AIO API instead of select type? which kind of AIO api is preferred?

Using GSource to integrate with the QEMU main loop would be an idea.
qemu_aio_wait would remain.

However, this is not relevant to libqblock.  My point is that APIs are
hard to get right, and even harder if you try to do too many things in
the first iteration.

Paolo
Wayne Xia - Aug. 31, 2012, 2:38 a.m.
于 2012-8-30 15:46, Paolo Bonzini 写道:
> Il 30/08/2012 03:59, Wenchao Xia ha scritto:
>>>>
>>>
>>> Busy waiting is not acceptable, and this is the reason why I had
>>> suggested to keep AIO out of the design for now.
>>>
>>> You need to provide an implementation of AIO for either glib or
>>> something else, but this is best done within QEMU first (and only later
>>> moved to libqblock).
>>>
>>    It is similar to qemu's "select" type of AIO, while (true ==
>> qb_aio_check(broker) is not neccessary but an example here
>> to ensure write i/o is executed first.
>>    Do you mean qemu's aio should be improved to another type of
>> AIO API instead of select type? which kind of AIO api is preferred?
>
> Using GSource to integrate with the QEMU main loop would be an idea.
> qemu_aio_wait would remain.
>
> However, this is not relevant to libqblock.  My point is that APIs are
> hard to get right, and even harder if you try to do too many things in
> the first iteration.
>
> Paolo
>
>
  OK, I got your point, will focus on a small set of API in the first
version, then bring AIO with GSource in next step.

Patch

diff --git a/libqblock/libqblock-test.c b/libqblock/libqblock-test.c
new file mode 100644
index 0000000..b293185
--- /dev/null
+++ b/libqblock/libqblock-test.c
@@ -0,0 +1,242 @@ 
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <string.h>
+
+#include "libqblock.h"
+
+static unsigned char buf_r[1024];
+static unsigned char buf_w[1024] = {4, 0, 0, 2};
+
+struct verify_data {
+    unsigned char *buf_r;
+    unsigned char *buf_w;
+    int len;
+};
+
+static void print_loc(struct QBlockOptionLoc *loc)
+{
+    switch (loc->prot_type) {
+    case QB_PROTO_NONE:
+        printf("protocol type [none].");
+        break;
+    case QB_PROTO_FILE:
+        printf("protocol type [file], filename [%s].",
+               loc->prot_op.o_file.filename);
+        break;
+    default:
+        printf("protocol type not supported.");
+        break;
+    }
+}
+
+static void print_info_image_static(struct QBlockInfoImageStatic *info)
+{
+    printf("=======image location:\n");
+    print_loc(&info->loc);
+    printf("\nvirtual_size %" PRId64 ", format type %d,",
+           info->virt_size, info->fmt_type);
+    printf("allocated size %" PRId64 ", encrypt %d,",
+           info->allocated_size, info->encrypt);
+    printf("\nbacking image location:\n");
+    print_loc(&info->backing_loc);
+    printf("\n");
+}
+
+static void aio_test_w_cb(void *opaque, int ret)
+{
+    printf("aio write complete.\n");
+}
+
+static void aio_test_r_cb(void *opaque, int ret)
+{
+    struct verify_data *vdata;
+    int cmp;
+    printf("aio read complete.\n");
+    if (opaque != NULL) {
+        vdata = opaque;
+        cmp = memcmp(vdata->buf_r, vdata->buf_w, vdata->len);
+        if (cmp == 0) {
+            printf("compare succeed, %d.\n", vdata->buf_r[24]);
+        } else {
+            printf("!!! compare fail, %d.\n", vdata->buf_r[24]);
+            exit(1);
+        }
+    }
+}
+
+int main(int argc, char **argv)
+{
+    char *filename1, *filename2;
+    struct QBroker *broker = NULL;
+    struct QBlockState *qbs = NULL;
+    struct QBlockOptionLoc *ol = NULL;
+    struct QBlockOptionFormat *of = NULL;
+    struct QBlockInfoImageStatic *info_st = NULL;
+    int ret, flag;
+    int test_offset = 0;
+    int test_len = 512;
+    struct verify_data vdata;
+    char err_str[1024];
+
+    vdata.buf_r = buf_r;
+    vdata.buf_w = buf_w;
+    vdata.len = test_len;
+
+    filename1 = argv[1];
+    filename2 = argv[2];
+    printf("qemu test, filename1 is %s, filename2 is %s.\n",
+                                       filename1, filename2);
+
+    libqblock_init();
+
+    ret = qb_broker_new(&broker);
+    if (ret < 0) {
+        goto free;
+    }
+
+    ret = qb_state_new(broker, &qbs);
+    if (ret < 0) {
+        goto free;
+    }
+
+    ret = qb_ol_new(broker, &ol);
+    if (ret < 0) {
+        goto free;
+    }
+
+    ret = qb_of_new(broker, &of);
+    if (ret < 0) {
+        goto free;
+    }
+
+    /* create a new image */
+
+    ol->prot_type = QB_PROTO_FILE;
+    ol->prot_op.o_file.filename = filename2;
+    of->fmt_type = QB_FMT_QCOW2;
+    of->fmt_op.o_qcow2.virt_size = 100 * 1024;
+    flag = 0;
+
+    ret = qb_create(broker, qbs, ol, of, flag);
+    if (ret < 0) {
+        qb_error_get_human_str(broker, err_str, sizeof(err_str));
+        printf("create fail 1. %s.\n", err_str);
+        goto unlink;
+    }
+
+    ol->prot_type = QB_PROTO_FILE;
+    ol->prot_op.o_file.filename = filename1;
+    of->fmt_type = QB_FMT_QCOW2;
+    of->fmt_op.o_qcow2.backing_loc.prot_type = QB_PROTO_FILE;
+    of->fmt_op.o_qcow2.backing_loc.prot_op.o_file.filename = filename2;
+    flag = 0;
+    ret = qb_create(broker, qbs, ol, of, flag);
+    if (ret < 0) {
+        qb_error_get_human_str(broker, err_str, sizeof(err_str));
+        printf("create fail 2. %s.\n", err_str);
+        goto unlink;
+    }
+
+    /* get informations */
+    ol->prot_type = QB_PROTO_FILE;
+    ol->prot_op.o_file.filename = filename1;
+    of->fmt_type = QB_FMT_NONE;
+    flag = LIBQBLOCK_O_NO_BACKING;
+    ret = qb_open(broker, qbs, ol, of, flag);
+    if (ret < 0) {
+        qb_error_get_human_str(broker, err_str, sizeof(err_str));
+        printf("info getting, open failed. %s.\n", err_str);
+        goto free;
+    }
+
+    while (1) {
+        ret = qb_info_image_static_get(broker, qbs, &info_st);
+        if (ret < 0) {
+            qb_error_get_human_str(broker, err_str, sizeof(err_str));
+            printf("info get error. %s.\n", err_str);
+            goto close;
+        }
+        print_info_image_static(info_st);
+        qb_close(broker, qbs);
+        if (info_st->backing_loc.prot_type == QB_FMT_NONE) {
+            break;
+        }
+        *ol = info_st->backing_loc;
+        ret = qb_open(broker, qbs, ol, of, flag);
+        if (ret < 0) {
+            qb_error_get_human_str(broker, err_str, sizeof(err_str));
+            printf("info getting, open failed in backing file. %s.\n",
+                                                       err_str);
+            goto free;
+        }
+        qb_info_image_static_delete(broker, &info_st);
+    }
+    /* read and write the image */
+    ol->prot_type = QB_PROTO_FILE;
+    ol->prot_op.o_file.filename = filename1;
+    of->fmt_type = QB_FMT_NONE;
+    flag = LIBQBLOCK_O_RDWR;
+    ret = qb_open(broker, qbs, ol, of, flag);
+    if (ret < 0) {
+        qb_error_get_human_str(broker, err_str, sizeof(err_str));
+        printf("open failed. %s.\n", err_str);
+        goto free;
+    }
+
+    buf_w[24] = 3;
+    memset(buf_r, 0, sizeof(buf_r));
+
+    ret = qb_aio_write(broker, qbs, buf_w, test_len, test_offset,
+                       aio_test_w_cb, NULL, NULL);
+    if (ret < 0) {
+        qb_error_get_human_str(broker, err_str, sizeof(err_str));
+        printf("%s.\n", err_str);
+        goto close;
+    }
+
+    static int check_times = 1;
+    printf("checking aio status for %d times.\n", check_times);
+    while (true == qb_aio_check(broker)) {
+        check_times++;
+        usleep(1);
+    }
+
+    ret = qb_aio_read(broker, qbs, buf_r, test_len, test_offset,
+                      aio_test_r_cb, &vdata, NULL);
+    if (ret < 0) {
+        qb_error_get_human_str(broker, err_str, sizeof(err_str));
+        printf("%s.\n", err_str);
+        goto close;
+    }
+
+    printf("checking aio status for %d times.\n", check_times);
+    while (true == qb_aio_check(broker)) {
+        check_times++;
+        usleep(1);
+    }
+
+ close:
+    qb_close(broker, qbs);
+ unlink:
+    unlink(filename1);
+    unlink(filename2);
+ free:
+    if (info_st != NULL) {
+        qb_info_image_static_delete(broker, &info_st);
+    }
+    if (qbs != NULL) {
+        qb_state_delete(broker, &qbs);
+    }
+    if (ol != NULL) {
+        qb_ol_delete(broker, &ol);
+    }
+    if (of != NULL) {
+        qb_of_delete(broker, &of);
+    }
+    if (broker != NULL) {
+        qb_broker_delete(&broker);
+    }
+    return 0;
+}