qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [qemu-devel] [PATCH V2 2/3] [RFC] libqblock-API design


From: Blue Swirl
Subject: Re: [Qemu-devel] [qemu-devel] [PATCH V2 2/3] [RFC] libqblock-API design
Date: Thu, 9 Aug 2012 17:36:19 +0000

On Thu, Aug 9, 2012 at 10:12 AM, Wenchao Xia <address@hidden> wrote:
>   This patch is the API design.
>
> Signed-off-by: Wenchao Xia <address@hidden>
> ---
>  libqblock.c |  670 
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  libqblock.h |  447 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 1117 insertions(+), 0 deletions(-)
>  create mode 100644 libqblock.c
>  create mode 100644 libqblock.h
>
> diff --git a/libqblock.c b/libqblock.c
> new file mode 100644
> index 0000000..52e46dc
> --- /dev/null
> +++ b/libqblock.c
> @@ -0,0 +1,670 @@
> +/*
> + * Copyright IBM Corp. 2012
> + *
> + * Authors:
> + *  Wenchao Xia <address@hidden>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA

Current address of FSF is:

51 Franklin Street, Fifth Floor
Boston, MA 02110-1301
USA

However, please use the recommended web version like other files.

> + */
> +
> +#include "libqblock.h"
> +
> +#include <unistd.h>
> +#include "block.h"
> +#include "block_int.h"
> +
> +#define FUNC_FREE free
> +#define FUNC_MALLOC malloc
> +#define FUNC_CALLOC calloc
> +
> +#define CLEAN_FREE(p) { \
> +        FUNC_FREE(p); \
> +        (p) = NULL; \
> +}

I don't think this is enough since block functions may use glib memory
allocation. Probably the block files have to be compiled with wrappers
for g_malloc and friends.

