diff mbox

[V2,1/6] libqblock API design

Message ID 1347265586-17698-2-git-send-email-xiawenc@linux.vnet.ibm.com
State New
Headers show

Commit Message

Wayne Xia Sept. 10, 2012, 8:26 a.m. UTC
This patch contains the major APIs in the library.
Important APIs:
  1 QBroker. These structure was used to retrieve errors, every thread must
create one first, later maybe thread related staff could be added into it.
  2 QBlockState. It stands for an block image object.
  3 QBlockStaticInfo. It contains static information such as location, backing
file, size.
  4 ABI was kept with reserved members.
  5 Sync I/O. It is similar to C file open, read, write and close operations.

Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
---
 libqblock/libqblock.c | 1077 +++++++++++++++++++++++++++++++++++++++++++++++++
 libqblock/libqblock.h |  292 +++++++++++++
 2 files changed, 1369 insertions(+), 0 deletions(-)
 create mode 100644 libqblock/libqblock.c
 create mode 100644 libqblock/libqblock.h

Comments

Eric Blake Sept. 10, 2012, 9:07 p.m. UTC | #1
On 09/10/2012 02:26 AM, Wenchao Xia wrote:
>   This patch contains the major APIs in the library.
> Important APIs:
>   1 QBroker. These structure was used to retrieve errors, every thread must
> create one first, later maybe thread related staff could be added into it.
>   2 QBlockState. It stands for an block image object.
>   3 QBlockStaticInfo. It contains static information such as location, backing
> file, size.
>   4 ABI was kept with reserved members.
>   5 Sync I/O. It is similar to C file open, read, write and close operations.
> 
> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
> ---
>  libqblock/libqblock.c | 1077 +++++++++++++++++++++++++++++++++++++++++++++++++
>  libqblock/libqblock.h |  292 +++++++++++++

Two new files, but no build machinery to build them to see if they have
blatant errors.  Yes, it is bisectable, but no, the bisection is not
useful.  I'd rather see the Makefile patches with stub files at the
beginning, then flesh out the stubs, where each patch builds along the way.

In particular,

> +++ b/libqblock/libqblock.c

> +#include "libqblock.h"
> +#include "libqblock-internal.h"

There is no libqblock-internal.h with just this patch applied, making it
impossible to validate this patch in order (the fact that 'make' isn't
flagging this incomplete patch is because you aren't building
libqblock-o yet).  I'm planning on overlooking the .c file and focusing
on the user interface (I'd rather leave the detailed review to those
more familiar with qemu, while I'm personally worried about how libvirt
would ever use libqblock if you ever solved the glib-aborts-on-OOM issue
to make the library even worth using).

> +++ b/libqblock/libqblock.h
> @@ -0,0 +1,292 @@
> +/*
> + * QEMU block layer library
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef LIBQBLOCK_H
> +#define LIBQBLOCK_H
> +
> +#include "libqblock-types.h"
> +#include "libqblock-error.h"

Even worse - you've introduced a public header that I'm supposed to be
able to use, but I can't use it because libqblock-types.h and
libqblock-error.h don't exist.  I'd much rather review a patch series
built incrementally from ground up, with each piece working, rather than
reviewing an API that depends on constructs that aren't defined until
later patches.

> +/**
> + * qb_broker_new: allocate a new broker
> + *
> + * Broker is used to pass operation to libqblock, and get feed back from it.

s/feed back/feedback/

> +/**
> + * qb_state_delete: free a QBlockState struct
> + *
> + * if image was opened, qb_close must be called before delete.

And if it wasn't closed, what happens?  Should this function return int,
instead of void, to error out in the case that it is called out of order?

> +/**
> + * qb_prot_info_new: create a new struct QBlockProtInfo.

Inconsistent on whether your descriptions end in '.' or not.

> +/* sync access */
> +/**
> + * qb_read: block sync read.
> + *
> + * return number of bytes read, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @qbs: pointer to struct QBlockState.
> + * @buf: buffer that receive the content.
> + * @len: length to read.
> + * @offset: offset in the block data.
> + */
> +DLL_PUBLIC
> +int64_t qb_read(struct QBroker *broker,
> +                struct QBlockState *qbs,
> +                uint8_t *buf,
> +                uint32_t len,
> +                uint64_t offset);

Seems odd to have 32 bit limit on input, when output handles 64 bit.

> +
> +/**
> + * qb_write: block sync write.
> + *
> + * return number of bytes written, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @qbs: pointer to struct QBlockState.
> + * @buf: buffer that receive the content.
> + * @len: length to write.
> + * @offset: offset in the block data.
> + */
> +DLL_PUBLIC
> +int64_t qb_write(struct QBroker *broker,
> +                 struct QBlockState *qbs,
> +                 const uint8_t *buf,
> +                 uint32_t len,
> +                 uint64_t offset);

and again.

> +/* advance image APIs */
> +/**
> + * qb_check_allocation: check if [start, start+lenth-1] was allocated on the
> + *  image.
> + *
> + * return 0 on success, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @qbs: pointer to struct QBlockState.
> + * @start: start position, unit is byte.
> + * @length: length to check, unit is byte.

Needs to be at least int32_t to match your read/write; or better yet
int64_t to allow probes of more than 2G at a time.

> + * @pstatus: pointer to receive the status, 1 means allocated,
> + *  0 means unallocated.
> + * @plength: pointer to receive the length that all have the same status as
> + *  *pstatus.
> + *
> + * Note: after return, start+*plength may have the same status as
> + *  start+*plength-1.
> + */
> +DLL_PUBLIC
> +int qb_check_allocation(struct QBroker *broker,
> +                        struct QBlockState *qbs,
> +                        uint64_t start,
> +                        int length,
> +                        int *pstatus,
> +                        int *plength);

If you change the type of length, then plength needs to match.

