Commit f1ab7a5a authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'kwolf/for-anthony' into staging



# By Kevin Wolf (16) and Stefan Hajnoczi (4)
# Via Kevin Wolf
* kwolf/for-anthony:
  qemu-iotests: add 053 unaligned compressed image size test
  block: Allow overriding backing.file.filename
  block: Remove filename parameter from .bdrv_file_open()
  vvfat: Use bdrv_open options instead of filename
  sheepdog: Use bdrv_open options instead of filename
  rbd: Use bdrv_open options instead of filename
  iscsi: Use bdrv_open options instead of filename
  gluster: Use bdrv_open options instead of filename
  curl: Use bdrv_open options instead of filename
  blkverify: Use bdrv_open options instead of filename
  blkdebug: Use bdrv_open options instead of filename
  raw-win32: Use bdrv_open options instead of filename
  raw-posix: Use bdrv_open options instead of filename
  block: Enable filename option
  block: Add driver-specific options for backing files
  block: Fail gracefully when using a format driver on protocol level
  qemu-iotests: Fix _filter_qemu
  qemu-img: do not zero-pad the compressed write buffer
  qcow: allow sub-cluster compressed write to last cluster
  qcow2: allow sub-cluster compressed write to last cluster

Message-id: 1366630294-18984-1-git-send-email-kwolf@redhat.com
Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
parents 25690739 7da94ca7
Loading
Loading
Loading
Loading
+56 −9
Original line number Diff line number Diff line
@@ -667,10 +667,10 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
 * Removes all processed options from *options.
 */
static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
    const char *filename, QDict *options,
    int flags, BlockDriver *drv)
    QDict *options, int flags, BlockDriver *drv)
{
    int ret, open_flags;
    const char *filename;

    assert(drv != NULL);
    assert(bs->file == NULL);
@@ -698,6 +698,12 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
        bdrv_enable_copy_on_read(bs);
    }

    if (file != NULL) {
        filename = file->filename;
    } else {
        filename = qdict_get_try_str(options, "filename");
    }

    if (filename != NULL) {
        pstrcpy(bs->filename, sizeof(bs->filename), filename);
    } else {
@@ -716,8 +722,15 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
    if (drv->bdrv_file_open) {
        assert(file == NULL);
        assert(drv->bdrv_parse_filename || filename != NULL);
        ret = drv->bdrv_file_open(bs, filename, options, open_flags);
        ret = drv->bdrv_file_open(bs, options, open_flags);
    } else {
        if (file == NULL) {
            qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't use '%s' as a "
                          "block driver for the protocol level",
                          drv->format_name);
            ret = -EINVAL;
            goto free_and_fail;
        }
        assert(file != NULL);
        bs->file = file;
        ret = drv->bdrv_open(bs, options, open_flags);
@@ -773,6 +786,18 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
    bs->options = options;
    options = qdict_clone_shallow(options);

    /* Fetch the file name from the options QDict if necessary */
    if (!filename) {
        filename = qdict_get_try_str(options, "filename");
    } else if (filename && !qdict_haskey(options, "filename")) {
        qdict_put(options, "filename", qstring_from_str(filename));
    } else {
        qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't specify 'file' and "
                      "'filename' options at the same time");
        ret = -EINVAL;
        goto fail;
    }

    /* Find the right block driver */
    drvname = qdict_get_try_str(options, "driver");
    if (drvname) {
@@ -801,6 +826,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
            ret = -EINVAL;
            goto fail;
        }
        qdict_del(options, "filename");
    } else if (!drv->bdrv_parse_filename && !filename) {
        qerror_report(ERROR_CLASS_GENERIC_ERROR,
                      "The '%s' block driver requires a file name",
@@ -809,7 +835,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
        goto fail;
    }

    ret = bdrv_open_common(bs, NULL, filename, options, flags, drv);
    ret = bdrv_open_common(bs, NULL, options, flags, drv);
    if (ret < 0) {
        goto fail;
    }
@@ -838,18 +864,35 @@ fail:
    return ret;
}

