All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Cc: kwolf@redhat.com, stefanha@gmail.com, aliguori@us.ibm.com,
	qemu-devel@nongnu.org, blauwirbel@gmail.com
Subject: Re: [Qemu-devel] [PATCH V11 6/7] libqblock API implement
Date: Mon, 26 Nov 2012 09:34:01 +0100	[thread overview]
Message-ID: <50B32979.6010905@redhat.com> (raw)
In-Reply-To: <1353749244-25676-7-git-send-email-xiawenc@linux.vnet.ibm.com>

Il 24/11/2012 10:27, Wenchao Xia ha scritto:
>   This patch contains implemention for APIs.
> Important APIs:
>   1 QBlockContext. This structure was used to retrieve errors, every thread
> must create one first.
>   2 QBlockImage. It stands for an block image object.
>   3 QBlockStaticInfo. It contains static information such as location, backing
> file, size.
>   4 Sync I/O. It is similar to C file open, read, write and close operations.
> 
> v11:
>   Moved API design out of this patch.
>   Spell fix.
>   Use a new function in libqblock-aio.c to do bdrv init and aio init, removed
> this section from library loading call back function, which allows map different
> aio-context to differenct QBlockContext in the future.
>   Renamed QBlockState to QBlockImage.
>   Added reference counter in QBlockImage, which is only used in new/delete pair
> function now.

With a reference count, the API should be new/ref/unref, not new/delete.
 The "delete" function should be internal, just call it from unref when
the reference count goes to zero.

Some other comments below.

>   Removed useless parentheses around & argument.
>   Move virt_size out of format unions, removed virt_size from QBlockStaticInfoAddr.
>   bdrv_read and bdrv_write, Report I/O error when block api return negative value.
>   qb_check_allocation, fixed the length check condition and added comments for
> it.
>   qb_info_image_static_get, renamed info to p_info and info_tmp to info, also
> renamed all double pointing parameters with prefix “p_”in all API.
>   qb_str2fmttype and qb_fmttype2str, added parameter check.
>   qb_setup_info_addr, moved memset into it.
>   qb_info_image_static_get, added format valid check, removed variable member_addr,
> moved memset to qb_setup_info_addr.
> 
> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
> ---
>  libqblock/libqblock-aio.c   |  110 ++++-
>  libqblock/libqblock-error.c |   57 ++
>  libqblock/libqblock.c       | 1191 ++++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 1349 insertions(+), 9 deletions(-)
> 
> diff --git a/libqblock/libqblock-aio.c b/libqblock/libqblock-aio.c
> index 605eee8..97d7ad9 100644
> --- a/libqblock/libqblock-aio.c
> +++ b/libqblock/libqblock-aio.c
> @@ -11,31 +11,63 @@
>   *
>   */
>  
> +/* This file was only used in libqblock, codes are copied from main-loop.c,
> + iohandler.c, compatfd.c now, it may have different implemention in the future.
> +*/
> +
>  #include <sys/syscall.h>
>  
> +#include "libqblock-aio.h"
> +
>  #include "qemu-common.h"
>  #include "qemu-aio.h"
>  #include "main-loop.h"
>  #include "compatfd.h"
>  
> -void qemu_notify_event(void)
> +#include "block.h"
> +
> +/* Aio support, copied from main-loop.c */
> +
> +static AioContext *qemu_aio_context;
> +
> +/* This function should only be called once now. */
> +void libqblock_aio_init(void)
>  {
> +    GSource *src;
> +
> +    qemu_aio_context = aio_context_new();
> +    /* bdrv_init must be called after qemu_aio_context was set. */
> +    bdrv_init();
> +
> +    src = aio_get_g_source(qemu_aio_context);
> +    g_source_attach(src, NULL);
> +    g_source_unref(src);

There is no need (yet) to do these three steps.  Once we add an
asynchronous I/O API, we can add an API to get an AioContext from a
QBlockContext.

This however requires support for multiple AioContexts, I think.  So
that's left for later.

>      return;
>  }
>  
> +void qemu_notify_event(void)
> +{
> +    if (!qemu_aio_context) {
> +        return;
> +    }
> +    aio_notify(qemu_aio_context);
> +}
> +
> +/* Functions to operate on the main QEMU AioContext.  */
> +
>  QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
>  {
> -    return NULL;
> +    return aio_bh_new(qemu_aio_context, cb, opaque);
>  }
>  
>  void qemu_aio_flush(void)
>  {
> -    return;
> +    aio_flush(qemu_aio_context);
>  }
>  
>  bool qemu_aio_wait(void)
>  {
> -    return false;
> +    return aio_poll(qemu_aio_context, true);
>  }
>  
>  #ifdef CONFIG_POSIX
> @@ -45,7 +77,8 @@ void qemu_aio_set_fd_handler(int fd,
>                               AioFlushHandler *io_flush,
>                               void *opaque)
>  {
> -    return;
> +    aio_set_fd_handler(qemu_aio_context, fd, io_read, io_write, io_flush,
> +                       opaque);
>  }
>  #endif
>  
> @@ -53,22 +86,83 @@ void qemu_aio_set_event_notifier(EventNotifier *notifier,
>                                   EventNotifierHandler *io_read,
>                                   AioFlushEventNotifierHandler *io_flush)
>  {
> -    return;
> +    aio_set_event_notifier(qemu_aio_context, notifier, io_read, io_flush);
>  }
>  
> +
> +/* Signal fd support, copied from compatfd.c */
> +
>  bool qemu_signalfd_available(void)
>  {
> +#ifdef CONFIG_SIGNALFD
> +    sigset_t mask;
> +    int fd;
> +    bool ok;
> +    sigemptyset(&mask);
> +    errno = 0;
> +    fd = syscall(SYS_signalfd, -1, &mask, _NSIG / 8);
> +    ok = (errno != ENOSYS);
> +    if (fd >= 0) {
> +        close(fd);
> +    }
> +    return ok;
> +#else
>      return false;
> +#endif
>  }