> +/**
> + * qb_fmttype2str: libqblock format enum type to a string.
> + *
> + * return a pointer to the string, or NULL if type is not supported, and
> + *  returned pointer do NOT need to free.

grammar; I suggest:
returned pointer must not be freed
Wayne Xia Sept. 11, 2012, 3:16 a.m. UTC | #2
于 2012-9-11 5:07, Eric Blake 写道:
> On 09/10/2012 02:26 AM, Wenchao Xia wrote:
>>    This patch contains the major APIs in the library.
>> Important APIs:
>>    1 QBroker. These structure was used to retrieve errors, every thread must
>> create one first, later maybe thread related staff could be added into it.
>>    2 QBlockState. It stands for an block image object.
>>    3 QBlockStaticInfo. It contains static information such as location, backing
>> file, size.
>>    4 ABI was kept with reserved members.
>>    5 Sync I/O. It is similar to C file open, read, write and close operations.
>>
>> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
>> ---
>>   libqblock/libqblock.c | 1077 +++++++++++++++++++++++++++++++++++++++++++++++++
>>   libqblock/libqblock.h |  292 +++++++++++++
>
> Two new files, but no build machinery to build them to see if they have
> blatant errors.  Yes, it is bisectable, but no, the bisection is not
> useful.  I'd rather see the Makefile patches with stub files at the
> beginning, then flesh out the stubs, where each patch builds along the way.
>
> In particular,
>
   OK, I understand the importance to make each patch workable to
maintainer, will adjust the patches to make each one works.

>> +++ b/libqblock/libqblock.c
>
>> +#include "libqblock.h"
>> +#include "libqblock-internal.h"
>
> There is no libqblock-internal.h with just this patch applied, making it
> impossible to validate this patch in order (the fact that 'make' isn't
> flagging this incomplete patch is because you aren't building
> libqblock-o yet).  I'm planning on overlooking the .c file and focusing
> on the user interface (I'd rather leave the detailed review to those
> more familiar with qemu, while I'm personally worried about how libvirt
> would ever use libqblock if you ever solved the glib-aborts-on-OOM issue
> to make the library even worth using).
>
   About the OOM issue, I think there are potential 3 ways to solve it:
1 modify qemu block layer code, in this way providing libqblock at first
will help, for that it will encapsulate and isolate all codes needed
for block layer, and we got test case on the top to validate OOM
behavior.
2 Using glib and forgot OOM now. Then at higher layer, they have two
choice: if they want no exiting on OOM, wrap the API with xmlrpc or
something like; otherwise directly use the API.
3 switch the implemention of libqblock, do not link qemu block code
directly, fork and execute qemu-img, qemu-nbd. This require a
re-implement about AIO in libqblock, with GSource AIO framework I am
not sure if it would exit on OOM, but I guess better to not involve any
glib in this case. Additional challenge would be, any more
functionalities adding require patch for qemu-img, qemu-io, qemu-nbd
first, such as image information retrieving, allocation detection,
and libqblock need to parse string output carefully, better to get
all output in json format. Personally I am worried to handle many
exception in string parsing.

   To me, the second way seems most reasonable, it allows qemu block
remain tightly bind to glib. The first way also make sense, but
need to loose the tight between qemu and glib. what do you think?

>> +++ b/libqblock/libqblock.h
>> @@ -0,0 +1,292 @@
>> +/*
>> + * QEMU block layer library
>> + *
>> + * 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.
>> + *
>> + */
>> +
>> +#ifndef LIBQBLOCK_H
>> +#define LIBQBLOCK_H
>> +
>> +#include "libqblock-types.h"
>> +#include "libqblock-error.h"
>
> Even worse - you've introduced a public header that I'm supposed to be
> able to use, but I can't use it because libqblock-types.h and
> libqblock-error.h don't exist.  I'd much rather review a patch series
> built incrementally from ground up, with each piece working, rather than
> reviewing an API that depends on constructs that aren't defined until
> later patches.
>
>> +/**
>> + * qb_broker_new: allocate a new broker
>> + *
>> + * Broker is used to pass operation to libqblock, and get feed back from it.
>
> s/feed back/feedback/
>
>> +/**
>> + * qb_state_delete: free a QBlockState struct
>> + *
>> + * if image was opened, qb_close must be called before delete.
>
> And if it wasn't closed, what happens?  Should this function return int,
> instead of void, to error out in the case that it is called out of order?
>
>> +/**
>> + * qb_prot_info_new: create a new struct QBlockProtInfo.
>
> Inconsistent on whether your descriptions end in '.' or not.
>
>> +/* sync access */
>> +/**
>> + * qb_read: block sync read.
>> + *
>> + * return number of bytes read, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: pointer to struct QBlockState.
>> + * @buf: buffer that receive the content.
>> + * @len: length to read.
>> + * @offset: offset in the block data.
>> + */
>> +DLL_PUBLIC
>> +int64_t qb_read(struct QBroker *broker,
>> +                struct QBlockState *qbs,
>> +                uint8_t *buf,
>> +                uint32_t len,
>> +                uint64_t offset);
>
> Seems odd to have 32 bit limit on input, when output handles 64 bit.
>
>> +
>> +/**
>> + * qb_write: block sync write.
>> + *
>> + * return number of bytes written, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: pointer to struct QBlockState.
>> + * @buf: buffer that receive the content.
>> + * @len: length to write.
>> + * @offset: offset in the block data.
>> + */
>> +DLL_PUBLIC
>> +int64_t qb_write(struct QBroker *broker,
>> +                 struct QBlockState *qbs,
>> +                 const uint8_t *buf,
>> +                 uint32_t len,
>> +                 uint64_t offset);
>
> and again.
>
>> +/* advance image APIs */
>> +/**
>> + * qb_check_allocation: check if [start, start+lenth-1] was allocated on the
>> + *  image.
>> + *
>> + * return 0 on success, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: pointer to struct QBlockState.
>> + * @start: start position, unit is byte.
>> + * @length: length to check, unit is byte.
>
> Needs to be at least int32_t to match your read/write; or better yet
> int64_t to allow probes of more than 2G at a time.
>
>> + * @pstatus: pointer to receive the status, 1 means allocated,
>> + *  0 means unallocated.
>> + * @plength: pointer to receive the length that all have the same status as
>> + *  *pstatus.
>> + *
>> + * Note: after return, start+*plength may have the same status as
>> + *  start+*plength-1.
>> + */
>> +DLL_PUBLIC
>> +int qb_check_allocation(struct QBroker *broker,
>> +                        struct QBlockState *qbs,
>> +                        uint64_t start,
>> +                        int length,
>> +                        int *pstatus,
>> +                        int *plength);
>
> If you change the type of length, then plength needs to match.
>
>> +/**
>> + * qb_fmttype2str: libqblock format enum type to a string.
>> + *
>> + * return a pointer to the string, or NULL if type is not supported, and
>> + *  returned pointer do NOT need to free.
>
> grammar; I suggest:
> returned pointer must not be freed
>
Blue Swirl Sept. 11, 2012, 8:28 p.m. UTC | #3
On Mon, Sep 10, 2012 at 8:26 AM, Wenchao Xia <xiawenc@linux.vnet.ibm.com> wrote:
>   This patch contains the major APIs in the library.
> Important APIs:
>   1 QBroker. These structure was used to retrieve errors, every thread must
> create one first, later maybe thread related staff could be added into it.
>   2 QBlockState. It stands for an block image object.
>   3 QBlockStaticInfo. It contains static information such as location, backing
> file, size.
>   4 ABI was kept with reserved members.
>   5 Sync I/O. It is similar to C file open, read, write and close operations.
>
> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
> ---
>  libqblock/libqblock.c | 1077 +++++++++++++++++++++++++++++++++++++++++++++++++
>  libqblock/libqblock.h |  292 +++++++++++++
>  2 files changed, 1369 insertions(+), 0 deletions(-)
>  create mode 100644 libqblock/libqblock.c
>  create mode 100644 libqblock/libqblock.h
>
> diff --git a/libqblock/libqblock.c b/libqblock/libqblock.c
> new file mode 100644
> index 0000000..133ac0f
> --- /dev/null
> +++ b/libqblock/libqblock.c
> @@ -0,0 +1,1077 @@
> +/*
> + * QEMU block layer library
> + *
> + * 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.
> + *
> + */
> +
> +#include <unistd.h>
> +#include <stdarg.h>
> +
> +#include "libqblock.h"
> +#include "libqblock-internal.h"
> +
> +#include "qemu-aio.h"
> +
> +struct LibqblockGlobalData {
> +    int init_flag;
> +};
> +
> +struct LibqblockGlobalData g_libqblock_data;
> +
> +__attribute__((constructor))
> +static void libqblock_init(void)
> +{
> +    if (g_libqblock_data.init_flag == 0) {
> +        bdrv_init();
> +        qemu_init_main_loop();
> +    }
> +    g_libqblock_data.init_flag = 1;
> +}
> +
> +const char *qb_fmttype2str(enum QBlockFmtType fmt_type)
> +{
> +    const char *ret = NULL;
> +    switch (fmt_type) {
> +    case QB_FMT_COW:
> +        ret = "cow";
> +        break;
> +    case QB_FMT_QED:
> +        ret = "qed";
> +        break;
> +    case QB_FMT_QCOW:
> +        ret = "qcow";
> +        break;
> +    case QB_FMT_QCOW2:
> +        ret = "qcow2";
> +        break;
> +    case QB_FMT_RAW:
> +        ret = "raw";
> +        break;
> +    case QB_FMT_RBD:
> +        ret = "rbd";
> +        break;
> +    case QB_FMT_SHEEPDOG:
> +        ret = "sheepdog";
> +        break;
> +    case QB_FMT_VDI:
> +        ret = "vdi";
> +        break;
> +    case QB_FMT_VMDK:
> +        ret = "vmdk";
> +        break;
> +    case QB_FMT_VPC:
> +        ret = "vpc";
> +        break;
> +    default:
> +        break;
> +    }
> +    return ret;
> +}
> +
> +enum QBlockFmtType qb_str2fmttype(const char *fmt_str)
> +{
> +    enum QBlockFmtType ret = QB_FMT_NONE;
> +    if (0 == strcmp(fmt_str, "cow")) {

This order is not common in QEMU.

> +        ret = QB_FMT_COW;
> +    } else if (0 == strcmp(fmt_str, "qed")) {
> +        ret = QB_FMT_QED;
> +    } else if (0 == strcmp(fmt_str, "qcow")) {
> +        ret = QB_FMT_QCOW;
> +    } else if (0 == strcmp(fmt_str, "qcow2")) {
> +        ret = QB_FMT_QCOW2;
> +    } else if (0 == strcmp(fmt_str, "raw")) {
> +        ret = QB_FMT_RAW;
> +    } else if (0 == strcmp(fmt_str, "rbd")) {
> +        ret = QB_FMT_RBD;
> +    } else if (0 == strcmp(fmt_str, "sheepdog")) {
> +        ret = QB_FMT_SHEEPDOG;
> +    } else if (0 == strcmp(fmt_str, "vdi")) {
> +        ret = QB_FMT_VDI;
> +    } else if (0 == strcmp(fmt_str, "vmdk")) {
> +        ret = QB_FMT_VMDK;
> +    } else if (0 == strcmp(fmt_str, "vpc")) {
> +        ret = QB_FMT_VPC;
> +    }
> +    return ret;
> +}
> +
> +static void set_broker_err(struct QBroker *broker, int err_ret,
> +                           const char *fmt, ...)
> +{
> +    va_list ap;
> +
> +    broker->err_ret = err_ret;
> +    if (err_ret == QB_ERR_INTERNAL_ERR) {
> +        broker->err_no = -errno;
> +    } else {
> +        broker->err_no = 0;
> +    }
> +
> +    va_start(ap, fmt);
> +    vsnprintf(broker->err_msg, sizeof(broker->err_msg), fmt, ap);
> +    va_end(ap);
> +}
> +
> +static void set_broker_err_nomem(struct QBroker *broker)
> +{
> +    set_broker_err(broker, QB_ERR_MEM_ERR, "No Memory.");
> +}
> +
> +int qb_broker_new(struct QBroker **broker)
> +{
> +    *broker = FUNC_CALLOC(1, sizeof(struct QBroker));
> +    if (*broker == NULL) {
> +        return QB_ERR_MEM_ERR;
> +    }
> +    return 0;
> +}
> +
> +void qb_broker_delete(struct QBroker **broker)
> +{
> +    CLEAN_FREE(*broker);
> +    return;
> +}
> +
> +int qb_state_new(struct QBroker *broker,
> +                 struct QBlockState **qbs)
> +{
> +    *qbs = FUNC_CALLOC(1, sizeof(struct QBlockState));
> +    if (*qbs == NULL) {
> +        set_broker_err_nomem(broker);
> +        return broker->err_ret;
> +    }
> +    (*qbs)->bdrvs = bdrv_new("hda");
> +    if ((*qbs)->bdrvs == NULL) {
> +        CLEAN_FREE(*qbs);
> +        set_broker_err(broker, QB_ERR_INTERNAL_ERR,
> +                       "failed to create the driver.");
> +        return broker->err_ret;
> +    }
> +    return 0;
> +}
> +
> +void qb_state_delete(struct QBroker *broker,
> +                     struct QBlockState **qbs)
> +{
> +    CLEAN_FREE((*qbs)->filename);
> +    if ((*qbs)->bdrvs != NULL) {
> +        bdrv_delete((*qbs)->bdrvs);
> +        (*qbs)->bdrvs = NULL;
> +    }
> +    CLEAN_FREE(*qbs);
> +    return;
> +}
> +
> +int qb_prot_info_new(struct QBroker *broker,
> +                     struct QBlockProtInfo **op)
> +{
> +    *op = FUNC_CALLOC(1, sizeof(struct QBlockProtInfo));
> +    if (*op == NULL) {
> +        set_broker_err_nomem(broker);
> +        return broker->err_ret;
> +    }
> +    return 0;
> +}
> +
> +void qb_prot_info_delete(struct QBroker *broker,
> +                         struct QBlockProtInfo **op)
> +{
> +    CLEAN_FREE(*op);
> +}
> +
> +int qb_fmt_info_new(struct QBroker *broker,
> +                    struct QBlockFmtInfo **op)
> +{
> +    *op = FUNC_CALLOC(1, sizeof(struct QBlockFmtInfo));
> +    if (*op == NULL) {
> +        set_broker_err_nomem(broker);
> +        return broker->err_ret;
> +    }
> +    return 0;
> +}
> +
> +void qb_fmt_info_delete(struct QBroker *broker,
> +                        struct QBlockFmtInfo **op)
> +{
> +    CLEAN_FREE(*op);
> +}
> +
> +/* return 0 if every thing is fine */
> +static int loc_check_params(struct QBroker *broker,
> +                            struct QBlockProtInfo *loc)
> +{
> +    broker->err_ret = 0;
> +
> +    switch (loc->prot_type) {
> +    case QB_PROT_FILE:
> +        if (loc->prot_op.o_file.filename == NULL) {
> +            set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                           "Filename was not set.");
> +            goto out;
> +        }
> +        if (path_has_protocol(loc->prot_op.o_file.filename) > 0) {
> +            set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                           "filename [%s] had protocol.",
> +                           loc->prot_op.o_file.filename);
> +            goto out;
> +        }
> +        break;
> +    default:
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                       "Protocol type [%d] was not valid.",
> +                       loc->prot_type);
> +        break;
> +    }
> +
> + out:
> +    return broker->err_ret;
> +}
> +
> +/* translate loc structure to internal filename, returned char* need free,
> + * assuming filename is not NULL. *filename would be set to NULL if no valid
> + * filename found. *filename must be freed later.
> + * return 0 if no error with *filename set.
> + */
> +static int loc2filename(struct QBroker *broker,
> +                        struct QBlockProtInfo *loc,
> +                        char **filename)
> +{
> +    broker->err_ret = 0;
> +
> +    if (*filename != NULL) {
> +        CLEAN_FREE(*filename);
> +    }
> +    switch (loc->prot_type) {
> +    case QB_PROT_FILE:
> +        *filename = strdup(loc->prot_op.o_file.filename);
> +        if (*filename == NULL) {
> +            set_broker_err_nomem(broker);
> +        }
> +        break;
> +    default:
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                 "protocol type [%d] is not supported.",
> +                  loc->prot_type);
> +        break;
> +    }
> +
> +    return broker->err_ret;
> +}
> +
> +/* translate filename to location, loc->prot_type = NONE if fail, filename
> +   must be valid. loc internal char pointer must be freed later.
> + * return 0 if no error.
> + */
> +static int filename2loc(struct QBroker *broker,
> +                        struct QBlockProtInfo *loc,
> +                        const char *filename)
> +{
> +    broker->err_ret = 0;
> +
> +    if (path_has_protocol(filename) > 0) {
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                     "Filename [%s] had protocol, not supported now.",
> +                     filename);
> +        goto out;
> +    }
> +
> +    loc->prot_type = QB_PROT_FILE;
> +    switch (loc->prot_type) {
> +    case QB_PROT_FILE:
> +        loc->prot_op.o_file.filename = strdup(filename);
> +        if (loc->prot_op.o_file.filename == NULL) {
> +            set_broker_err_nomem(broker);
> +            goto out;
> +        }
> +        break;
> +    default:
> +        break;
> +    }
> +
> + out:
> +    return broker->err_ret;
> +}
> +
> +/* return 0 if OK, or qblock error number */
> +static int set_backing_file_options(struct QBroker *broker,
> +                                    QEMUOptionParameter *param,
> +                                    struct QBlockProtInfo *loc,
> +                                    enum QBlockFmtType *fmt)
> +{
> +    char *backing_filename = NULL;
> +    const char *fmtstr_backing = NULL;
> +    int ret = 0;
> +
> +    if (loc == NULL) {
> +        goto out;
> +    }
> +
> +    ret = loc2filename(broker, loc, &backing_filename);
> +    /* ret can < 0 if loc have not been set, mean user did not specify backing
> +       file */
> +    if (ret == QB_ERR_MEM_ERR) {
> +        goto out;
> +    }
> +    ret = 0;
> +
> +    if (backing_filename) {
> +        ret = set_option_parameter(param,
> +                            BLOCK_OPT_BACKING_FILE, backing_filename);
> +        assert(ret == 0);
> +        if (fmt == NULL) {
> +            goto out;
> +        }
> +        fmtstr_backing = qb_fmttype2str(*fmt);
> +        if (fmtstr_backing) {
> +            ret = set_option_parameter(param,
> +                                BLOCK_OPT_BACKING_FMT, fmtstr_backing);
> +            assert(ret == 0);
> +        }
> +    }
> +
> + out:
> +    FUNC_FREE(backing_filename);
> +    return ret;
> +}
> +
> +int qb_create(struct QBroker *broker,
> +              struct QBlockState *qbs,
> +              struct QBlockProtInfo *loc,
> +              struct QBlockFmtInfo *fmt,
> +              int flag)
> +{
> +    int ret = 0, bd_ret;
> +    char *filename = NULL;
> +    BlockDriverState *bs = NULL;
> +    BlockDriver *drv = NULL, *backing_drv = NULL;
> +    bool tmp_bool;
> +
> +    const char *fmtstr = NULL, *tmp = NULL;
> +    QEMUOptionParameter *param = NULL, *create_options = NULL;
> +    QEMUOptionParameter *backing_fmt, *backing_file, *size;
> +    struct QBlockFmtOptionCow *o_cow = NULL;
> +    struct QBlockFmtOptionQed *o_qed = NULL;
> +    struct QBlockFmtOptionQcow *o_qcow = NULL;
> +    struct QBlockFmtOptionQcow2 *o_qcow2 = NULL;
> +    struct QBlockFmtOptionRaw *o_raw = NULL;
> +    struct QBlockFmtOptionRbd *o_rbd = NULL;
> +    struct QBlockFmtOptionSheepdog *o_sd = NULL;
> +    struct QBlockFmtOptionVdi *o_vdi = NULL;
> +    struct QBlockFmtOptionVmdk *o_vmdk = NULL;
> +    struct QBlockFmtOptionVpc *o_vpc = NULL;
> +
> +
> +    /* check parameters */
> +    if (flag & (~LIBQBLOCK_O_VALID_MASK)) {
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                           "invalid flag was set.");
> +        ret = broker->err_ret;
> +        goto out;
> +    }
> +
> +    if ((loc == NULL) || (qbs == NULL) || (fmt == NULL)) {
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                          "Got unexpected NULL pointer in parameters.");
> +        ret = broker->err_ret;
> +        goto out;
> +    }
> +
> +    ret = loc_check_params(broker, loc);
> +    if (ret != 0) {
> +        goto out;
> +    }
> +
> +    /* internal translate */
> +    ret = loc2filename(broker, loc, &filename);
> +    if (ret != 0) {
> +        goto out;
> +    }
> +
> +    fmtstr = qb_fmttype2str(fmt->fmt_type);
> +    if (fmtstr == NULL) {
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                 "Got unexpected NULL pointer in parameters.");
> +        ret = broker->err_ret;
> +        goto out;
> +    }
> +
> +    drv = bdrv_find_format(fmtstr);
> +    assert(drv != NULL);
> +
> +    create_options = append_option_parameters(create_options,
> +                                              drv->create_options);
> +    param = parse_option_parameters("", create_options, param);
> +
> +    switch (fmt->fmt_type) {
> +    case QB_FMT_COW:
> +        o_cow = &(fmt->fmt_op.o_cow);
> +        bd_ret = set_option_parameter_int(param,
> +                                BLOCK_OPT_SIZE, o_cow->virt_size);
> +        assert(bd_ret == 0);
> +        /* do not need to check loc, it may be not set */
> +        ret = set_backing_file_options(broker, param,
> +                                       &o_cow->backing_loc, NULL);
> +        if (ret != 0) {
> +            goto out;
> +        }
> +        break;
> +    case QB_FMT_QED:
> +        o_qed = &(fmt->fmt_op.o_qed);
> +        bd_ret = set_option_parameter_int(param,
> +                                BLOCK_OPT_SIZE, o_qed->virt_size);
> +        assert(bd_ret == 0);
> +        ret = set_backing_file_options(broker, param,
> +                                 &o_qed->backing_loc, &o_qed->backing_fmt);
> +        if (ret != 0) {
> +            goto out;
> +        }
> +        bd_ret = set_option_parameter_int(param,
> +                                BLOCK_OPT_CLUSTER_SIZE, o_qed->cluster_size);
> +        assert(bd_ret == 0);
> +        bd_ret = set_option_parameter_int(param,
> +                                BLOCK_OPT_TABLE_SIZE, o_qed->table_size);
> +        assert(bd_ret == 0);
> +        break;
> +    case QB_FMT_QCOW:
> +        o_qcow = &(fmt->fmt_op.o_qcow);
> +        bd_ret = set_option_parameter_int(param,
> +                                BLOCK_OPT_SIZE, o_qcow->virt_size);
> +        assert(bd_ret == 0);
> +        ret = set_backing_file_options(broker, param,
> +                                       &o_qcow->backing_loc, NULL);
> +        if (ret != 0) {
> +            goto out;
> +        }
> +        tmp = o_qcow->encrypt ? "on" : "off";
> +        bd_ret = set_option_parameter(param, BLOCK_OPT_ENCRYPT, tmp);
> +        assert(bd_ret == 0);
> +        break;
> +    case QB_FMT_QCOW2:
> +        o_qcow2 = &(fmt->fmt_op.o_qcow2);
> +        bd_ret = set_option_parameter_int(param,
> +                              BLOCK_OPT_SIZE, o_qcow2->virt_size);
> +        assert(bd_ret == 0);
> +        ret = set_backing_file_options(broker, param,
> +                              &o_qcow2->backing_loc, &o_qcow2->backing_fmt);
> +        if (ret != 0) {
> +            goto out;
> +        }
> +        tmp = o_qcow2->encrypt ? "on" : "off";
> +        bd_ret = set_option_parameter(param, BLOCK_OPT_ENCRYPT, tmp);
> +        assert(bd_ret == 0);
> +        bd_ret = set_option_parameter_int(param,
> +                              BLOCK_OPT_CLUSTER_SIZE, o_qcow2->cluster_size);
> +        assert(bd_ret == 0);
> +
> +        if (o_qcow2->cpt_lv != QBO_FMT_QCOW2_CPT_NONE) {
> +            tmp = o_qcow2->cpt_lv == QBO_FMT_QCOW2_CPT_V010 ? "0.10" : "1.1";
> +            bd_ret = set_option_parameter(param,
> +                              BLOCK_OPT_COMPAT_LEVEL, tmp);
> +            assert(bd_ret == 0);
> +        }
> +
> +        if (o_qcow2->pre_mode != QBO_FMT_QCOW2_PREALLOC_NONE) {
> +            tmp = o_qcow2->pre_mode == QBO_FMT_QCOW2_PREALLOC_OFF ?
> +                                         "off" : "metadata";
> +            bd_ret = set_option_parameter(param,
> +                              BLOCK_OPT_PREALLOC, tmp);
> +            assert(bd_ret == 0);
> +        }
> +        break;
> +
> +    case QB_FMT_RAW:
> +        o_raw = &(fmt->fmt_op.o_raw);
> +        bd_ret = set_option_parameter_int(param,
> +                              BLOCK_OPT_SIZE, o_raw->virt_size);
> +        assert(bd_ret == 0);
> +        break;
> +    case QB_FMT_RBD:
> +        o_rbd = &(fmt->fmt_op.o_rbd);
> +        bd_ret = set_option_parameter_int(param,
> +                              BLOCK_OPT_SIZE, o_rbd->virt_size);
> +        assert(bd_ret == 0);
> +        bd_ret = set_option_parameter_int(param,
> +                              BLOCK_OPT_CLUSTER_SIZE, o_rbd->cluster_size);
> +        assert(bd_ret == 0);
> +        break;
> +    case QB_FMT_SHEEPDOG:
> +        o_sd = &(fmt->fmt_op.o_sheepdog);
> +        bd_ret = set_option_parameter_int(param,
> +                              BLOCK_OPT_SIZE, o_sd->virt_size);
> +        assert(bd_ret == 0);
> +        ret = set_backing_file_options(broker, param,
> +                                       &o_sd->backing_loc, NULL);
> +        if (ret != 0) {
> +            goto out;
> +        }
> +        if (o_sd->pre_mode != QBO_FMT_SD_PREALLOC_NONE) {
> +            tmp = o_sd->pre_mode == QBO_FMT_SD_PREALLOC_OFF ? "off" : "full";
> +            bd_ret = set_option_parameter(param,
> +                              BLOCK_OPT_PREALLOC, tmp);
> +            assert(bd_ret == 0);
> +        }
> +        break;
> +    case QB_FMT_VDI:
> +        o_vdi = &(fmt->fmt_op.o_vdi);
> +        bd_ret = set_option_parameter_int(param,
> +                              BLOCK_OPT_SIZE, o_vdi->virt_size);
> +        assert(bd_ret == 0);
> +        /* following option is not always valid depends on configuration */
> +        set_option_parameter_int(param,
> +                              BLOCK_OPT_CLUSTER_SIZE, o_vdi->cluster_size);
> +        if (o_vdi->pre_mode != QBO_FMT_VDI_PREALLOC_NONE) {
> +            tmp_bool = o_sd->pre_mode == QBO_FMT_VDI_PREALLOC_TRUE ?
> +                                                     true : false;
> +            set_option_parameter_int(param, "static", tmp_bool);
> +        }
> +        break;
> +    case QB_FMT_VMDK:
> +        o_vmdk = &(fmt->fmt_op.o_vmdk);
> +        bd_ret = set_option_parameter_int(param,
> +                              BLOCK_OPT_SIZE, o_vmdk->virt_size);
> +        assert(bd_ret == 0);
> +        ret = set_backing_file_options(broker, param,
> +                                       &o_vmdk->backing_loc, NULL);
> +        if (ret != 0) {
> +            goto out;
> +        }
> +
> +        if (o_vmdk->cpt_lv != QBO_FMT_VMDK_CPT_NONE) {
> +            tmp_bool = o_vmdk->cpt_lv == QBO_FMT_VMDK_CPT_VMDKV6_TRUE ?
> +                                                     true : false;
> +            bd_ret = set_option_parameter_int(param, BLOCK_OPT_COMPAT6,
> +                                                     tmp_bool);
> +            assert(bd_ret == 0);
> +        }
> +        if (o_vmdk->subfmt != QBO_FMT_VMDK_SUBFMT_MONOLITHIC_NONE) {
> +            switch (o_vmdk->subfmt) {
> +            case QBO_FMT_VMDK_SUBFMT_MONOLITHIC_SPARSE:
> +                tmp = "monolithicSparse";
> +                break;
> +            case QBO_FMT_VMDK_SUBFMT_MONOLITHIC_FLAT:
> +                tmp = "monolithicFlat";
> +                break;
> +            case QBO_FMT_VMDK_SUBFMT_TWOGBMAX_EXTENT_SPARSE:
> +                tmp = "twoGbMaxExtentSparse";
> +                break;
> +            case QBO_FMT_VMDK_SUBFMT_TWOGBMAX_EXTENT_FLAT:
> +                tmp = "twoGbMaxExtentFlat";
> +                break;
> +            case QBO_FMT_VMDK_SUBFMT_STREAM_OPTIMIZED:
> +                tmp = "streamOptimized";
> +                break;
> +            default:
> +                assert(false);
> +                break;
> +            }
> +            bd_ret = set_option_parameter(param,
> +                              BLOCK_OPT_SUBFMT, tmp);
> +            assert(bd_ret == 0);
> +        }
> +        break;
> +    case QB_FMT_VPC:
> +        o_vpc = &(fmt->fmt_op.o_vpc);
> +        bd_ret = set_option_parameter_int(param,
> +                               BLOCK_OPT_SIZE, o_vpc->virt_size);
> +        assert(bd_ret == 0);
> +        if (o_vpc->subfmt != QBO_FMT_VPC_SUBFMT_NONE) {
> +            tmp = o_vpc->subfmt == QBO_FMT_VPC_SUBFMT_DYNAMIC ?
> +                                               "dynamic" : "fixed";
> +            bd_ret = set_option_parameter(param,
> +                               BLOCK_OPT_SUBFMT, tmp);
> +            assert(bd_ret == 0);
> +        }
> +        break;
> +    default:
> +        assert(false);

abort()

> +        break;
> +    }
> +
> +    backing_file = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
> +    if (backing_file && backing_file->value.s) {
> +        if (!strcmp(filename, backing_file->value.s)) {
> +            set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                          "Backing file is the same with new file.");
> +            ret = broker->err_ret;
> +            goto out;
> +        }
> +    }
> +
> +    backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
> +    if (backing_fmt && backing_fmt->value.s) {
> +        backing_drv = bdrv_find_format(backing_fmt->value.s);
> +        assert(backing_drv != NULL);
> +    }
> +
> +    size = get_option_parameter(param, BLOCK_OPT_SIZE);
> +    if (size && size->value.n <= 0) {
> +        if (backing_file && backing_file->value.s) {
> +            uint64_t size;
> +            char buf[32];
> +            int back_flags;
> +
> +            /* backing files always opened read-only */
> +            back_flags =
> +                flag &
> +                ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
> +
> +            bs = bdrv_new("");
> +
> +            ret = bdrv_open(bs, backing_file->value.s,
> +                                back_flags, backing_drv);
> +            if (ret < 0) {
> +                set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                               "Failed to open the backing file.");
> +                ret = broker->err_ret;
> +                goto out;
> +            }
> +            bdrv_get_geometry(bs, &size);
> +            size *= BDRV_SECTOR_SIZE;
> +
> +            snprintf(buf, sizeof(buf), "%" PRId64, size);
> +            set_option_parameter(param, BLOCK_OPT_SIZE, buf);
> +        } else {
> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
> +                           "Neither size or backing file was not set.");
> +            ret = broker->err_ret;
> +            goto out;
> +        }
> +    }
> +
> +    bd_ret = bdrv_create(drv, filename, param);
> +
> +
> +    if (bd_ret < 0) {
> +        const char *errstr;
> +        if (bd_ret == -ENOTSUP) {
> +            errstr = "formatting option not supported.";
> +        } else if (bd_ret == -EFBIG) {
> +            errstr = "The image size is too large.";
> +        } else {
> +            errstr = "Error in creating the image.";
> +        }
> +        set_broker_err(broker, QB_ERR_INTERNAL_ERR, errstr);
> +        ret = broker->err_ret;
> +    }
> +
> +out:
> +    free_option_parameters(create_options);
> +    free_option_parameters(param);
> +    FUNC_FREE(filename);
> +    if (bs) {
> +        bdrv_delete(bs);
> +    }
> +
> +    return ret;
> +}
> +
> +int qb_open(struct QBroker *broker,
> +            struct QBlockState *qbs,
> +            struct QBlockProtInfo *loc,
> +            struct QBlockFmtInfo *fmt,
> +            int flag)
> +{
> +    int ret = 0, bd_ret;
> +    BlockDriverState *bs;
> +    BlockDriver *bd;
> +    const char *fmtstr;
> +    char *filename = NULL;
> +
> +    /* take care of user settings */
> +    /* do nothing now */
> +
> +    /* check parameters */
> +    if (flag & (~LIBQBLOCK_O_VALID_MASK)) {
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                      "Invalid flag was set.");
> +        ret = broker->err_ret;
> +        goto out;
> +    }
> +
> +    if ((loc == NULL) || (qbs == NULL)) {
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                      "Got unexpected NULL pointer in parameters.");
> +        ret = broker->err_ret;
> +        goto out;
> +    }
> +
> +    ret = loc_check_params(broker, loc);
> +    if (ret != 0) {
> +        goto out;
> +    }
> +
> +    /* internal translate */
> +    ret = loc2filename(broker, loc, &filename);
> +    if (ret != 0) {
> +        goto out;
> +    }
> +
> +    fmtstr = NULL;
> +    bd = NULL;
> +    if (fmt != NULL) {
> +        fmtstr = qb_fmttype2str(fmt->fmt_type);
> +    }
> +
> +    if (fmtstr != NULL) {
> +        bd = bdrv_find_format(fmtstr);
> +        assert(bd != NULL);
> +    }
> +
> +    /* do real openning */

opening