> +
> +/* details should be hidden to user */
> +struct QBlockState {
> +    BlockDriverState *bdrvs;
> +    char *filename;
> +    const char *err_msg;
> +    int err_no;
> +};
> +
> +static void set_err_nomem(struct QBlockState *qbs)
> +{
> +    qbs->err_msg = NULL;
> +    qbs->err_no = 0;
> +}
> +
> +void libqblock_init(void)
> +{
> +    bdrv_init();
> +    return;

Useless return.

> +}
> +
> +int qb_state_new(struct QBlockState **qbs)
> +{
> +    *qbs = FUNC_CALLOC(1, sizeof(struct QBlockState));
> +    if (*qbs == NULL) {
> +        return QB_ERR_MEM_ERR;
> +    }
> +    (*qbs)->bdrvs = bdrv_new("hda");
> +    if ((*qbs)->bdrvs == NULL) {
> +        CLEAN_FREE(*qbs);
> +        return QB_ERR_INTERNAL_ERR;
> +    }
> +    return 0;
> +}
> +
> +void qb_state_free(struct QBlockState **qbs)
> +{
> +    CLEAN_FREE((*qbs)->filename);
> +    if ((*qbs)->bdrvs == NULL) {
> +        bdrv_delete((*qbs)->bdrvs);
> +        (*qbs)->bdrvs = NULL;
> +    }
> +    CLEAN_FREE(*qbs);
> +    return;

Remove.

> +}
> +
> +static const char *fmt2str(enum QBlockFormat fmt)
> +{
> +    const char *ret = NULL;
> +    switch (fmt) {
> +    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;
> +}
> +
> +static enum QBlockFormat str2fmt(const char *fmt)
> +{
> +    enum QBlockFormat ret = QB_FMT_NONE;
> +    if (0 == strcmp(fmt, "cow")) {

Please use natural order:
strcmp(fmt, "cow") == 0

> +        ret = QB_FMT_COW;
> +    } else if (0 == strcmp(fmt, "qed")) {
> +        ret = QB_FMT_QED;
> +    } else if (0 == strcmp(fmt, "qcow")) {
> +        ret = QB_FMT_QCOW;
> +    } else if (0 == strcmp(fmt, "qcow2")) {
> +        ret = QB_FMT_QCOW2;
> +    } else if (0 == strcmp(fmt, "raw")) {
> +        ret = QB_FMT_RAW;
> +    } else if (0 == strcmp(fmt, "rbd")) {
> +        ret = QB_FMT_RBD;
> +    } else if (0 == strcmp(fmt, "sheepdog")) {
> +        ret = QB_FMT_SHEEPDOG;
> +    } else if (0 == strcmp(fmt, "vdi")) {
> +        ret = QB_FMT_VDI;
> +    } else if (0 == strcmp(fmt, "vmdk")) {
> +        ret = QB_FMT_VMDK;
> +    } else if (0 == strcmp(fmt, "vpc")) {
> +        ret = QB_FMT_VPC;
> +    }
> +    return ret;
> +}
> +
> +/* copy information and take care the member difference in differect version.
> +   Assuming all new member are added in the tail, struct size is the first
> +   member, this is old to new version, src have its struct_size set. */
> +static void qboo_adjust_o2n(struct QBlockOptionOpen *dest,
> +                            struct QBlockOptionOpen *src)
> +{
> +    /* for simple it does memcpy now, need to take care of embbed structure 
> */
> +    memcpy(dest, src, src->struct_size);

Since later there will be a field by field copy, I'd use:
*dest = *src;

> +}
> +
> +int qb_open(struct QBlockState *qbs, struct QBlockOptionOpen *op)
> +{
> +    int ret = 0, bd_ret;
> +    BlockDriverState *bs;
> +    struct QBlockOptionOpen qboo;
> +    BlockDriver *bd;
> +    const char *fmt;
> +
> +    /* take care of user settings */
> +    qboo_adjust_o2n(&qboo, op);
> +
> +    /* check parameters */
> +    if (qboo.o_loc.filename == NULL) {
> +        ret = QB_ERR_INVALID_PARAM;
> +        qbs->err_msg = "filename was not set.";
> +        qbs->err_no = 0;
> +        goto out;
> +    }
> +
> +    if (path_has_protocol(qboo.o_loc.filename) > 0) {
> +        ret = QB_ERR_INVALID_PARAM;
> +        qbs->err_msg = "filename have protocol.";

had

> +        qbs->err_no = 0;
> +        goto out;
> +    }
> +
> +    if (qboo.o_loc.protocol >= QB_PROTO_MAX) {
> +        ret = QB_ERR_INVALID_PARAM;
> +        qbs->err_msg = "protocol was not supported.";
> +        qbs->err_no = 0;
> +        goto out;
> +    }
> +
> +    bd = NULL;
> +    fmt = fmt2str(qboo.o_fmt_type);
> +    if (fmt != NULL) {
> +        bd = bdrv_find_format(fmt);
> +        assert(bd != NULL);
> +    }

What should happen in the NULL fmt case, goto out?

> +
> +
> +    /* do real openning */
> +    bs = qbs->bdrvs;
> +    bd_ret = bdrv_open(bs, qboo.o_loc.filename, qboo.o_flag, bd);
> +    if (bd_ret < 0) {
> +        ret = QB_ERR_INTERNAL_ERR;
> +        qbs->err_msg = "failed to open the file.";
> +        qbs->err_no = -errno;
> +        goto out;
> +    }
> +
> +    if (qbs->filename != NULL) {
> +        FUNC_FREE(qbs->filename);
> +    }
> +    qbs->filename = strdup(qboo.o_loc.filename);
> +    if (qbs->filename == NULL) {
> +        ret = QB_ERR_INVALID_PARAM;
> +        set_err_nomem(qbs);
> +        goto out;
> +    }
> +
> + out:
> +    return ret;
> +}
> +
> +void qb_close(struct QBlockState *qbs)
> +{
> +    BlockDriverState *bs;
> +
> +    bs = qbs->bdrvs;
> +    bdrv_close(bs);
> +    return;

Delete return

> +}
> +
> +/* copy information and take care the member difference in differect version.
> +   Assuming all new member are added in the tail, struct size is the first
> +   member, this is old to new version, src have its struct_size set. */
> +static void qboc_adjust_o2n(struct QBlockOptionCreate *dest,
> +                            struct QBlockOptionCreate *src)
> +{
> +    /* for simple it does memcpy now, need to take care of embbed structure 
> */
> +    memcpy(dest, src, src->struct_size);
> +}
> +
> +int qb_create(struct QBlockState *qbs, struct QBlockOptionCreate *op)
> +{
> +    int ret = 0, bd_ret;
> +    BlockDriverState *bs = NULL;
> +    BlockDriver *drv = NULL, *backing_drv = NULL;
> +    struct QBlockOptionCreate qbco;
> +    const char *fmt = NULL, *fmt_backing_str = NULL, *tmp;
> +    QEMUOptionParameter *param = NULL, *create_options = NULL;
> +    QEMUOptionParameter *backing_fmt, *backing_file, *size;
> +    struct QBlockOption_cow *o_cow = NULL;
> +    struct QBlockOption_qed *o_qed = NULL;
> +    struct QBlockOption_qcow *o_qcow = NULL;
> +    struct QBlockOption_qcow2 *o_qcow2 = NULL;
> +    struct QBlockOption_raw *o_raw = NULL;
> +    struct QBlockOption_rbd *o_rbd = NULL;
> +    struct QBlockOption_sheepdog *o_sd = NULL;
> +    struct QBlockOption_vdi *o_vdi = NULL;
> +    struct QBlockOption_vmdk *o_vmdk = NULL;
> +    struct QBlockOption_vpc *o_vpc = NULL;
> +    int backing_flag = 0;
> +
> +    /* take care of user settings */
> +    qboc_adjust_o2n(&qbco, op);
> +
> +    /* check parameters */
> +    if (qbco.o_loc.filename == NULL) {
> +        ret = QB_ERR_INVALID_PARAM;
> +        qbs->err_msg = "filename was not set.";
> +        qbs->err_no = 0;
> +        goto out;
> +    }
> +
> +    if (path_has_protocol(qbco.o_loc.filename) > 0) {
> +        ret = QB_ERR_INVALID_PARAM;
> +        qbs->err_msg = "filename have protocol.";
> +        qbs->err_no = 0;
> +        goto out;
> +    }
> +
> +    if (qbco.o_loc.protocol >= QB_PROTO_MAX) {
> +        ret = QB_ERR_INVALID_PARAM;
> +        qbs->err_msg = "protocol was not supported.";
> +        qbs->err_no = 0;
> +        goto out;
> +    }
> +
> +    /* set parameters */
> +    fmt = fmt2str(qbco.o_fmt.fmt_type);
> +    if (fmt == NULL) {
> +        ret = QB_ERR_INVALID_PARAM;
> +        qbs->err_msg = "format is not valid.";
> +        qbs->err_no = 0;
> +        goto out;
> +    }
> +    drv = bdrv_find_format(fmt);
> +    assert(drv != NULL);
> +
> +    create_options = append_option_parameters(create_options,
> +                                              drv->create_options);
> +    param = parse_option_parameters("", create_options, param);
> +
> +    switch (qbco.o_fmt.fmt_type) {
> +    case QB_FMT_COW:
> +        o_cow = &qbco.o_fmt.fmt_op.o_cow;
> +        assert(0 == set_option_parameter_int(param,
> +                                BLOCK_OPT_SIZE, o_cow->virt_size));

expr == 0, also below

> +        if (o_cow->backing_file) {
> +            assert(0 == set_option_parameter(param,
> +                                BLOCK_OPT_BACKING_FILE, 
> o_cow->backing_file));
> +        }
> +        backing_flag = o_cow->backing_flag;
> +        break;
> +    case QB_FMT_QED:
> +        o_qed = &qbco.o_fmt.fmt_op.o_qed;
> +        assert(0 == set_option_parameter_int(param,
> +                                BLOCK_OPT_SIZE, o_qed->virt_size));
> +        if (o_qed->backing_file) {
> +            assert(0 == set_option_parameter(param,
> +                                BLOCK_OPT_BACKING_FILE, 
> o_qed->backing_file));
> +        }
> +        fmt_backing_str = fmt2str(o_qed->backing_fmt);
> +        if (fmt_backing_str) {
> +            assert(0 == set_option_parameter(param,
> +                                BLOCK_OPT_BACKING_FMT, fmt_backing_str));
> +        }
> +        assert(0 == set_option_parameter_int(param,
> +                                BLOCK_OPT_CLUSTER_SIZE, 
> o_qed->cluster_size));
> +        assert(0 == set_option_parameter_int(param,
> +                                BLOCK_OPT_TABLE_SIZE, o_qed->table_size));
> +        backing_flag = o_qed->backing_flag;
> +        break;
> +    case QB_FMT_QCOW:
> +        o_qcow = &qbco.o_fmt.fmt_op.o_qcow;
> +        assert(0 == set_option_parameter_int(param,
> +                                BLOCK_OPT_SIZE, o_qcow->virt_size));
> +        if (o_qcow->backing_file) {
> +            assert(0 == set_option_parameter(param,
> +                                BLOCK_OPT_BACKING_FILE, 
> o_qcow->backing_file));
> +        }
> +        tmp = o_qcow->encrypt ? "on" : "off";
> +        assert(0 == set_option_parameter(param, BLOCK_OPT_ENCRYPT, tmp));
> +        backing_flag = o_qcow->backing_flag;
> +        break;
> +    case QB_FMT_QCOW2:
> +        o_qcow2 = &qbco.o_fmt.fmt_op.o_qcow2;
> +        assert(0 == set_option_parameter_int(param,
> +                              BLOCK_OPT_SIZE, o_qcow2->virt_size));
> +        if (o_qcow2->backing_file) {
> +            assert(0 == set_option_parameter(param,
> +                              BLOCK_OPT_BACKING_FILE, 
> o_qcow2->backing_file));
> +        }
> +        fmt_backing_str = fmt2str(o_qcow2->backing_fmt);
> +        if (fmt_backing_str) {
> +            assert(0 == set_option_parameter(param,
> +                              BLOCK_OPT_BACKING_FMT, fmt_backing_str));
> +        }
> +        if (o_qcow2->compat_level) {
> +            assert(0 == set_option_parameter(param,
> +                              BLOCK_OPT_COMPAT_LEVEL, 
> o_qcow2->compat_level));
> +        }
> +        tmp = o_qcow2->encrypt ? "on" : "off";
> +        assert(0 == set_option_parameter(param, BLOCK_OPT_ENCRYPT, tmp));
> +        assert(0 == set_option_parameter_int(param,
> +                              BLOCK_OPT_CLUSTER_SIZE, 
> o_qcow2->cluster_size));
> +        if (o_qcow2->prealloc_mode) {
> +            assert(0 == set_option_parameter(param,
> +                              BLOCK_OPT_PREALLOC, o_qcow2->prealloc_mode));
> +        }
> +        backing_flag = o_qcow2->backing_flag;
> +        break;
> +    case QB_FMT_RAW:
> +        o_raw = &qbco.o_fmt.fmt_op.o_raw;
> +        assert(0 == set_option_parameter_int(param,
> +                              BLOCK_OPT_SIZE, o_raw->virt_size));
> +        break;
> +    case QB_FMT_RBD:
> +        o_rbd = &qbco.o_fmt.fmt_op.o_rbd;
> +        assert(0 == set_option_parameter_int(param,
> +                              BLOCK_OPT_SIZE, o_rbd->virt_size));
> +        assert(0 == set_option_parameter_int(param,
> +                              BLOCK_OPT_CLUSTER_SIZE, o_rbd->cluster_size));
> +        break;
> +    case QB_FMT_SHEEPDOG:
> +        o_sd = &qbco.o_fmt.fmt_op.o_sheepdog;
> +        assert(0 == set_option_parameter_int(param,
> +                              BLOCK_OPT_SIZE, o_sd->virt_size));
> +        if (o_sd->backing_file) {
> +            assert(0 == set_option_parameter(param,
> +                              BLOCK_OPT_BACKING_FILE, o_sd->backing_file));
> +        }
> +        if (o_sd->prealloc_mode) {
> +            assert(0 == set_option_parameter(param,
> +                              BLOCK_OPT_PREALLOC, o_sd->prealloc_mode));
> +        }
> +        backing_flag = o_sd->backing_flag;
> +        break;
> +    case QB_FMT_VDI:
> +        o_vdi = &qbco.o_fmt.fmt_op.o_vdi;
> +        assert(0 == set_option_parameter_int(param,
> +                              BLOCK_OPT_SIZE, o_vdi->virt_size));
> +        /* following option is not always valid depends on configuration */
> +        set_option_parameter_int(param,
> +                              BLOCK_OPT_CLUSTER_SIZE, o_vdi->cluster_size);
> +        set_option_parameter_int(param, "static", o_vdi->prealloc_mode);
> +        break;
> +    case QB_FMT_VMDK:
> +        o_vmdk = &qbco.o_fmt.fmt_op.o_vmdk;
> +        assert(0 == set_option_parameter_int(param,
> +                              BLOCK_OPT_SIZE, o_vmdk->virt_size));
> +        if (o_vmdk->backing_file) {
> +            assert(0 == set_option_parameter(param,
> +                              BLOCK_OPT_BACKING_FILE, o_vmdk->backing_file));
> +        }
> +        tmp = o_vmdk->compat_version6 ? "on" : "off";
> +        assert(0 == set_option_parameter(param, BLOCK_OPT_COMPAT6, tmp));
> +        if (o_vmdk->subfmt) {
> +            assert(0 == set_option_parameter(param,
> +                              BLOCK_OPT_SUBFMT, o_vmdk->subfmt));
> +        }
> +        backing_flag = o_vmdk->backing_flag;
> +        break;
> +    case QB_FMT_VPC:
> +        o_vpc = &qbco.o_fmt.fmt_op.o_vpc;
> +        assert(0 == set_option_parameter_int(param,
> +                               BLOCK_OPT_SIZE, o_vpc->virt_size));
> +        if (o_vpc->subfmt) {
> +            assert(0 == set_option_parameter(param,
> +                               BLOCK_OPT_SUBFMT, o_vpc->subfmt));
> +        }
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    backing_file = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
> +    if (backing_file && backing_file->value.s) {
> +        if (!strcmp(op->o_loc.filename, backing_file->value.s)) {
> +            ret = QB_ERR_INVALID_PARAM;
> +            qbs->err_msg = "backing file is the same with new file.";

same as the new file

> +            qbs->err_no = 0;
> +            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 =
> +                backing_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) {
> +                ret = QB_ERR_INTERNAL_ERR;
> +                qbs->err_msg = "failed to open the backing file.";
> +                qbs->err_no = -errno;
> +                goto out;
> +            }
> +            bdrv_get_geometry(bs, &size);
> +            size *= 512;

Where's the #define?

> +
> +            snprintf(buf, sizeof(buf), "%" PRId64, size);
> +            set_option_parameter(param, BLOCK_OPT_SIZE, buf);
> +        } else {
> +            ret = QB_ERR_INVALID_PARAM;
> +            qbs->err_msg = "neither size or backing file was not set.";
> +            qbs->err_no = 0;
> +            goto out;
> +        }
> +    }
> +
> +    bd_ret = bdrv_create(drv, op->o_loc.filename, param);
> +
> +    if (bd_ret < 0) {
> +        ret = QB_ERR_INTERNAL_ERR;
> +        qbs->err_no = bd_ret;
> +        if (bd_ret == -ENOTSUP) {
> +            qbs->err_msg = "formatting option not supported.";

s/f/F/

> +        } else if (bd_ret == -EFBIG) {
> +            qbs->err_msg = "The image size is too large.";
> +        } else {
> +            qbs->err_msg = "Error in creating the image.";
> +        }
> +        goto out;
> +    }
> +
> +out:
> +    free_option_parameters(create_options);
> +    free_option_parameters(param);
> +
> +    if (bs) {
> +        bdrv_delete(bs);
> +    }
> +
> +    return ret;
> +}
> +
> +/* ignore case that len is not alligned to 512 now. */

aligned

> +int qb_read(struct QBlockState *qbs, const void *buf, size_t len,
> +                                                      off_t offset)
> +{
> +    int ret = 0, bd_ret;
> +    BlockDriverState *bs;
> +
> +    bs = qbs->bdrvs;
> +
> +    assert((len & 0x01ff) == 0);
> +    assert((offset & 0x01ff) == 0);

Also here use the #defined constant.

> +    bd_ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, len >> 9);
> +    if (bd_ret < 0) {
> +        ret = QB_ERR_INTERNAL_ERR;
> +        qbs->err_no = bd_ret;
> +        if (bd_ret == -EIO) {
> +            qbs->err_msg = "Generic I/O error.";
> +        } else if (bd_ret == -ENOMEDIUM) {
> +            qbs->err_msg = "No meida inserted.";

media

> +        } else if (bd_ret == -EINVAL) {
> +            qbs->err_msg = "Sector was not correct.";
> +        } else {
> +            qbs->err_msg = "Internal error.";
> +        }
> +    }
> +    return ret;
> +}
> +
> +/* ignore case that len is not alligned to 512 now. */
> +int qb_write(struct QBlockState *qbs, const void *buf, size_t len,
> +                                                       off_t offset)
> +{
> +    int ret = 0, bd_ret;
> +    BlockDriverState *bs;
> +
> +    bs = qbs->bdrvs;
> +
> +    assert((len & 0x01ff) == 0);
> +    assert((offset & 0x01ff) == 0);
> +    bd_ret = bdrv_write(bs, offset >> 9, buf, len >> 9);
> +    if (bd_ret < 0) {
> +        ret = QB_ERR_INTERNAL_ERR;
> +        qbs->err_no = bd_ret;
> +        if (bd_ret == -EIO) {
> +            qbs->err_msg = "Generic I/O error.";
> +        } else if (bd_ret == -ENOMEDIUM) {
> +            qbs->err_msg = "No meida inserted.";
> +        } else if (bd_ret == -EINVAL) {
> +            qbs->err_msg = "Sector was not correct.";
> +        } else if (bd_ret == -EACCES) {
> +            qbs->err_msg = "Ready only device.";
> +        } else {
> +            qbs->err_msg = "Internal error.";
> +        }
> +    }
> +    return ret;
> +}
> +
> +int qb_flush(struct QBlockState *qbs)
> +{
> +    int ret = 0, bd_ret;
> +    BlockDriverState *bs;
> +
> +    bs = qbs->bdrvs;
> +    bd_ret = bdrv_flush(bs);
> +    if (bd_ret < 0) {
> +        ret = QB_ERR_INTERNAL_ERR;
> +        qbs->err_no = bd_ret;
> +        qbs->err_msg = NULL;
> +    }
> +    return ret;
> +}
> +
> +int qb_infoimage_get(struct QBlockState *qbs, struct QBlockInfoImage **info)
> +{
> +    int ret = 0;
> +    BlockDriverState *bs;
> +    const char *tmp;
> +    uint64_t total_sectors;
> +    char backing_filename[1024];
> +
> +    struct QBlockInfoImage *ifimg = FUNC_CALLOC(1,
> +                                           sizeof(struct QBlockInfoImage));
> +    if (ifimg == NULL) {
> +        ret = QB_ERR_MEM_ERR;
> +        set_err_nomem(qbs);
> +        goto out;
> +    }
> +
> +    bs = qbs->bdrvs;
> +    ifimg->filename = strdup(qbs->filename);
> +    if (ifimg->filename == NULL) {
> +        ret = QB_ERR_MEM_ERR;
> +        set_err_nomem(qbs);
> +        goto err;
> +    }
> +    tmp = bdrv_get_format_name(bs);
> +    ifimg->format = str2fmt(tmp);
> +    /* support only file now */
> +    ifimg->protocol = QB_PROTO_FILE;
> +
> +    bdrv_get_geometry(bs, &total_sectors);
> +    ifimg->virt_size = total_sectors * 512;
> +    ifimg->allocated_size = bdrv_get_allocated_file_size(bs);
> +    ifimg->encrypt = bdrv_is_encrypted(bs);
> +    bdrv_get_full_backing_filename(bs, backing_filename,
> +                                   sizeof(backing_filename));
> +    if (backing_filename[0] != '\0') {
> +        ifimg->backing_filename = strdup(backing_filename);
> +        if (ifimg->backing_filename == NULL) {
> +            ret = QB_ERR_MEM_ERR;
> +            set_err_nomem(qbs);
> +            goto err;
> +        }
> +    }
> +
> +    *info = ifimg;
> + out:
> +    return ret;
> + err:
> +    qb_infoimage_free(&ifimg);
> +    return ret;
> +}
> +
> +void qb_infoimage_free(struct QBlockInfoImage **info)
> +{
> +    if (*info == NULL) {
> +        return;
> +    }
> +    FUNC_FREE((*info)->filename);
> +    FUNC_FREE((*info)->backing_filename);
> +    FUNC_FREE(*info);
> +    *info = NULL;
> +    return;
> +}
> +
> +bool qb_supports_format(enum QBlockFormat fmt)
> +{
> +    if (fmt < QB_FMT_MAX) {
> +        return true;
> +    }
> +    return false;
> +}
> +
> +bool qb_supports_protocol(enum QBlockProtocol proto)
> +{
> +    if (proto < QB_PROTO_MAX) {
> +        return true;
> +    }
> +    return false;
> +}
> +
> +const char *qb_error_get_detail(struct QBlockState *qbs, int *err_num)
> +{
> +    *err_num = qbs->err_no;
> +    return qbs->err_msg;
> +}
> diff --git a/libqblock.h b/libqblock.h
> new file mode 100644
> index 0000000..d2e9502
> --- /dev/null
> +++ b/libqblock.h
> @@ -0,0 +1,447 @@
> +/*
> + * Copyright IBM Corp. 2012
> + *
> + * Authors:
> + *  Wenchao Xia <address@hidden>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA

web version

> + */
> +
> +#ifndef LIBQBLOCK_H
> +#define LIBQBLOCK_H
> +
> +#include <stdio.h>
> +#include <stdint.h>
> +#include <stdlib.h>
> +
> +#define bool _Bool