Please just return false.

> -typedef struct IOHandlerRecord IOHandlerRecord;
>  
> +/* Fd handler support, copied from iohandler.c. */
> +
> +typedef struct IOHandlerRecord {
> +    IOCanReadHandler *fd_read_poll;
> +    IOHandler *fd_read;
> +    IOHandler *fd_write;
> +    void *opaque;
> +    QLIST_ENTRY(IOHandlerRecord) next;
> +    int fd;
> +    bool deleted;
> +} IOHandlerRecord;
> +
> +static QLIST_HEAD(, IOHandlerRecord) io_handlers =
> +    QLIST_HEAD_INITIALIZER(io_handlers);
> +
> +/* XXX: fd_read_poll should be suppressed, but an API change is
> +   necessary in the character devices to suppress fd_can_read(). */
>  int qemu_set_fd_handler2(int fd,
>                           IOCanReadHandler *fd_read_poll,
>                           IOHandler *fd_read,
>                           IOHandler *fd_write,
>                           void *opaque)
>  {
> +    IOHandlerRecord *ioh;
> +
> +    assert(fd >= 0);
> +
> +    if (!fd_read && !fd_write) {
> +        QLIST_FOREACH(ioh, &io_handlers, next) {
> +            if (ioh->fd == fd) {
> +                ioh->deleted = 1;
> +                break;
> +            }
> +        }
> +    } else {
> +        QLIST_FOREACH(ioh, &io_handlers, next) {
> +            if (ioh->fd == fd) {
> +                goto found;
> +            }
> +        }
> +        ioh = g_malloc0(sizeof(IOHandlerRecord));
> +        QLIST_INSERT_HEAD(&io_handlers, ioh, next);
> +    found:
> +        ioh->fd = fd;
> +        ioh->fd_read_poll = fd_read_poll;
> +        ioh->fd_read = fd_read;
> +        ioh->fd_write = fd_write;
> +        ioh->opaque = opaque;
> +        ioh->deleted = 0;
> +        qemu_notify_event();
> +    }
>      return 0;
>  }
>  
> @@ -77,5 +171,5 @@ int qemu_set_fd_handler(int fd,
>                          IOHandler *fd_write,
>                          void *opaque)
>  {
> -    return 0;
> +    return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
>  }

The stubs/ version is enough for qemu_set_fd_handler2. The only use of
qemu_set_fd_handler is in event_notifier-posix.c, either change it to
qemu_set_fd_handler2 or add another file to stubs/.