> +    bs = qbs->bdrvs;
> +    bd_ret = bdrv_open(bs, filename, flag, bd);
> +    if (bd_ret < 0) {
> +        set_broker_err(broker, QB_ERR_INTERNAL_ERR,
> +                      "Failed in opening with driver, bd_ret is %d.", bd_ret);
> +        ret = broker->err_ret;
> +        goto out;
> +    }
> +
> +    if (qbs->filename != NULL) {
> +        FUNC_FREE(qbs->filename);
> +    }
> +    qbs->filename = strdup(filename);
> +    if (qbs->filename == NULL) {
> +        set_broker_err_nomem(broker);
> +        ret = broker->err_ret;
> +        bdrv_close(bs);
> +        goto out;
> +    }
> +
> + out:
> +    FUNC_FREE(filename);
> +    return ret;
> +}
> +
> +void qb_close(struct QBroker *broker,
> +              struct QBlockState *qbs)
> +{
> +    BlockDriverState *bs;
> +
> +    bs = qbs->bdrvs;
> +
> +    if (qbs->filename != NULL) {
> +        CLEAN_FREE(qbs->filename);
> +        bdrv_close(bs);
> +    }
> +    return;
> +}
> +
> +int64_t qb_read(struct QBroker *broker,
> +                struct QBlockState *qbs,
> +                uint8_t *buf,
> +                uint32_t len,
> +                uint64_t offset)
> +{
> +    int bd_ret;
> +    BlockDriverState *bs;
> +    uint8_t temp_buf[BDRV_SECTOR_SIZE], *p;
> +    uint64_t sector_start;
> +    int sector_num, byte_offset, cp_len;
> +    int remains;
> +
> +    broker->err_ret = 0;
> +    bs = qbs->bdrvs;
> +
> +    if (len <= 0) {
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                      "Param len is less or equal to zero.");
> +        return broker->err_ret;
> +    }
> +
> +    p = buf;
> +    remains = len;
> +
> +    sector_start = offset >> BDRV_SECTOR_BITS;
> +
> +    byte_offset = offset & (~BDRV_SECTOR_MASK);
> +    if (byte_offset != 0) {
> +        /* the start sector is not aligned, need to read/write this sector. */
> +        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
> +        if (bd_ret < 0) {
> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
> +                           "QEMU internal block error.");
> +            return broker->err_ret;
> +        }
> +        cp_len = BDRV_SECTOR_SIZE - byte_offset;
> +        memcpy(p, temp_buf + byte_offset, cp_len);
> +
> +        remains -= cp_len;
> +        p += cp_len;
> +        sector_start++;
> +    }
> +
> +    /* now start position is aligned. */
> +    if (remains >= BDRV_SECTOR_SIZE) {
> +        sector_num = len >> BDRV_SECTOR_BITS;
> +        bd_ret = bdrv_read(bs, sector_start, p, sector_num);
> +        if (bd_ret < 0) {
> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
> +                           "QEMU internal block error.");
> +            return broker->err_ret;
> +        }
> +        remains -= sector_num << BDRV_SECTOR_BITS;
> +        p += sector_num << BDRV_SECTOR_BITS;
> +        sector_start += sector_num;
> +    }
> +
> +    if (remains > 0) {
> +        /* there is some request remains, less than 1 sector */
> +        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
> +        if (bd_ret < 0) {
> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
> +                           "QEMU internal block error.");
> +            return broker->err_ret;
> +        }
> +        memcpy(p, temp_buf, remains);
> +        remains -= remains;
> +    }
> +
> +    return len-remains;
> +}
> +
> +int64_t qb_write(struct QBroker *broker,
> +                 struct QBlockState *qbs,
> +                 const uint8_t *buf,
> +                 uint32_t len,
> +                 uint64_t offset)
> +{
> +    int bd_ret;
> +    BlockDriverState *bs;
> +    uint8_t temp_buf[BDRV_SECTOR_SIZE];
> +    const uint8_t *p;
> +    uint64_t sector_start;
> +    int sector_num, byte_offset, cp_len;
> +    int remains;
> +
> +    broker->err_ret = 0;
> +    bs = qbs->bdrvs;
> +
> +    if (len <= 0) {
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                      "Param len is less or equal to zero.");
> +        return broker->err_ret;
> +    }
> +
> +    p = buf;
> +    remains = len;
> +
> +    sector_start = offset >> BDRV_SECTOR_BITS;
> +
> +    byte_offset = offset & (~BDRV_SECTOR_MASK);
> +    if (byte_offset != 0) {
> +        /* the start sector is not aligned, need to read/write this sector. */
> +        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
> +        if (bd_ret < 0) {
> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
> +                           "QEMU internal block error.");
> +            return broker->err_ret;
> +        }
> +        cp_len = BDRV_SECTOR_SIZE - byte_offset;
> +        memcpy(temp_buf + byte_offset, p, cp_len);
> +        bd_ret = bdrv_write(bs, sector_start, temp_buf, 1);
> +        if (bd_ret < 0) {
> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
> +                           "QEMU internal block error.");
> +            return broker->err_ret;
> +        }
> +        remains -= cp_len;
> +        p += cp_len;
> +        sector_start++;
> +    }
> +
> +    /* now start position is aligned. */
> +    if (remains >= BDRV_SECTOR_SIZE) {
> +        sector_num = len >> BDRV_SECTOR_BITS;
> +        bd_ret = bdrv_write(bs, sector_start, p, sector_num);
> +        if (bd_ret < 0) {
> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
> +                           "QEMU internal block error.");
> +            return broker->err_ret;
> +        }
> +        remains -= sector_num << BDRV_SECTOR_BITS;
> +        p += sector_num << BDRV_SECTOR_BITS;
> +        sector_start += sector_num;
> +    }
> +
> +    if (remains > 0) {
> +        /* there is some request remains, less than 1 sector */
> +        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
> +        if (bd_ret < 0) {
> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
> +                           "QEMU internal block error.");
> +            return broker->err_ret;
> +        }
> +        memcpy(temp_buf, p, remains);
> +        bd_ret = bdrv_write(bs, sector_start, temp_buf, 1);
> +        if (bd_ret < 0) {
> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
> +                           "QEMU internal block error.");
> +            return broker->err_ret;
> +        }
> +        remains -= remains;
> +    }
> +
> +    return len-remains;
> +}
> +
> +int qb_flush(struct QBroker *broker,
> +             struct QBlockState *qbs)
> +{
> +    int bd_ret;
> +    BlockDriverState *bs;
> +
> +    broker->err_ret = 0;
> +    bs = qbs->bdrvs;
> +    bd_ret = bdrv_flush(bs);
> +    if (bd_ret < 0) {
> +        set_broker_err(broker, QB_ERR_INTERNAL_ERR,
> +                       "Internal error.");
> +    }
> +    return broker->err_ret;
> +}
> +
> +int qb_check_allocation(struct QBroker *broker,
> +                        struct QBlockState *qbs,
> +                        uint64_t start,
> +                        int length,
> +                        int *pstatus,
> +                        int *plength)
> +{
> +    int ret;
> +    int sector_start, sector_num, num;
> +    BlockDriverState *bs;
> +    unsigned int real_len, ret_len;
> +
> +    broker->err_ret = 0;
> +    bs = qbs->bdrvs;
> +
> +    if (qbs->filename == NULL) {
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                       "Image was not opened first.");
> +        goto out;
> +    }
> +
> +    if (length <= 0) {
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                       "length is not valid.");
> +        goto out;
> +    }
> +
> +    /* translate to sector */
> +    sector_start = start >> BDRV_SECTOR_BITS;
> +    real_len = (start & (~BDRV_SECTOR_MASK)) + length;
> +    sector_num = real_len >> BDRV_SECTOR_BITS;
> +    if ((real_len & (~BDRV_SECTOR_MASK)) != 0) {
> +        sector_num++;
> +    }
> +
> +    ret = bdrv_is_allocated(bs, sector_start, sector_num, &num);
> +    if ((ret == 0) && (num == 0)) {
> +        set_broker_err(broker, QB_ERR_BLOCK_OUT_OF_RANGE,
> +                       "Start position was bigger than the image's size.");
> +        goto out;
> +    }
> +
> +    *pstatus = ret;
> +    ret_len = (num << BDRV_SECTOR_BITS) - (start & (~BDRV_SECTOR_MASK));
> +    if (ret_len > length) {
> +        ret_len = length;
> +    }
> +    *plength = ret_len;
> +
> + out:
> +    return broker->err_ret;
> +}
> +
> +int qb_info_image_static_get(struct QBroker *broker,
> +                             struct QBlockState *qbs,
> +                             struct QBlockStaticInfo **info)
> +{
> +    int ret = 0;
> +    BlockDriverState *bs;
> +    struct QBlockStaticInfo *info_tmp;
> +    const char *fmt_str;
> +    size_t total_sectors;
> +    char backing_filename[1024];
> +
> +    if (qbs->filename == NULL) {
> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
> +                       "Block Image was not openned.");
> +        ret = broker->err_ret;
> +        goto out;
> +    }
> +
> +    info_tmp = FUNC_CALLOC(1, sizeof(struct QBlockStaticInfo));
> +    if (info_tmp == NULL) {
> +        set_broker_err_nomem(broker);
> +        ret = broker->err_ret;
> +        goto out;
> +    }
> +
> +    bs = qbs->bdrvs;
> +
> +    ret = filename2loc(broker,
> +                       &(info_tmp->loc),
> +                       qbs->filename);
> +    if (ret < 0) {
> +        goto free;
> +    }
> +
> +    fmt_str = bdrv_get_format_name(bs);
> +    info_tmp->fmt_type = qb_str2fmttype(fmt_str);
> +
> +    bdrv_get_geometry(bs, &total_sectors);
> +    info_tmp->virt_size = total_sectors * BDRV_SECTOR_SIZE;
> +
> +    info_tmp->encrypt = bdrv_is_encrypted(bs);
> +
> +    bdrv_get_full_backing_filename(bs, backing_filename,
> +                                   sizeof(backing_filename));
> +    if (backing_filename[0] != '\0') {
> +        ret = filename2loc(broker,
> +                           &(info_tmp->backing_loc),
> +                           backing_filename);
> +        if (ret < 0) {
> +            goto free;
> +        }
> +    }
> +
> +    info_tmp->sector_size = BDRV_SECTOR_SIZE;
> +    *info = info_tmp;
> +
> + out:
> +    return ret;
> + free:
> +    qb_info_image_static_delete(broker, &info_tmp);
> +    return ret;
> +}
> +
> +/* free locations if it has string allocated on heap. */
> +static void loc_free(struct QBlockProtInfo *loc)
> +{
> +    switch (loc->prot_type) {
> +    case QB_PROT_FILE:
> +        FUNC_FREE((void *)(loc->prot_op.o_file.filename));
> +        loc->prot_op.o_file.filename = NULL;
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +void qb_info_image_static_delete(struct QBroker *broker,
> +                                 struct QBlockStaticInfo **info)
> +{
> +    loc_free(&(*info)->loc);
> +    loc_free(&(*info)->backing_loc);
> +
> +    CLEAN_FREE(*info);
> +}
> diff --git a/libqblock/libqblock.h b/libqblock/libqblock.h
> new file mode 100644
> index 0000000..97e6c7c
> --- /dev/null
> +++ b/libqblock/libqblock.h
> @@ -0,0 +1,292 @@
> +/*
> + * QEMU block layer library
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef LIBQBLOCK_H
> +#define LIBQBLOCK_H
> +
> +#include "libqblock-types.h"
> +#include "libqblock-error.h"
> +
> +/**
> + * qb_broker_new: allocate a new broker
> + *
> + * Broker is used to pass operation to libqblock, and get feed back from it.
> + *
> + * Returns 0 on success, libqblock negative error value on fail.
> + *
> + * @broker: used to receive the created struct.
> + */
> +DLL_PUBLIC
> +int qb_broker_new(struct QBroker **broker);
> +
> +/**
> + * qb_broker_delete: delete broker
> + *
> + * Broker will be freed and set to NULL.
> + *
> + * @broker: operation broker to be deleted.
> + */
> +DLL_PUBLIC
> +void qb_broker_delete(struct QBroker **broker);
> +
> +/**
> + * qb_state_new: allocate a new QBlockState struct
> + *
> + * Subsequent qblock actions will use this struct
> + *
> + * Returns 0 if succeed, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @qbs: used to receive the created struct.
> + */
> +DLL_PUBLIC
> +int qb_state_new(struct QBroker *broker,
> +                 struct QBlockState **qbs);
> +
> +/**
> + * qb_state_delete: free a QBlockState struct
> + *
> + * if image was opened, qb_close must be called before delete.
> + *
> + * @broker: operation broker.
> + * @qbs: pointer to the struct's pointer.
> + */
> +DLL_PUBLIC
> +void qb_state_delete(struct QBroker *broker,
> +                     struct QBlockState **qbs);
> +
> +/**
> + * qb_prot_info_new: create a new struct QBlockProtInfo.
> + *
> + * return 0 on success, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @op: pointer to receive the new created one.
> + */
> +DLL_PUBLIC
> +int qb_prot_info_new(struct QBroker *broker,
> +                     struct QBlockProtInfo **op);
> +
> +/**
> + * qb_prot_info_delete: free a struct QBlockProtInfo.
> + *
> + * @broker: operation broker.
> + * @op: pointer to the object, *op would be set to NULL.
> + */
> +DLL_PUBLIC
> +void qb_prot_info_delete(struct QBroker *broker,
> +                         struct QBlockProtInfo **op);
> +
> +/**
> + * qb_fmt_info_new: create a new QBlockFmtInfo structure.
> + *
> + * return 0 on success, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @op: pointer that will receive created struct.
> + */
> +DLL_PUBLIC
> +int qb_fmt_info_new(struct QBroker *broker,
> +                    struct QBlockFmtInfo **op);
> +
> +/**
> + * qb_fmt_info_delete: free QBlockFmtInfo structure.
> + *
> + * @broker: operation broker.
> + * @op: pointer to the struct, *op would be set to NULL.
> + */
> +DLL_PUBLIC
> +void qb_fmt_info_delete(struct QBroker *broker,
> +                        struct QBlockFmtInfo **op);
> +
> +
> +/**
> + * qb_open: open a block object.
> + *
> + * return 0 on success, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @qbs: pointer to struct QBlockState.
> + * @loc: location options for open, how to find the image.
> + * @fmt: format options, how to extract the data, only valid member now is
> + *    fmt->fmt_type, set to NULL if you want to auto discovery the format.
> + * @flag: behavior control flags, it is LIBQBLOCK_O_XXX's combination.
> + *
> + * Note: For raw image, there is a risk that it's content is changed to some
> + *  magic value resulting a wrong probing done by libqblock, so don't do
> + * probing on raw images.
> + */
> +DLL_PUBLIC
> +int qb_open(struct QBroker *broker,
> +            struct QBlockState *qbs,
> +            struct QBlockProtInfo *loc,
> +            struct QBlockFmtInfo *fmt,
> +            int flag);
> +
> +/**
> + * qb_close: close a block object.
> + *
> + * qb_flush is automatically done inside.
> + *
> + * @broker: operation broker.
> + * @qbs: pointer to struct QBlockState.
> + */
> +DLL_PUBLIC
> +void qb_close(struct QBroker *broker,
> +              struct QBlockState *qbs);
> +
> +/**
> + * qb_create: create a block image or object.
> + *
> + * Note: Create operation would not open the image automatically.
> + *
> + * return 0 on success, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @qbs: pointer to struct QBlockState.
> + * @loc: location options for open, how to find the image.
> + * @fmt: format options, how to extract the data.
> + * @flag: behavior control flags, LIBQBLOCK_O_XXX's combination.
> + */
> +DLL_PUBLIC
> +int qb_create(struct QBroker *broker,
> +              struct QBlockState *qbs,
> +              struct QBlockProtInfo *loc,
> +              struct QBlockFmtInfo *fmt,
> +              int flag);
> +
> +
> +/* sync access */
> +/**
> + * qb_read: block sync read.
> + *
> + * return number of bytes read, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @qbs: pointer to struct QBlockState.
> + * @buf: buffer that receive the content.
> + * @len: length to read.
> + * @offset: offset in the block data.
> + */
> +DLL_PUBLIC
> +int64_t qb_read(struct QBroker *broker,
> +                struct QBlockState *qbs,
> +                uint8_t *buf,
> +                uint32_t len,
> +                uint64_t offset);
> +
> +/**
> + * qb_write: block sync write.
> + *
> + * return number of bytes written, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @qbs: pointer to struct QBlockState.
> + * @buf: buffer that receive the content.
> + * @len: length to write.
> + * @offset: offset in the block data.
> + */
> +DLL_PUBLIC
> +int64_t qb_write(struct QBroker *broker,
> +                 struct QBlockState *qbs,
> +                 const uint8_t *buf,
> +                 uint32_t len,
> +                 uint64_t offset);
> +
> +/**
> + * qb_flush: block sync flush.
> + *
> + * return 0 on success, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @qbs: pointer to struct QBlockState.
> + */
> +DLL_PUBLIC
> +int qb_flush(struct QBroker *broker,
> +             struct QBlockState *qbs);
> +
> +
> +/* advance image APIs */
> +/**
> + * qb_check_allocation: check if [start, start+lenth-1] was allocated on the
> + *  image.
> + *
> + * return 0 on success, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @qbs: pointer to struct QBlockState.
> + * @start: start position, unit is byte.
> + * @length: length to check, unit is byte.
> + * @pstatus: pointer to receive the status, 1 means allocated,
> + *  0 means unallocated.
> + * @plength: pointer to receive the length that all have the same status as
> + *  *pstatus.
> + *
> + * Note: after return, start+*plength may have the same status as
> + *  start+*plength-1.
> + */
> +DLL_PUBLIC
> +int qb_check_allocation(struct QBroker *broker,
> +                        struct QBlockState *qbs,
> +                        uint64_t start,
> +                        int length,
> +                        int *pstatus,
> +                        int *plength);
> +
> +/* image information */
> +/**
> + * qb_get_image_info: get image info.
> + *
> + * return 0 on success, libqblock negative error value on fail.
> + *
> + * @broker: operation broker.
> + * @qbs: pointer to struct QBlockState.
> + * @info: pointer that would receive the information.
> + */
> +DLL_PUBLIC
> +int qb_info_image_static_get(struct QBroker *broker,
> +                             struct QBlockState *qbs,
> +                             struct QBlockStaticInfo **info);
> +
> +/**
> + * qb_delete_image_info: free image info.
> + *
> + * @broker: operation broker.
> + * @info: pointer to the information struct.
> + */
> +DLL_PUBLIC
> +void qb_info_image_static_delete(struct QBroker *broker,
> +                                 struct QBlockStaticInfo **info);
> +
> +/* helper functions */
> +/**
> + * qb_str2fmttype: translate format string to libqblock format enum type.
> + *
> + * return the type, or QB_FMT_NONE if string matches none of supported types.
> + *
> + * @fmt: the format string.
> + */
> +DLL_PUBLIC
> +enum QBlockFmtType qb_str2fmttype(const char *fmt_str);
> +
> +/**
> + * qb_fmttype2str: libqblock format enum type to a string.
> + *
> + * return a pointer to the string, or NULL if type is not supported, and
> + *  returned pointer do NOT need to free.
> + *
> + * @fmt: the format enum type.
> + */
> +DLL_PUBLIC
> +const char *qb_fmttype2str(enum QBlockFmtType fmt_type);
> +#endif
> --
> 1.7.1
>
>
Wayne Xia Sept. 12, 2012, 2:54 a.m. UTC | #4
All changed, thanks.

> On Mon, Sep 10, 2012 at 8:26 AM, Wenchao Xia <xiawenc@linux.vnet.ibm.com> wrote:
>>    This patch contains the major APIs in the library.
>> Important APIs:
>>    1 QBroker. These structure was used to retrieve errors, every thread must
>> create one first, later maybe thread related staff could be added into it.
>>    2 QBlockState. It stands for an block image object.
>>    3 QBlockStaticInfo. It contains static information such as location, backing
>> file, size.
>>    4 ABI was kept with reserved members.
>>    5 Sync I/O. It is similar to C file open, read, write and close operations.
>>
>> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
>> ---
>>   libqblock/libqblock.c | 1077 +++++++++++++++++++++++++++++++++++++++++++++++++
>>   libqblock/libqblock.h |  292 +++++++++++++
>>   2 files changed, 1369 insertions(+), 0 deletions(-)
>>   create mode 100644 libqblock/libqblock.c
>>   create mode 100644 libqblock/libqblock.h
>>
>> diff --git a/libqblock/libqblock.c b/libqblock/libqblock.c
>> new file mode 100644
>> index 0000000..133ac0f
>> --- /dev/null
>> +++ b/libqblock/libqblock.c
>> @@ -0,0 +1,1077 @@
>> +/*
>> + * QEMU block layer library
>> + *
>> + * 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.
>> + *
>> + */
>> +
>> +#include <unistd.h>
>> +#include <stdarg.h>
>> +
>> +#include "libqblock.h"
>> +#include "libqblock-internal.h"
>> +
>> +#include "qemu-aio.h"
>> +
>> +struct LibqblockGlobalData {
>> +    int init_flag;
>> +};
>> +
>> +struct LibqblockGlobalData g_libqblock_data;
>> +
>> +__attribute__((constructor))
>> +static void libqblock_init(void)
>> +{
>> +    if (g_libqblock_data.init_flag == 0) {
>> +        bdrv_init();
>> +        qemu_init_main_loop();
>> +    }
>> +    g_libqblock_data.init_flag = 1;
>> +}
>> +
>> +const char *qb_fmttype2str(enum QBlockFmtType fmt_type)
>> +{
>> +    const char *ret = NULL;
>> +    switch (fmt_type) {
>> +    case QB_FMT_COW:
>> +        ret = "cow";
>> +        break;
>> +    case QB_FMT_QED:
>> +        ret = "qed";
>> +        break;
>> +    case QB_FMT_QCOW:
>> +        ret = "qcow";
>> +        break;
>> +    case QB_FMT_QCOW2:
>> +        ret = "qcow2";
>> +        break;
>> +    case QB_FMT_RAW:
>> +        ret = "raw";
>> +        break;
>> +    case QB_FMT_RBD:
>> +        ret = "rbd";
>> +        break;
>> +    case QB_FMT_SHEEPDOG:
>> +        ret = "sheepdog";
>> +        break;
>> +    case QB_FMT_VDI:
>> +        ret = "vdi";
>> +        break;
>> +    case QB_FMT_VMDK:
>> +        ret = "vmdk";
>> +        break;
>> +    case QB_FMT_VPC:
>> +        ret = "vpc";
>> +        break;
>> +    default:
>> +        break;
>> +    }
>> +    return ret;
>> +}
>> +
>> +enum QBlockFmtType qb_str2fmttype(const char *fmt_str)
>> +{
>> +    enum QBlockFmtType ret = QB_FMT_NONE;
>> +    if (0 == strcmp(fmt_str, "cow")) {
>
> This order is not common in QEMU.
>
>> +        ret = QB_FMT_COW;
>> +    } else if (0 == strcmp(fmt_str, "qed")) {
>> +        ret = QB_FMT_QED;
>> +    } else if (0 == strcmp(fmt_str, "qcow")) {
>> +        ret = QB_FMT_QCOW;
>> +    } else if (0 == strcmp(fmt_str, "qcow2")) {
>> +        ret = QB_FMT_QCOW2;
>> +    } else if (0 == strcmp(fmt_str, "raw")) {
>> +        ret = QB_FMT_RAW;
>> +    } else if (0 == strcmp(fmt_str, "rbd")) {
>> +        ret = QB_FMT_RBD;
>> +    } else if (0 == strcmp(fmt_str, "sheepdog")) {
>> +        ret = QB_FMT_SHEEPDOG;
>> +    } else if (0 == strcmp(fmt_str, "vdi")) {
>> +        ret = QB_FMT_VDI;
>> +    } else if (0 == strcmp(fmt_str, "vmdk")) {
>> +        ret = QB_FMT_VMDK;
>> +    } else if (0 == strcmp(fmt_str, "vpc")) {
>> +        ret = QB_FMT_VPC;
>> +    }
>> +    return ret;
>> +}
>> +
>> +static void set_broker_err(struct QBroker *broker, int err_ret,
>> +                           const char *fmt, ...)
>> +{
>> +    va_list ap;
>> +
>> +    broker->err_ret = err_ret;
>> +    if (err_ret == QB_ERR_INTERNAL_ERR) {
>> +        broker->err_no = -errno;
>> +    } else {
>> +        broker->err_no = 0;
>> +    }
>> +
>> +    va_start(ap, fmt);
>> +    vsnprintf(broker->err_msg, sizeof(broker->err_msg), fmt, ap);
>> +    va_end(ap);
>> +}
>> +
>> +static void set_broker_err_nomem(struct QBroker *broker)
>> +{
>> +    set_broker_err(broker, QB_ERR_MEM_ERR, "No Memory.");
>> +}
>> +
>> +int qb_broker_new(struct QBroker **broker)
>> +{
>> +    *broker = FUNC_CALLOC(1, sizeof(struct QBroker));
>> +    if (*broker == NULL) {
>> +        return QB_ERR_MEM_ERR;
>> +    }
>> +    return 0;
>> +}
>> +
>> +void qb_broker_delete(struct QBroker **broker)
>> +{
>> +    CLEAN_FREE(*broker);
>> +    return;
>> +}
>> +
>> +int qb_state_new(struct QBroker *broker,
>> +                 struct QBlockState **qbs)
>> +{
>> +    *qbs = FUNC_CALLOC(1, sizeof(struct QBlockState));
>> +    if (*qbs == NULL) {
>> +        set_broker_err_nomem(broker);
>> +        return broker->err_ret;
>> +    }
>> +    (*qbs)->bdrvs = bdrv_new("hda");
>> +    if ((*qbs)->bdrvs == NULL) {
>> +        CLEAN_FREE(*qbs);
>> +        set_broker_err(broker, QB_ERR_INTERNAL_ERR,
>> +                       "failed to create the driver.");
>> +        return broker->err_ret;
>> +    }
>> +    return 0;
>> +}
>> +
>> +void qb_state_delete(struct QBroker *broker,
>> +                     struct QBlockState **qbs)
>> +{
>> +    CLEAN_FREE((*qbs)->filename);
>> +    if ((*qbs)->bdrvs != NULL) {
>> +        bdrv_delete((*qbs)->bdrvs);
>> +        (*qbs)->bdrvs = NULL;
>> +    }
>> +    CLEAN_FREE(*qbs);
>> +    return;
>> +}
>> +
>> +int qb_prot_info_new(struct QBroker *broker,
>> +                     struct QBlockProtInfo **op)
>> +{
>> +    *op = FUNC_CALLOC(1, sizeof(struct QBlockProtInfo));
>> +    if (*op == NULL) {
>> +        set_broker_err_nomem(broker);
>> +        return broker->err_ret;
>> +    }
>> +    return 0;
>> +}
>> +
>> +void qb_prot_info_delete(struct QBroker *broker,
>> +                         struct QBlockProtInfo **op)
>> +{
>> +    CLEAN_FREE(*op);
>> +}
>> +
>> +int qb_fmt_info_new(struct QBroker *broker,
>> +                    struct QBlockFmtInfo **op)
>> +{
>> +    *op = FUNC_CALLOC(1, sizeof(struct QBlockFmtInfo));
>> +    if (*op == NULL) {
>> +        set_broker_err_nomem(broker);
>> +        return broker->err_ret;
>> +    }
>> +    return 0;
>> +}
>> +
>> +void qb_fmt_info_delete(struct QBroker *broker,
>> +                        struct QBlockFmtInfo **op)
>> +{
>> +    CLEAN_FREE(*op);
>> +}
>> +
>> +/* return 0 if every thing is fine */
>> +static int loc_check_params(struct QBroker *broker,
>> +                            struct QBlockProtInfo *loc)
>> +{
>> +    broker->err_ret = 0;
>> +
>> +    switch (loc->prot_type) {
>> +    case QB_PROT_FILE:
>> +        if (loc->prot_op.o_file.filename == NULL) {
>> +            set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                           "Filename was not set.");
>> +            goto out;
>> +        }
>> +        if (path_has_protocol(loc->prot_op.o_file.filename) > 0) {
>> +            set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                           "filename [%s] had protocol.",
>> +                           loc->prot_op.o_file.filename);
>> +            goto out;
>> +        }
>> +        break;
>> +    default:
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                       "Protocol type [%d] was not valid.",
>> +                       loc->prot_type);
>> +        break;
>> +    }
>> +
>> + out:
>> +    return broker->err_ret;
>> +}
>> +
>> +/* translate loc structure to internal filename, returned char* need free,
>> + * assuming filename is not NULL. *filename would be set to NULL if no valid
>> + * filename found. *filename must be freed later.
>> + * return 0 if no error with *filename set.
>> + */
>> +static int loc2filename(struct QBroker *broker,
>> +                        struct QBlockProtInfo *loc,
>> +                        char **filename)
>> +{
>> +    broker->err_ret = 0;
>> +
>> +    if (*filename != NULL) {
>> +        CLEAN_FREE(*filename);
>> +    }
>> +    switch (loc->prot_type) {
>> +    case QB_PROT_FILE:
>> +        *filename = strdup(loc->prot_op.o_file.filename);
>> +        if (*filename == NULL) {
>> +            set_broker_err_nomem(broker);
>> +        }
>> +        break;
>> +    default:
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                 "protocol type [%d] is not supported.",
>> +                  loc->prot_type);
>> +        break;
>> +    }
>> +
>> +    return broker->err_ret;
>> +}
>> +
>> +/* translate filename to location, loc->prot_type = NONE if fail, filename
>> +   must be valid. loc internal char pointer must be freed later.
>> + * return 0 if no error.
>> + */
>> +static int filename2loc(struct QBroker *broker,
>> +                        struct QBlockProtInfo *loc,
>> +                        const char *filename)
>> +{
>> +    broker->err_ret = 0;
>> +
>> +    if (path_has_protocol(filename) > 0) {
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                     "Filename [%s] had protocol, not supported now.",
>> +                     filename);
>> +        goto out;
>> +    }
>> +
>> +    loc->prot_type = QB_PROT_FILE;
>> +    switch (loc->prot_type) {
>> +    case QB_PROT_FILE:
>> +        loc->prot_op.o_file.filename = strdup(filename);
>> +        if (loc->prot_op.o_file.filename == NULL) {
>> +            set_broker_err_nomem(broker);
>> +            goto out;
>> +        }
>> +        break;
>> +    default:
>> +        break;
>> +    }
>> +
>> + out:
>> +    return broker->err_ret;
>> +}
>> +
>> +/* return 0 if OK, or qblock error number */
>> +static int set_backing_file_options(struct QBroker *broker,
>> +                                    QEMUOptionParameter *param,
>> +                                    struct QBlockProtInfo *loc,
>> +                                    enum QBlockFmtType *fmt)
>> +{
>> +    char *backing_filename = NULL;
>> +    const char *fmtstr_backing = NULL;
>> +    int ret = 0;
>> +
>> +    if (loc == NULL) {
>> +        goto out;
>> +    }
>> +
>> +    ret = loc2filename(broker, loc, &backing_filename);
>> +    /* ret can < 0 if loc have not been set, mean user did not specify backing
>> +       file */
>> +    if (ret == QB_ERR_MEM_ERR) {
>> +        goto out;
>> +    }
>> +    ret = 0;
>> +
>> +    if (backing_filename) {
>> +        ret = set_option_parameter(param,
>> +                            BLOCK_OPT_BACKING_FILE, backing_filename);
>> +        assert(ret == 0);
>> +        if (fmt == NULL) {
>> +            goto out;
>> +        }
>> +        fmtstr_backing = qb_fmttype2str(*fmt);
>> +        if (fmtstr_backing) {
>> +            ret = set_option_parameter(param,
>> +                                BLOCK_OPT_BACKING_FMT, fmtstr_backing);
>> +            assert(ret == 0);
>> +        }
>> +    }
>> +
>> + out:
>> +    FUNC_FREE(backing_filename);
>> +    return ret;
>> +}
>> +
>> +int qb_create(struct QBroker *broker,
>> +              struct QBlockState *qbs,
>> +              struct QBlockProtInfo *loc,
>> +              struct QBlockFmtInfo *fmt,
>> +              int flag)
>> +{
>> +    int ret = 0, bd_ret;
>> +    char *filename = NULL;
>> +    BlockDriverState *bs = NULL;
>> +    BlockDriver *drv = NULL, *backing_drv = NULL;
>> +    bool tmp_bool;
>> +
>> +    const char *fmtstr = NULL, *tmp = NULL;
>> +    QEMUOptionParameter *param = NULL, *create_options = NULL;
>> +    QEMUOptionParameter *backing_fmt, *backing_file, *size;
>> +    struct QBlockFmtOptionCow *o_cow = NULL;
>> +    struct QBlockFmtOptionQed *o_qed = NULL;
>> +    struct QBlockFmtOptionQcow *o_qcow = NULL;
>> +    struct QBlockFmtOptionQcow2 *o_qcow2 = NULL;
>> +    struct QBlockFmtOptionRaw *o_raw = NULL;
>> +    struct QBlockFmtOptionRbd *o_rbd = NULL;
>> +    struct QBlockFmtOptionSheepdog *o_sd = NULL;
>> +    struct QBlockFmtOptionVdi *o_vdi = NULL;
>> +    struct QBlockFmtOptionVmdk *o_vmdk = NULL;
>> +    struct QBlockFmtOptionVpc *o_vpc = NULL;
>> +
>> +
>> +    /* check parameters */
>> +    if (flag & (~LIBQBLOCK_O_VALID_MASK)) {
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                           "invalid flag was set.");
>> +        ret = broker->err_ret;
>> +        goto out;
>> +    }
>> +
>> +    if ((loc == NULL) || (qbs == NULL) || (fmt == NULL)) {
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                          "Got unexpected NULL pointer in parameters.");
>> +        ret = broker->err_ret;
>> +        goto out;
>> +    }
>> +
>> +    ret = loc_check_params(broker, loc);
>> +    if (ret != 0) {
>> +        goto out;
>> +    }
>> +
>> +    /* internal translate */
>> +    ret = loc2filename(broker, loc, &filename);
>> +    if (ret != 0) {
>> +        goto out;
>> +    }
>> +
>> +    fmtstr = qb_fmttype2str(fmt->fmt_type);
>> +    if (fmtstr == NULL) {
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                 "Got unexpected NULL pointer in parameters.");
>> +        ret = broker->err_ret;
>> +        goto out;
>> +    }
>> +
>> +    drv = bdrv_find_format(fmtstr);
>> +    assert(drv != NULL);
>> +
>> +    create_options = append_option_parameters(create_options,
>> +                                              drv->create_options);
>> +    param = parse_option_parameters("", create_options, param);
>> +
>> +    switch (fmt->fmt_type) {
>> +    case QB_FMT_COW:
>> +        o_cow = &(fmt->fmt_op.o_cow);
>> +        bd_ret = set_option_parameter_int(param,
>> +                                BLOCK_OPT_SIZE, o_cow->virt_size);
>> +        assert(bd_ret == 0);
>> +        /* do not need to check loc, it may be not set */
>> +        ret = set_backing_file_options(broker, param,
>> +                                       &o_cow->backing_loc, NULL);
>> +        if (ret != 0) {
>> +            goto out;
>> +        }
>> +        break;
>> +    case QB_FMT_QED:
>> +        o_qed = &(fmt->fmt_op.o_qed);
>> +        bd_ret = set_option_parameter_int(param,
>> +                                BLOCK_OPT_SIZE, o_qed->virt_size);
>> +        assert(bd_ret == 0);
>> +        ret = set_backing_file_options(broker, param,
>> +                                 &o_qed->backing_loc, &o_qed->backing_fmt);
>> +        if (ret != 0) {
>> +            goto out;
>> +        }
>> +        bd_ret = set_option_parameter_int(param,
>> +                                BLOCK_OPT_CLUSTER_SIZE, o_qed->cluster_size);
>> +        assert(bd_ret == 0);
>> +        bd_ret = set_option_parameter_int(param,
>> +                                BLOCK_OPT_TABLE_SIZE, o_qed->table_size);
>> +        assert(bd_ret == 0);
>> +        break;
>> +    case QB_FMT_QCOW:
>> +        o_qcow = &(fmt->fmt_op.o_qcow);
>> +        bd_ret = set_option_parameter_int(param,
>> +                                BLOCK_OPT_SIZE, o_qcow->virt_size);
>> +        assert(bd_ret == 0);
>> +        ret = set_backing_file_options(broker, param,
>> +                                       &o_qcow->backing_loc, NULL);
>> +        if (ret != 0) {
>> +            goto out;
>> +        }
>> +        tmp = o_qcow->encrypt ? "on" : "off";
>> +        bd_ret = set_option_parameter(param, BLOCK_OPT_ENCRYPT, tmp);
>> +        assert(bd_ret == 0);
>> +        break;
>> +    case QB_FMT_QCOW2:
>> +        o_qcow2 = &(fmt->fmt_op.o_qcow2);
>> +        bd_ret = set_option_parameter_int(param,
>> +                              BLOCK_OPT_SIZE, o_qcow2->virt_size);
>> +        assert(bd_ret == 0);
>> +        ret = set_backing_file_options(broker, param,
>> +                              &o_qcow2->backing_loc, &o_qcow2->backing_fmt);
>> +        if (ret != 0) {
>> +            goto out;
>> +        }
>> +        tmp = o_qcow2->encrypt ? "on" : "off";
>> +        bd_ret = set_option_parameter(param, BLOCK_OPT_ENCRYPT, tmp);
>> +        assert(bd_ret == 0);
>> +        bd_ret = set_option_parameter_int(param,
>> +                              BLOCK_OPT_CLUSTER_SIZE, o_qcow2->cluster_size);
>> +        assert(bd_ret == 0);
>> +
>> +        if (o_qcow2->cpt_lv != QBO_FMT_QCOW2_CPT_NONE) {
>> +            tmp = o_qcow2->cpt_lv == QBO_FMT_QCOW2_CPT_V010 ? "0.10" : "1.1";
>> +            bd_ret = set_option_parameter(param,
>> +                              BLOCK_OPT_COMPAT_LEVEL, tmp);
>> +            assert(bd_ret == 0);
>> +        }
>> +
>> +        if (o_qcow2->pre_mode != QBO_FMT_QCOW2_PREALLOC_NONE) {
>> +            tmp = o_qcow2->pre_mode == QBO_FMT_QCOW2_PREALLOC_OFF ?
>> +                                         "off" : "metadata";
>> +            bd_ret = set_option_parameter(param,
>> +                              BLOCK_OPT_PREALLOC, tmp);
>> +            assert(bd_ret == 0);
>> +        }
>> +        break;
>> +
>> +    case QB_FMT_RAW:
>> +        o_raw = &(fmt->fmt_op.o_raw);
>> +        bd_ret = set_option_parameter_int(param,
>> +                              BLOCK_OPT_SIZE, o_raw->virt_size);
>> +        assert(bd_ret == 0);
>> +        break;
>> +    case QB_FMT_RBD:
>> +        o_rbd = &(fmt->fmt_op.o_rbd);
>> +        bd_ret = set_option_parameter_int(param,
>> +                              BLOCK_OPT_SIZE, o_rbd->virt_size);
>> +        assert(bd_ret == 0);
>> +        bd_ret = set_option_parameter_int(param,
>> +                              BLOCK_OPT_CLUSTER_SIZE, o_rbd->cluster_size);
>> +        assert(bd_ret == 0);
>> +        break;
>> +    case QB_FMT_SHEEPDOG:
>> +        o_sd = &(fmt->fmt_op.o_sheepdog);
>> +        bd_ret = set_option_parameter_int(param,
>> +                              BLOCK_OPT_SIZE, o_sd->virt_size);
>> +        assert(bd_ret == 0);
>> +        ret = set_backing_file_options(broker, param,
>> +                                       &o_sd->backing_loc, NULL);
>> +        if (ret != 0) {
>> +            goto out;
>> +        }
>> +        if (o_sd->pre_mode != QBO_FMT_SD_PREALLOC_NONE) {
>> +            tmp = o_sd->pre_mode == QBO_FMT_SD_PREALLOC_OFF ? "off" : "full";
>> +            bd_ret = set_option_parameter(param,
>> +                              BLOCK_OPT_PREALLOC, tmp);
>> +            assert(bd_ret == 0);
>> +        }
>> +        break;
>> +    case QB_FMT_VDI:
>> +        o_vdi = &(fmt->fmt_op.o_vdi);
>> +        bd_ret = set_option_parameter_int(param,
>> +                              BLOCK_OPT_SIZE, o_vdi->virt_size);
>> +        assert(bd_ret == 0);
>> +        /* following option is not always valid depends on configuration */
>> +        set_option_parameter_int(param,
>> +                              BLOCK_OPT_CLUSTER_SIZE, o_vdi->cluster_size);
>> +        if (o_vdi->pre_mode != QBO_FMT_VDI_PREALLOC_NONE) {
>> +            tmp_bool = o_sd->pre_mode == QBO_FMT_VDI_PREALLOC_TRUE ?
>> +                                                     true : false;
>> +            set_option_parameter_int(param, "static", tmp_bool);
>> +        }
>> +        break;
>> +    case QB_FMT_VMDK:
>> +        o_vmdk = &(fmt->fmt_op.o_vmdk);
>> +        bd_ret = set_option_parameter_int(param,
>> +                              BLOCK_OPT_SIZE, o_vmdk->virt_size);
>> +        assert(bd_ret == 0);
>> +        ret = set_backing_file_options(broker, param,
>> +                                       &o_vmdk->backing_loc, NULL);
>> +        if (ret != 0) {
>> +            goto out;
>> +        }
>> +
>> +        if (o_vmdk->cpt_lv != QBO_FMT_VMDK_CPT_NONE) {
>> +            tmp_bool = o_vmdk->cpt_lv == QBO_FMT_VMDK_CPT_VMDKV6_TRUE ?
>> +                                                     true : false;
>> +            bd_ret = set_option_parameter_int(param, BLOCK_OPT_COMPAT6,
>> +                                                     tmp_bool);
>> +            assert(bd_ret == 0);
>> +        }
>> +        if (o_vmdk->subfmt != QBO_FMT_VMDK_SUBFMT_MONOLITHIC_NONE) {
>> +            switch (o_vmdk->subfmt) {
>> +            case QBO_FMT_VMDK_SUBFMT_MONOLITHIC_SPARSE:
>> +                tmp = "monolithicSparse";
>> +                break;
>> +            case QBO_FMT_VMDK_SUBFMT_MONOLITHIC_FLAT:
>> +                tmp = "monolithicFlat";
>> +                break;
>> +            case QBO_FMT_VMDK_SUBFMT_TWOGBMAX_EXTENT_SPARSE:
>> +                tmp = "twoGbMaxExtentSparse";
>> +                break;
>> +            case QBO_FMT_VMDK_SUBFMT_TWOGBMAX_EXTENT_FLAT:
>> +                tmp = "twoGbMaxExtentFlat";
>> +                break;
>> +            case QBO_FMT_VMDK_SUBFMT_STREAM_OPTIMIZED:
>> +                tmp = "streamOptimized";
>> +                break;
>> +            default:
>> +                assert(false);
>> +                break;
>> +            }
>> +            bd_ret = set_option_parameter(param,
>> +                              BLOCK_OPT_SUBFMT, tmp);
>> +            assert(bd_ret == 0);
>> +        }
>> +        break;
>> +    case QB_FMT_VPC:
>> +        o_vpc = &(fmt->fmt_op.o_vpc);
>> +        bd_ret = set_option_parameter_int(param,
>> +                               BLOCK_OPT_SIZE, o_vpc->virt_size);
>> +        assert(bd_ret == 0);
>> +        if (o_vpc->subfmt != QBO_FMT_VPC_SUBFMT_NONE) {
>> +            tmp = o_vpc->subfmt == QBO_FMT_VPC_SUBFMT_DYNAMIC ?
>> +                                               "dynamic" : "fixed";
>> +            bd_ret = set_option_parameter(param,
>> +                               BLOCK_OPT_SUBFMT, tmp);
>> +            assert(bd_ret == 0);
>> +        }
>> +        break;
>> +    default:
>> +        assert(false);
>
> abort()
>
>> +        break;
>> +    }
>> +
>> +    backing_file = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
>> +    if (backing_file && backing_file->value.s) {
>> +        if (!strcmp(filename, backing_file->value.s)) {
>> +            set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                          "Backing file is the same with new file.");
>> +            ret = broker->err_ret;
>> +            goto out;
>> +        }
>> +    }
>> +
>> +    backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
>> +    if (backing_fmt && backing_fmt->value.s) {
>> +        backing_drv = bdrv_find_format(backing_fmt->value.s);
>> +        assert(backing_drv != NULL);
>> +    }
>> +
>> +    size = get_option_parameter(param, BLOCK_OPT_SIZE);
>> +    if (size && size->value.n <= 0) {
>> +        if (backing_file && backing_file->value.s) {
>> +            uint64_t size;
>> +            char buf[32];
>> +            int back_flags;
>> +
>> +            /* backing files always opened read-only */
>> +            back_flags =
>> +                flag &
>> +                ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
>> +
>> +            bs = bdrv_new("");
>> +
>> +            ret = bdrv_open(bs, backing_file->value.s,
>> +                                back_flags, backing_drv);
>> +            if (ret < 0) {
>> +                set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                               "Failed to open the backing file.");
>> +                ret = broker->err_ret;
>> +                goto out;
>> +            }
>> +            bdrv_get_geometry(bs, &size);
>> +            size *= BDRV_SECTOR_SIZE;
>> +
>> +            snprintf(buf, sizeof(buf), "%" PRId64, size);
>> +            set_option_parameter(param, BLOCK_OPT_SIZE, buf);
>> +        } else {
>> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
>> +                           "Neither size or backing file was not set.");
>> +            ret = broker->err_ret;
>> +            goto out;
>> +        }
>> +    }
>> +
>> +    bd_ret = bdrv_create(drv, filename, param);
>> +
>> +
>> +    if (bd_ret < 0) {
>> +        const char *errstr;
>> +        if (bd_ret == -ENOTSUP) {
>> +            errstr = "formatting option not supported.";
>> +        } else if (bd_ret == -EFBIG) {
>> +            errstr = "The image size is too large.";
>> +        } else {
>> +            errstr = "Error in creating the image.";
>> +        }
>> +        set_broker_err(broker, QB_ERR_INTERNAL_ERR, errstr);
>> +        ret = broker->err_ret;
>> +    }
>> +
>> +out:
>> +    free_option_parameters(create_options);
>> +    free_option_parameters(param);
>> +    FUNC_FREE(filename);
>> +    if (bs) {
>> +        bdrv_delete(bs);
>> +    }
>> +
>> +    return ret;
>> +}
>> +
>> +int qb_open(struct QBroker *broker,
>> +            struct QBlockState *qbs,
>> +            struct QBlockProtInfo *loc,
>> +            struct QBlockFmtInfo *fmt,
>> +            int flag)
>> +{
>> +    int ret = 0, bd_ret;
>> +    BlockDriverState *bs;
>> +    BlockDriver *bd;
>> +    const char *fmtstr;
>> +    char *filename = NULL;
>> +
>> +    /* take care of user settings */
>> +    /* do nothing now */
>> +
>> +    /* check parameters */
>> +    if (flag & (~LIBQBLOCK_O_VALID_MASK)) {
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                      "Invalid flag was set.");
>> +        ret = broker->err_ret;
>> +        goto out;
>> +    }
>> +
>> +    if ((loc == NULL) || (qbs == NULL)) {
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                      "Got unexpected NULL pointer in parameters.");
>> +        ret = broker->err_ret;
>> +        goto out;
>> +    }
>> +
>> +    ret = loc_check_params(broker, loc);
>> +    if (ret != 0) {
>> +        goto out;
>> +    }
>> +
>> +    /* internal translate */
>> +    ret = loc2filename(broker, loc, &filename);
>> +    if (ret != 0) {
>> +        goto out;
>> +    }
>> +
>> +    fmtstr = NULL;
>> +    bd = NULL;
>> +    if (fmt != NULL) {
>> +        fmtstr = qb_fmttype2str(fmt->fmt_type);
>> +    }
>> +
>> +    if (fmtstr != NULL) {
>> +        bd = bdrv_find_format(fmtstr);
>> +        assert(bd != NULL);
>> +    }
>> +
>> +    /* do real openning */
>
> opening
>
>> +    bs = qbs->bdrvs;
>> +    bd_ret = bdrv_open(bs, filename, flag, bd);
>> +    if (bd_ret < 0) {
>> +        set_broker_err(broker, QB_ERR_INTERNAL_ERR,
>> +                      "Failed in opening with driver, bd_ret is %d.", bd_ret);
>> +        ret = broker->err_ret;
>> +        goto out;
>> +    }
>> +
>> +    if (qbs->filename != NULL) {
>> +        FUNC_FREE(qbs->filename);
>> +    }
>> +    qbs->filename = strdup(filename);
>> +    if (qbs->filename == NULL) {
>> +        set_broker_err_nomem(broker);
>> +        ret = broker->err_ret;
>> +        bdrv_close(bs);
>> +        goto out;
>> +    }
>> +
>> + out:
>> +    FUNC_FREE(filename);
>> +    return ret;
>> +}
>> +
>> +void qb_close(struct QBroker *broker,
>> +              struct QBlockState *qbs)
>> +{
>> +    BlockDriverState *bs;
>> +
>> +    bs = qbs->bdrvs;
>> +
>> +    if (qbs->filename != NULL) {
>> +        CLEAN_FREE(qbs->filename);
>> +        bdrv_close(bs);
>> +    }
>> +    return;
>> +}
>> +
>> +int64_t qb_read(struct QBroker *broker,
>> +                struct QBlockState *qbs,
>> +                uint8_t *buf,
>> +                uint32_t len,
>> +                uint64_t offset)
>> +{
>> +    int bd_ret;
>> +    BlockDriverState *bs;
>> +    uint8_t temp_buf[BDRV_SECTOR_SIZE], *p;
>> +    uint64_t sector_start;
>> +    int sector_num, byte_offset, cp_len;
>> +    int remains;
>> +
>> +    broker->err_ret = 0;
>> +    bs = qbs->bdrvs;
>> +
>> +    if (len <= 0) {
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                      "Param len is less or equal to zero.");
>> +        return broker->err_ret;
>> +    }
>> +
>> +    p = buf;
>> +    remains = len;
>> +
>> +    sector_start = offset >> BDRV_SECTOR_BITS;
>> +
>> +    byte_offset = offset & (~BDRV_SECTOR_MASK);
>> +    if (byte_offset != 0) {
>> +        /* the start sector is not aligned, need to read/write this sector. */
>> +        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
>> +        if (bd_ret < 0) {
>> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
>> +                           "QEMU internal block error.");
>> +            return broker->err_ret;
>> +        }
>> +        cp_len = BDRV_SECTOR_SIZE - byte_offset;
>> +        memcpy(p, temp_buf + byte_offset, cp_len);
>> +
>> +        remains -= cp_len;
>> +        p += cp_len;
>> +        sector_start++;
>> +    }
>> +
>> +    /* now start position is aligned. */
>> +    if (remains >= BDRV_SECTOR_SIZE) {
>> +        sector_num = len >> BDRV_SECTOR_BITS;
>> +        bd_ret = bdrv_read(bs, sector_start, p, sector_num);
>> +        if (bd_ret < 0) {
>> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
>> +                           "QEMU internal block error.");
>> +            return broker->err_ret;
>> +        }
>> +        remains -= sector_num << BDRV_SECTOR_BITS;
>> +        p += sector_num << BDRV_SECTOR_BITS;
>> +        sector_start += sector_num;
>> +    }
>> +
>> +    if (remains > 0) {
>> +        /* there is some request remains, less than 1 sector */
>> +        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
>> +        if (bd_ret < 0) {
>> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
>> +                           "QEMU internal block error.");
>> +            return broker->err_ret;
>> +        }
>> +        memcpy(p, temp_buf, remains);
>> +        remains -= remains;
>> +    }
>> +
>> +    return len-remains;
>> +}
>> +
>> +int64_t qb_write(struct QBroker *broker,
>> +                 struct QBlockState *qbs,
>> +                 const uint8_t *buf,
>> +                 uint32_t len,
>> +                 uint64_t offset)
>> +{
>> +    int bd_ret;
>> +    BlockDriverState *bs;
>> +    uint8_t temp_buf[BDRV_SECTOR_SIZE];
>> +    const uint8_t *p;
>> +    uint64_t sector_start;
>> +    int sector_num, byte_offset, cp_len;
>> +    int remains;
>> +
>> +    broker->err_ret = 0;
>> +    bs = qbs->bdrvs;
>> +
>> +    if (len <= 0) {
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                      "Param len is less or equal to zero.");
>> +        return broker->err_ret;
>> +    }
>> +
>> +    p = buf;
>> +    remains = len;
>> +
>> +    sector_start = offset >> BDRV_SECTOR_BITS;
>> +
>> +    byte_offset = offset & (~BDRV_SECTOR_MASK);
>> +    if (byte_offset != 0) {
>> +        /* the start sector is not aligned, need to read/write this sector. */
>> +        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
>> +        if (bd_ret < 0) {
>> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
>> +                           "QEMU internal block error.");
>> +            return broker->err_ret;
>> +        }
>> +        cp_len = BDRV_SECTOR_SIZE - byte_offset;
>> +        memcpy(temp_buf + byte_offset, p, cp_len);
>> +        bd_ret = bdrv_write(bs, sector_start, temp_buf, 1);
>> +        if (bd_ret < 0) {
>> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
>> +                           "QEMU internal block error.");
>> +            return broker->err_ret;
>> +        }
>> +        remains -= cp_len;
>> +        p += cp_len;
>> +        sector_start++;
>> +    }
>> +
>> +    /* now start position is aligned. */
>> +    if (remains >= BDRV_SECTOR_SIZE) {
>> +        sector_num = len >> BDRV_SECTOR_BITS;
>> +        bd_ret = bdrv_write(bs, sector_start, p, sector_num);
>> +        if (bd_ret < 0) {
>> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
>> +                           "QEMU internal block error.");
>> +            return broker->err_ret;
>> +        }
>> +        remains -= sector_num << BDRV_SECTOR_BITS;
>> +        p += sector_num << BDRV_SECTOR_BITS;
>> +        sector_start += sector_num;
>> +    }
>> +
>> +    if (remains > 0) {
>> +        /* there is some request remains, less than 1 sector */
>> +        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
>> +        if (bd_ret < 0) {
>> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
>> +                           "QEMU internal block error.");
>> +            return broker->err_ret;
>> +        }
>> +        memcpy(temp_buf, p, remains);
>> +        bd_ret = bdrv_write(bs, sector_start, temp_buf, 1);
>> +        if (bd_ret < 0) {
>> +            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
>> +                           "QEMU internal block error.");
>> +            return broker->err_ret;
>> +        }
>> +        remains -= remains;
>> +    }
>> +
>> +    return len-remains;
>> +}
>> +
>> +int qb_flush(struct QBroker *broker,
>> +             struct QBlockState *qbs)
>> +{
>> +    int bd_ret;
>> +    BlockDriverState *bs;
>> +
>> +    broker->err_ret = 0;
>> +    bs = qbs->bdrvs;
>> +    bd_ret = bdrv_flush(bs);
>> +    if (bd_ret < 0) {
>> +        set_broker_err(broker, QB_ERR_INTERNAL_ERR,
>> +                       "Internal error.");
>> +    }
>> +    return broker->err_ret;
>> +}
>> +
>> +int qb_check_allocation(struct QBroker *broker,
>> +                        struct QBlockState *qbs,
>> +                        uint64_t start,
>> +                        int length,
>> +                        int *pstatus,
>> +                        int *plength)
>> +{
>> +    int ret;
>> +    int sector_start, sector_num, num;
>> +    BlockDriverState *bs;
>> +    unsigned int real_len, ret_len;
>> +
>> +    broker->err_ret = 0;
>> +    bs = qbs->bdrvs;
>> +
>> +    if (qbs->filename == NULL) {
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                       "Image was not opened first.");
>> +        goto out;
>> +    }
>> +
>> +    if (length <= 0) {
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                       "length is not valid.");
>> +        goto out;
>> +    }
>> +
>> +    /* translate to sector */
>> +    sector_start = start >> BDRV_SECTOR_BITS;
>> +    real_len = (start & (~BDRV_SECTOR_MASK)) + length;
>> +    sector_num = real_len >> BDRV_SECTOR_BITS;
>> +    if ((real_len & (~BDRV_SECTOR_MASK)) != 0) {
>> +        sector_num++;
>> +    }
>> +
>> +    ret = bdrv_is_allocated(bs, sector_start, sector_num, &num);
>> +    if ((ret == 0) && (num == 0)) {
>> +        set_broker_err(broker, QB_ERR_BLOCK_OUT_OF_RANGE,
>> +                       "Start position was bigger than the image's size.");
>> +        goto out;
>> +    }
>> +
>> +    *pstatus = ret;
>> +    ret_len = (num << BDRV_SECTOR_BITS) - (start & (~BDRV_SECTOR_MASK));
>> +    if (ret_len > length) {
>> +        ret_len = length;
>> +    }
>> +    *plength = ret_len;
>> +
>> + out:
>> +    return broker->err_ret;
>> +}
>> +
>> +int qb_info_image_static_get(struct QBroker *broker,
>> +                             struct QBlockState *qbs,
>> +                             struct QBlockStaticInfo **info)
>> +{
>> +    int ret = 0;
>> +    BlockDriverState *bs;
>> +    struct QBlockStaticInfo *info_tmp;
>> +    const char *fmt_str;
>> +    size_t total_sectors;
>> +    char backing_filename[1024];
>> +
>> +    if (qbs->filename == NULL) {
>> +        set_broker_err(broker, QB_ERR_INVALID_PARAM,
>> +                       "Block Image was not openned.");
>> +        ret = broker->err_ret;
>> +        goto out;
>> +    }
>> +
>> +    info_tmp = FUNC_CALLOC(1, sizeof(struct QBlockStaticInfo));
>> +    if (info_tmp == NULL) {
>> +        set_broker_err_nomem(broker);
>> +        ret = broker->err_ret;
>> +        goto out;
>> +    }
>> +
>> +    bs = qbs->bdrvs;
>> +
>> +    ret = filename2loc(broker,
>> +                       &(info_tmp->loc),
>> +                       qbs->filename);
>> +    if (ret < 0) {
>> +        goto free;
>> +    }
>> +
>> +    fmt_str = bdrv_get_format_name(bs);
>> +    info_tmp->fmt_type = qb_str2fmttype(fmt_str);
>> +
>> +    bdrv_get_geometry(bs, &total_sectors);
>> +    info_tmp->virt_size = total_sectors * BDRV_SECTOR_SIZE;
>> +
>> +    info_tmp->encrypt = bdrv_is_encrypted(bs);
>> +
>> +    bdrv_get_full_backing_filename(bs, backing_filename,
>> +                                   sizeof(backing_filename));
>> +    if (backing_filename[0] != '\0') {
>> +        ret = filename2loc(broker,
>> +                           &(info_tmp->backing_loc),
>> +                           backing_filename);
>> +        if (ret < 0) {
>> +            goto free;
>> +        }
>> +    }
>> +
>> +    info_tmp->sector_size = BDRV_SECTOR_SIZE;
>> +    *info = info_tmp;
>> +
>> + out:
>> +    return ret;
>> + free:
>> +    qb_info_image_static_delete(broker, &info_tmp);
>> +    return ret;
>> +}
>> +
>> +/* free locations if it has string allocated on heap. */
>> +static void loc_free(struct QBlockProtInfo *loc)
>> +{
>> +    switch (loc->prot_type) {
>> +    case QB_PROT_FILE:
>> +        FUNC_FREE((void *)(loc->prot_op.o_file.filename));
>> +        loc->prot_op.o_file.filename = NULL;
>> +        break;
>> +    default:
>> +        break;
>> +    }
>> +}
>> +
>> +void qb_info_image_static_delete(struct QBroker *broker,
>> +                                 struct QBlockStaticInfo **info)
>> +{
>> +    loc_free(&(*info)->loc);
>> +    loc_free(&(*info)->backing_loc);
>> +
>> +    CLEAN_FREE(*info);
>> +}
>> diff --git a/libqblock/libqblock.h b/libqblock/libqblock.h
>> new file mode 100644
>> index 0000000..97e6c7c
>> --- /dev/null
>> +++ b/libqblock/libqblock.h
>> @@ -0,0 +1,292 @@
>> +/*
>> + * QEMU block layer library
>> + *
>> + * 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.
>> + *
>> + */
>> +
>> +#ifndef LIBQBLOCK_H
>> +#define LIBQBLOCK_H
>> +
>> +#include "libqblock-types.h"
>> +#include "libqblock-error.h"
>> +
>> +/**
>> + * qb_broker_new: allocate a new broker
>> + *
>> + * Broker is used to pass operation to libqblock, and get feed back from it.
>> + *
>> + * Returns 0 on success, libqblock negative error value on fail.
>> + *
>> + * @broker: used to receive the created struct.
>> + */
>> +DLL_PUBLIC
>> +int qb_broker_new(struct QBroker **broker);
>> +
>> +/**
>> + * qb_broker_delete: delete broker
>> + *
>> + * Broker will be freed and set to NULL.
>> + *
>> + * @broker: operation broker to be deleted.
>> + */
>> +DLL_PUBLIC
>> +void qb_broker_delete(struct QBroker **broker);
>> +
>> +/**
>> + * qb_state_new: allocate a new QBlockState struct
>> + *
>> + * Subsequent qblock actions will use this struct
>> + *
>> + * Returns 0 if succeed, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: used to receive the created struct.
>> + */
>> +DLL_PUBLIC
>> +int qb_state_new(struct QBroker *broker,
>> +                 struct QBlockState **qbs);
>> +
>> +/**
>> + * qb_state_delete: free a QBlockState struct
>> + *
>> + * if image was opened, qb_close must be called before delete.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: pointer to the struct's pointer.
>> + */
>> +DLL_PUBLIC
>> +void qb_state_delete(struct QBroker *broker,
>> +                     struct QBlockState **qbs);
>> +
>> +/**
>> + * qb_prot_info_new: create a new struct QBlockProtInfo.
>> + *
>> + * return 0 on success, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @op: pointer to receive the new created one.
>> + */
>> +DLL_PUBLIC
>> +int qb_prot_info_new(struct QBroker *broker,
>> +                     struct QBlockProtInfo **op);
>> +
>> +/**
>> + * qb_prot_info_delete: free a struct QBlockProtInfo.
>> + *
>> + * @broker: operation broker.
>> + * @op: pointer to the object, *op would be set to NULL.
>> + */
>> +DLL_PUBLIC
>> +void qb_prot_info_delete(struct QBroker *broker,
>> +                         struct QBlockProtInfo **op);
>> +
>> +/**
>> + * qb_fmt_info_new: create a new QBlockFmtInfo structure.
>> + *
>> + * return 0 on success, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @op: pointer that will receive created struct.
>> + */
>> +DLL_PUBLIC
>> +int qb_fmt_info_new(struct QBroker *broker,
>> +                    struct QBlockFmtInfo **op);
>> +
>> +/**
>> + * qb_fmt_info_delete: free QBlockFmtInfo structure.
>> + *
>> + * @broker: operation broker.
>> + * @op: pointer to the struct, *op would be set to NULL.
>> + */
>> +DLL_PUBLIC
>> +void qb_fmt_info_delete(struct QBroker *broker,
>> +                        struct QBlockFmtInfo **op);
>> +
>> +
>> +/**
>> + * qb_open: open a block object.
>> + *
>> + * return 0 on success, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: pointer to struct QBlockState.
>> + * @loc: location options for open, how to find the image.
>> + * @fmt: format options, how to extract the data, only valid member now is
>> + *    fmt->fmt_type, set to NULL if you want to auto discovery the format.
>> + * @flag: behavior control flags, it is LIBQBLOCK_O_XXX's combination.
>> + *
>> + * Note: For raw image, there is a risk that it's content is changed to some
>> + *  magic value resulting a wrong probing done by libqblock, so don't do
>> + * probing on raw images.
>> + */
>> +DLL_PUBLIC
>> +int qb_open(struct QBroker *broker,
>> +            struct QBlockState *qbs,
>> +            struct QBlockProtInfo *loc,
>> +            struct QBlockFmtInfo *fmt,
>> +            int flag);
>> +
>> +/**
>> + * qb_close: close a block object.
>> + *
>> + * qb_flush is automatically done inside.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: pointer to struct QBlockState.
>> + */
>> +DLL_PUBLIC
>> +void qb_close(struct QBroker *broker,
>> +              struct QBlockState *qbs);
>> +
>> +/**
>> + * qb_create: create a block image or object.
>> + *
>> + * Note: Create operation would not open the image automatically.
>> + *
>> + * return 0 on success, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: pointer to struct QBlockState.
>> + * @loc: location options for open, how to find the image.
>> + * @fmt: format options, how to extract the data.
>> + * @flag: behavior control flags, LIBQBLOCK_O_XXX's combination.
>> + */
>> +DLL_PUBLIC
>> +int qb_create(struct QBroker *broker,
>> +              struct QBlockState *qbs,
>> +              struct QBlockProtInfo *loc,
>> +              struct QBlockFmtInfo *fmt,
>> +              int flag);
>> +
>> +
>> +/* sync access */
>> +/**
>> + * qb_read: block sync read.
>> + *
>> + * return number of bytes read, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: pointer to struct QBlockState.
>> + * @buf: buffer that receive the content.
>> + * @len: length to read.
>> + * @offset: offset in the block data.
>> + */
>> +DLL_PUBLIC
>> +int64_t qb_read(struct QBroker *broker,
>> +                struct QBlockState *qbs,
>> +                uint8_t *buf,
>> +                uint32_t len,
>> +                uint64_t offset);
>> +
>> +/**
>> + * qb_write: block sync write.
>> + *
>> + * return number of bytes written, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: pointer to struct QBlockState.
>> + * @buf: buffer that receive the content.
>> + * @len: length to write.
>> + * @offset: offset in the block data.
>> + */
>> +DLL_PUBLIC
>> +int64_t qb_write(struct QBroker *broker,
>> +                 struct QBlockState *qbs,
>> +                 const uint8_t *buf,
>> +                 uint32_t len,
>> +                 uint64_t offset);
>> +
>> +/**
>> + * qb_flush: block sync flush.
>> + *
>> + * return 0 on success, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: pointer to struct QBlockState.
>> + */
>> +DLL_PUBLIC
>> +int qb_flush(struct QBroker *broker,
>> +             struct QBlockState *qbs);
>> +
>> +
>> +/* advance image APIs */
>> +/**
>> + * qb_check_allocation: check if [start, start+lenth-1] was allocated on the
>> + *  image.
>> + *
>> + * return 0 on success, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: pointer to struct QBlockState.
>> + * @start: start position, unit is byte.
>> + * @length: length to check, unit is byte.
>> + * @pstatus: pointer to receive the status, 1 means allocated,
>> + *  0 means unallocated.
>> + * @plength: pointer to receive the length that all have the same status as
>> + *  *pstatus.
>> + *
>> + * Note: after return, start+*plength may have the same status as
>> + *  start+*plength-1.
>> + */
>> +DLL_PUBLIC
>> +int qb_check_allocation(struct QBroker *broker,
>> +                        struct QBlockState *qbs,
>> +                        uint64_t start,
>> +                        int length,
>> +                        int *pstatus,
>> +                        int *plength);
>> +
>> +/* image information */
>> +/**
>> + * qb_get_image_info: get image info.
>> + *
>> + * return 0 on success, libqblock negative error value on fail.
>> + *
>> + * @broker: operation broker.
>> + * @qbs: pointer to struct QBlockState.
>> + * @info: pointer that would receive the information.
>> + */
>> +DLL_PUBLIC
>> +int qb_info_image_static_get(struct QBroker *broker,
>> +                             struct QBlockState *qbs,
>> +                             struct QBlockStaticInfo **info);
>> +
>> +/**
>> + * qb_delete_image_info: free image info.
>> + *
>> + * @broker: operation broker.
>> + * @info: pointer to the information struct.
>> + */
>> +DLL_PUBLIC
>> +void qb_info_image_static_delete(struct QBroker *broker,
>> +                                 struct QBlockStaticInfo **info);
>> +
>> +/* helper functions */
>> +/**
>> + * qb_str2fmttype: translate format string to libqblock format enum type.
>> + *
>> + * return the type, or QB_FMT_NONE if string matches none of supported types.
>> + *
>> + * @fmt: the format string.
>> + */
>> +DLL_PUBLIC
>> +enum QBlockFmtType qb_str2fmttype(const char *fmt_str);
>> +
>> +/**
>> + * qb_fmttype2str: libqblock format enum type to a string.
>> + *
>> + * return a pointer to the string, or NULL if type is not supported, and
>> + *  returned pointer do NOT need to free.
>> + *
>> + * @fmt: the format enum type.
>> + */
>> +DLL_PUBLIC
>> +const char *qb_fmttype2str(enum QBlockFmtType fmt_type);
>> +#endif
>> --
>> 1.7.1
>>
>>
>
>
Kevin Wolf Sept. 12, 2012, 8:19 a.m. UTC | #5
Am 11.09.2012 22:28, schrieb Blue Swirl:
> On Mon, Sep 10, 2012 at 8:26 AM, Wenchao Xia <xiawenc@linux.vnet.ibm.com> wrote:
>>   This patch contains the major APIs in the library.
>> Important APIs:
>>   1 QBroker. These structure was used to retrieve errors, every thread must
>> create one first, later maybe thread related staff could be added into it.
>>   2 QBlockState. It stands for an block image object.
>>   3 QBlockStaticInfo. It contains static information such as location, backing
>> file, size.
>>   4 ABI was kept with reserved members.
>>   5 Sync I/O. It is similar to C file open, read, write and close operations.
>>
>> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
>> ---
>>  libqblock/libqblock.c | 1077 +++++++++++++++++++++++++++++++++++++++++++++++++
>>  libqblock/libqblock.h |  292 +++++++++++++
>>  2 files changed, 1369 insertions(+), 0 deletions(-)
>>  create mode 100644 libqblock/libqblock.c
>>  create mode 100644 libqblock/libqblock.h
>>
>> diff --git a/libqblock/libqblock.c b/libqblock/libqblock.c
>> new file mode 100644
>> index 0000000..133ac0f
>> --- /dev/null
>> +++ b/libqblock/libqblock.c
>> @@ -0,0 +1,1077 @@
>> +/*
>> + * QEMU block layer library
>> + *
>> + * 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.
>> + *
>> + */
>> +
>> +#include <unistd.h>
>> +#include <stdarg.h>
>> +
>> +#include "libqblock.h"
>> +#include "libqblock-internal.h"
>> +
>> +#include "qemu-aio.h"
>> +
>> +struct LibqblockGlobalData {
>> +    int init_flag;
>> +};
>> +
>> +struct LibqblockGlobalData g_libqblock_data;
>> +
>> +__attribute__((constructor))
>> +static void libqblock_init(void)
>> +{
>> +    if (g_libqblock_data.init_flag == 0) {
>> +        bdrv_init();
>> +        qemu_init_main_loop();
>> +    }
>> +    g_libqblock_data.init_flag = 1;
>> +}
>> +
>> +const char *qb_fmttype2str(enum QBlockFmtType fmt_type)
>> +{
>> +    const char *ret = NULL;
>> +    switch (fmt_type) {
>> +    case QB_FMT_COW:
>> +        ret = "cow";
>> +        break;
>> +    case QB_FMT_QED:
>> +        ret = "qed";
>> +        break;
>> +    case QB_FMT_QCOW:
>> +        ret = "qcow";
>> +        break;
>> +    case QB_FMT_QCOW2:
>> +        ret = "qcow2";
>> +        break;
>> +    case QB_FMT_RAW:
>> +        ret = "raw";
>> +        break;
>> +    case QB_FMT_RBD:
>> +        ret = "rbd";
>> +        break;
>> +    case QB_FMT_SHEEPDOG:
>> +        ret = "sheepdog";
>> +        break;
>> +    case QB_FMT_VDI:
>> +        ret = "vdi";
>> +        break;
>> +    case QB_FMT_VMDK:
>> +        ret = "vmdk";
>> +        break;
>> +    case QB_FMT_VPC:
>> +        ret = "vpc";
>> +        break;
>> +    default:
>> +        break;
>> +    }
>> +    return ret;
>> +}
>> +
>> +enum QBlockFmtType qb_str2fmttype(const char *fmt_str)
>> +{
>> +    enum QBlockFmtType ret = QB_FMT_NONE;
>> +    if (0 == strcmp(fmt_str, "cow")) {
> 
> This order is not common in QEMU.

How about just changing the whole thing to a table that maps
QBlockFmtType to strings, and then both conversion functions could just
search that table?

> 
>> +        ret = QB_FMT_COW;
>> +    } else if (0 == strcmp(fmt_str, "qed")) {
>> +        ret = QB_FMT_QED;
>> +    } else if (0 == strcmp(fmt_str, "qcow")) {
>> +        ret = QB_FMT_QCOW;
>> +    } else if (0 == strcmp(fmt_str, "qcow2")) {
>> +        ret = QB_FMT_QCOW2;
>> +    } else if (0 == strcmp(fmt_str, "raw")) {
>> +        ret = QB_FMT_RAW;
>> +    } else if (0 == strcmp(fmt_str, "rbd")) {
>> +        ret = QB_FMT_RBD;
>> +    } else if (0 == strcmp(fmt_str, "sheepdog")) {
>> +        ret = QB_FMT_SHEEPDOG;
>> +    } else if (0 == strcmp(fmt_str, "vdi")) {
>> +        ret = QB_FMT_VDI;
>> +    } else if (0 == strcmp(fmt_str, "vmdk")) {
>> +        ret = QB_FMT_VMDK;
>> +    } else if (0 == strcmp(fmt_str, "vpc")) {
>> +        ret = QB_FMT_VPC;
>> +    }
>> +    return ret;
>> +}