#include <stdbool.h>

> +
> +#define QB_ERR_MEM_ERR (-1)
> +#define QB_ERR_INTERNAL_ERR (-2)
> +#define QB_ERR_INVALID_PARAM (-3)
> +
> +/* this library is designed around this core struct. */
> +struct QBlockState;
> +
> +/*
> +   libarary init

library

> +   This function get the library ready to use.
> + */

Please use markup for the comments, see for example memory.h.

> +void libqblock_init(void);
> +
> +/*
> +   create a new qbs object
> +   params:
> +     qbs: out, pointer that will receive created obj.
> +   return:
> +     0 on succeed, negative on failure.
> + */
> +int qb_state_new(struct QBlockState **qbs);
> +
> +/*
> +   delete a qbs object
> +   params:
> +     qbs: in, pointer that will be freed. *qbs will be set to NULL.
> +   return:
> +     void.
> + */
> +void qb_state_free(struct QBlockState **qbs);
> +
> +
> +/* flag used in open and create */
> +#define LIBQBLOCK_O_RDWR        0x0002
> +/* open the file read only and save writes in a snapshot */
> +#define LIBQBLOCK_O_SNAPSHOT    0x0008
> +/* do not use the host page cache */
> +#define LIBQBLOCK_O_NOCACHE     0x0020
> +/* use write-back caching */
> +#define LIBQBLOCK_O_CACHE_WB    0x0040
> +/* use native AIO instead of the thread pool */
> +#define LIBQBLOCK_O_NATIVE_AIO  0x0080
> +/* don't open the backing file */
> +#define LIBQBLOCK_O_NO_BACKING  0x0100
> +/* disable flushing on this disk */
> +#define LIBQBLOCK_O_NO_FLUSH    0x0200
> +/* copy read backing sectors into image */
> +#define LIBQBLOCK_O_COPY_ON_READ 0x0400
> +/* consistency hint for incoming migration */
> +#define LIBQBLOCK_O_INCOMING    0x0800
> +
> +#define LIBQBLOCK_O_CACHE_MASK \
> +   (LIBQBLOCK_O_NOCACHE | LIBQBLOCK_O_CACHE_WB | LIBQBLOCK_O_NO_FLUSH)
> +
> +enum QBlockProtocol {
> +    QB_PROTO_FILE = 0,
> +    QB_PROTO_MAX
> +};
> +
> +enum QBlockFormat {
> +    QB_FMT_NONE = 0,
> +    QB_FMT_COW,
> +    QB_FMT_QED,
> +    QB_FMT_QCOW,
> +    QB_FMT_QCOW2,
> +    QB_FMT_RAW,
> +    QB_FMT_RBD,
> +    QB_FMT_SHEEPDOG,
> +    QB_FMT_VDI,
> +    QB_FMT_VMDK,
> +    QB_FMT_VPC,
> +    QB_FMT_MAX
> +};
> +
> +/* block target location info, it include all information about how to find
> +   the image */
> +struct QBlockLocInfo {
> +    int struct_size;
> +    const char *filename;
> +    enum QBlockProtocol protocol;
> +};
> +
> +/* how to open the image */
> +struct QBlockOptionOpen {
> +    int struct_size;
> +    struct QBlockLocInfo o_loc; /* how to find */
> +    enum QBlockFormat o_fmt_type; /* how to extract */
> +    int o_flag; /* how to control */
> +};
> +
> +/*
> +   create a new QBlockOptionOpen structure.
> +   params:
> +     op: out, pointer that will receive created structure.
> +   return:
> +     0 on succeed, negative on failure.
> + */
> +static inline int qb_oo_new(struct QBlockOptionOpen **op)
> +{
> +    *op = calloc(1, sizeof(struct QBlockOptionOpen));

calloc() is not wrapped by your macros.

> +    if (*op == NULL) {
> +        return QB_ERR_MEM_ERR;
> +    }
> +    (*op)->struct_size = sizeof(struct QBlockOptionOpen);
> +    (*op)->o_loc.struct_size = sizeof(struct QBlockLocInfo);
> +    return 0;
> +}
> +
> +/*
> +   free QBlockOptionOpen structure.
> +   params:
> +     op: in, *op will be set as NULL after called.
> +   return:
> +     void
> + */
> +static inline void qb_oo_free(struct QBlockOptionOpen **op)
> +{
> +    free(*op);

Also free() here.

> +    *op = NULL;
> +}
> +
> +/*
> +   open a block object.
> +   params:
> +     qbs: in, pointer to QBlockState.
> +     op: in, options for open.
> +   return:
> +     0 on success, negative on fail.
> + */
> +int qb_open(struct QBlockState *qbs, struct QBlockOptionOpen *op);
> +
> +/*
> +   close a block object.
> +   params:
> +     qbs: in, pointer to QBlockState.
> +   return:
> +     void.
> + */
> +void qb_close(struct QBlockState *qbs);
> +
> +/* format related options, struct_size must be set. */
> +struct QBlockOption_cow {
> +    int struct_size;
> +    size_t virt_size;
> +    const char *backing_file;
> +    int backing_flag;
> +};
> +
> +struct QBlockOption_qed {
> +    int struct_size;
> +    size_t virt_size;
> +    const char *backing_file;
> +    enum QBlockFormat backing_fmt;
> +    int backing_flag;
> +    size_t cluster_size; /* unit is bytes */
> +    size_t table_size; /* unit is clusters */
> +};
> +
> +struct QBlockOption_qcow {
> +    int struct_size;
> +    size_t virt_size;
> +    const char *backing_file;
> +    int backing_flag;
> +    bool encrypt;
> +};
> +
> +struct QBlockOption_qcow2 {
> +    int struct_size;
> +    size_t virt_size;
> +    const char *compat_level; /* "Compatibility level (0.10 or 1.1)" */
> +    const char *backing_file;
> +    enum QBlockFormat backing_fmt;
> +    int backing_flag;
> +    bool encrypt;
> +    size_t cluster_size; /* unit is bytes */
> +    const char *prealloc_mode; /* off or metadata */
> +};
> +
> +struct QBlockOption_raw {
> +    int struct_size;
> +    size_t virt_size;
> +};
> +
> +struct QBlockOption_rbd {
> +    int struct_size;
> +    size_t virt_size;
> +    size_t cluster_size;
> +};
> +
> +struct QBlockOption_sheepdog {
> +    int struct_size;
> +    size_t virt_size;
> +    const char *backing_file;
> +    int backing_flag;
> +    const char *prealloc_mode; /* off or full */
> +};
> +
> +struct QBlockOption_vdi {
> +    int struct_size;
> +    size_t virt_size;
> +    size_t cluster_size;
> +    bool prealloc_mode;
> +};
> +
> +struct QBlockOption_vmdk {
> +    int struct_size;
> +    size_t virt_size;
> +    const char *backing_file;
> +    int backing_flag;
> +    bool compat_version6;
> +    const char *subfmt;
> +    /* vmdk flat extent format, values:
> +   "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse |
> +    twoGbMaxExtentFlat | streamOptimized} */
> +};
> +
> +struct QBlockOption_vpc {
> +    int struct_size;
> +    size_t virt_size;
> +    const char *subfmt; /* "{dynamic (default) | fixed} " */
> +};

