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: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
commit
f1ab7a5acf
65
block.c
65
block.c
@ -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;
|
||||
}
|
||||
|
101
block/blkdebug.c
101
block/blkdebug.c
@ -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;
|
||||
}
|
||||
|
||||
config = g_strdup(filename);
|
||||
config[c - filename] = '\0';
|
||||
ret = read_config(s, config);
|
||||
g_free(config);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Read rules from config file */
|
||||
config = qemu_opt_get(opts, "config");
|
||||
if (config) {
|
||||
ret = read_config(s, config);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set initial state */
|
||||
s->state = 1;
|
||||
|
||||
/* Open the backing file */
|
||||
ret = bdrv_file_open(&bs->file, filename, NULL, flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
filename = qemu_opt_get(opts, "x-image");
|
||||
if (filename == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = bdrv_file_open(&bs->file, filename, NULL, flags);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
ret = bdrv_file_open(&bs->file, raw, NULL, flags);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
|
82
block/curl.c
82
block/curl.c
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -1003,12 +1003,25 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO Convert to fine grained options */
|
||||
static QemuOptsList runtime_opts = {
|
||||
.name = "iscsi",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "filename",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "URL to the iscsi image",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* We support iscsi url's on the form
|
||||
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
|
||||
*/
|
||||
static int iscsi_open(BlockDriverState *bs, const char *filename,
|
||||
QDict *options, int flags)
|
||||
static int iscsi_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct iscsi_context *iscsi = NULL;
|
||||
@ -1016,6 +1029,9 @@ static int iscsi_open(BlockDriverState *bs, const char *filename,
|
||||
struct scsi_task *task = NULL;
|
||||
struct scsi_inquiry_standard *inq = NULL;
|
||||
char *initiator_name = NULL;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
const char *filename;
|
||||
int ret;
|
||||
|
||||
if ((BDRV_SECTOR_SIZE % 512) != 0) {
|
||||
@ -1025,6 +1041,18 @@ static int iscsi_open(BlockDriverState *bs, const char *filename,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
|
||||
iscsi_url = iscsi_parse_full_url(iscsi, filename);
|
||||
if (iscsi_url == NULL) {
|
||||
error_report("Failed to parse URL : %s", filename);
|
||||
@ -1126,6 +1154,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename,
|
||||
#endif
|
||||
|
||||
out:
|
||||
qemu_opts_del(opts);
|
||||
if (initiator_name != NULL) {
|
||||
g_free(initiator_name);
|
||||
}
|
||||
@ -1190,6 +1219,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options)
|
||||
int64_t total_size = 0;
|
||||
BlockDriverState bs;
|
||||
IscsiLun *iscsilun = NULL;
|
||||
QDict *bs_options;
|
||||
|
||||
memset(&bs, 0, sizeof(BlockDriverState));
|
||||
|
||||
@ -1204,7 +1234,11 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options)
|
||||
bs.opaque = g_malloc0(sizeof(struct IscsiLun));
|
||||
iscsilun = bs.opaque;
|
||||
|
||||
ret = iscsi_open(&bs, filename, NULL, 0);
|
||||
bs_options = qdict_new();
|
||||
qdict_put(bs_options, "filename", qstring_from_str(filename));
|
||||
ret = iscsi_open(&bs, bs_options, 0);
|
||||
QDECREF(bs_options);
|
||||
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -507,7 +507,7 @@ static void mirror_complete(BlockJob *job, Error **errp)
|
||||
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
|
||||
int ret;
|
||||
|
||||
ret = bdrv_open_backing_file(s->target);
|
||||
ret = bdrv_open_backing_file(s->target, NULL);
|
||||
if (ret < 0) {
|
||||
char backing_filename[PATH_MAX];
|
||||
bdrv_get_full_backing_filename(s->target, backing_filename,
|
||||
|
@ -454,8 +454,7 @@ static void nbd_teardown_connection(BlockDriverState *bs)
|
||||
closesocket(s->sock);
|
||||
}
|
||||
|
||||
static int nbd_open(BlockDriverState *bs, const char* filename,
|
||||
QDict *options, int flags)
|
||||
static int nbd_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVNBDState *s = bs->opaque;
|
||||
int result;
|
||||
|
17
block/qcow.c
17
block/qcow.c
@ -787,8 +787,21 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *out_buf;
|
||||
uint64_t cluster_offset;
|
||||
|
||||
if (nb_sectors != s->cluster_sectors)
|
||||
return -EINVAL;
|
||||
if (nb_sectors != s->cluster_sectors) {
|
||||
ret = -EINVAL;
|
||||
|
||||
/* Zero-pad last write if image size is not cluster aligned */
|
||||
if (sector_num + nb_sectors == bs->total_sectors &&
|
||||
nb_sectors < s->cluster_sectors) {
|
||||
uint8_t *pad_buf = qemu_blockalign(bs, s->cluster_size);
|
||||
memset(pad_buf, 0, s->cluster_size);
|
||||
memcpy(pad_buf, buf, nb_sectors * BDRV_SECTOR_SIZE);
|
||||
ret = qcow_write_compressed(bs, sector_num,
|
||||
pad_buf, s->cluster_sectors);
|
||||
qemu_vfree(pad_buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
|
||||
|
||||
|
@ -1537,8 +1537,21 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nb_sectors != s->cluster_sectors)
|
||||
return -EINVAL;
|
||||
if (nb_sectors != s->cluster_sectors) {
|
||||
ret = -EINVAL;
|
||||
|
||||
/* Zero-pad last write if image size is not cluster aligned */
|
||||
if (sector_num + nb_sectors == bs->total_sectors &&
|
||||
nb_sectors < s->cluster_sectors) {
|
||||
uint8_t *pad_buf = qemu_blockalign(bs, s->cluster_size);
|
||||
memset(pad_buf, 0, s->cluster_size);
|
||||
memcpy(pad_buf, buf, nb_sectors * BDRV_SECTOR_SIZE);
|
||||
ret = qcow2_write_compressed(bs, sector_num,
|
||||
pad_buf, s->cluster_sectors);
|
||||
qemu_vfree(pad_buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
|
||||
|
||||
|
@ -262,15 +262,42 @@ error:
|
||||
}
|
||||
#endif
|
||||
|
||||
static int raw_open_common(BlockDriverState *bs, const char *filename,
|
||||
static QemuOptsList raw_runtime_opts = {
|
||||
.name = "raw",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "filename",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "File name of the image",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
int bdrv_flags, int open_flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
const char *filename;
|
||||
int fd, ret;
|
||||
|
||||
opts = qemu_opts_create_nofail(&raw_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;
|
||||
}
|
||||
|
||||
filename = qemu_opt_get(opts, "filename");
|
||||
|
||||
ret = raw_normalize_devicepath(&filename);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->open_flags = open_flags;
|
||||
@ -280,16 +307,18 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
|
||||
fd = qemu_open(filename, s->open_flags, 0644);
|
||||
if (fd < 0) {
|
||||
ret = -errno;
|
||||
if (ret == -EROFS)
|
||||
if (ret == -EROFS) {
|
||||
ret = -EACCES;
|
||||
return ret;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
s->fd = fd;
|
||||
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
if (raw_set_aio(&s->aio_ctx, &s->use_aio, bdrv_flags)) {
|
||||
qemu_close(fd);
|
||||
return -errno;
|
||||
ret = -errno;
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -300,16 +329,18 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
fail:
|
||||
qemu_opts_del(opts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int raw_open(BlockDriverState *bs, const char *filename,
|
||||
QDict *options, int flags)
|
||||
static int raw_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
s->type = FTYPE_FILE;
|
||||
return raw_open_common(bs, filename, flags, 0);
|
||||
return raw_open_common(bs, options, flags, 0);
|
||||
}
|
||||
|
||||
static int raw_reopen_prepare(BDRVReopenState *state,
|
||||
@ -1293,11 +1324,11 @@ static int check_hdev_writable(BDRVRawState *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdev_open(BlockDriverState *bs, const char *filename,
|
||||
QDict *options, int flags)
|
||||
static int hdev_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
const char *filename = qdict_get_str(options, "filename");
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
if (strstart(filename, "/dev/cdrom", NULL)) {
|
||||
@ -1338,7 +1369,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename,
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = raw_open_common(bs, filename, flags, 0);
|
||||
ret = raw_open_common(bs, options, flags, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -1532,8 +1563,7 @@ static BlockDriver bdrv_host_device = {
|
||||
};
|
||||
|
||||
#ifdef __linux__
|
||||
static int floppy_open(BlockDriverState *bs, const char *filename,
|
||||
QDict *options, int flags)
|
||||
static int floppy_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
@ -1541,7 +1571,7 @@ static int floppy_open(BlockDriverState *bs, const char *filename,
|
||||
s->type = FTYPE_FD;
|
||||
|
||||
/* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
|
||||
ret = raw_open_common(bs, filename, flags, O_NONBLOCK);
|
||||
ret = raw_open_common(bs, options, flags, O_NONBLOCK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1655,15 +1685,14 @@ static BlockDriver bdrv_host_floppy = {
|
||||
.bdrv_eject = floppy_eject,
|
||||
};
|
||||
|
||||
static int cdrom_open(BlockDriverState *bs, const char *filename,
|
||||
QDict *options, int flags)
|
||||
static int cdrom_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
s->type = FTYPE_CD;
|
||||
|
||||
/* open will not fail even if no CD is inserted, so add O_NONBLOCK */
|
||||
return raw_open_common(bs, filename, flags, O_NONBLOCK);
|
||||
return raw_open_common(bs, options, flags, O_NONBLOCK);
|
||||
}
|
||||
|
||||
static int cdrom_probe_device(const char *filename)
|
||||
@ -1764,15 +1793,14 @@ static BlockDriver bdrv_host_cdrom = {
|
||||
#endif /* __linux__ */
|
||||
|
||||
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
static int cdrom_open(BlockDriverState *bs, const char *filename,
|
||||
QDict *options, int flags)
|
||||
static int cdrom_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
|
||||
s->type = FTYPE_CD;
|
||||
|
||||
ret = raw_open_common(bs, filename, flags, 0);
|
||||
ret = raw_open_common(bs, options, flags, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -221,21 +221,49 @@ static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_open(BlockDriverState *bs, const char *filename,
|
||||
QDict *options, int flags)
|
||||
static QemuOptsList raw_runtime_opts = {
|
||||
.name = "raw",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "filename",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "File name of the image",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static int raw_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int access_flags;
|
||||
DWORD overlapped;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
const char *filename;
|
||||
int ret;
|
||||
|
||||
s->type = FTYPE_FILE;
|
||||
|
||||
opts = qemu_opts_create_nofail(&raw_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;
|
||||
}
|
||||
|
||||
filename = qemu_opt_get(opts, "filename");
|
||||
|
||||
raw_parse_flags(flags, &access_flags, &overlapped);
|
||||
|
||||
if ((flags & BDRV_O_NATIVE_AIO) && aio == NULL) {
|
||||
aio = win32_aio_init();
|
||||
if (aio == NULL) {
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,20 +273,27 @@ static int raw_open(BlockDriverState *bs, const char *filename,
|
||||
if (s->hfile == INVALID_HANDLE_VALUE) {
|
||||
int err = GetLastError();
|
||||
|
||||
if (err == ERROR_ACCESS_DENIED)
|
||||
return -EACCES;
|
||||
return -EINVAL;
|
||||
if (err == ERROR_ACCESS_DENIED) {
|
||||
ret = -EACCES;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (flags & BDRV_O_NATIVE_AIO) {
|
||||
int ret = win32_aio_attach(aio, s->hfile);
|
||||
ret = win32_aio_attach(aio, s->hfile);
|
||||
if (ret < 0) {
|
||||
CloseHandle(s->hfile);
|
||||
return ret;
|
||||
goto fail;
|
||||
}
|
||||
s->aio = aio;
|
||||
}
|
||||
return 0;
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
qemu_opts_del(opts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
|
||||
@ -495,13 +530,13 @@ static int hdev_probe_device(const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdev_open(BlockDriverState *bs, const char *filename,
|
||||
QDict *options, int flags)
|
||||
static int hdev_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int access_flags, create_flags;
|
||||
DWORD overlapped;
|
||||
char device_name[64];
|
||||
const char *filename = qdict_get_str(options, "filename");
|
||||
|
||||
if (strstart(filename, "/dev/cdrom", NULL)) {
|
||||
if (find_cdrom(device_name, sizeof(device_name)) < 0)
|
||||
|
32
block/rbd.c
32
block/rbd.c
@ -441,8 +441,21 @@ static int qemu_rbd_aio_flush_cb(void *opaque)
|
||||
return (s->qemu_aio_count > 0);
|
||||
}
|
||||
|
||||
static int qemu_rbd_open(BlockDriverState *bs, const char *filename,
|
||||
QDict *options, int flags)
|
||||
/* TODO Convert to fine grained options */
|
||||
static QemuOptsList runtime_opts = {
|
||||
.name = "rbd",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "filename",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Specification of the rbd image",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVRBDState *s = bs->opaque;
|
||||
char pool[RBD_MAX_POOL_NAME_SIZE];
|
||||
@ -450,8 +463,23 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename,
|
||||
char conf[RBD_MAX_CONF_SIZE];
|
||||
char clientname_buf[RBD_MAX_CONF_SIZE];
|
||||
char *clientname;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
const char *filename;
|
||||
int r;
|
||||
|
||||
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);
|
||||
qemu_opts_del(opts);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
filename = qemu_opt_get(opts, "filename");
|
||||
qemu_opts_del(opts);
|
||||
|
||||
if (qemu_rbd_parsename(filename, pool, sizeof(pool),
|
||||
snap_buf, sizeof(snap_buf),
|
||||
s->name, sizeof(s->name),
|
||||
|
@ -1126,8 +1126,21 @@ static int write_object(int fd, char *buf, uint64_t oid, int copies,
|
||||
create, cache_flags);
|
||||
}
|
||||
|
||||
static int sd_open(BlockDriverState *bs, const char *filename,
|
||||
QDict *options, int flags)
|
||||
/* TODO Convert to fine grained options */
|
||||
static QemuOptsList runtime_opts = {
|
||||
.name = "sheepdog",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "filename",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "URL to the sheepdog image",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static int sd_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
int ret, fd;
|
||||
uint32_t vid = 0;
|
||||
@ -1135,6 +1148,20 @@ static int sd_open(BlockDriverState *bs, const char *filename,
|
||||
char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
|
||||
uint32_t snapid;
|
||||
char *buf = NULL;
|
||||
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");
|
||||
|
||||
QLIST_INIT(&s->inflight_aio_head);
|
||||
QLIST_INIT(&s->pending_aio_head);
|
||||
@ -1199,6 +1226,7 @@ static int sd_open(BlockDriverState *bs, const char *filename,
|
||||
bs->total_sectors = s->inode.vdi_size / SECTOR_SIZE;
|
||||
pstrcpy(s->name, sizeof(s->name), vdi);
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
qemu_opts_del(opts);
|
||||
g_free(buf);
|
||||
return 0;
|
||||
out:
|
||||
@ -1206,6 +1234,7 @@ out:
|
||||
if (s->fd >= 0) {
|
||||
closesocket(s->fd);
|
||||
}
|
||||
qemu_opts_del(opts);
|
||||
g_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
@ -608,8 +608,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ssh_file_open(BlockDriverState *bs, const char *filename,
|
||||
QDict *options, int bdrv_flags)
|
||||
static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags)
|
||||
{
|
||||
BDRVSSHState *s = bs->opaque;
|
||||
int ret;
|
||||
|
197
block/vvfat.c
197
block/vvfat.c
@ -1,4 +1,4 @@
|
||||
/* vim:set shiftwidth=4 ts=8: */
|
||||
/* vim:set shiftwidth=4 ts=4: */
|
||||
/*
|
||||
* QEMU Block driver for virtual VFAT (shadows a local directory)
|
||||
*
|
||||
@ -28,6 +28,8 @@
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/module.h"
|
||||
#include "migration/migration.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
|
||||
#ifndef S_IWGRP
|
||||
#define S_IWGRP 0
|
||||
@ -988,11 +990,90 @@ static void vvfat_rebind(BlockDriverState *bs)
|
||||
s->bs = bs;
|
||||
}
|
||||
|
||||
static int vvfat_open(BlockDriverState *bs, const char* dirname,
|
||||
QDict *options, int flags)
|
||||
static QemuOptsList runtime_opts = {
|
||||
.name = "vvfat",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "dir",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Host directory to map to the vvfat device",
|
||||
},
|
||||
{
|
||||
.name = "fat-type",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "FAT type (12, 16 or 32)",
|
||||
},
|
||||
{
|
||||
.name = "floppy",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Create a floppy rather than a hard disk image",
|
||||
},
|
||||
{
|
||||
.name = "rw",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Make the image writable",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static void vvfat_parse_filename(const char *filename, QDict *options,
|
||||
Error **errp)
|
||||
{
|
||||
int fat_type = 0;
|
||||
bool floppy = false;
|
||||
bool rw = false;
|
||||
int i;
|
||||
|
||||
if (!strstart(filename, "fat:", NULL)) {
|
||||
error_setg(errp, "File name string must start with 'fat:'");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parse options */
|
||||
if (strstr(filename, ":32:")) {
|
||||
fat_type = 32;
|
||||
} else if (strstr(filename, ":16:")) {
|
||||
fat_type = 16;
|
||||
} else if (strstr(filename, ":12:")) {
|
||||
fat_type = 12;
|
||||
}
|
||||
|
||||
if (strstr(filename, ":floppy:")) {
|
||||
floppy = true;
|
||||
}
|
||||
|
||||
if (strstr(filename, ":rw:")) {
|
||||
rw = true;
|
||||
}
|
||||
|
||||
/* Get the directory name without options */
|
||||
i = strrchr(filename, ':') - filename;
|
||||
assert(i >= 3);
|
||||
if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) {
|
||||
/* workaround for DOS drive names */
|
||||
filename += i - 1;
|
||||
} else {
|
||||
filename += i + 1;
|
||||
}
|
||||
|
||||
/* Fill in the options QDict */
|
||||
qdict_put(options, "dir", qstring_from_str(filename));
|
||||
qdict_put(options, "fat-type", qint_from_int(fat_type));
|
||||
qdict_put(options, "floppy", qbool_from_int(floppy));
|
||||
qdict_put(options, "rw", qbool_from_int(rw));
|
||||
}
|
||||
|
||||
static int vvfat_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVVVFATState *s = bs->opaque;
|
||||
int i, cyls, heads, secs;
|
||||
int cyls, heads, secs;
|
||||
bool floppy;
|
||||
const char *dirname;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
#ifdef DEBUG
|
||||
vvv = s;
|
||||
@ -1003,34 +1084,27 @@ DLOG(if (stderr == NULL) {
|
||||
setbuf(stderr, NULL);
|
||||
})
|
||||
|
||||
s->bs = bs;
|
||||
|
||||
/* LATER TODO: if FAT32, adjust */
|
||||
s->sectors_per_cluster=0x10;
|
||||
|
||||
s->current_cluster=0xffffffff;
|
||||
|
||||
s->first_sectors_number=0x40;
|
||||
/* read only is the default for safety */
|
||||
bs->read_only = 1;
|
||||
s->qcow = s->write_target = NULL;
|
||||
s->qcow_filename = NULL;
|
||||
s->fat2 = NULL;
|
||||
s->downcase_short_names = 1;
|
||||
|
||||
if (!strstart(dirname, "fat:", NULL))
|
||||
return -1;
|
||||
|
||||
if (strstr(dirname, ":32:")) {
|
||||
fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
|
||||
s->fat_type = 32;
|
||||
} else if (strstr(dirname, ":16:")) {
|
||||
s->fat_type = 16;
|
||||
} else if (strstr(dirname, ":12:")) {
|
||||
s->fat_type = 12;
|
||||
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;
|
||||
}
|
||||
|
||||
if (strstr(dirname, ":floppy:")) {
|
||||
dirname = qemu_opt_get(opts, "dir");
|
||||
if (!dirname) {
|
||||
qerror_report(ERROR_CLASS_GENERIC_ERROR, "vvfat block driver requires "
|
||||
"a 'dir' option");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->fat_type = qemu_opt_get_number(opts, "fat-type", 0);
|
||||
floppy = qemu_opt_get_bool(opts, "floppy", false);
|
||||
|
||||
if (floppy) {
|
||||
/* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */
|
||||
if (!s->fat_type) {
|
||||
s->fat_type = 12;
|
||||
@ -1052,29 +1126,56 @@ DLOG(if (stderr == NULL) {
|
||||
heads = 16;
|
||||
secs = 63;
|
||||
}
|
||||
|
||||
switch (s->fat_type) {
|
||||
case 32:
|
||||
fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. "
|
||||
"You are welcome to do so!\n");
|
||||
break;
|
||||
case 16:
|
||||
case 12:
|
||||
break;
|
||||
default:
|
||||
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Valid FAT types are only "
|
||||
"12, 16 and 32");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
s->bs = bs;
|
||||
|
||||
/* LATER TODO: if FAT32, adjust */
|
||||
s->sectors_per_cluster=0x10;
|
||||
|
||||
s->current_cluster=0xffffffff;
|
||||
|
||||
s->first_sectors_number=0x40;
|
||||
/* read only is the default for safety */
|
||||
bs->read_only = 1;
|
||||
s->qcow = s->write_target = NULL;
|
||||
s->qcow_filename = NULL;
|
||||
s->fat2 = NULL;
|
||||
s->downcase_short_names = 1;
|
||||
|
||||
fprintf(stderr, "vvfat %s chs %d,%d,%d\n",
|
||||
dirname, cyls, heads, secs);
|
||||
|
||||
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
|
||||
|
||||
if (strstr(dirname, ":rw:")) {
|
||||
if (enable_write_target(s))
|
||||
return -1;
|
||||
if (qemu_opt_get_bool(opts, "rw", false)) {
|
||||
if (enable_write_target(s)) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
bs->read_only = 0;
|
||||
}
|
||||
|
||||
i = strrchr(dirname, ':') - dirname;
|
||||
assert(i >= 3);
|
||||
if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
|
||||
/* workaround for DOS drive names */
|
||||
dirname += i-1;
|
||||
else
|
||||
dirname += i+1;
|
||||
|
||||
bs->total_sectors = cyls * heads * secs;
|
||||
|
||||
if (init_directories(s, dirname, heads, secs)) {
|
||||
return -1;
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
|
||||
@ -1094,7 +1195,10 @@ DLOG(if (stderr == NULL) {
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
fail:
|
||||
qemu_opts_del(opts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void vvfat_close_current_file(BDRVVVFATState *s)
|
||||
@ -2867,14 +2971,17 @@ static void vvfat_close(BlockDriverState *bs)
|
||||
|
||||
static BlockDriver bdrv_vvfat = {
|
||||
.format_name = "vvfat",
|
||||
.protocol_name = "fat",
|
||||
.instance_size = sizeof(BDRVVVFATState),
|
||||
|
||||
.bdrv_parse_filename = vvfat_parse_filename,
|
||||
.bdrv_file_open = vvfat_open,
|
||||
.bdrv_close = vvfat_close,
|
||||
.bdrv_rebind = vvfat_rebind,
|
||||
|
||||
.bdrv_read = vvfat_co_read,
|
||||
.bdrv_write = vvfat_co_write,
|
||||
.bdrv_close = vvfat_close,
|
||||
.bdrv_co_is_allocated = vvfat_co_is_allocated,
|
||||
.protocol_name = "fat",
|
||||
};
|
||||
|
||||
static void bdrv_vvfat_init(void)
|
||||
|
@ -137,7 +137,7 @@ int bdrv_parse_cache_flags(const char *mode, int *flags);
|
||||
int bdrv_parse_discard_flags(const char *mode, int *flags);
|
||||
int bdrv_file_open(BlockDriverState **pbs, const char *filename,
|
||||
QDict *options, int flags);
|
||||
int bdrv_open_backing_file(BlockDriverState *bs);
|
||||
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options);
|
||||
int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
|
||||
int flags, BlockDriver *drv);
|
||||
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
|
||||
|
@ -87,8 +87,7 @@ struct BlockDriver {
|
||||
void (*bdrv_reopen_abort)(BDRVReopenState *reopen_state);
|
||||
|
||||
int (*bdrv_open)(BlockDriverState *bs, QDict *options, int flags);
|
||||
int (*bdrv_file_open)(BlockDriverState *bs, const char *filename,
|
||||
QDict *options, int flags);
|
||||
int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags);
|
||||
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
|
||||
|
@ -1425,12 +1425,8 @@ static int img_convert(int argc, char **argv)
|
||||
}
|
||||
assert (remainder == 0);
|
||||
|
||||
if (n < cluster_sectors) {
|
||||
memset(buf + n * 512, 0, cluster_size - n * 512);
|
||||
}
|
||||
if (!buffer_is_zero(buf, cluster_size)) {
|
||||
ret = bdrv_write_compressed(out_bs, sector_num, buf,
|
||||
cluster_sectors);
|
||||
if (!buffer_is_zero(buf, n * BDRV_SECTOR_SIZE)) {
|
||||
ret = bdrv_write_compressed(out_bs, sector_num, buf, n);
|
||||
if (ret != 0) {
|
||||
error_report("error while compressing sector %" PRId64
|
||||
": %s", sector_num, strerror(-ret));
|
||||
|
@ -142,6 +142,13 @@ run_qemu -drive media=cdrom,cache=writethrough
|
||||
run_qemu -drive media=cdrom,cache=unsafe
|
||||
run_qemu -drive media=cdrom,cache=invalid_value
|
||||
|
||||
echo
|
||||
echo === Specifying the protocol layer ===
|
||||
echo
|
||||
|
||||
run_qemu -drive file=$TEST_IMG,file.driver=file
|
||||
run_qemu -drive file=$TEST_IMG,file.driver=qcow2
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
|
@ -159,4 +159,14 @@ q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||
Testing: -drive media=cdrom,cache=invalid_value
|
||||
QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option
|
||||
|
||||
|
||||
=== Specifying the protocol layer ===
|
||||
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file
|
||||
q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2
|
||||
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: Can't use 'qcow2' as a block driver for the protocol level
|
||||
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: could not open disk image TEST_DIR/t.qcow2: Invalid argument
|
||||
|
||||
*** done
|
||||
|
73
tests/qemu-iotests/053
Executable file
73
tests/qemu-iotests/053
Executable file
@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test qemu-img convert when image length is not a multiple of cluster size
|
||||
#
|
||||
# Copyright (C) 2013 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=stefanha@redhat.com
|
||||
|
||||
seq=`basename $0`
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here=`pwd`
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
rm -f $TEST_IMG.orig
|
||||
_cleanup_test_img
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow2 qcow
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
echo
|
||||
echo "== Creating single sector image =="
|
||||
|
||||
_make_test_img 512
|
||||
$QEMU_IO -c "write -P0xa 0 512" $TEST_IMG | _filter_qemu_io
|
||||
mv $TEST_IMG $TEST_IMG.orig
|
||||
|
||||
echo
|
||||
echo "== Converting the image, compressed =="
|
||||
|
||||
$QEMU_IMG convert -c -O $IMGFMT $TEST_IMG.orig $TEST_IMG
|
||||
_check_test_img
|
||||
|
||||
echo
|
||||
echo "== Checking compressed image virtual disk size =="
|
||||
|
||||
_img_info | grep '^virtual size:'
|
||||
|
||||
echo
|
||||
echo "== Verifying the compressed image =="
|
||||
|
||||
$QEMU_IO -c "read -P0xa 0 512" $TEST_IMG | _filter_qemu_io
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
||||
|
17
tests/qemu-iotests/053.out
Normal file
17
tests/qemu-iotests/053.out
Normal file
@ -0,0 +1,17 @@
|
||||
QA output created by 053
|
||||
|
||||
== Creating single sector image ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=512
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
== Converting the image, compressed ==
|
||||
No errors were found on the image.
|
||||
|
||||
== Checking compressed image virtual disk size ==
|
||||
virtual size: 512 (512 bytes)
|
||||
|
||||
== Verifying the compressed image ==
|
||||
read 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
*** done
|
@ -155,7 +155,7 @@ _filter_qemu_io()
|
||||
# replace occurrences of QEMU_PROG with "qemu"
|
||||
_filter_qemu()
|
||||
{
|
||||
sed -e "s#$(basename $QEMU_PROG)#QEMU_PROG#g"
|
||||
sed -e "s#^$(basename $QEMU_PROG):#QEMU_PROG:#"
|
||||
}
|
||||
|
||||
# make sure this script returns success
|
||||
|
@ -59,3 +59,4 @@
|
||||
050 rw auto backing quick
|
||||
051 rw auto
|
||||
052 rw auto backing
|
||||
053 rw auto
|
||||
|
Loading…
Reference in New Issue
Block a user