Kevin
Wayne Xia Sept. 12, 2012, 9:21 a.m. UTC | #6
于 2012-9-12 16:19, Kevin Wolf 写道:
> Am 11.09.2012 22:28, schrieb Blue Swirl:
>> On Mon, Sep 10, 2012 at 8:26 AM, Wenchao Xia <xiawenc@linux.vnet.ibm.com> wrote:
>>>    This patch contains the major APIs in the library.
>>> Important APIs:
>>>    1 QBroker. These structure was used to retrieve errors, every thread must
>>> create one first, later maybe thread related staff could be added into it.
>>>    2 QBlockState. It stands for an block image object.
>>>    3 QBlockStaticInfo. It contains static information such as location, backing
>>> file, size.
>>>    4 ABI was kept with reserved members.
>>>    5 Sync I/O. It is similar to C file open, read, write and close operations.
>>>
>>> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
>>> ---
>>>   libqblock/libqblock.c | 1077 +++++++++++++++++++++++++++++++++++++++++++++++++
>>>   libqblock/libqblock.h |  292 +++++++++++++
>>>   2 files changed, 1369 insertions(+), 0 deletions(-)
>>>   create mode 100644 libqblock/libqblock.c
>>>   create mode 100644 libqblock/libqblock.h
>>>
>>> diff --git a/libqblock/libqblock.c b/libqblock/libqblock.c
>>> new file mode 100644
>>> index 0000000..133ac0f
>>> --- /dev/null
>>> +++ b/libqblock/libqblock.c
>>> @@ -0,0 +1,1077 @@
>>> +/*
>>> + * QEMU block layer library
>>> + *
>>> + * 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.
>>> + *
>>> + */
>>> +
>>> +#include <unistd.h>
>>> +#include <stdarg.h>
>>> +
>>> +#include "libqblock.h"
>>> +#include "libqblock-internal.h"
>>> +
>>> +#include "qemu-aio.h"
>>> +
>>> +struct LibqblockGlobalData {
>>> +    int init_flag;
>>> +};
>>> +
>>> +struct LibqblockGlobalData g_libqblock_data;
>>> +
>>> +__attribute__((constructor))
>>> +static void libqblock_init(void)
>>> +{
>>> +    if (g_libqblock_data.init_flag == 0) {
>>> +        bdrv_init();
>>> +        qemu_init_main_loop();
>>> +    }
>>> +    g_libqblock_data.init_flag = 1;
>>> +}
>>> +
>>> +const char *qb_fmttype2str(enum QBlockFmtType fmt_type)
>>> +{
>>> +    const char *ret = NULL;
>>> +    switch (fmt_type) {
>>> +    case QB_FMT_COW:
>>> +        ret = "cow";
>>> +        break;
>>> +    case QB_FMT_QED:
>>> +        ret = "qed";
>>> +        break;
>>> +    case QB_FMT_QCOW:
>>> +        ret = "qcow";
>>> +        break;
>>> +    case QB_FMT_QCOW2:
>>> +        ret = "qcow2";
>>> +        break;
>>> +    case QB_FMT_RAW:
>>> +        ret = "raw";
>>> +        break;
>>> +    case QB_FMT_RBD:
>>> +        ret = "rbd";
>>> +        break;
>>> +    case QB_FMT_SHEEPDOG:
>>> +        ret = "sheepdog";
>>> +        break;
>>> +    case QB_FMT_VDI:
>>> +        ret = "vdi";
>>> +        break;
>>> +    case QB_FMT_VMDK:
>>> +        ret = "vmdk";
>>> +        break;
>>> +    case QB_FMT_VPC:
>>> +        ret = "vpc";
>>> +        break;
>>> +    default:
>>> +        break;
>>> +    }
>>> +    return ret;
>>> +}
>>> +
>>> +enum QBlockFmtType qb_str2fmttype(const char *fmt_str)
>>> +{
>>> +    enum QBlockFmtType ret = QB_FMT_NONE;
>>> +    if (0 == strcmp(fmt_str, "cow")) {
>>
>> This order is not common in QEMU.
>
> How about just changing the whole thing to a table that maps
> QBlockFmtType to strings, and then both conversion functions could just
> search that table?
>
   Good idea, will go this way.

>>
>>> +        ret = QB_FMT_COW;
>>> +    } else if (0 == strcmp(fmt_str, "qed")) {
>>> +        ret = QB_FMT_QED;
>>> +    } else if (0 == strcmp(fmt_str, "qcow")) {
>>> +        ret = QB_FMT_QCOW;
>>> +    } else if (0 == strcmp(fmt_str, "qcow2")) {
>>> +        ret = QB_FMT_QCOW2;
>>> +    } else if (0 == strcmp(fmt_str, "raw")) {
>>> +        ret = QB_FMT_RAW;
>>> +    } else if (0 == strcmp(fmt_str, "rbd")) {
>>> +        ret = QB_FMT_RBD;
>>> +    } else if (0 == strcmp(fmt_str, "sheepdog")) {
>>> +        ret = QB_FMT_SHEEPDOG;
>>> +    } else if (0 == strcmp(fmt_str, "vdi")) {
>>> +        ret = QB_FMT_VDI;
>>> +    } else if (0 == strcmp(fmt_str, "vmdk")) {
>>> +        ret = QB_FMT_VMDK;
>>> +    } else if (0 == strcmp(fmt_str, "vpc")) {
>>> +        ret = QB_FMT_VPC;
>>> +    }
>>> +    return ret;
>>> +}
>
> Kevin
>
Wayne Xia Sept. 14, 2012, 2:03 a.m. UTC | #7
Hi,
  about the OOM issue, I plan to drop the OOM request for now in