> diff --git a/libqblock/libqblock-error.c b/libqblock/libqblock-error.c
> index e69de29..2a59970 100644
> --- a/libqblock/libqblock-error.c
> +++ b/libqblock/libqblock-error.c
> @@ -0,0 +1,57 @@
> +/*
> + * 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 "libqblock-error.h"
> +#include "libqblock-internal.h"
> +
> +void qb_error_get_human_str(QBlockContext *context,
> +                            char *buf, size_t buf_size)
> +{
> +    const char *err_ret_str;
> +    switch (context->err_ret) {
> +    case QB_ERR_INTERNAL_ERR:
> +        err_ret_str = "Internal error.";
> +        break;
> +    case QB_ERR_INVALID_PARAM:
> +        err_ret_str = "Invalid param.";
> +        break;
> +    case QB_ERR_BLOCK_OUT_OF_RANGE:
> +        err_ret_str = "request is out of image's range.";
> +        break;
> +    default:
> +        err_ret_str = "Unknown error.";
> +        break;
> +    }
> +    if (context == NULL) {
> +        snprintf(buf, buf_size, "%s", err_ret_str);
> +        return;
> +    }
> +
> +    if (context->err_ret == QB_ERR_INTERNAL_ERR) {
> +        snprintf(buf, buf_size, "%s %s errno [%d]. strerror [%s].",
> +                     err_ret_str, context->g_error->message,
> +                     context->err_no, strerror(-context->err_no));
> +    } else {
> +        snprintf(buf, buf_size, "%s %s",
> +                     err_ret_str, context->g_error->message);
> +    }
> +    return;
> +}
> +
> +int qb_error_get_errno(QBlockContext *context)
> +{
> +    if (context->err_ret == QB_ERR_INTERNAL_ERR) {
> +        return context->err_no;
> +    }
> +    return 0;
> +}
> diff --git a/libqblock/libqblock.c b/libqblock/libqblock.c
> index 4c18c41..89e3c54 100644
> --- a/libqblock/libqblock.c
> +++ b/libqblock/libqblock.c
> @@ -1,6 +1,1195 @@
> +/*
> + * 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 <pthread.h>
> +
>  #include "libqblock.h"
> +#include "libqblock-internal.h"
> +
> +#include "block_int.h"
> +#include "qemu-aio.h"
> +#include "libqblock-aio.h"
> +
> +#define LIBQB_FILENAME_MAX 4096
> +
> +typedef struct LibqblockGlobalData {
> +    int init_flag;
> +    pthread_mutex_t *mutex;
> +} LibqblockGlobalData;
> +
> +LibqblockGlobalData libqb_global_data;
> +
> +typedef struct LibqbFormatStrMapping {
> +    const char *fmt_str;
> +    QBlockFormat fmt_type;
> +} LibqbFormatStrMapping;
> +
> +LibqbFormatStrMapping libqb_fmtstr_table[] = {
> +    {"cow", QB_FMT_COW},
> +    {"qed", QB_FMT_QED},
> +    {"qcow", QB_FMT_QCOW},
> +    {"qcow2", QB_FMT_QCOW2},
> +    {"raw", QB_FMT_RAW},
> +    {"rbd", QB_FMT_RBD},
> +    {"sheepdog", QB_FMT_SHEEPDOG},
> +    {"vdi", QB_FMT_VDI},
> +    {"vmdk", QB_FMT_VMDK},
> +    {"vpc", QB_FMT_VPC},
> +    {NULL, 0},
> +};
> +
> +__attribute__((constructor))
> +static void libqblock_init(void)
> +{
> +    /* Todo: add an assertion about the ABI. */
> +    int ret;
> +    if (libqb_global_data.init_flag == 0) {
> +        libqb_global_data.mutex = g_malloc(sizeof(pthread_mutex_t));
> +        ret = pthread_mutex_init(libqb_global_data.mutex, NULL);
> +        g_assert(ret == 0);
> +        libqb_global_data.init_flag = 1;
> +    }
> +}
> +
> +const char *qb_fmttype2str(QBlockFormat fmt_type)
> +{
> +    int i = 0;
> +    LibqbFormatStrMapping *tb = libqb_fmtstr_table;
>  
> -int libqb_test(void)
> +    if ((fmt_type <= QB_FMT_NONE) || (fmt_type >= QB_FMT_MAX)) {
> +        return NULL;
> +    }
> +    while (tb[i].fmt_str != NULL) {
> +        if (tb[i].fmt_type == fmt_type) {
> +            return tb[i].fmt_str;
> +        }
> +        i++;
> +    }
> +    return NULL;
> +}
> +
> +QBlockFormat qb_str2fmttype(const char *fmt_str)
>  {
> +    int i = 0;
> +    LibqbFormatStrMapping *tb = libqb_fmtstr_table;
> +
> +    if (fmt_str == NULL) {
> +        return QB_FMT_NONE;
> +    }
> +    while (tb[i].fmt_str != NULL) {
> +        if ((strcmp(fmt_str, tb[i].fmt_str) == 0)) {
> +            return tb[i].fmt_type;
> +        }
> +        i++;
> +    }
> +    return QB_FMT_NONE;
> +}
> +
> +static void set_context_err(QBlockContext *context, int err_ret,
> +                            const char *fmt, ...)
> +{
> +    va_list ap;
> +
> +    if (context->g_error != NULL) {
> +        g_error_free(context->g_error);
> +    }
> +
> +    va_start(ap, fmt);
> +    context->g_error = g_error_new_valist(G_LIBQBLOCK_ERROR, err_ret, fmt, ap);
> +    va_end(ap);
> +
> +    context->err_ret = err_ret;
> +    if (err_ret == QB_ERR_INTERNAL_ERR) {
> +        context->err_no = -errno;
> +    } else {
> +        context->err_no = 0;
> +    }
> +}
> +
> +int qb_context_new(QBlockContext **p_context)
> +{
> +    *p_context = g_malloc0_n(1, sizeof(QBlockContext));
> +
> +    /* Following will be replaced when multi-thread aio comes. Although this
> +lib is not thread safe now, add a lock here ahead is not bad. */
> +    pthread_mutex_t *mutex = libqb_global_data.mutex;
> +    pthread_mutex_lock(mutex);
> +    static int aio_init_flag;
> +    if (aio_init_flag == 0) {
> +        libqblock_aio_init();
> +        aio_init_flag = 1;
> +    }
> +    pthread_mutex_unlock(mutex);
>      return 0;
>  }
> +
> +void qb_context_delete(QBlockContext **p_context)
> +{
> +    if ((*p_context)->g_error != NULL) {
> +        g_error_free((*p_context)->g_error);
> +    }
> +    QB_FREE(*p_context);
> +    return;
> +}
> +
> +int qb_image_new(QBlockContext *context,
> +                 QBlockImage **p_qbi)
> +{
> +    *p_qbi = g_malloc0_n(1, sizeof(QBlockImage));
> +    /* Assume ref_count is already set to 0 in malloc. */
> +    (*p_qbi)->ref_count++;
> +    (*p_qbi)->bdrvs = bdrv_new("hda");
> +    if ((*p_qbi)->bdrvs == NULL) {
> +        QB_FREE(*p_qbi);
> +        set_context_err(context, QB_ERR_INTERNAL_ERR,
> +                       "failed to create the driver.");
> +        return context->err_ret;
> +    }
> +    return 0;
> +}
> +
> +void qb_image_delete(QBlockContext *context,
> +                     QBlockImage **p_qbi)
> +{
> +    (*p_qbi)->ref_count--;
> +    if ((*p_qbi)->ref_count > 0) {
> +        return;
> +    }
> +    if ((*p_qbi)->filename != NULL) {
> +        qb_close(context, *p_qbi);
> +    }
> +    if ((*p_qbi)->bdrvs != NULL) {
> +        bdrv_delete((*p_qbi)->bdrvs);
> +        (*p_qbi)->bdrvs = NULL;
> +    }
> +    QB_FREE(*p_qbi);
> +    return;
> +}
> +
> +int qb_loc_info_new(QBlockContext *context,
> +                    QBlockLocationInfo **p_loc)
> +{
> +    *p_loc = g_malloc0_n(1, sizeof(QBlockLocationInfo));
> +    return 0;
> +}
> +
> +void qb_loc_info_delete(QBlockContext *context,
> +                         QBlockLocationInfo **p_loc)
> +{
> +    QB_FREE(*p_loc);
> +}
> +
> +int qb_fmt_info_new(QBlockContext *context,
> +                    QBlockFormatInfo **p_fmt)
> +{
> +    *p_fmt = g_malloc0_n(1, sizeof(QBlockFormatInfo));
> +    return 0;
> +}
> +
> +void qb_fmt_info_delete(QBlockContext *context,
> +                        QBlockFormatInfo **p_fmt)
> +{
> +    QB_FREE(*p_fmt);
> +}
> +
> +/* return 0 if every thing is fine */
> +static int loc_check_params(QBlockContext *context,
> +                            QBlockLocationInfo *loc)
> +{
> +    context->err_ret = 0;
> +
> +    switch (loc->prot_type) {
> +    case QB_PROTO_FILE:
> +        if (loc->o_file.filename == NULL) {
> +            set_context_err(context, QB_ERR_INVALID_PARAM,
> +                           "Filename was not set.");
> +            goto out;
> +        }
> +        if (path_has_protocol(loc->o_file.filename) > 0) {
> +            set_context_err(context, QB_ERR_INVALID_PARAM,
> +                           "filename [%s] had protocol.",
> +                           loc->o_file.filename);
> +            goto out;
> +        }
> +        break;
> +    default:
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                       "Protocol type [%d] was not valid.",
> +                       loc->prot_type);
> +        break;
> +    }
> +
> + out:
> +    return context->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(QBlockContext *context,
> +                        QBlockLocationInfo *loc,
> +                        char **p_filename)
> +{
> +    context->err_ret = 0;
> +
> +    if (*p_filename != NULL) {
> +        QB_FREE(*p_filename);
> +    }
> +    switch (loc->prot_type) {
> +    case QB_PROTO_FILE:
> +        *p_filename = g_strdup(loc->o_file.filename);
> +        break;
> +    default:
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                 "protocol type [%d] is not supported.",
> +                  loc->prot_type);
> +        break;
> +    }
> +
> +    return context->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(QBlockContext *context,
> +                        QBlockLocationInfo *loc,
> +                        const char *filename)
> +{
> +    context->err_ret = 0;
> +
> +    if (path_has_protocol(filename) > 0) {
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                     "Filename [%s] had protocol, not supported now.",
> +                     filename);
> +        goto out;
> +    }
> +
> +    loc->prot_type = QB_PROTO_FILE;
> +    switch (loc->prot_type) {
> +    case QB_PROTO_FILE:
> +        loc->o_file.filename = g_strdup(filename);
> +        break;
> +    default:
> +        break;
> +    }
> +
> + out:
> +    return context->err_ret;
> +}
> +
> +/* return 0 if OK, or qblock error number */
> +static int set_backing_file_options(QBlockContext *context,
> +                                    QEMUOptionParameter *param,
> +                                    QBlockLocationInfo *loc,
> +                                    QBlockFormat *fmt)
> +{
> +    char *backing_filename = NULL;
> +    const char *fmtstr_backing = NULL;
> +    int ret = 0;
> +
> +    if (loc == NULL) {
> +        goto out;
> +    }
> +
> +    ret = loc2filename(context, loc, &backing_filename);
> +    /* ret can < 0 if loc have not been set, mean user did not specify backing
> +       file, so need to check return value */
> +
> +    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:
> +    g_free(backing_filename);
> +    return ret;
> +}
> +
> +int qb_create(QBlockContext *context,
> +              QBlockImage *qbi,
> +              QBlockLocationInfo *loc,
> +              QBlockFormatInfo *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;
> +    QBlockFormatOptionsCOW *o_cow = NULL;
> +    QBlockFormatOptionsQED *o_qed = NULL;
> +    QBlockFormatOptionsQCOW *o_qcow = NULL;
> +    QBlockFormatOptionsQCOW2 *o_qcow2 = NULL;
> +    QBlockFormatOptionsRAW *o_raw = NULL;
> +    QBlockFormatOptionsRBD *o_rbd = NULL;
> +    QBlockFormatOptionsSD *o_sd = NULL;
> +    QBlockFormatOptionsVDI *o_vdi = NULL;
> +    QBlockFormatOptionsVMDK *o_vmdk = NULL;
> +    QBlockFormatOptionsVPC *o_vpc = NULL;
> +
> +
> +    /* check parameters */
> +    if (flag & (~LIBQBLOCK_O_VALID_MASK)) {
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                           "invalid flag was set.");
> +        ret = context->err_ret;
> +        goto out;
> +    }
> +
> +    if ((loc == NULL) || (qbi == NULL) || (fmt == NULL)) {
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                          "Got unexpected NULL pointer in parameters.");
> +        ret = context->err_ret;
> +        goto out;
> +    }
> +
> +    ret = loc_check_params(context, loc);
> +    if (ret != 0) {
> +        goto out;
> +    }
> +
> +    /* internal translate */
> +    ret = loc2filename(context, loc, &filename);
> +    if (ret != 0) {
> +        goto out;
> +    }
> +
> +    fmtstr = qb_fmttype2str(fmt->fmt_type);
> +    if (fmtstr == NULL) {
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                 "Got unexpected NULL pointer in parameters.");
> +        ret = context->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);
> +
> +    bd_ret = set_option_parameter_int(param,
> +                                BLOCK_OPT_SIZE, fmt->virt_size);
> +    assert(bd_ret == 0);
> +
> +    switch (fmt->fmt_type) {
> +    case QB_FMT_COW:
> +        o_cow = &fmt->o_cow;
> +        /* do not need to check loc, it may be not set */
> +        ret = set_backing_file_options(context, param,
> +                                       &o_cow->backing_loc, NULL);
> +        if (ret != 0) {
> +            goto out;
> +        }
> +        break;
> +    case QB_FMT_QED:
> +        o_qed = &fmt->o_qed;
> +        ret = set_backing_file_options(context, 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->o_qcow;
> +        ret = set_backing_file_options(context, 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->o_qcow2;
> +        ret = set_backing_file_options(context, 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 != QB_FMT_QCOW2_COMPAT_DEFAULT) {
> +            tmp = o_qcow2->cpt_lv == QB_FMT_QCOW2_COMPAT_V0_10 ? "0.10" : "1.1";
> +            bd_ret = set_option_parameter(param,
> +                              BLOCK_OPT_COMPAT_LEVEL, tmp);
> +            assert(bd_ret == 0);
> +        }
> +
> +        if (o_qcow2->pre_mode != QB_FMT_QCOW2_PREALLOC_DEFAULT) {
> +            tmp = o_qcow2->pre_mode == QB_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->o_raw;
> +        /* do nothing now. */
> +        break;
> +    case QB_FMT_RBD:
> +        o_rbd = &fmt->o_rbd;
> +        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->o_sd;
> +        ret = set_backing_file_options(context, param,
> +                                       &o_sd->backing_loc, NULL);
> +        if (ret != 0) {
> +            goto out;
> +        }
> +        if (o_sd->pre_mode != QB_FMT_SD_PREALLOC_DEFAULT) {
> +            tmp = o_sd->pre_mode == QB_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->o_vdi;
> +        /* 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 != QB_FMT_VDI_PREALLOC_DEFAULT) {
> +            tmp_bool = o_sd->pre_mode == QB_FMT_VDI_PREALLOC_METADATA ?
> +                                                     true : false;
> +            set_option_parameter_int(param, "static", tmp_bool);
> +        }
> +        break;
> +    case QB_FMT_VMDK:
> +        o_vmdk = &fmt->o_vmdk;
> +        ret = set_backing_file_options(context, param,
> +                                       &o_vmdk->backing_loc, NULL);
> +        if (ret != 0) {
> +            goto out;
> +        }
> +
> +        if (o_vmdk->cpt_lv != QB_FMT_VMDK_COMPAT_DEFAULT) {
> +            tmp_bool = o_vmdk->cpt_lv == QB_FMT_VMDK_COMPAT_VMDKV6_TRUE ?
> +                                                     true : false;
> +            bd_ret = set_option_parameter_int(param, BLOCK_OPT_COMPAT6,
> +                                                     tmp_bool);
> +            assert(bd_ret == 0);
> +        }
> +        if (o_vmdk->subfmt != QB_FMT_VMDK_SUBFMT_DEFAULT) {
> +            switch (o_vmdk->subfmt) {
> +            case QB_FMT_VMDK_SUBFMT_MONOLITHIC_SPARSE:
> +                tmp = "monolithicSparse";
> +                break;
> +            case QB_FMT_VMDK_SUBFMT_MONOLITHIC_FLAT:
> +                tmp = "monolithicFlat";
> +                break;
> +            case QB_FMT_VMDK_SUBFMT_TWOGBMAX_EXTENT_SPARSE:
> +                tmp = "twoGbMaxExtentSparse";
> +                break;
> +            case QB_FMT_VMDK_SUBFMT_TWOGBMAX_EXTENT_FLAT:
> +                tmp = "twoGbMaxExtentFlat";
> +                break;
> +            case QB_FMT_VMDK_SUBFMT_STREAM_OPTIMIZED:
> +                tmp = "streamOptimized";
> +                break;
> +            default:
> +                set_context_err(context, QB_ERR_INVALID_PARAM,
> +                    "invalid VMDK sumfmt type %d was set.", o_vmdk->subfmt);
> +                ret = context->err_ret;
> +                goto out;
> +                break;
> +            }
> +            bd_ret = set_option_parameter(param,
> +                              BLOCK_OPT_SUBFMT, tmp);
> +            assert(bd_ret == 0);
> +        }
> +        break;
> +    case QB_FMT_VPC:
> +        o_vpc = &fmt->o_vpc;
> +        if (o_vpc->subfmt != QB_FMT_VPC_SUBFMT_DEFAULT) {
> +            tmp = o_vpc->subfmt == QB_FMT_VPC_SUBFMT_DYNAMIC ?
> +                                               "dynamic" : "fixed";
> +            bd_ret = set_option_parameter(param,
> +                               BLOCK_OPT_SUBFMT, tmp);
> +            assert(bd_ret == 0);
> +        }
> +        break;
> +    default:
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                        "invalid format type %d was set.", fmt->fmt_type);
> +        ret = context->err_ret;
> +        goto out;
> +        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_context_err(context, QB_ERR_INVALID_PARAM,
> +                          "Backing file is the same with new file.");
> +            ret = context->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_context_err(context, QB_ERR_INVALID_PARAM,
> +                               "Failed to open the backing file.");
> +                ret = context->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_context_err(context, QB_ERR_INTERNAL_ERR,
> +                           "Neither size or backing file was not set.");
> +            ret = context->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_context_err(context, QB_ERR_INTERNAL_ERR, errstr);
> +        ret = context->err_ret;
> +    }
> +
> +out:
> +    free_option_parameters(create_options);
> +    free_option_parameters(param);
> +    g_free(filename);
> +    if (bs) {
> +        bdrv_delete(bs);
> +    }
> +
> +    return ret;
> +}
> +
> +int qb_open(QBlockContext *context,
> +            QBlockImage *qbi,
> +            QBlockLocationInfo *loc,
> +            QBlockFormatInfo *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_context_err(context, QB_ERR_INVALID_PARAM,
> +                      "Invalid flag was set.");
> +        ret = context->err_ret;
> +        goto out;
> +    }
> +
> +    if ((loc == NULL) || (qbi == NULL)) {
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                      "Got unexpected NULL pointer in parameters.");
> +        ret = context->err_ret;
> +        goto out;
> +    }
> +
> +    ret = loc_check_params(context, loc);
> +    if (ret != 0) {
> +        goto out;
> +    }
> +
> +    /* internal translate */
> +    ret = loc2filename(context, 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 opening */
> +    bs = qbi->bdrvs;
> +    bd_ret = bdrv_open(bs, filename, flag, bd);
> +    if (bd_ret < 0) {
> +        set_context_err(context, QB_ERR_INTERNAL_ERR,
> +                      "Failed in opening with driver, bd_ret is %d.", bd_ret);
> +        ret = context->err_ret;
> +        goto out;
> +    }
> +
> +    if (qbi->filename != NULL) {
> +        g_free(qbi->filename);
> +    }
> +    qbi->filename = g_strdup(filename);
> +
> + out:
> +    g_free(filename);
> +    return ret;
> +}
> +
> +void qb_close(QBlockContext *context,
> +              QBlockImage *qbi)
> +{
> +    BlockDriverState *bs;
> +
> +    bs = qbi->bdrvs;
> +
> +    if (qbi->filename != NULL) {
> +        QB_FREE(qbi->filename);
> +        bdrv_close(bs);
> +    }
> +    return;
> +}
> +
> +int32_t qb_read(QBlockContext *context,
> +                QBlockImage *qbi,
> +                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;
> +    uint32_t remains;
> +
> +    context->err_ret = 0;
> +    bs = qbi->bdrvs;
> +
> +    if (len <= 0) {
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                      "Param len is less or equal to zero.");
> +        return context->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 alligned, need to read/write this sector. */
> +        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
> +        if (bd_ret < 0) {
> +            set_context_err(context, QB_ERR_INTERNAL_ERR,
> +                           "I/O errors.");
> +            context->err_no = bd_ret;
> +            return context->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 alligned. */
> +    if (remains >= BDRV_SECTOR_SIZE) {
> +        sector_num = remains >> BDRV_SECTOR_BITS;
> +        bd_ret = bdrv_read(bs, sector_start, p, sector_num);
> +        if (bd_ret < 0) {
> +            set_context_err(context, QB_ERR_INTERNAL_ERR,
> +                           "I/O errors.");
> +            context->err_no = bd_ret;
> +            return context->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_context_err(context, QB_ERR_INTERNAL_ERR,
> +                           "I/O errors.");
> +            context->err_no = bd_ret;
> +            return context->err_ret;
> +        }
> +        memcpy(p, temp_buf, remains);
> +        remains -= remains;
> +    }
> +
> +    return len-remains;
> +}
> +
> +int32_t qb_write(QBlockContext *context,
> +                 QBlockImage *qbi,
> +                 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;
> +    uint32_t remains;
> +
> +    context->err_ret = 0;
> +    bs = qbi->bdrvs;
> +
> +    if (len <= 0) {
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                      "Param len is less or equal to zero.");
> +        return context->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 alligned, need to read/write this sector. */
> +        bd_ret = bdrv_read(bs, sector_start, temp_buf, 1);
> +        if (bd_ret < 0) {
> +            set_context_err(context, QB_ERR_INTERNAL_ERR,
> +                           "I/O errors.");
> +            context->err_no = bd_ret;
> +            return context->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_context_err(context, QB_ERR_INTERNAL_ERR,
> +                           "I/O errors.");
> +            context->err_no = bd_ret;
> +            return context->err_ret;
> +        }
> +        remains -= cp_len;
> +        p += cp_len;
> +        sector_start++;
> +    }
> +
> +    /* now start position is alligned. */
> +    if (remains >= BDRV_SECTOR_SIZE) {
> +        sector_num = remains >> BDRV_SECTOR_BITS;
> +        bd_ret = bdrv_write(bs, sector_start, p, sector_num);
> +        if (bd_ret < 0) {
> +            set_context_err(context, QB_ERR_INTERNAL_ERR,
> +                           "I/O errors.");
> +            context->err_no = bd_ret;
> +            return context->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_context_err(context, QB_ERR_INTERNAL_ERR,
> +                           "I/O errors.");
> +            context->err_no = bd_ret;
> +            return context->err_ret;
> +        }
> +        memcpy(temp_buf, p, remains);
> +        bd_ret = bdrv_write(bs, sector_start, temp_buf, 1);
> +        if (bd_ret < 0) {
> +            set_context_err(context, QB_ERR_INTERNAL_ERR,
> +                           "I/O errors.");
> +            context->err_no = bd_ret;
> +            return context->err_ret;
> +        }
> +        remains -= remains;
> +    }
> +
> +    return len-remains;
> +}
> +
> +int qb_flush(QBlockContext *context,
> +             QBlockImage *qbi)
> +{
> +    int bd_ret;
> +    BlockDriverState *bs;
> +
> +    context->err_ret = 0;
> +    bs = qbi->bdrvs;
> +    bd_ret = bdrv_flush(bs);
> +    if (bd_ret < 0) {
> +        set_context_err(context, QB_ERR_INTERNAL_ERR,
> +                       "Internal error.");
> +    }
> +    return context->err_ret;
> +}
> +
> +int qb_check_allocation(QBlockContext *context,
> +                        QBlockImage *qbi,
> +                        uint64_t start,
> +                        int64_t length,
> +                        int *pstatus,
> +                        int64_t *plength)
> +{
> +    int ret;
> +    int sector_start, sector_num, num;
> +    BlockDriverState *bs;
> +    unsigned int real_len, ret_len;
> +
> +    context->err_ret = 0;
> +    bs = qbi->bdrvs;
> +
> +    /* Now bdrv_is_allocated take nb_sectors as int with unit sector, but this
> +    API take length as int64_t with unit bytes, so a check is needed to ensure
> +    no silent error will happen in translating bytes to sector later if length
> +    is too big.
> +       max_sectors is set to INT_MAX - 1 in case of that real_len is bigger
> +    than length.
> +       Gcc issue? a = (0x7ffffffe << 9) was compiled to 0xfffffffffffffc00, it
> +    should be 0xfffffffc00, so use variable instead of direct macro
> +    calculation. */
> +    int64_t max_sectors = INT_MAX - 1;
> +    int64_t max_bytes = max_sectors << BDRV_SECTOR_BITS;
> +
> +    if (length > max_bytes) {
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                       "Length is too big.");
> +        goto out;
> +    }
> +
> +    if (length <= 0) {
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                       "Length is not valid.");
> +        goto out;
> +    }
> +
> +    if (qbi->filename == NULL) {
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                       "Image was not opened first.");
> +        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_context_err(context, 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 context->err_ret;
> +}
> +
> +static void qb_setup_info_addr(const QBlockStaticInfo *info,
> +                               QBlockStaticInfoAddr *info_addr)
> +{
> +    const QBlockLocationInfo *backing_loc = NULL;
> +    const bool *encrypt = NULL;
> +    const QBlockFormatInfo *fmt = &info->fmt;
> +
> +    memset(info_addr, 0, sizeof(QBlockStaticInfoAddr));
> +
> +    switch (fmt->fmt_type) {
> +    case QB_FMT_COW:
> +        backing_loc = &fmt->o_cow.backing_loc;
> +        break;
> +    case QB_FMT_QED:
> +        backing_loc = &fmt->o_qed.backing_loc;
> +        break;
> +    case QB_FMT_QCOW:
> +        backing_loc = &fmt->o_qcow.backing_loc;
> +        encrypt = &fmt->o_qcow.encrypt;
> +        break;
> +    case QB_FMT_QCOW2:
> +        backing_loc = &fmt->o_qcow2.backing_loc;
> +        encrypt = &fmt->o_qcow2.encrypt;
> +        break;
> +    case QB_FMT_RAW:
> +        break;
> +    case QB_FMT_RBD:
> +        break;
> +    case QB_FMT_SHEEPDOG:
> +        backing_loc = &fmt->o_sd.backing_loc;
> +        break;
> +    case QB_FMT_VDI:
> +        break;
> +    case QB_FMT_VMDK:
> +        backing_loc = &fmt->o_vmdk.backing_loc;
> +        break;
> +    case QB_FMT_VPC:
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    info_addr->backing_loc = (QBlockLocationInfo *)backing_loc;
> +    info_addr->encrypt = (bool *)encrypt;
> +    return;
> +}
> +
> +const uint64_t *qb_get_virt_size(const QBlockStaticInfo *info)
> +{
> +    return &info->fmt.virt_size;
> +}
> +
> +const QBlockLocationInfo *qb_get_backing_loc(const QBlockStaticInfo *info)
> +{
> +    QBlockStaticInfoAddr addr;
> +    qb_setup_info_addr(info, &addr);
> +    return addr.backing_loc;
> +}
> +
> +const bool *qb_get_encrypt(const QBlockStaticInfo *info)
> +{
> +    QBlockStaticInfoAddr addr;
> +    qb_setup_info_addr(info, &addr);
> +    return addr.encrypt;
> +}
> +
> +int qb_info_image_static_get(QBlockContext *context,
> +                             QBlockImage *qbi,
> +                             QBlockStaticInfo **p_info)
> +{
> +    int ret = 0;
> +    BlockDriverState *bs;
> +    QBlockStaticInfo *info;
> +    QBlockStaticInfoAddr addr;
> +    const char *fmt_str;
> +    uint64_t total_sectors;
> +    char backing_filename[LIBQB_FILENAME_MAX];
> +
> +    if (qbi->filename == NULL) {
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                       "Block Image was not opened.");
> +        ret = context->err_ret;
> +        goto out;
> +    }
> +
> +    info = g_malloc0_n(1, sizeof(QBlockStaticInfo));
> +
> +    bs = qbi->bdrvs;
> +
> +    ret = filename2loc(context,
> +                       &info->loc,
> +                       qbi->filename);
> +    if (ret < 0) {
> +        goto free;
> +    }
> +
> +    fmt_str = bdrv_get_format_name(bs);
> +    info->fmt.fmt_type = qb_str2fmttype(fmt_str);
> +    if (info->fmt.fmt_type == QB_FMT_NONE) {
> +        set_context_err(context, QB_ERR_INVALID_PARAM,
> +                       "Image format %s not valid.", fmt_str);
> +        ret = context->err_ret;
> +        goto free;
> +    }
> +
> +    /* we got the format type and basic location info now, setup the struct
> +    pointer to the internal members */
> +    qb_setup_info_addr(info, &addr);
> +
> +    bdrv_get_geometry(bs, &total_sectors);
> +    info->fmt.virt_size = total_sectors * BDRV_SECTOR_SIZE;
> +
> +    if (addr.encrypt != NULL) {
> +        *(addr.encrypt) = bdrv_is_encrypted(bs);
> +    }
> +
> +    bdrv_get_full_backing_filename(bs, backing_filename,
> +                                   sizeof(backing_filename));
> +    if (backing_filename[0] != '\0') {
> +        assert(addr.backing_loc != NULL);
> +        ret = filename2loc(context,
> +                           addr.backing_loc,
> +                           backing_filename);
> +        if (ret < 0) {
> +            goto free;
> +        }
> +    }
> +
> +    info->sector_size = BDRV_SECTOR_SIZE;
> +    *p_info = info;
> +
> + out:
> +    return ret;
> + free:
> +    qb_info_image_static_delete(context, &info);
> +    return ret;
> +}
> +
> +/* free locations if it has string allocated on heap. */
> +static void loc_free(QBlockLocationInfo *loc)
> +{
> +    switch (loc->prot_type) {
> +    case QB_PROTO_FILE:
> +        g_free((void *)(loc->o_file.filename));
> +        loc->o_file.filename = NULL;
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +/* free fmt related resoure. */
> +static void fmt_free(QBlockFormatInfo *fmt)
> +{
> +    switch (fmt->fmt_type) {
> +    case QB_FMT_COW:
> +        loc_free(&fmt->o_cow.backing_loc);
> +        break;
> +    case QB_FMT_QED:
> +        loc_free(&fmt->o_qed.backing_loc);
> +        break;
> +    case QB_FMT_QCOW:
> +        loc_free(&fmt->o_qcow.backing_loc);
> +        break;
> +    case QB_FMT_QCOW2:
> +        loc_free(&fmt->o_qcow2.backing_loc);
> +        break;
> +    case QB_FMT_RAW:
> +        break;
> +    case QB_FMT_RBD:
> +        break;
> +    case QB_FMT_SHEEPDOG:
> +        loc_free(&fmt->o_sd.backing_loc);
> +        break;
> +    case QB_FMT_VDI:
> +        break;
> +    case QB_FMT_VMDK:
> +        loc_free(&fmt->o_vmdk.backing_loc);
> +        break;
> +    case QB_FMT_VPC:
> +        break;
> +    default:
> +        break;
> +    }
> +    return;
> +}
> +
> +void qb_info_image_static_delete(QBlockContext *context,
> +                                 QBlockStaticInfo **p_info)
> +{
> +    loc_free(&(*p_info)->loc);
> +    fmt_free(&(*p_info)->fmt);
> +    QB_FREE(*p_info);
> +}
> +
> +QBlockLocationInfo *qb_loc_info_dup(const QBlockLocationInfo *prot)
> +{
> +    QBlockLocationInfo *p = g_malloc0_n(1, sizeof(QBlockLocationInfo));
> +    p->prot_type = prot->prot_type;
> +    switch (p->prot_type) {
> +    case QB_PROTO_FILE:
> +        p->o_file.filename =
> +                          g_strdup(prot->o_file.filename);
> +        break;
> +    default:
> +        break;
> +    }
> +    return p;
> +}
> 

  reply	other threads:[~2012-11-26  8:34 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-11-24  9:27 [Qemu-devel] [PATCH V11 0/7] libqblock qemu block layer library Wenchao Xia
2012-11-24  9:27 ` [Qemu-devel] [PATCH V11 1/7] Build system fix distclean error for pixman Wenchao Xia
2012-11-24 21:02   ` Blue Swirl
2012-11-24  9:27 ` [Qemu-devel] [PATCH V11 2/7] Build system clean tests directory clearly Wenchao Xia
2012-11-24  9:27 ` [Qemu-devel] [PATCH V11 3/7] block export function path_has_protocol Wenchao Xia
2012-11-24  9:27 ` [Qemu-devel] [PATCH V11 4/7] libqblock build system Wenchao Xia
2012-11-26  7:36   ` Paolo Bonzini
2012-11-27  3:07     ` Wenchao Xia
2012-11-27  9:09       ` Paolo Bonzini
2012-11-24  9:27 ` [Qemu-devel] [PATCH V11 5/7] libqblock API design and type defines Wenchao Xia
2012-11-24  9:27 ` [Qemu-devel] [PATCH V11 6/7] libqblock API implement Wenchao Xia
2012-11-26  8:34   ` Paolo Bonzini [this message]
2012-11-27  3:22     ` Wenchao Xia
2012-11-27  9:11       ` Paolo Bonzini
2012-11-24  9:27 ` [Qemu-devel] [PATCH V11 7/7] libqblock test example Wenchao Xia

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=50B32979.6010905@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=aliguori@us.ibm.com \
    --cc=blauwirbel@gmail.com \
    --cc=kwolf@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@gmail.com \
    --cc=xiawenc@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.