I'd rather have different open functions than variant structures.

> +
> +union QBlockOption_fmt {
> +    struct QBlockOption_cow       o_cow;
> +    struct QBlockOption_qed       o_qed;
> +    struct QBlockOption_qcow      o_qcow;
> +    struct QBlockOption_qcow2     o_qcow2;
> +    struct QBlockOption_raw       o_raw;
> +    struct QBlockOption_rbd       o_rbd;
> +    struct QBlockOption_sheepdog  o_sheepdog;
> +    struct QBlockOption_vdi       o_vdi;
> +    struct QBlockOption_vmdk      o_vmdk;
> +    struct QBlockOption_vpc       o_vpc;
> +};
> +
> +struct QBlockOptionFormat {
> +    int struct_size;
> +    enum QBlockFormat fmt_type;
> +    union QBlockOption_fmt fmt_op;
> +};
> +
> +/* struct_size in o_loc and o_fmt must set. To make this structure 
> extensible,
> +   all new member must be added in the tail of each structure. */
> +struct QBlockOptionCreate {
> +    int struct_size;
> +    struct QBlockLocInfo o_loc;
> +    struct QBlockOptionFormat o_fmt;
> +};
> +
> +/*
> +   create a new QBlockOptionCreate structure.
> +   params:
> +     op: out, pointer that will receive created structure.
> +     fmt: format want to use.
> +   return:
> +     0 on succeed, negative on failure.
> + */
> +static inline int qb_oc_new(struct QBlockOptionCreate **op,
> +                            enum QBlockFormat fmt)
> +{
> +    *op = calloc(1, sizeof(struct QBlockOptionCreate));
> +    if (*op == NULL) {
> +        return QB_ERR_MEM_ERR;
> +    }
> +    (*op)->struct_size = sizeof(struct QBlockOptionCreate);
> +    (*op)->o_loc.struct_size = sizeof(struct QBlockLocInfo);
> +    (*op)->o_fmt.struct_size = sizeof(struct QBlockOptionFormat);
> +
> +    switch (fmt) {
> +    case QB_FMT_COW:
> +        (*op)->o_fmt.fmt_op.o_cow.struct_size =
> +                                          sizeof(struct QBlockOption_cow);
> +        break;
> +    case QB_FMT_QED:
> +        (*op)->o_fmt.fmt_op.o_qed.struct_size =
> +                                          sizeof(struct QBlockOption_qed);
> +        break;
> +    case QB_FMT_QCOW:
> +        (*op)->o_fmt.fmt_op.o_qcow.struct_size =
> +                                          sizeof(struct QBlockOption_qcow);
> +        break;
> +    case QB_FMT_QCOW2:
> +        (*op)->o_fmt.fmt_op.o_qcow2.struct_size =
> +                                          sizeof(struct QBlockOption_qcow2);
> +        break;
> +    case QB_FMT_RAW:
> +        (*op)->o_fmt.fmt_op.o_raw.struct_size =
> +                                          sizeof(struct QBlockOption_raw);
> +        break;
> +    case QB_FMT_RBD:
> +        (*op)->o_fmt.fmt_op.o_rbd.struct_size =
> +                                          sizeof(struct QBlockOption_rbd);
> +        break;
> +    case QB_FMT_SHEEPDOG:
> +        (*op)->o_fmt.fmt_op.o_sheepdog.struct_size =
> +                                          sizeof(struct 
> QBlockOption_sheepdog);
> +        break;
> +    case QB_FMT_VDI:
> +        (*op)->o_fmt.fmt_op.o_vdi.struct_size =
> +                                          sizeof(struct QBlockOption_vdi);
> +        break;
> +    case QB_FMT_VMDK:
> +        (*op)->o_fmt.fmt_op.o_vmdk.struct_size =
> +                                          sizeof(struct QBlockOption_vmdk);
> +        break;
> +    case QB_FMT_VPC:
> +        (*op)->o_fmt.fmt_op.o_vpc.struct_size =
> +                                          sizeof(struct QBlockOption_vpc);
> +        break;
> +    default:
> +        break;
> +    }
> +    (*op)->o_fmt.fmt_type = fmt;
> +    return 0;
> +}
> +
> +/*
> +   free QBlockOptionCreate structure.
> +   params:
> +     op: in, *op will be set as NULL after called.
> +   return:
> +     void
> + */
> +static inline void qb_oc_free(struct QBlockOptionCreate **op)
> +{
> +    free(*op);
> +    *op = NULL;
> +}
> +/*
> +   create a block file.
> +   params:
> +     qbs: in, pointer to QBlockState.
> +     op: in, create option.
> +   return:
> +     negative on fail, 0 on success.
> + */
> +int qb_create(struct QBlockState *qbs, struct QBlockOptionCreate *op);
> +
> +
> +/* sync access */
> +/*
> +   block sync read.
> +   params:
> +     qbs: in, pointer to QBlockState.
> +     buf: out, buffer that receive the content.
> +     len: in, length to read.
> +     offset: in, offset in the block data.
> +   return:
> +     negative on fail, 0 on success.
> + */
> +int qb_read(struct QBlockState *qbs, const void *buf, size_t len,
> +                                                      off_t offset);
> +
> +/*
> +   block sync read.
> +   params:
> +     qbs: in, pointer to QBlockState.
> +     buf: in, buffer that would be wrote.
> +     len: in, length to write.
> +     offset: in, offset in the block data.
> +   return:
> +     negative on fail, 0 on success.
> + */
> +int qb_write(struct QBlockState *qbs, const void *buf, size_t len,
> +                                                       off_t offset);
> +
> +/*
> +   block sync flush.
> +   params:
> +     qbs: in, pointer to QBlockState.
> +   return:
> +     negative on fail, 0 on success.
> + */
> +int qb_flush(struct QBlockState *qbs);
> +
> +/* information */
> +/* image related info, static information, from user perspective. */
> +/* now it is a plain structure, wonder if it could be foldered into embbed 
> one
> +   to reflect that format related information better. */
> +struct QBlockInfoImage {
> +    int struct_size;
> +    char *filename;
> +    enum QBlockProtocol protocol;
> +    enum QBlockFormat format;
> +    size_t virt_size;
> +    /* advance info */
> +    size_t allocated_size;
> +    bool encrypt;
> +    char *backing_filename;
> +};
> +
> +/* image info */
> +/*
> +   get image info.
> +   params:
> +     qbs: in, pointer to QBlockState.
> +     info, out, pointer that would receive the information.
> +   return:
> +     negative on fail, 0 on success.
> + */
> +int qb_infoimage_get(struct QBlockState *qbs, struct QBlockInfoImage **info);
> +
> +/*
> +   free image info.
> +   params:
> +     info, in, pointer, *info would be set to NULL after function called.
> +   return:
> +     void.
> + */
> +void qb_infoimage_free(struct QBlockInfoImage **info);
> +
> +/* misc */
> +bool qb_supports_format(enum QBlockFormat fmt);
> +bool qb_supports_protocol(enum QBlockProtocol proto);
> +
>

A comment here stating that the string may not be free()d.

 +const char *qb_error_get_detail(struct QBlockState *qbs, int *err_num);
> +#endif
> --
> 1.7.1
>
>
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]