implemention, and at next step use rpc to wrap these APIs, then
user can select to link directly against the library or the wrapped
API, what do you think about it?
> 于 2012-9-11 5:07, Eric Blake 写道:
>> On 09/10/2012 02:26 AM, Wenchao Xia wrote:
>>>    This patch contains the major APIs in the library.
>>> Important APIs:
>>>    1 QBroker. These structure was used to retrieve errors, every 
>>> thread must
>>> create one first, later maybe thread related staff could be added 
>>> into it.
>>>    2 QBlockState. It stands for an block image object.
>>>    3 QBlockStaticInfo. It contains static information such as 
>>> location, backing
>>> file, size.
>>>    4 ABI was kept with reserved members.
>>>    5 Sync I/O. It is similar to C file open, read, write and close 
>>> operations.
>>>
>>> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
>>> ---
>>>   libqblock/libqblock.c | 1077 
>>> +++++++++++++++++++++++++++++++++++++++++++++++++
>>>   libqblock/libqblock.h |  292 +++++++++++++
>>
>> Two new files, but no build machinery to build them to see if they have
>> blatant errors.  Yes, it is bisectable, but no, the bisection is not
>> useful.  I'd rather see the Makefile patches with stub files at the
>> beginning, then flesh out the stubs, where each patch builds along the 
>> way.
>>
>> In particular,
>>
>    OK, I understand the importance to make each patch workable to
> maintainer, will adjust the patches to make each one works.
> 
>>> +++ b/libqblock/libqblock.c
>>
>>> +#include "libqblock.h"
>>> +#include "libqblock-internal.h"
>>
>> There is no libqblock-internal.h with just this patch applied, making it
>> impossible to validate this patch in order (the fact that 'make' isn't
>> flagging this incomplete patch is because you aren't building
>> libqblock-o yet).  I'm planning on overlooking the .c file and focusing
>> on the user interface (I'd rather leave the detailed review to those
>> more familiar with qemu, while I'm personally worried about how libvirt
>> would ever use libqblock if you ever solved the glib-aborts-on-OOM issue
>> to make the library even worth using).
>>
>    About the OOM issue, I think there are potential 3 ways to solve it:
> 1 modify qemu block layer code, in this way providing libqblock at first
> will help, for that it will encapsulate and isolate all codes needed
> for block layer, and we got test case on the top to validate OOM
> behavior.
> 2 Using glib and forgot OOM now. Then at higher layer, they have two
> choice: if they want no exiting on OOM, wrap the API with xmlrpc or
> something like; otherwise directly use the API.
> 3 switch the implemention of libqblock, do not link qemu block code
> directly, fork and execute qemu-img, qemu-nbd. This require a
> re-implement about AIO in libqblock, with GSource AIO framework I am
> not sure if it would exit on OOM, but I guess better to not involve any
> glib in this case. Additional challenge would be, any more
> functionalities adding require patch for qemu-img, qemu-io, qemu-nbd
> first, such as image information retrieving, allocation detection,
> and libqblock need to parse string output carefully, better to get
> all output in json format. Personally I am worried to handle many
> exception in string parsing.
> 
>    To me, the second way seems most reasonable, it allows qemu block
> remain tightly bind to glib. The first way also make sense, but
> need to loose the tight between qemu and glib. what do you think?
> 
>>> +++ b/libqblock/libqblock.h
>>> @@ -0,0 +1,292 @@
>>> +/*
>>> + * QEMU block layer library
>>> + *
>>> + * 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.
>>> + *
>>> + */
>>> +
>>> +#ifndef LIBQBLOCK_H
>>> +#define LIBQBLOCK_H
>>> +
>>> +#include "libqblock-types.h"
>>> +#include "libqblock-error.h"
>>
>> Even worse - you've introduced a public header that I'm supposed to be
>> able to use, but I can't use it because libqblock-types.h and
>> libqblock-error.h don't exist.  I'd much rather review a patch series
>> built incrementally from ground up, with each piece working, rather than
>> reviewing an API that depends on constructs that aren't defined until
>> later patches.
>>
>>> +/**
>>> + * qb_broker_new: allocate a new broker
>>> + *
>>> + * Broker is used to pass operation to libqblock, and get feed back 
>>> from it.
>>
>> s/feed back/feedback/
>>
>>> +/**
>>> + * qb_state_delete: free a QBlockState struct
>>> + *
>>> + * if image was opened, qb_close must be called before delete.
>>
>> And if it wasn't closed, what happens?  Should this function return int,
>> instead of void, to error out in the case that it is called out of order?
>>
>>> +/**
>>> + * qb_prot_info_new: create a new struct QBlockProtInfo.
>>
>> Inconsistent on whether your descriptions end in '.' or not.
>>
>>> +/* sync access */
>>> +/**
>>> + * qb_read: block sync read.
>>> + *
>>> + * return number of bytes read, libqblock negative error value on fail.
>>> + *
>>> + * @broker: operation broker.
>>> + * @qbs: pointer to struct QBlockState.
>>> + * @buf: buffer that receive the content.
>>> + * @len: length to read.
>>> + * @offset: offset in the block data.
>>> + */
>>> +DLL_PUBLIC
>>> +int64_t qb_read(struct QBroker *broker,
>>> +                struct QBlockState *qbs,
>>> +                uint8_t *buf,
>>> +                uint32_t len,
>>> +                uint64_t offset);
>>
>> Seems odd to have 32 bit limit on input, when output handles 64 bit.
>>
>>> +
>>> +/**
>>> + * qb_write: block sync write.
>>> + *
>>> + * return number of bytes written, libqblock negative error value on 
>>> fail.
>>> + *
>>> + * @broker: operation broker.
>>> + * @qbs: pointer to struct QBlockState.
>>> + * @buf: buffer that receive the content.
>>> + * @len: length to write.
>>> + * @offset: offset in the block data.
>>> + */
>>> +DLL_PUBLIC
>>> +int64_t qb_write(struct QBroker *broker,
>>> +                 struct QBlockState *qbs,
>>> +                 const uint8_t *buf,
>>> +                 uint32_t len,
>>> +                 uint64_t offset);
>>
>> and again.
>>
>>> +/* advance image APIs */
>>> +/**
>>> + * qb_check_allocation: check if [start, start+lenth-1] was 
>>> allocated on the
>>> + *  image.
>>> + *
>>> + * return 0 on success, libqblock negative error value on fail.
>>> + *
>>> + * @broker: operation broker.
>>> + * @qbs: pointer to struct QBlockState.
>>> + * @start: start position, unit is byte.
>>> + * @length: length to check, unit is byte.
>>
>> Needs to be at least int32_t to match your read/write; or better yet
>> int64_t to allow probes of more than 2G at a time.
>>
>>> + * @pstatus: pointer to receive the status, 1 means allocated,
>>> + *  0 means unallocated.
>>> + * @plength: pointer to receive the length that all have the same 
>>> status as
>>> + *  *pstatus.
>>> + *
>>> + * Note: after return, start+*plength may have the same status as
>>> + *  start+*plength-1.
>>> + */
>>> +DLL_PUBLIC
>>> +int qb_check_allocation(struct QBroker *broker,
>>> +                        struct QBlockState *qbs,
>>> +                        uint64_t start,
>>> +                        int length,
>>> +                        int *pstatus,
>>> +                        int *plength);
>>
>> If you change the type of length, then plength needs to match.
>>
>>> +/**
>>> + * qb_fmttype2str: libqblock format enum type to a string.
>>> + *
>>> + * return a pointer to the string, or NULL if type is not supported, 
>>> and
>>> + *  returned pointer do NOT need to free.
>>
>> grammar; I suggest:
>> returned pointer must not be freed
>>
> 
>
Blue Swirl Sept. 14, 2012, 7:08 p.m. UTC | #8
On Wed, Sep 12, 2012 at 8:19 AM, Kevin Wolf <kwolf@redhat.com> wrote:
> Am 11.09.2012 22:28, schrieb Blue Swirl:
>> On Mon, Sep 10, 2012 at 8:26 AM, Wenchao Xia <xiawenc@linux.vnet.ibm.com> wrote:
>>>   This patch contains the major APIs in the library.
>>> Important APIs:
>>>   1 QBroker. These structure was used to retrieve errors, every thread must
>>> create one first, later maybe thread related staff could be added into it.
>>>   2 QBlockState. It stands for an block image object.
>>>   3 QBlockStaticInfo. It contains static information such as location, backing
>>> file, size.
>>>   4 ABI was kept with reserved members.
>>>   5 Sync I/O. It is similar to C file open, read, write and close operations.
>>>
>>> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
>>> ---
>>>  libqblock/libqblock.c | 1077 +++++++++++++++++++++++++++++++++++++++++++++++++
>>>  libqblock/libqblock.h |  292 +++++++++++++
>>>  2 files changed, 1369 insertions(+), 0 deletions(-)
>>>  create mode 100644 libqblock/libqblock.c
>>>  create mode 100644 libqblock/libqblock.h
>>>
>>> diff --git a/libqblock/libqblock.c b/libqblock/libqblock.c
>>> new file mode 100644
>>> index 0000000..133ac0f
>>> --- /dev/null
>>> +++ b/libqblock/libqblock.c
>>> @@ -0,0 +1,1077 @@
>>> +/*
>>> + * QEMU block layer library
>>> + *
>>> + * 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.
>>> + *
>>> + */
>>> +
>>> +#include <unistd.h>
>>> +#include <stdarg.h>
>>> +
>>> +#include "libqblock.h"
>>> +#include "libqblock-internal.h"
>>> +
>>> +#include "qemu-aio.h"
>>> +
>>> +struct LibqblockGlobalData {
>>> +    int init_flag;
>>> +};
>>> +
>>> +struct LibqblockGlobalData g_libqblock_data;
>>> +
>>> +__attribute__((constructor))
>>> +static void libqblock_init(void)
>>> +{
>>> +    if (g_libqblock_data.init_flag == 0) {
>>> +        bdrv_init();
>>> +        qemu_init_main_loop();
>>> +    }
>>> +    g_libqblock_data.init_flag = 1;
>>> +}
>>> +
>>> +const char *qb_fmttype2str(enum QBlockFmtType fmt_type)
>>> +{
>>> +    const char *ret = NULL;
>>> +    switch (fmt_type) {
>>> +    case QB_FMT_COW:
>>> +        ret = "cow";
>>> +        break;
>>> +    case QB_FMT_QED:
>>> +        ret = "qed";
>>> +        break;
>>> +    case QB_FMT_QCOW:
>>> +        ret = "qcow";
>>> +        break;
>>> +    case QB_FMT_QCOW2:
>>> +        ret = "qcow2";
>>> +        break;
>>> +    case QB_FMT_RAW:
>>> +        ret = "raw";
>>> +        break;
>>> +    case QB_FMT_RBD:
>>> +        ret = "rbd";
>>> +        break;
>>> +    case QB_FMT_SHEEPDOG:
>>> +        ret = "sheepdog";
>>> +        break;
>>> +    case QB_FMT_VDI:
>>> +        ret = "vdi";
>>> +        break;
>>> +    case QB_FMT_VMDK:
>>> +        ret = "vmdk";
>>> +        break;
>>> +    case QB_FMT_VPC:
>>> +        ret = "vpc";
>>> +        break;
>>> +    default:
>>> +        break;
>>> +    }
>>> +    return ret;
>>> +}
>>> +
>>> +enum QBlockFmtType qb_str2fmttype(const char *fmt_str)
>>> +{
>>> +    enum QBlockFmtType ret = QB_FMT_NONE;
>>> +    if (0 == strcmp(fmt_str, "cow")) {
>>
>> This order is not common in QEMU.
>
> How about just changing the whole thing to a table that maps
> QBlockFmtType to strings, and then both conversion functions could just
> search that table?

Yes, better.

>
>>
>>> +        ret = QB_FMT_COW;
>>> +    } else if (0 == strcmp(fmt_str, "qed")) {
>>> +        ret = QB_FMT_QED;
>>> +    } else if (0 == strcmp(fmt_str, "qcow")) {
>>> +        ret = QB_FMT_QCOW;
>>> +    } else if (0 == strcmp(fmt_str, "qcow2")) {
>>> +        ret = QB_FMT_QCOW2;
>>> +    } else if (0 == strcmp(fmt_str, "raw")) {
>>> +        ret = QB_FMT_RAW;
>>> +    } else if (0 == strcmp(fmt_str, "rbd")) {
>>> +        ret = QB_FMT_RBD;
>>> +    } else if (0 == strcmp(fmt_str, "sheepdog")) {
>>> +        ret = QB_FMT_SHEEPDOG;
>>> +    } else if (0 == strcmp(fmt_str, "vdi")) {
>>> +        ret = QB_FMT_VDI;
>>> +    } else if (0 == strcmp(fmt_str, "vmdk")) {
>>> +        ret = QB_FMT_VMDK;
>>> +    } else if (0 == strcmp(fmt_str, "vpc")) {
>>> +        ret = QB_FMT_VPC;
>>> +    }
>>> +    return ret;
>>> +}
>
> Kevin
diff mbox