int bdrv_open_backing_file(BlockDriverState *bs)
/*
 * Opens the backing file for a BlockDriverState if not yet open
 *
 * options is a QDict of options to pass to the block drivers, or NULL for an
 * empty set of options. The reference to the QDict is transferred to this
 * function (even on failure), so if the caller intends to reuse the dictionary,
 * it needs to use QINCREF() before calling bdrv_file_open.
 */
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options)
{
    char backing_filename[PATH_MAX];
    int back_flags, ret;
    BlockDriver *back_drv = NULL;

    if (bs->backing_hd != NULL) {
        QDECREF(options);
        return 0;
    }

    /* NULL means an empty set of options */
    if (options == NULL) {
        options = qdict_new();
    }

    bs->open_flags &= ~BDRV_O_NO_BACKING;
    if (bs->backing_file[0] == '\0') {
    if (qdict_haskey(options, "file.filename")) {
        backing_filename[0] = '\0';
    } else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
        QDECREF(options);
        return 0;
    }

@@ -864,7 +907,8 @@ int bdrv_open_backing_file(BlockDriverState *bs)
    /* backing files always opened read-only */
    back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT);

    ret = bdrv_open(bs->backing_hd, backing_filename, NULL,
    ret = bdrv_open(bs->backing_hd,
                    *backing_filename ? backing_filename : NULL, options,
                    back_flags, back_drv);
    if (ret < 0) {
        bdrv_delete(bs->backing_hd);
@@ -1008,7 +1052,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
    }

    /* Open the image */
    ret = bdrv_open_common(bs, file, filename, options, flags, drv);
    ret = bdrv_open_common(bs, file, options, flags, drv);
    if (ret < 0) {
        goto unlink_and_fail;
    }
@@ -1020,7 +1064,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,

    /* If there is a backing file, use it */
    if ((flags & BDRV_O_NO_BACKING) == 0) {
        ret = bdrv_open_backing_file(bs);
        QDict *backing_options;

        extract_subqdict(options, &backing_options, "backing.");
        ret = bdrv_open_backing_file(bs, backing_options);
        if (ret < 0) {
            goto close_and_fail;
        }
+81 −32
Original line number Diff line number Diff line
@@ -273,11 +273,6 @@ static int read_config(BDRVBlkdebugState *s, const char *filename)
    int ret;
    struct add_rule_data d;

    /* Allow usage without config file */
    if (!*filename) {
        return 0;
    }

    f = fopen(filename, "r");
    if (f == NULL) {
        return -errno;
@@ -304,44 +299,98 @@ fail:
}

/* Valid blkdebug filenames look like blkdebug:path/to/config:path/to/image */
static int blkdebug_open(BlockDriverState *bs, const char *filename,
                         QDict *options, int flags)
static void blkdebug_parse_filename(const char *filename, QDict *options,
                                    Error **errp)
{
    BDRVBlkdebugState *s = bs->opaque;
    int ret;
    char *config, *c;
    const char *c;

    /* Parse the blkdebug: prefix */
    if (strncmp(filename, "blkdebug:", strlen("blkdebug:"))) {
        return -EINVAL;
    if (!strstart(filename, "blkdebug:", &filename)) {
        error_setg(errp, "File name string must start with 'blkdebug:'");
        return;
    }
    filename += strlen("blkdebug:");

    /* Read rules from config file */
    /* Parse config file path */
    c = strchr(filename, ':');
    if (c == NULL) {
        return -EINVAL;
        error_setg(errp, "blkdebug requires both config file and image path");
        return;
    }

    if (c != filename) {
        QString *config_path;
        config_path = qstring_from_substr(filename, 0, c - filename - 1);
        qdict_put(options, "config", config_path);
    }

    /* TODO Allow multi-level nesting and set file.filename here */
    filename = c + 1;
    qdict_put(options, "x-image", qstring_from_str(filename));
}

static QemuOptsList runtime_opts = {
    .name = "blkdebug",
    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
    .desc = {
        {
            .name = "config",
            .type = QEMU_OPT_STRING,
            .help = "Path to the configuration file",
        },
        {
            .name = "x-image",
            .type = QEMU_OPT_STRING,
            .help = "[internal use only, will be removed]",
        },
        { /* end of list */ }
    },
};

static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags)
{
    BDRVBlkdebugState *s = bs->opaque;
    QemuOpts *opts;
    Error *local_err = NULL;
    const char *filename, *config;
    int ret;

    opts = qemu_opts_create_nofail(&runtime_opts);
    qemu_opts_absorb_qdict(opts, options, &local_err);
    if (error_is_set(&local_err)) {
        qerror_report_err(local_err);
        error_free(local_err);
        ret = -EINVAL;
        goto fail;
    }

    config = g_strdup(filename);
    config[c - filename] = '\0';
    /* Read rules from config file */
    config = qemu_opt_get(opts, "config");
    if (config) {
        ret = read_config(s, config);
    g_free(config);
        if (ret < 0) {
        return ret;
            goto fail;
        }
    }
    filename = c + 1;

    /* Set initial state */
    s->state = 1;

    /* Open the backing file */
    filename = qemu_opt_get(opts, "x-image");
    if (filename == NULL) {
        ret = -EINVAL;
        goto fail;
    }

    ret = bdrv_file_open(&bs->file, filename, NULL, flags);
    if (ret < 0) {
        return ret;
        goto fail;
    }

    return 0;
    ret = 0;
fail:
    qemu_opts_del(opts);
    return ret;
}

static void error_callback_bh(void *opaque)
@@ -571,9 +620,9 @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
static BlockDriver bdrv_blkdebug = {
    .format_name            = "blkdebug",
    .protocol_name          = "blkdebug",

    .instance_size          = sizeof(BDRVBlkdebugState),

    .bdrv_parse_filename    = blkdebug_parse_filename,
    .bdrv_file_open         = blkdebug_open,
    .bdrv_close             = blkdebug_close,
    .bdrv_getlength         = blkdebug_getlength,
+84 −29
Original line number Diff line number Diff line
@@ -69,44 +69,100 @@ static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb,
}

/* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */
static int blkverify_open(BlockDriverState *bs, const char *filename,
                          QDict *options, int flags)
static void blkverify_parse_filename(const char *filename, QDict *options,
                                     Error **errp)
{
    BDRVBlkverifyState *s = bs->opaque;
    int ret;
    char *raw, *c;
    const char *c;
    QString *raw_path;


    /* Parse the blkverify: prefix */
    if (strncmp(filename, "blkverify:", strlen("blkverify:"))) {
        return -EINVAL;
    if (!strstart(filename, "blkverify:", &filename)) {
        error_setg(errp, "File name string must start with 'blkverify:'");
        return;
    }
    filename += strlen("blkverify:");

    /* Parse the raw image filename */
    c = strchr(filename, ':');
    if (c == NULL) {
        return -EINVAL;
        error_setg(errp, "blkverify requires raw copy and original image path");
        return;
    }

    /* TODO Implement option pass-through and set raw.filename here */
    raw_path = qstring_from_substr(filename, 0, c - filename - 1);
    qdict_put(options, "x-raw", raw_path);

    /* TODO Allow multi-level nesting and set file.filename here */
    filename = c + 1;
    qdict_put(options, "x-image", qstring_from_str(filename));
}

static QemuOptsList runtime_opts = {
    .name = "blkverify",
    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
    .desc = {
        {
            .name = "x-raw",
            .type = QEMU_OPT_STRING,
            .help = "[internal use only, will be removed]",
        },
        {
            .name = "x-image",
            .type = QEMU_OPT_STRING,
            .help = "[internal use only, will be removed]",
        },
        { /* end of list */ }
    },
};

static int blkverify_open(BlockDriverState *bs, QDict *options, int flags)
{
    BDRVBlkverifyState *s = bs->opaque;
    QemuOpts *opts;
    Error *local_err = NULL;
    const char *filename, *raw;
    int ret;

    opts = qemu_opts_create_nofail(&runtime_opts);
    qemu_opts_absorb_qdict(opts, options, &local_err);
    if (error_is_set(&local_err)) {
        qerror_report_err(local_err);
        error_free(local_err);
        ret = -EINVAL;
        goto fail;
    }

    /* Parse the raw image filename */
    raw = qemu_opt_get(opts, "x-raw");
    if (raw == NULL) {
        ret = -EINVAL;
        goto fail;
    }

    raw = g_strdup(filename);
    raw[c - filename] = '\0';
    ret = bdrv_file_open(&bs->file, raw, NULL, flags);
    g_free(raw);
    if (ret < 0) {
        return ret;
        goto fail;
    }
    filename = c + 1;

    /* Open the test file */
    filename = qemu_opt_get(opts, "x-image");
    if (filename == NULL) {
        ret = -EINVAL;
        goto fail;
    }

    s->test_file = bdrv_new("");
    ret = bdrv_open(s->test_file, filename, NULL, flags, NULL);
    if (ret < 0) {
        bdrv_delete(s->test_file);
        s->test_file = NULL;
        return ret;
        goto fail;
    }

    return 0;
    ret = 0;
fail:
    return ret;
}

static void blkverify_close(BlockDriverState *bs)
@@ -346,13 +402,12 @@ static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs,
static BlockDriver bdrv_blkverify = {
    .format_name            = "blkverify",
    .protocol_name          = "blkverify",

    .instance_size          = sizeof(BDRVBlkverifyState),

    .bdrv_getlength     = blkverify_getlength,

    .bdrv_parse_filename    = blkverify_parse_filename,
    .bdrv_file_open         = blkverify_open,
    .bdrv_close             = blkverify_close,
    .bdrv_getlength         = blkverify_getlength,

    .bdrv_aio_readv         = blkverify_aio_readv,
    .bdrv_aio_writev        = blkverify_aio_writev,
+101 −51
Original line number Diff line number Diff line
@@ -335,12 +335,9 @@ static void curl_clean_state(CURLState *s)
    s->in_use = 0;
}

static int curl_open(BlockDriverState *bs, const char *filename,
                     QDict *options, int flags)
static void curl_parse_filename(const char *filename, QDict *options,
                                Error **errp)
{
    BDRVCURLState *s = bs->opaque;
    CURLState *state = NULL;
    double d;

    #define RA_OPTSTR ":readahead="
    char *file;
@@ -348,19 +345,17 @@ static int curl_open(BlockDriverState *bs, const char *filename,
    const char *ra_val;
    int parse_state = 0;

    static int inited = 0;

    file = g_strdup(filename);
    s->readahead_size = READ_AHEAD_SIZE;

    /* Parse a trailing ":readahead=#:" param, if present. */
    ra = file + strlen(file) - 1;
    while (ra >= file) {
        if (parse_state == 0) {
            if (*ra == ':')
            if (*ra == ':') {
                parse_state++;
            else
            } else {
                break;
            }
        } else if (parse_state == 1) {
            if (*ra > '9' || *ra < '0') {
                char *opt_start = ra - strlen(RA_OPTSTR) + 1;
@@ -369,29 +364,77 @@ static int curl_open(BlockDriverState *bs, const char *filename,
                    ra_val = ra + 1;
                    ra -= strlen(RA_OPTSTR) - 1;
                    *ra = '\0';
                    s->readahead_size = atoi(ra_val);
                    break;
                } else {
                    break;
                    qdict_put(options, "readahead", qstring_from_str(ra_val));
                }
                break;
            }
        }
        ra--;
    }

    qdict_put(options, "url", qstring_from_str(file));

    g_free(file);
}

static QemuOptsList runtime_opts = {
    .name = "curl",
    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
    .desc = {
        {
            .name = "url",
            .type = QEMU_OPT_STRING,
            .help = "URL to open",
        },
        {
            .name = "readahead",
            .type = QEMU_OPT_SIZE,
            .help = "Readahead size",
        },
        { /* end of list */ }
    },
};

static int curl_open(BlockDriverState *bs, QDict *options, int flags)
{
    BDRVCURLState *s = bs->opaque;
    CURLState *state = NULL;
    QemuOpts *opts;
    Error *local_err = NULL;
    const char *file;
    double d;

    static int inited = 0;

    opts = qemu_opts_create_nofail(&runtime_opts);
    qemu_opts_absorb_qdict(opts, options, &local_err);
    if (error_is_set(&local_err)) {
        qerror_report_err(local_err);
        error_free(local_err);
        goto out_noclean;
    }

    s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE);
    if ((s->readahead_size & 0x1ff) != 0) {
        fprintf(stderr, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512\n",
                s->readahead_size);
        goto out_noclean;
    }

    file = qemu_opt_get(opts, "url");
    if (file == NULL) {
        qerror_report(ERROR_CLASS_GENERIC_ERROR, "curl block driver requires "
                      "an 'url' option");
        goto out_noclean;
    }

    if (!inited) {
        curl_global_init(CURL_GLOBAL_ALL);
        inited = 1;
    }

    DPRINTF("CURL: Opening %s\n", file);
    s->url = file;
    s->url = g_strdup(file);
    state = curl_init_state(s);
    if (!state)
        goto out_noclean;
@@ -423,6 +466,7 @@ static int curl_open(BlockDriverState *bs, const char *filename,
    curl_multi_setopt( s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb ); 
    curl_multi_do(s);

    qemu_opts_del(opts);
    return 0;

out:
@@ -430,7 +474,8 @@ out:
    curl_easy_cleanup(state->curl);
    state->curl = NULL;
out_noclean:
    g_free(file);
    g_free(s->url);
    qemu_opts_del(opts);
    return -EINVAL;
}

@@ -572,6 +617,7 @@ static BlockDriver bdrv_http = {
    .protocol_name          = "http",

    .instance_size          = sizeof(BDRVCURLState),
    .bdrv_parse_filename    = curl_parse_filename,
    .bdrv_file_open         = curl_open,
    .bdrv_close             = curl_close,
    .bdrv_getlength         = curl_getlength,
@@ -584,6 +630,7 @@ static BlockDriver bdrv_https = {
    .protocol_name          = "https",

    .instance_size          = sizeof(BDRVCURLState),
    .bdrv_parse_filename    = curl_parse_filename,
    .bdrv_file_open         = curl_open,
    .bdrv_close             = curl_close,
    .bdrv_getlength         = curl_getlength,
@@ -596,6 +643,7 @@ static BlockDriver bdrv_ftp = {
    .protocol_name          = "ftp",

    .instance_size          = sizeof(BDRVCURLState),
    .bdrv_parse_filename    = curl_parse_filename,
    .bdrv_file_open         = curl_open,
    .bdrv_close             = curl_close,
    .bdrv_getlength         = curl_getlength,
@@ -608,6 +656,7 @@ static BlockDriver bdrv_ftps = {
    .protocol_name          = "ftps",

    .instance_size          = sizeof(BDRVCURLState),
    .bdrv_parse_filename    = curl_parse_filename,
    .bdrv_file_open         = curl_open,
    .bdrv_close             = curl_close,
    .bdrv_getlength         = curl_getlength,
@@ -620,6 +669,7 @@ static BlockDriver bdrv_tftp = {
    .protocol_name          = "tftp",

    .instance_size          = sizeof(BDRVCURLState),
    .bdrv_parse_filename    = curl_parse_filename,
    .bdrv_file_open         = curl_open,
    .bdrv_close             = curl_close,
    .bdrv_getlength         = curl_getlength,
+32 −2
Original line number Diff line number Diff line
@@ -282,13 +282,42 @@ static int qemu_gluster_aio_flush_cb(void *opaque)
    return (s->qemu_aio_count > 0);
}

static int qemu_gluster_open(BlockDriverState *bs, const char *filename,
    QDict *options, int bdrv_flags)
/* TODO Convert to fine grained options */
static QemuOptsList runtime_opts = {
    .name = "gluster",
    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
    .desc = {
        {
            .name = "filename",
            .type = QEMU_OPT_STRING,
            .help = "URL to the gluster image",
        },
        { /* end of list */ }
    },
};

static int qemu_gluster_open(BlockDriverState *bs,  QDict *options,
                             int bdrv_flags)
{
    BDRVGlusterState *s = bs->opaque;
    int open_flags = O_BINARY;
    int ret = 0;
    GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
    QemuOpts *opts;
    Error *local_err = NULL;
    const char *filename;

    opts = qemu_opts_create_nofail(&runtime_opts);
    qemu_opts_absorb_qdict(opts, options, &local_err);
    if (error_is_set(&local_err)) {
        qerror_report_err(local_err);
        error_free(local_err);
        ret = -EINVAL;
        goto out;
    }

    filename = qemu_opt_get(opts, "filename");


    s->glfs = qemu_gluster_init(gconf, filename);
    if (!s->glfs) {
@@ -322,6 +351,7 @@ static int qemu_gluster_open(BlockDriverState *bs, const char *filename,
        qemu_gluster_aio_event_reader, NULL, qemu_gluster_aio_flush_cb, s);

out:
    qemu_opts_del(opts);
    qemu_gluster_gconf_free(gconf);
    if (!ret) {
        return ret;
Loading