qemu-devel
[Top][All Lists]
Advanced

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

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


From: Wenchao Xia
Subject: [Qemu-devel] [qemu-devel] [PATCH V2 2/3] [RFC] libqblock-API design
Date: Thu, 9 Aug 2012 18:12:17 +0800

  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
+ */
+
+#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; \
+}
+
+/* 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;
+}
+
+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;
+}
+
+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")) {
+        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);
+}
+
+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.";
+        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);
+    }
+
+
+    /* 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;
+}
+
+/* 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));
+        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.";
+            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;
+
+            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.";
+        } 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. */
+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);
+    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.";
+        } 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
+ */
+
+#ifndef LIBQBLOCK_H
+#define LIBQBLOCK_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define bool _Bool
+
+#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
+   This function get the library ready to use.
+ */
+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));
+    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);
+    *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} " */
+};
+
+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);
+
+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]