Patch

diff --git a/libqblock/libqblock.c b/libqblock/libqblock.c
new file mode 100644
index 0000000..133ac0f
--- /dev/null
+++ b/libqblock/libqblock.c
@@ -0,0 +1,1077 @@ 
+/*
+ * QEMU block layer library
+ *
+ * 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.
+ *
+ */
+
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "libqblock.h"
+#include "libqblock-internal.h"
+
+#include "qemu-aio.h"
+
+struct LibqblockGlobalData {
+    int init_flag;
+};
+
+struct LibqblockGlobalData g_libqblock_data;
+
+__attribute__((constructor))
+static void libqblock_init(void)
+{
+    if (g_libqblock_data.init_flag == 0) {
+        bdrv_init();
+        qemu_init_main_loop();
+    }
+    g_libqblock_data.init_flag = 1;
+}
+
+const char *qb_fmttype2str(enum QBlockFmtType fmt_type)
+{
+    const char *ret = NULL;
+    switch (fmt_type) {
+    case QB_FMT_COW:
+        ret = "cow";
+        break;
+    case QB_FMT_QED:
+        ret = "qed";
+        break;
+    case QB_FMT_QCOW:
+        ret = "qcow";
+        break;
+    case QB_FMT_QCOW2:
+        ret = "qcow2";
+        break;
+    case QB_FMT_RAW:
+        ret = "raw";
+        break;
+    case QB_FMT_RBD:
+        ret = "rbd";
+        break;
+    case QB_FMT_SHEEPDOG:
+        ret = "sheepdog";
+        break;
+    case QB_FMT_VDI:
+        ret = "vdi";
+        break;
+    case QB_FMT_VMDK:
+        ret = "vmdk";
+        break;
+    case QB_FMT_VPC:
+        ret = "vpc";
+        break;
+    default:
+        break;
+    }
+    return ret;
+}
+
+enum QBlockFmtType qb_str2fmttype(const char *fmt_str)
+{
+    enum QBlockFmtType ret = QB_FMT_NONE;
+    if (0 == strcmp(fmt_str, "cow")) {
+        ret = QB_FMT_COW;
+    } else if (0 == strcmp(fmt_str, "qed")) {
+        ret = QB_FMT_QED;
+    } else if (0 == strcmp(fmt_str, "qcow")) {
+        ret = QB_FMT_QCOW;
+    } else if (0 == strcmp(fmt_str, "qcow2")) {
+        ret = QB_FMT_QCOW2;
+    } else if (0 == strcmp(fmt_str, "raw")) {
+        ret = QB_FMT_RAW;
+    } else if (0 == strcmp(fmt_str, "rbd")) {
+        ret = QB_FMT_RBD;
+    } else if (0 == strcmp(fmt_str, "sheepdog")) {
+        ret = QB_FMT_SHEEPDOG;
+    } else if (0 == strcmp(fmt_str, "vdi")) {
+        ret = QB_FMT_VDI;
+    } else if (0 == strcmp(fmt_str, "vmdk")) {
+        ret = QB_FMT_VMDK;
+    } else if (0 == strcmp(fmt_str, "vpc")) {
+        ret = QB_FMT_VPC;
+    }
+    return ret;
+}
+
+static void set_broker_err(struct QBroker *broker, int err_ret,
+                           const char *fmt, ...)
+{
+    va_list ap;
+
+    broker->err_ret = err_ret;
+    if (err_ret == QB_ERR_INTERNAL_ERR) {
+        broker->err_no = -errno;
+    } else {
+        broker->err_no = 0;
+    }
+
+    va_start(ap, fmt);
+    vsnprintf(broker->err_msg, sizeof(broker->err_msg), fmt, ap);
+    va_end(ap);
+}
+
+static void set_broker_err_nomem(struct QBroker *broker)
+{
+    set_broker_err(broker, QB_ERR_MEM_ERR, "No Memory.");
+}
+
+int qb_broker_new(struct QBroker **broker)
+{
+    *broker = FUNC_CALLOC(1, sizeof(struct QBroker));
+    if (*broker == NULL) {
+        return QB_ERR_MEM_ERR;
+    }
+    return 0;
+}
+
+void qb_broker_delete(struct QBroker **broker)
+{
+    CLEAN_FREE(*broker);
+    return;
+}
+
+int qb_state_new(struct QBroker *broker,
+                 struct QBlockState **qbs)
+{
+    *qbs = FUNC_CALLOC(1, sizeof(struct QBlockState));
+    if (*qbs == NULL) {
+        set_broker_err_nomem(broker);
+        return broker->err_ret;
+    }
+    (*qbs)->bdrvs = bdrv_new("hda");
+    if ((*qbs)->bdrvs == NULL) {
+        CLEAN_FREE(*qbs);
+        set_broker_err(broker, QB_ERR_INTERNAL_ERR,
+                       "failed to create the driver.");
+        return broker->err_ret;
+    }
+    return 0;
+}
+
+void qb_state_delete(struct QBroker *broker,
+                     struct QBlockState **qbs)
+{
+    CLEAN_FREE((*qbs)->filename);
+    if ((*qbs)->bdrvs != NULL) {
+        bdrv_delete((*qbs)->bdrvs);
+        (*qbs)->bdrvs = NULL;
+    }
+    CLEAN_FREE(*qbs);
+    return;
+}
+
+int qb_prot_info_new(struct QBroker *broker,
+                     struct QBlockProtInfo **op)
+{
+    *op = FUNC_CALLOC(1, sizeof(struct QBlockProtInfo));
+    if (*op == NULL) {
+        set_broker_err_nomem(broker);
+        return broker->err_ret;
+    }
+    return 0;
+}
+
+void qb_prot_info_delete(struct QBroker *broker,
+                         struct QBlockProtInfo **op)
+{
+    CLEAN_FREE(*op);
+}
+
+int qb_fmt_info_new(struct QBroker *broker,
+                    struct QBlockFmtInfo **op)
+{
+    *op = FUNC_CALLOC(1, sizeof(struct QBlockFmtInfo));
+    if (*op == NULL) {
+        set_broker_err_nomem(broker);
+        return broker->err_ret;
+    }
+    return 0;
+}
+
+void qb_fmt_info_delete(struct QBroker *broker,
+                        struct QBlockFmtInfo **op)
+{
+    CLEAN_FREE(*op);
+}
+
+/* return 0 if every thing is fine */
+static int loc_check_params(struct QBroker *broker,
+                            struct QBlockProtInfo *loc)
+{
+    broker->err_ret = 0;
+
+    switch (loc->prot_type) {
+    case QB_PROT_FILE:
+        if (loc->prot_op.o_file.filename == NULL) {
+            set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                           "Filename was not set.");
+            goto out;
+        }
+        if (path_has_protocol(loc->prot_op.o_file.filename) > 0) {
+            set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                           "filename [%s] had protocol.",
+                           loc->prot_op.o_file.filename);
+            goto out;
+        }
+        break;
+    default:
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                       "Protocol type [%d] was not valid.",
+                       loc->prot_type);
+        break;
+    }
+
+ out:
+    return broker->err_ret;
+}
+
+/* translate loc structure to internal filename, returned char* need free,
+ * assuming filename is not NULL. *filename would be set to NULL if no valid
+ * filename found. *filename must be freed later.
+ * return 0 if no error with *filename set.
+ */
+static int loc2filename(struct QBroker *broker,
+                        struct QBlockProtInfo *loc,
+                        char **filename)
+{
+    broker->err_ret = 0;
+
+    if (*filename != NULL) {
+        CLEAN_FREE(*filename);
+    }
+    switch (loc->prot_type) {
+    case QB_PROT_FILE:
+        *filename = strdup(loc->prot_op.o_file.filename);
+        if (*filename == NULL) {
+            set_broker_err_nomem(broker);
+        }
+        break;
+    default:
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                 "protocol type [%d] is not supported.",
+                  loc->prot_type);
+        break;
+    }
+
+    return broker->err_ret;
+}
+
+/* translate filename to location, loc->prot_type = NONE if fail, filename
+   must be valid. loc internal char pointer must be freed later.
+ * return 0 if no error.
+ */
+static int filename2loc(struct QBroker *broker,
+                        struct QBlockProtInfo *loc,
+                        const char *filename)
+{
+    broker->err_ret = 0;
+
+    if (path_has_protocol(filename) > 0) {
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                     "Filename [%s] had protocol, not supported now.",
+                     filename);
+        goto out;
+    }
+
+    loc->prot_type = QB_PROT_FILE;
+    switch (loc->prot_type) {
+    case QB_PROT_FILE:
+        loc->prot_op.o_file.filename = strdup(filename);
+        if (loc->prot_op.o_file.filename == NULL) {
+            set_broker_err_nomem(broker);
+            goto out;
+        }
+        break;
+    default:
+        break;
+    }
+
+ out:
+    return broker->err_ret;
+}
+
+/* return 0 if OK, or qblock error number */
+static int set_backing_file_options(struct QBroker *broker,
+                                    QEMUOptionParameter *param,
+                                    struct QBlockProtInfo *loc,
+                                    enum QBlockFmtType *fmt)
+{
+    char *backing_filename = NULL;
+    const char *fmtstr_backing = NULL;
+    int ret = 0;
+
+    if (loc == NULL) {
+        goto out;
+    }
+
+    ret = loc2filename(broker, loc, &backing_filename);
+    /* ret can < 0 if loc have not been set, mean user did not specify backing
+       file */
+    if (ret == QB_ERR_MEM_ERR) {
+        goto out;
+    }
+    ret = 0;
+
+    if (backing_filename) {
+        ret = set_option_parameter(param,
+                            BLOCK_OPT_BACKING_FILE, backing_filename);
+        assert(ret == 0);
+        if (fmt == NULL) {
+            goto out;
+        }
+        fmtstr_backing = qb_fmttype2str(*fmt);
+        if (fmtstr_backing) {
+            ret = set_option_parameter(param,
+                                BLOCK_OPT_BACKING_FMT, fmtstr_backing);
+            assert(ret == 0);
+        }
+    }
+
+ out:
+    FUNC_FREE(backing_filename);
+    return ret;
+}
+
+int qb_create(struct QBroker *broker,
+              struct QBlockState *qbs,
+              struct QBlockProtInfo *loc,
+              struct QBlockFmtInfo *fmt,
+              int flag)
+{
+    int ret = 0, bd_ret;
+    char *filename = NULL;
+    BlockDriverState *bs = NULL;
+    BlockDriver *drv = NULL, *backing_drv = NULL;
+    bool tmp_bool;
+
+    const char *fmtstr = NULL, *tmp = NULL;
+    QEMUOptionParameter *param = NULL, *create_options = NULL;
+    QEMUOptionParameter *backing_fmt, *backing_file, *size;
+    struct QBlockFmtOptionCow *o_cow = NULL;
+    struct QBlockFmtOptionQed *o_qed = NULL;
+    struct QBlockFmtOptionQcow *o_qcow = NULL;
+    struct QBlockFmtOptionQcow2 *o_qcow2 = NULL;
+    struct QBlockFmtOptionRaw *o_raw = NULL;
+    struct QBlockFmtOptionRbd *o_rbd = NULL;
+    struct QBlockFmtOptionSheepdog *o_sd = NULL;
+    struct QBlockFmtOptionVdi *o_vdi = NULL;
+    struct QBlockFmtOptionVmdk *o_vmdk = NULL;
+    struct QBlockFmtOptionVpc *o_vpc = NULL;
+
+
+    /* check parameters */
+    if (flag & (~LIBQBLOCK_O_VALID_MASK)) {
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                           "invalid flag was set.");
+        ret = broker->err_ret;
+        goto out;
+    }
+
+    if ((loc == NULL) || (qbs == NULL) || (fmt == NULL)) {
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                          "Got unexpected NULL pointer in parameters.");
+        ret = broker->err_ret;
+        goto out;
+    }
+
+    ret = loc_check_params(broker, loc);
+    if (ret != 0) {
+        goto out;
+    }
+
+    /* internal translate */
+    ret = loc2filename(broker, loc, &filename);
+    if (ret != 0) {
+        goto out;
+    }
+
+    fmtstr = qb_fmttype2str(fmt->fmt_type);
+    if (fmtstr == NULL) {
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                 "Got unexpected NULL pointer in parameters.");
+        ret = broker->err_ret;
+        goto out;
+    }
+
+    drv = bdrv_find_format(fmtstr);
+    assert(drv != NULL);
+
+    create_options = append_option_parameters(create_options,
+                                              drv->create_options);
+    param = parse_option_parameters("", create_options, param);
+
+    switch (fmt->fmt_type) {
+    case QB_FMT_COW:
+        o_cow = &(fmt->fmt_op.o_cow);
+        bd_ret = set_option_parameter_int(param,
+                                BLOCK_OPT_SIZE, o_cow->virt_size);
+        assert(bd_ret == 0);
+        /* do not need to check loc, it may be not set */
+        ret = set_backing_file_options(broker, param,
+                                       &o_cow->backing_loc, NULL);
+        if (ret != 0) {
+            goto out;
+        }
+        break;
+    case QB_FMT_QED:
+        o_qed = &(fmt->fmt_op.o_qed);
+        bd_ret = set_option_parameter_int(param,
+                                BLOCK_OPT_SIZE, o_qed->virt_size);
+        assert(bd_ret == 0);
+        ret = set_backing_file_options(broker, param,
+                                 &o_qed->backing_loc, &o_qed->backing_fmt);
+        if (ret != 0) {
+            goto out;
+        }
+        bd_ret = set_option_parameter_int(param,
+                                BLOCK_OPT_CLUSTER_SIZE, o_qed->cluster_size);
+        assert(bd_ret == 0);
+        bd_ret = set_option_parameter_int(param,
+                                BLOCK_OPT_TABLE_SIZE, o_qed->table_size);
+        assert(bd_ret == 0);
+        break;
+    case QB_FMT_QCOW:
+        o_qcow = &(fmt->fmt_op.o_qcow);
+        bd_ret = set_option_parameter_int(param,
+                                BLOCK_OPT_SIZE, o_qcow->virt_size);
+        assert(bd_ret == 0);
+        ret = set_backing_file_options(broker, param,
+                                       &o_qcow->backing_loc, NULL);
+        if (ret != 0) {
+            goto out;
+        }
+        tmp = o_qcow->encrypt ? "on" : "off";
+        bd_ret = set_option_parameter(param, BLOCK_OPT_ENCRYPT, tmp);
+        assert(bd_ret == 0);
+        break;
+    case QB_FMT_QCOW2:
+        o_qcow2 = &(fmt->fmt_op.o_qcow2);
+        bd_ret = set_option_parameter_int(param,
+                              BLOCK_OPT_SIZE, o_qcow2->virt_size);
+        assert(bd_ret == 0);
+        ret = set_backing_file_options(broker, param,
+                              &o_qcow2->backing_loc, &o_qcow2->backing_fmt);
+        if (ret != 0) {
+            goto out;
+        }
+        tmp = o_qcow2->encrypt ? "on" : "off";
+        bd_ret = set_option_parameter(param, BLOCK_OPT_ENCRYPT, tmp);
+        assert(bd_ret == 0);
+        bd_ret = set_option_parameter_int(param,
+                              BLOCK_OPT_CLUSTER_SIZE, o_qcow2->cluster_size);
+        assert(bd_ret == 0);
+
+        if (o_qcow2->cpt_lv != QBO_FMT_QCOW2_CPT_NONE) {
+            tmp = o_qcow2->cpt_lv == QBO_FMT_QCOW2_CPT_V010 ? "0.10" : "1.1";
+            bd_ret = set_option_parameter(param,
+                              BLOCK_OPT_COMPAT_LEVEL, tmp);
+            assert(bd_ret == 0);
+        }
+
+        if (o_qcow2->pre_mode != QBO_FMT_QCOW2_PREALLOC_NONE) {
+            tmp = o_qcow2->pre_mode == QBO_FMT_QCOW2_PREALLOC_OFF ?
+                                         "off" : "metadata";
+            bd_ret = set_option_parameter(param,
+                              BLOCK_OPT_PREALLOC, tmp);
+            assert(bd_ret == 0);
+        }
+        break;
+
+    case QB_FMT_RAW:
+        o_raw = &(fmt->fmt_op.o_raw);
+        bd_ret = set_option_parameter_int(param,
+                              BLOCK_OPT_SIZE, o_raw->virt_size);
+        assert(bd_ret == 0);
+        break;
+    case QB_FMT_RBD:
+        o_rbd = &(fmt->fmt_op.o_rbd);
+        bd_ret = set_option_parameter_int(param,
+                              BLOCK_OPT_SIZE, o_rbd->virt_size);
+        assert(bd_ret == 0);
+        bd_ret = set_option_parameter_int(param,
+                              BLOCK_OPT_CLUSTER_SIZE, o_rbd->cluster_size);
+        assert(bd_ret == 0);
+        break;
+    case QB_FMT_SHEEPDOG:
+        o_sd = &(fmt->fmt_op.o_sheepdog);
+        bd_ret = set_option_parameter_int(param,
+                              BLOCK_OPT_SIZE, o_sd->virt_size);
+        assert(bd_ret == 0);
+        ret = set_backing_file_options(broker, param,
+                                       &o_sd->backing_loc, NULL);
+        if (ret != 0) {
+            goto out;
+        }
+        if (o_sd->pre_mode != QBO_FMT_SD_PREALLOC_NONE) {
+            tmp = o_sd->pre_mode == QBO_FMT_SD_PREALLOC_OFF ? "off" : "full";
+            bd_ret = set_option_parameter(param,
+                              BLOCK_OPT_PREALLOC, tmp);
+            assert(bd_ret == 0);
+        }
+        break;
+    case QB_FMT_VDI:
+        o_vdi = &(fmt->fmt_op.o_vdi);
+        bd_ret = set_option_parameter_int(param,
+                              BLOCK_OPT_SIZE, o_vdi->virt_size);
+        assert(bd_ret == 0);
+        /* following option is not always valid depends on configuration */
+        set_option_parameter_int(param,
+                              BLOCK_OPT_CLUSTER_SIZE, o_vdi->cluster_size);
+        if (o_vdi->pre_mode != QBO_FMT_VDI_PREALLOC_NONE) {
+            tmp_bool = o_sd->pre_mode == QBO_FMT_VDI_PREALLOC_TRUE ?
+                                                     true : false;
+            set_option_parameter_int(param, "static", tmp_bool);
+        }
+        break;
+    case QB_FMT_VMDK:
+        o_vmdk = &(fmt->fmt_op.o_vmdk);
+        bd_ret = set_option_parameter_int(param,
+                              BLOCK_OPT_SIZE, o_vmdk->virt_size);
+        assert(bd_ret == 0);
+        ret = set_backing_file_options(broker, param,
+                                       &o_vmdk->backing_loc, NULL);
+        if (ret != 0) {
+            goto out;
+        }
+
+        if (o_vmdk->cpt_lv != QBO_FMT_VMDK_CPT_NONE) {
+            tmp_bool = o_vmdk->cpt_lv == QBO_FMT_VMDK_CPT_VMDKV6_TRUE ?
+                                                     true : false;
+            bd_ret = set_option_parameter_int(param, BLOCK_OPT_COMPAT6,
+                                                     tmp_bool);
+            assert(bd_ret == 0);
+        }
+        if (o_vmdk->subfmt != QBO_FMT_VMDK_SUBFMT_MONOLITHIC_NONE) {
+            switch (o_vmdk->subfmt) {
+            case QBO_FMT_VMDK_SUBFMT_MONOLITHIC_SPARSE:
+                tmp = "monolithicSparse";
+                break;
+            case QBO_FMT_VMDK_SUBFMT_MONOLITHIC_FLAT:
+                tmp = "monolithicFlat";
+                break;
+            case QBO_FMT_VMDK_SUBFMT_TWOGBMAX_EXTENT_SPARSE:
+                tmp = "twoGbMaxExtentSparse";
+                break;
+            case QBO_FMT_VMDK_SUBFMT_TWOGBMAX_EXTENT_FLAT:
+                tmp = "twoGbMaxExtentFlat";
+                break;
+            case QBO_FMT_VMDK_SUBFMT_STREAM_OPTIMIZED:
+                tmp = "streamOptimized";
+                break;
+            default:
+                assert(false);
+                break;
+            }
+            bd_ret = set_option_parameter(param,
+                              BLOCK_OPT_SUBFMT, tmp);
+            assert(bd_ret == 0);
+        }
+        break;
+    case QB_FMT_VPC:
+        o_vpc = &(fmt->fmt_op.o_vpc);
+        bd_ret = set_option_parameter_int(param,
+                               BLOCK_OPT_SIZE, o_vpc->virt_size);
+        assert(bd_ret == 0);
+        if (o_vpc->subfmt != QBO_FMT_VPC_SUBFMT_NONE) {
+            tmp = o_vpc->subfmt == QBO_FMT_VPC_SUBFMT_DYNAMIC ?
+                                               "dynamic" : "fixed";
+            bd_ret = set_option_parameter(param,
+                               BLOCK_OPT_SUBFMT, tmp);
+            assert(bd_ret == 0);
+        }
+        break;
+    default:
+        assert(false);
+        break;
+    }
+
+    backing_file = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
+    if (backing_file && backing_file->value.s) {
+        if (!strcmp(filename, backing_file->value.s)) {
+            set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                          "Backing file is the same with new file.");
+            ret = broker->err_ret;
+            goto out;
+        }
+    }
+
+    backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
+    if (backing_fmt && backing_fmt->value.s) {
+        backing_drv = bdrv_find_format(backing_fmt->value.s);
+        assert(backing_drv != NULL);
+    }
+
+    size = get_option_parameter(param, BLOCK_OPT_SIZE);
+    if (size && size->value.n <= 0) {
+        if (backing_file && backing_file->value.s) {
+            uint64_t size;
+            char buf[32];
+            int back_flags;
+
+            /* backing files always opened read-only */
+            back_flags =
+                flag &
+                ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
+
+            bs = bdrv_new("");
+
+            ret = bdrv_open(bs, backing_file->value.s,
+                                back_flags, backing_drv);
+            if (ret < 0) {
+                set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                               "Failed to open the backing file.");
+                ret = broker->err_ret;
+                goto out;
+            }
+            bdrv_get_geometry(bs, &size);
+            size *= BDRV_SECTOR_SIZE;
+
+            snprintf(buf, sizeof(buf), "%" PRId64, size);
+            set_option_parameter(param, BLOCK_OPT_SIZE, buf);
+        } else {
+            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
+                           "Neither size or backing file was not set.");
+            ret = broker->err_ret;
+            goto out;
+        }
+    }
+
+    bd_ret = bdrv_create(drv, filename, param);
+
+
+    if (bd_ret < 0) {
+        const char *errstr;
+        if (bd_ret == -ENOTSUP) {
+            errstr = "formatting option not supported.";
+        } else if (bd_ret == -EFBIG) {
+            errstr = "The image size is too large.";
+        } else {
+            errstr = "Error in creating the image.";
+        }
+        set_broker_err(broker, QB_ERR_INTERNAL_ERR, errstr);
+        ret = broker->err_ret;
+    }
+
+out:
+    free_option_parameters(create_options);
+    free_option_parameters(param);
+    FUNC_FREE(filename);
+    if (bs) {
+        bdrv_delete(bs);
+    }
+
+    return ret;
+}
+
+int qb_open(struct QBroker *broker,
+            struct QBlockState *qbs,
+            struct QBlockProtInfo *loc,
+            struct QBlockFmtInfo *fmt,
+            int flag)
+{
+    int ret = 0, bd_ret;
+    BlockDriverState *bs;
+    BlockDriver *bd;
+    const char *fmtstr;
+    char *filename = NULL;
+
+    /* take care of user settings */
+    /* do nothing now */
+
+    /* check parameters */
+    if (flag & (~LIBQBLOCK_O_VALID_MASK)) {
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                      "Invalid flag was set.");
+        ret = broker->err_ret;
+        goto out;
+    }
+
+    if ((loc == NULL) || (qbs == NULL)) {
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                      "Got unexpected NULL pointer in parameters.");
+        ret = broker->err_ret;
+        goto out;
+    }
+
+    ret = loc_check_params(broker, loc);
+    if (ret != 0) {
+        goto out;
+    }
+
+    /* internal translate */
+    ret = loc2filename(broker, loc, &filename);
+    if (ret != 0) {
+        goto out;
+    }
+
+    fmtstr = NULL;
+    bd = NULL;
+    if (fmt != NULL) {
+        fmtstr = qb_fmttype2str(fmt->fmt_type);
+    }
+
+    if (fmtstr != NULL) {
+        bd = bdrv_find_format(fmtstr);
+        assert(bd != NULL);
+    }
+
+    /* do real openning */
+    bs = qbs->bdrvs;
+    bd_ret = bdrv_open(bs, filename, flag, bd);
+    if (bd_ret < 0) {
+        set_broker_err(broker, QB_ERR_INTERNAL_ERR,
+                      "Failed in opening with driver, bd_ret is %d.", bd_ret);
+        ret = broker->err_ret;
+        goto out;
+    }
+
+    if (qbs->filename != NULL) {
+        FUNC_FREE(qbs->filename);
+    }
+    qbs->filename = strdup(filename);
+    if (qbs->filename == NULL) {
+        set_broker_err_nomem(broker);
+        ret = broker->err_ret;
+        bdrv_close(bs);
+        goto out;
+    }
+
+ out:
+    FUNC_FREE(filename);
+    return ret;
+}
+
+void qb_close(struct QBroker *broker,
+              struct QBlockState *qbs)
+{
+    BlockDriverState *bs;
+
+    bs = qbs->bdrvs;
+
+    if (qbs->filename != NULL) {
+        CLEAN_FREE(qbs->filename);
+        bdrv_close(bs);
+    }
+    return;
+}
+
+int64_t qb_read(struct QBroker *broker,
+                struct QBlockState *qbs,
+                uint8_t *buf,
+                uint32_t len,
+                uint64_t offset)
+{
+    int bd_ret;
+    BlockDriverState *bs;
+    uint8_t temp_buf[BDRV_SECTOR_SIZE], *p;
+    uint64_t sector_start;
+    int sector_num, byte_offset, cp_len;
+    int remains;
+
+    broker->err_ret = 0;
+    bs = qbs->bdrvs;
+
+    if (len <= 0) {
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                      "Param len is less or equal to zero.");
+        return broker->err_ret;
+    }
+
+    p = buf;
+    remains = len;
+
+    sector_start = offset >> BDRV_SECTOR_BITS;
+
+    byte_offset = offset & (~BDRV_SECTOR_MASK);
+    if (byte_offset != 0) {
+        /* the start sector is not aligned, need to read/write this sector. */
+        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
+        if (bd_ret < 0) {
+            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
+                           "QEMU internal block error.");
+            return broker->err_ret;
+        }
+        cp_len = BDRV_SECTOR_SIZE - byte_offset;
+        memcpy(p, temp_buf + byte_offset, cp_len);
+
+        remains -= cp_len;
+        p += cp_len;
+        sector_start++;
+    }
+
+    /* now start position is aligned. */
+    if (remains >= BDRV_SECTOR_SIZE) {
+        sector_num = len >> BDRV_SECTOR_BITS;
+        bd_ret = bdrv_read(bs, sector_start, p, sector_num);
+        if (bd_ret < 0) {
+            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
+                           "QEMU internal block error.");
+            return broker->err_ret;
+        }
+        remains -= sector_num << BDRV_SECTOR_BITS;
+        p += sector_num << BDRV_SECTOR_BITS;
+        sector_start += sector_num;
+    }
+
+    if (remains > 0) {
+        /* there is some request remains, less than 1 sector */
+        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
+        if (bd_ret < 0) {
+            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
+                           "QEMU internal block error.");
+            return broker->err_ret;
+        }
+        memcpy(p, temp_buf, remains);
+        remains -= remains;
+    }
+
+    return len-remains;
+}
+
+int64_t qb_write(struct QBroker *broker,
+                 struct QBlockState *qbs,
+                 const uint8_t *buf,
+                 uint32_t len,
+                 uint64_t offset)
+{
+    int bd_ret;
+    BlockDriverState *bs;
+    uint8_t temp_buf[BDRV_SECTOR_SIZE];
+    const uint8_t *p;
+    uint64_t sector_start;
+    int sector_num, byte_offset, cp_len;
+    int remains;
+
+    broker->err_ret = 0;
+    bs = qbs->bdrvs;
+
+    if (len <= 0) {
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                      "Param len is less or equal to zero.");
+        return broker->err_ret;
+    }
+
+    p = buf;
+    remains = len;
+
+    sector_start = offset >> BDRV_SECTOR_BITS;
+
+    byte_offset = offset & (~BDRV_SECTOR_MASK);
+    if (byte_offset != 0) {
+        /* the start sector is not aligned, need to read/write this sector. */
+        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
+        if (bd_ret < 0) {
+            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
+                           "QEMU internal block error.");
+            return broker->err_ret;
+        }
+        cp_len = BDRV_SECTOR_SIZE - byte_offset;
+        memcpy(temp_buf + byte_offset, p, cp_len);
+        bd_ret = bdrv_write(bs, sector_start, temp_buf, 1);
+        if (bd_ret < 0) {
+            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
+                           "QEMU internal block error.");
+            return broker->err_ret;
+        }
+        remains -= cp_len;
+        p += cp_len;
+        sector_start++;
+    }
+
+    /* now start position is aligned. */
+    if (remains >= BDRV_SECTOR_SIZE) {
+        sector_num = len >> BDRV_SECTOR_BITS;
+        bd_ret = bdrv_write(bs, sector_start, p, sector_num);
+        if (bd_ret < 0) {
+            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
+                           "QEMU internal block error.");
+            return broker->err_ret;
+        }
+        remains -= sector_num << BDRV_SECTOR_BITS;
+        p += sector_num << BDRV_SECTOR_BITS;
+        sector_start += sector_num;
+    }
+
+    if (remains > 0) {
+        /* there is some request remains, less than 1 sector */
+        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
+        if (bd_ret < 0) {
+            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
+                           "QEMU internal block error.");
+            return broker->err_ret;
+        }
+        memcpy(temp_buf, p, remains);
+        bd_ret = bdrv_write(bs, sector_start, temp_buf, 1);
+        if (bd_ret < 0) {
+            set_broker_err(broker, QB_ERR_INTERNAL_ERR,
+                           "QEMU internal block error.");
+            return broker->err_ret;
+        }
+        remains -= remains;
+    }
+
+    return len-remains;
+}
+
+int qb_flush(struct QBroker *broker,
+             struct QBlockState *qbs)
+{
+    int bd_ret;
+    BlockDriverState *bs;
+
+    broker->err_ret = 0;
+    bs = qbs->bdrvs;
+    bd_ret = bdrv_flush(bs);
+    if (bd_ret < 0) {
+        set_broker_err(broker, QB_ERR_INTERNAL_ERR,
+                       "Internal error.");
+    }
+    return broker->err_ret;
+}
+
+int qb_check_allocation(struct QBroker *broker,
+                        struct QBlockState *qbs,
+                        uint64_t start,
+                        int length,
+                        int *pstatus,
+                        int *plength)
+{
+    int ret;
+    int sector_start, sector_num, num;
+    BlockDriverState *bs;
+    unsigned int real_len, ret_len;
+
+    broker->err_ret = 0;
+    bs = qbs->bdrvs;
+
+    if (qbs->filename == NULL) {
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                       "Image was not opened first.");
+        goto out;
+    }
+
+    if (length <= 0) {
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                       "length is not valid.");
+        goto out;
+    }
+
+    /* translate to sector */
+    sector_start = start >> BDRV_SECTOR_BITS;
+    real_len = (start & (~BDRV_SECTOR_MASK)) + length;
+    sector_num = real_len >> BDRV_SECTOR_BITS;
+    if ((real_len & (~BDRV_SECTOR_MASK)) != 0) {
+        sector_num++;
+    }
+
+    ret = bdrv_is_allocated(bs, sector_start, sector_num, &num);
+    if ((ret == 0) && (num == 0)) {
+        set_broker_err(broker, QB_ERR_BLOCK_OUT_OF_RANGE,
+                       "Start position was bigger than the image's size.");
+        goto out;
+    }
+
+    *pstatus = ret;
+    ret_len = (num << BDRV_SECTOR_BITS) - (start & (~BDRV_SECTOR_MASK));
+    if (ret_len > length) {
+        ret_len = length;
+    }
+    *plength = ret_len;
+
+ out:
+    return broker->err_ret;
+}
+
+int qb_info_image_static_get(struct QBroker *broker,
+                             struct QBlockState *qbs,
+                             struct QBlockStaticInfo **info)
+{
+    int ret = 0;
+    BlockDriverState *bs;
+    struct QBlockStaticInfo *info_tmp;
+    const char *fmt_str;
+    size_t total_sectors;
+    char backing_filename[1024];
+
+    if (qbs->filename == NULL) {
+        set_broker_err(broker, QB_ERR_INVALID_PARAM,
+                       "Block Image was not openned.");
+        ret = broker->err_ret;
+        goto out;
+    }
+
+    info_tmp = FUNC_CALLOC(1, sizeof(struct QBlockStaticInfo));
+    if (info_tmp == NULL) {
+        set_broker_err_nomem(broker);
+        ret = broker->err_ret;
+        goto out;
+    }
+
+    bs = qbs->bdrvs;
+
+    ret = filename2loc(broker,
+                       &(info_tmp->loc),
+                       qbs->filename);
+    if (ret < 0) {
+        goto free;
+    }
+
+    fmt_str = bdrv_get_format_name(bs);
+    info_tmp->fmt_type = qb_str2fmttype(fmt_str);
+
+    bdrv_get_geometry(bs, &total_sectors);
+    info_tmp->virt_size = total_sectors * BDRV_SECTOR_SIZE;
+
+    info_tmp->encrypt = bdrv_is_encrypted(bs);
+
+    bdrv_get_full_backing_filename(bs, backing_filename,
+                                   sizeof(backing_filename));
+    if (backing_filename[0] != '\0') {
+        ret = filename2loc(broker,
+                           &(info_tmp->backing_loc),
+                           backing_filename);
+        if (ret < 0) {
+            goto free;
+        }
+    }
+
+    info_tmp->sector_size = BDRV_SECTOR_SIZE;
+    *info = info_tmp;
+
+ out:
+    return ret;
+ free:
+    qb_info_image_static_delete(broker, &info_tmp);
+    return ret;
+}
+
+/* free locations if it has string allocated on heap. */
+static void loc_free(struct QBlockProtInfo *loc)
+{
+    switch (loc->prot_type) {
+    case QB_PROT_FILE:
+        FUNC_FREE((void *)(loc->prot_op.o_file.filename));
+        loc->prot_op.o_file.filename = NULL;
+        break;
+    default:
+        break;
+    }
+}
+
+void qb_info_image_static_delete(struct QBroker *broker,
+                                 struct QBlockStaticInfo **info)
+{
+    loc_free(&(*info)->loc);
+    loc_free(&(*info)->backing_loc);
+
+    CLEAN_FREE(*info);
+}
diff --git a/libqblock/libqblock.h b/libqblock/libqblock.h
new file mode 100644
index 0000000..97e6c7c
--- /dev/null
+++ b/libqblock/libqblock.h
@@ -0,0 +1,292 @@ 
+/*
+ * QEMU block layer library
+ *
+ * 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.
+ *
+ */
+
+#ifndef LIBQBLOCK_H
+#define LIBQBLOCK_H
+
+#include "libqblock-types.h"
+#include "libqblock-error.h"
+
+/**
+ * qb_broker_new: allocate a new broker
+ *
+ * Broker is used to pass operation to libqblock, and get feed back from it.
+ *
+ * Returns 0 on success, libqblock negative error value on fail.
+ *
+ * @broker: used to receive the created struct.
+ */
+DLL_PUBLIC
+int qb_broker_new(struct QBroker **broker);
+
+/**
+ * qb_broker_delete: delete broker
+ *
+ * Broker will be freed and set to NULL.
+ *
+ * @broker: operation broker to be deleted.
+ */
+DLL_PUBLIC
+void qb_broker_delete(struct QBroker **broker);
+
+/**
+ * qb_state_new: allocate a new QBlockState struct
+ *
+ * Subsequent qblock actions will use this struct
+ *
+ * Returns 0 if succeed, libqblock negative error value on fail.
+ *
+ * @broker: operation broker.
+ * @qbs: used to receive the created struct.
+ */
+DLL_PUBLIC
+int qb_state_new(struct QBroker *broker,
+                 struct QBlockState **qbs);
+
+/**
+ * qb_state_delete: free a QBlockState struct
+ *
+ * if image was opened, qb_close must be called before delete.
+ *
+ * @broker: operation broker.
+ * @qbs: pointer to the struct's pointer.
+ */
+DLL_PUBLIC
+void qb_state_delete(struct QBroker *broker,
+                     struct QBlockState **qbs);
+
+/**
+ * qb_prot_info_new: create a new struct QBlockProtInfo.
+ *
+ * return 0 on success, libqblock negative error value on fail.
+ *
+ * @broker: operation broker.
+ * @op: pointer to receive the new created one.
+ */
+DLL_PUBLIC
+int qb_prot_info_new(struct QBroker *broker,
+                     struct QBlockProtInfo **op);
+
+/**
+ * qb_prot_info_delete: free a struct QBlockProtInfo.
+ *
+ * @broker: operation broker.
+ * @op: pointer to the object, *op would be set to NULL.
+ */
+DLL_PUBLIC
+void qb_prot_info_delete(struct QBroker *broker,
+                         struct QBlockProtInfo **op);
+
+/**
+ * qb_fmt_info_new: create a new QBlockFmtInfo structure.
+ *
+ * return 0 on success, libqblock negative error value on fail.
+ *
+ * @broker: operation broker.
+ * @op: pointer that will receive created struct.
+ */
+DLL_PUBLIC
+int qb_fmt_info_new(struct QBroker *broker,
+                    struct QBlockFmtInfo **op);
+
+/**
+ * qb_fmt_info_delete: free QBlockFmtInfo structure.
+ *
+ * @broker: operation broker.
+ * @op: pointer to the struct, *op would be set to NULL.
+ */
+DLL_PUBLIC
+void qb_fmt_info_delete(struct QBroker *broker,
+                        struct QBlockFmtInfo **op);
+
+
+/**
+ * qb_open: open a block object.
+ *
+ * return 0 on success, libqblock negative error value on fail.
+ *
+ * @broker: operation broker.
+ * @qbs: pointer to struct QBlockState.
+ * @loc: location options for open, how to find the image.
+ * @fmt: format options, how to extract the data, only valid member now is
+ *    fmt->fmt_type, set to NULL if you want to auto discovery the format.
+ * @flag: behavior control flags, it is LIBQBLOCK_O_XXX's combination.
+ *
+ * Note: For raw image, there is a risk that it's content is changed to some
+ *  magic value resulting a wrong probing done by libqblock, so don't do
+ * probing on raw images.
+ */
+DLL_PUBLIC
+int qb_open(struct QBroker *broker,
+            struct QBlockState *qbs,
+            struct QBlockProtInfo *loc,
+            struct QBlockFmtInfo *fmt,
+            int flag);
+
+/**
+ * qb_close: close a block object.
+ *
+ * qb_flush is automatically done inside.
+ *
+ * @broker: operation broker.
+ * @qbs: pointer to struct QBlockState.
+ */
+DLL_PUBLIC
+void qb_close(struct QBroker *broker,
+              struct QBlockState *qbs);
+
+/**
+ * qb_create: create a block image or object.
+ *
+ * Note: Create operation would not open the image automatically.
+ *
+ * return 0 on success, libqblock negative error value on fail.
+ *
+ * @broker: operation broker.
+ * @qbs: pointer to struct QBlockState.
+ * @loc: location options for open, how to find the image.
+ * @fmt: format options, how to extract the data.
+ * @flag: behavior control flags, LIBQBLOCK_O_XXX's combination.
+ */
+DLL_PUBLIC
+int qb_create(struct QBroker *broker,
+              struct QBlockState *qbs,
+              struct QBlockProtInfo *loc,
+              struct QBlockFmtInfo *fmt,
+              int flag);
+
+
+/* sync access */
+/**
+ * qb_read: block sync read.
+ *
+ * return number of bytes read, libqblock negative error value on fail.
+ *
+ * @broker: operation broker.
+ * @qbs: pointer to struct QBlockState.
+ * @buf: buffer that receive the content.
+ * @len: length to read.
+ * @offset: offset in the block data.
+ */
+DLL_PUBLIC
+int64_t qb_read(struct QBroker *broker,
+                struct QBlockState *qbs,
+                uint8_t *buf,
+                uint32_t len,
+                uint64_t offset);
+
+/**
+ * qb_write: block sync write.
+ *
+ * return number of bytes written, libqblock negative error value on fail.
+ *
+ * @broker: operation broker.
+ * @qbs: pointer to struct QBlockState.
+ * @buf: buffer that receive the content.
+ * @len: length to write.
+ * @offset: offset in the block data.
+ */
+DLL_PUBLIC
+int64_t qb_write(struct QBroker *broker,
+                 struct QBlockState *qbs,
+                 const uint8_t *buf,
+                 uint32_t len,
+                 uint64_t offset);
+
+/**
+ * qb_flush: block sync flush.
+ *
+ * return 0 on success, libqblock negative error value on fail.
+ *
+ * @broker: operation broker.
+ * @qbs: pointer to struct QBlockState.
+ */
+DLL_PUBLIC
+int qb_flush(struct QBroker *broker,
+             struct QBlockState *qbs);
+
+
+/* advance image APIs */
+/**
+ * qb_check_allocation: check if [start, start+lenth-1] was allocated on the
+ *  image.
+ *
+ * return 0 on success, libqblock negative error value on fail.
+ *
+ * @broker: operation broker.
+ * @qbs: pointer to struct QBlockState.
+ * @start: start position, unit is byte.
+ * @length: length to check, unit is byte.
+ * @pstatus: pointer to receive the status, 1 means allocated,
+ *  0 means unallocated.
+ * @plength: pointer to receive the length that all have the same status as
+ *  *pstatus.
+ *
+ * Note: after return, start+*plength may have the same status as
+ *  start+*plength-1.
+ */
+DLL_PUBLIC
+int qb_check_allocation(struct QBroker *broker,
+                        struct QBlockState *qbs,
+                        uint64_t start,
+                        int length,
+                        int *pstatus,
+                        int *plength);
+
+/* image information */
+/**
+ * qb_get_image_info: get image info.
+ *
+ * return 0 on success, libqblock negative error value on fail.
+ *
+ * @broker: operation broker.
+ * @qbs: pointer to struct QBlockState.
+ * @info: pointer that would receive the information.
+ */
+DLL_PUBLIC
+int qb_info_image_static_get(struct QBroker *broker,
+                             struct QBlockState *qbs,
+                             struct QBlockStaticInfo **info);
+
+/**
+ * qb_delete_image_info: free image info.
+ *
+ * @broker: operation broker.
+ * @info: pointer to the information struct.
+ */
+DLL_PUBLIC
+void qb_info_image_static_delete(struct QBroker *broker,
+                                 struct QBlockStaticInfo **info);
+
+/* helper functions */
+/**
+ * qb_str2fmttype: translate format string to libqblock format enum type.
+ *
+ * return the type, or QB_FMT_NONE if string matches none of supported types.
+ *
+ * @fmt: the format string.
+ */
+DLL_PUBLIC
+enum QBlockFmtType qb_str2fmttype(const char *fmt_str);
+
+/**
+ * qb_fmttype2str: libqblock format enum type to a string.
+ *
+ * return a pointer to the string, or NULL if type is not supported, and
+ *  returned pointer do NOT need to free.
+ *
+ * @fmt: the format enum type.
+ */
+DLL_PUBLIC
+const char *qb_fmttype2str(enum QBlockFmtType fmt_type);
+#endif