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

# By Max Reitz (16) and others
# Via Kevin Wolf
* kwolf/for-anthony: (33 commits)
  qemu-iotests: Fix test 038
  block: Assert validity of BdrvActionOps
  qemu-iotests: Cleanup test image in test number 007
  qemu-img: fix invalid JSON
  coroutine: add ./configure --disable-coroutine-pool
  qemu-iotests: Adjustments due to error propagation
  qcow2: Use Error parameter
  qemu-img create: Emit filename on error
  block: Error parameter for create functions
  block: Error parameter for open functions
  bdrv: Use "Error" for creating images
  bdrv: Use "Error" for opening images
  qemu-iotests: add 057 internal snapshot for block device test case
  hmp: add interface hmp_snapshot_delete_blkdev_internal
  hmp: add interface hmp_snapshot_blkdev_internal
  qmp: add interface blockdev-snapshot-delete-internal-sync
  qmp: add interface blockdev-snapshot-internal-sync
  qmp: add internal snapshot support in qmp_transaction
  snapshot: distinguish id and name in snapshot delete
  snapshot: new function bdrv_snapshot_find_by_id_and_name()
  ...

Message-id: 1379073063-14963-1-git-send-email-kwolf@redhat.com
This commit is contained in:
Anthony Liguori
2013-09-17 09:51:40 -05:00
73 changed files with 2878 additions and 425 deletions
+6
View File
@@ -188,3 +188,9 @@ class QEMUMonitorProtocol:
def settimeout(self, timeout):
self.__sock.settimeout(timeout)
def get_sock_fd(self):
return self.__sock.fileno()
def is_scm_available(self):
return self.__sock.family == socket.AF_UNIX
+126 -58
View File
@@ -394,18 +394,26 @@ typedef struct CreateCo {
char *filename;
QEMUOptionParameter *options;
int ret;
Error *err;
} CreateCo;
static void coroutine_fn bdrv_create_co_entry(void *opaque)
{
Error *local_err = NULL;
int ret;
CreateCo *cco = opaque;
assert(cco->drv);
cco->ret = cco->drv->bdrv_create(cco->filename, cco->options);
ret = cco->drv->bdrv_create(cco->filename, cco->options, &local_err);
if (error_is_set(&local_err)) {
error_propagate(&cco->err, local_err);
}
cco->ret = ret;
}
int bdrv_create(BlockDriver *drv, const char* filename,
QEMUOptionParameter *options)
QEMUOptionParameter *options, Error **errp)
{
int ret;
@@ -415,9 +423,11 @@ int bdrv_create(BlockDriver *drv, const char* filename,
.filename = g_strdup(filename),
.options = options,
.ret = NOT_DONE,
.err = NULL,
};
if (!drv->bdrv_create) {
error_setg(errp, "Driver '%s' does not support image creation", drv->format_name);
ret = -ENOTSUP;
goto out;
}
@@ -434,22 +444,37 @@ int bdrv_create(BlockDriver *drv, const char* filename,
}
ret = cco.ret;
if (ret < 0) {
if (error_is_set(&cco.err)) {
error_propagate(errp, cco.err);
} else {
error_setg_errno(errp, -ret, "Could not create image");
}
}
out:
g_free(cco.filename);
return ret;
}
int bdrv_create_file(const char* filename, QEMUOptionParameter *options)
int bdrv_create_file(const char* filename, QEMUOptionParameter *options,
Error **errp)
{
BlockDriver *drv;
Error *local_err = NULL;
int ret;
drv = bdrv_find_protocol(filename, true);
if (drv == NULL) {
error_setg(errp, "Could not find protocol for file '%s'", filename);
return -ENOENT;
}
return bdrv_create(drv, filename, options);
ret = bdrv_create(drv, filename, options, &local_err);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
}
return ret;
}
/*
@@ -552,7 +577,7 @@ BlockDriver *bdrv_find_protocol(const char *filename,
}
static int find_image_format(BlockDriverState *bs, const char *filename,
BlockDriver **pdrv)
BlockDriver **pdrv, Error **errp)
{
int score, score_max;
BlockDriver *drv1, *drv;
@@ -563,6 +588,7 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
if (bs->sg || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) {
drv = bdrv_find_format("raw");
if (!drv) {
error_setg(errp, "Could not find raw image format");
ret = -ENOENT;
}
*pdrv = drv;
@@ -571,6 +597,8 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
ret = bdrv_pread(bs, 0, buf, sizeof(buf));
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read image for determining its "
"format");
*pdrv = NULL;
return ret;
}
@@ -587,6 +615,8 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
}
}
if (!drv) {
error_setg(errp, "Could not determine image format: No compatible "
"driver found");
ret = -ENOENT;
}
*pdrv = drv;
@@ -706,10 +736,11 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
* Removes all processed options from *options.
*/
static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
QDict *options, int flags, BlockDriver *drv)
QDict *options, int flags, BlockDriver *drv, Error **errp)
{
int ret, open_flags;
const char *filename;
Error *local_err = NULL;
assert(drv != NULL);
assert(bs->file == NULL);
@@ -738,6 +769,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
bs->read_only = !(open_flags & BDRV_O_RDWR);
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) {
error_setg(errp, "Driver '%s' is not whitelisted", drv->format_name);
return -ENOTSUP;
}
@@ -761,25 +793,32 @@ 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, options, open_flags);
ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
} 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);
error_setg(errp, "Can't use '%s' as a block driver for the "
"protocol level", drv->format_name);
ret = -EINVAL;
goto free_and_fail;
}
bs->file = file;
ret = drv->bdrv_open(bs, options, open_flags);
ret = drv->bdrv_open(bs, options, open_flags, &local_err);
}
if (ret < 0) {
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
} else if (filename) {
error_setg_errno(errp, -ret, "Could not open '%s'", filename);
} else {
error_setg_errno(errp, -ret, "Could not open image");
}
goto free_and_fail;
}
ret = refresh_total_sectors(bs, bs->total_sectors);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not refresh total sector count");
goto free_and_fail;
}
@@ -808,12 +847,13 @@ free_and_fail:
* dictionary, it needs to use QINCREF() before calling bdrv_file_open.
*/
int bdrv_file_open(BlockDriverState **pbs, const char *filename,
QDict *options, int flags)
QDict *options, int flags, Error **errp)
{
BlockDriverState *bs;
BlockDriver *drv;
const char *drvname;
bool allow_protocol_prefix = false;
Error *local_err = NULL;
int ret;
/* NULL means an empty set of options */
@@ -832,8 +872,8 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
qdict_put(options, "filename", qstring_from_str(filename));
allow_protocol_prefix = true;
} else {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't specify 'file' and "
"'filename' options at the same time");
error_setg(errp, "Can't specify 'file' and 'filename' options at the "
"same time");
ret = -EINVAL;
goto fail;
}
@@ -842,53 +882,53 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
drvname = qdict_get_try_str(options, "driver");
if (drvname) {
drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR));
if (!drv) {
error_setg(errp, "Unknown driver '%s'", drvname);
}
qdict_del(options, "driver");
} else if (filename) {
drv = bdrv_find_protocol(filename, allow_protocol_prefix);
if (!drv) {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Unknown protocol");
error_setg(errp, "Unknown protocol");
}
} else {
qerror_report(ERROR_CLASS_GENERIC_ERROR,
"Must specify either driver or file");
error_setg(errp, "Must specify either driver or file");
drv = NULL;
}
if (!drv) {
/* errp has been set already */
ret = -ENOENT;
goto fail;
}
/* Parse the filename and open it */
if (drv->bdrv_parse_filename && filename) {
Error *local_err = NULL;
drv->bdrv_parse_filename(filename, options, &local_err);
if (error_is_set(&local_err)) {
qerror_report_err(local_err);
error_free(local_err);
error_propagate(errp, local_err);
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",
drv->format_name);
error_setg(errp, "The '%s' block driver requires a file name",
drv->format_name);
ret = -EINVAL;
goto fail;
}
ret = bdrv_open_common(bs, NULL, options, flags, drv);
ret = bdrv_open_common(bs, NULL, options, flags, drv, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto fail;
}
/* Check if any unknown options were used */
if (qdict_size(options) != 0) {
const QDictEntry *entry = qdict_first(options);
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Block protocol '%s' doesn't "
"support the option '%s'",
drv->format_name, entry->key);
error_setg(errp, "Block protocol '%s' doesn't support the option '%s'",
drv->format_name, entry->key);
ret = -EINVAL;
goto fail;
}
@@ -915,11 +955,12 @@ fail:
* 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)
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
{
char backing_filename[PATH_MAX];
int back_flags, ret;
BlockDriver *back_drv = NULL;
Error *local_err = NULL;
if (bs->backing_hd != NULL) {
QDECREF(options);
@@ -952,11 +993,12 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options)
ret = bdrv_open(bs->backing_hd,
*backing_filename ? backing_filename : NULL, options,
back_flags, back_drv);
back_flags, back_drv, &local_err);
if (ret < 0) {
bdrv_unref(bs->backing_hd);
bs->backing_hd = NULL;
bs->open_flags |= BDRV_O_NO_BACKING;
error_propagate(errp, local_err);
return ret;
}
return 0;
@@ -990,7 +1032,7 @@ static void extract_subqdict(QDict *src, QDict **dst, const char *start)
* dictionary, it needs to use QINCREF() before calling bdrv_open.
*/
int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
int flags, BlockDriver *drv)
int flags, BlockDriver *drv, Error **errp)
{
int ret;
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
@@ -998,6 +1040,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
BlockDriverState *file = NULL;
QDict *file_options = NULL;
const char *drvname;
Error *local_err = NULL;
/* NULL means an empty set of options */
if (options == NULL) {
@@ -1016,7 +1059,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
char backing_filename[PATH_MAX];
if (qdict_size(options) != 0) {
error_report("Can't use snapshot=on with driver-specific options");
error_setg(errp, "Can't use snapshot=on with driver-specific options");
ret = -EINVAL;
goto fail;
}
@@ -1027,7 +1070,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
/* if there is a backing file, use it */
bs1 = bdrv_new("");
ret = bdrv_open(bs1, filename, NULL, 0, drv);
ret = bdrv_open(bs1, filename, NULL, 0, drv, &local_err);
if (ret < 0) {
bdrv_unref(bs1);
goto fail;
@@ -1038,6 +1081,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not get temporary filename");
goto fail;
}
@@ -1046,6 +1090,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
snprintf(backing_filename, sizeof(backing_filename),
"%s", filename);
} else if (!realpath(filename, backing_filename)) {
error_setg_errno(errp, errno, "Could not resolve path '%s'", filename);
ret = -errno;
goto fail;
}
@@ -1062,9 +1107,14 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
drv->format_name);
}
ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options);
ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
free_option_parameters(create_options);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not create temporary overlay "
"'%s': %s", tmp_filename,
error_get_pretty(local_err));
error_free(local_err);
local_err = NULL;
goto fail;
}
@@ -1081,7 +1131,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
extract_subqdict(options, &file_options, "file.");
ret = bdrv_file_open(&file, filename, file_options,
bdrv_open_flags(bs, flags | BDRV_O_UNMAP));
bdrv_open_flags(bs, flags | BDRV_O_UNMAP), &local_err);
if (ret < 0) {
goto fail;
}
@@ -1094,7 +1144,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
}
if (!drv) {
ret = find_image_format(file, filename, &drv);
ret = find_image_format(file, filename, &drv, &local_err);
}
if (!drv) {
@@ -1102,7 +1152,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
}
/* Open the image */
ret = bdrv_open_common(bs, file, options, flags, drv);
ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
if (ret < 0) {
goto unlink_and_fail;
}
@@ -1117,7 +1167,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
QDict *backing_options;
extract_subqdict(options, &backing_options, "backing.");
ret = bdrv_open_backing_file(bs, backing_options);
ret = bdrv_open_backing_file(bs, backing_options, &local_err);
if (ret < 0) {
goto close_and_fail;
}
@@ -1126,9 +1176,9 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
/* Check if any unknown options were used */
if (qdict_size(options) != 0) {
const QDictEntry *entry = qdict_first(options);
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Block format '%s' used by "
"device '%s' doesn't support the option '%s'",
drv->format_name, bs->device_name, entry->key);
error_setg(errp, "Block format '%s' used by device '%s' doesn't "
"support the option '%s'", drv->format_name, bs->device_name,
entry->key);
ret = -EINVAL;
goto close_and_fail;
@@ -1152,11 +1202,17 @@ fail:
QDECREF(bs->options);
QDECREF(options);
bs->options = NULL;
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
}
return ret;
close_and_fail:
bdrv_close(bs);
QDECREF(options);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
}
return ret;
}
@@ -4433,6 +4489,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
BlockDriverState *bs = NULL;
BlockDriver *drv, *proto_drv;
BlockDriver *backing_drv = NULL;
Error *local_err = NULL;
int ret = 0;
/* Find driver and parse its options */
@@ -4519,10 +4576,13 @@ void bdrv_img_create(const char *filename, const char *fmt,
bs = bdrv_new("");
ret = bdrv_open(bs, backing_file->value.s, NULL, back_flags,
backing_drv);
backing_drv, &local_err);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not open '%s'",
backing_file->value.s);
error_setg_errno(errp, -ret, "Could not open '%s': %s",
backing_file->value.s,
error_get_pretty(local_err));
error_free(local_err);
local_err = NULL;
goto out;
}
bdrv_get_geometry(bs, &size);
@@ -4541,22 +4601,19 @@ void bdrv_img_create(const char *filename, const char *fmt,
print_option_parameters(param);
puts("");
}
ret = bdrv_create(drv, filename, param);
if (ret < 0) {
if (ret == -ENOTSUP) {
error_setg(errp,"Formatting or formatting option not supported for "
"file format '%s'", fmt);
} else if (ret == -EFBIG) {
const char *cluster_size_hint = "";
if (get_option_parameter(create_options, BLOCK_OPT_CLUSTER_SIZE)) {
cluster_size_hint = " (try using a larger cluster size)";
}
error_setg(errp, "The image size is too large for file format '%s'%s",
fmt, cluster_size_hint);
} else {
error_setg(errp, "%s: error while creating %s: %s", filename, fmt,
strerror(-ret));
ret = bdrv_create(drv, filename, param, &local_err);
if (ret == -EFBIG) {
/* This is generally a better message than whatever the driver would
* deliver (especially because of the cluster_size_hint), since that
* is most probably not much different from "image too large". */
const char *cluster_size_hint = "";
if (get_option_parameter(create_options, BLOCK_OPT_CLUSTER_SIZE)) {
cluster_size_hint = " (try using a larger cluster size)";
}
error_setg(errp, "The image size is too large for file format '%s'"
"%s", fmt, cluster_size_hint);
error_free(local_err);
local_err = NULL;
}
out:
@@ -4566,6 +4623,9 @@ out:
if (bs) {
bdrv_unref(bs);
}
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
}
}
AioContext *bdrv_get_aio_context(BlockDriverState *bs)
@@ -4579,3 +4639,11 @@ void bdrv_add_before_write_notifier(BlockDriverState *bs,
{
notifier_with_return_list_add(&bs->before_write_notifiers, notifier);
}
int bdrv_amend_options(BlockDriverState *bs, QEMUOptionParameter *options)
{
if (bs->drv->bdrv_amend_options == NULL) {
return -ENOTSUP;
}
return bs->drv->bdrv_amend_options(bs, options);
}
+5 -2
View File
@@ -350,7 +350,8 @@ static QemuOptsList runtime_opts = {
},
};
static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags)
static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVBlkdebugState *s = bs->opaque;
QemuOpts *opts;
@@ -386,8 +387,10 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags)
goto fail;
}
ret = bdrv_file_open(&bs->file, filename, NULL, flags);
ret = bdrv_file_open(&bs->file, filename, NULL, flags, &local_err);
if (ret < 0) {
qerror_report_err(local_err);
error_free(local_err);
goto fail;
}
+8 -3
View File
@@ -116,7 +116,8 @@ static QemuOptsList runtime_opts = {
},
};
static int blkverify_open(BlockDriverState *bs, QDict *options, int flags)
static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVBlkverifyState *s = bs->opaque;
QemuOpts *opts;
@@ -140,8 +141,10 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags)
goto fail;
}
ret = bdrv_file_open(&bs->file, raw, NULL, flags);
ret = bdrv_file_open(&bs->file, raw, NULL, flags, &local_err);
if (ret < 0) {
qerror_report_err(local_err);
error_free(local_err);
goto fail;
}
@@ -153,8 +156,10 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags)
}
s->test_file = bdrv_new("");
ret = bdrv_open(s->test_file, filename, NULL, flags, NULL);
ret = bdrv_open(s->test_file, filename, NULL, flags, NULL, &local_err);
if (ret < 0) {
qerror_report_err(local_err);
error_free(local_err);
bdrv_unref(s->test_file);
s->test_file = NULL;
goto fail;
+2 -1
View File
@@ -108,7 +108,8 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int bochs_open(BlockDriverState *bs, QDict *options, int flags)
static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVBochsState *s = bs->opaque;
int i;
+2 -1
View File
@@ -53,7 +53,8 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int cloop_open(BlockDriverState *bs, QDict *options, int flags)
static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVCloopState *s = bs->opaque;
uint32_t offsets_size, max_compressed_block_size = 1, i;
+11 -4
View File
@@ -58,7 +58,8 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int cow_open(BlockDriverState *bs, QDict *options, int flags)
static int cow_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVCowState *s = bs->opaque;
struct cow_header_v2 cow_header;
@@ -294,12 +295,14 @@ static void cow_close(BlockDriverState *bs)
{
}
static int cow_create(const char *filename, QEMUOptionParameter *options)
static int cow_create(const char *filename, QEMUOptionParameter *options,
Error **errp)
{
struct cow_header_v2 cow_header;
struct stat st;
int64_t image_sectors = 0;
const char *image_filename = NULL;
Error *local_err = NULL;
int ret;
BlockDriverState *cow_bs;
@@ -313,13 +316,17 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
options++;
}
ret = bdrv_create_file(filename, options);
ret = bdrv_create_file(filename, options, &local_err);
if (ret < 0) {
qerror_report_err(local_err);
error_free(local_err);
return ret;
}
ret = bdrv_file_open(&cow_bs, filename, NULL, BDRV_O_RDWR);
ret = bdrv_file_open(&cow_bs, filename, NULL, BDRV_O_RDWR, &local_err);
if (ret < 0) {
qerror_report_err(local_err);
error_free(local_err);
return ret;
}
+2 -1
View File
@@ -395,7 +395,8 @@ static QemuOptsList runtime_opts = {
},
};
static int curl_open(BlockDriverState *bs, QDict *options, int flags)
static int curl_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVCURLState *s = bs->opaque;
CURLState *state = NULL;
+2 -1
View File
@@ -92,7 +92,8 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
return 0;
}
static int dmg_open(BlockDriverState *bs, QDict *options, int flags)
static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVDMGState *s = bs->opaque;
uint64_t info_begin,info_end,last_in_offset,last_out_offset;
+2 -2
View File
@@ -288,7 +288,7 @@ static QemuOptsList runtime_opts = {
};
static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
int bdrv_flags)
int bdrv_flags, Error **errp)
{
BDRVGlusterState *s = bs->opaque;
int open_flags = O_BINARY;
@@ -357,7 +357,7 @@ out:
}
static int qemu_gluster_create(const char *filename,
QEMUOptionParameter *options)
QEMUOptionParameter *options, Error **errp)
{
struct glfs *glfs;
struct glfs_fd *fd;
+5 -3
View File
@@ -1216,7 +1216,8 @@ fail:
* We support iscsi url's on the form
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
*/
static int iscsi_open(BlockDriverState *bs, QDict *options, int flags)
static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = NULL;
@@ -1447,7 +1448,8 @@ static int iscsi_has_zero_init(BlockDriverState *bs)
return 0;
}
static int iscsi_create(const char *filename, QEMUOptionParameter *options)
static int iscsi_create(const char *filename, QEMUOptionParameter *options,
Error **errp)
{
int ret = 0;
int64_t total_size = 0;
@@ -1470,7 +1472,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options)
bs_options = qdict_new();
qdict_put(bs_options, "filename", qstring_from_str(filename));
ret = iscsi_open(bs, bs_options, 0);
ret = iscsi_open(bs, bs_options, 0, NULL);
QDECREF(bs_options);
if (ret != 0) {
+3 -2
View File
@@ -505,14 +505,15 @@ static void mirror_iostatus_reset(BlockJob *job)
static void mirror_complete(BlockJob *job, Error **errp)
{
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
Error *local_err = NULL;
int ret;
ret = bdrv_open_backing_file(s->target, NULL);
ret = bdrv_open_backing_file(s->target, NULL, &local_err);
if (ret < 0) {
char backing_filename[PATH_MAX];
bdrv_get_full_backing_filename(s->target, backing_filename,
sizeof(backing_filename));
error_setg_file_open(errp, -ret, backing_filename);
error_propagate(errp, local_err);
return;
}
if (!s->synced) {
+2 -1
View File
@@ -453,7 +453,8 @@ static void nbd_teardown_connection(BlockDriverState *bs)
closesocket(s->sock);
}
static int nbd_open(BlockDriverState *bs, QDict *options, int flags)
static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVNBDState *s = bs->opaque;
int result;
+2 -1
View File
@@ -68,7 +68,8 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam
return 0;
}
static int parallels_open(BlockDriverState *bs, QDict *options, int flags)
static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVParallelsState *s = bs->opaque;
int i;
+11 -4
View File
@@ -92,7 +92,8 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int qcow_open(BlockDriverState *bs, QDict *options, int flags)
static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVQcowState *s = bs->opaque;
int len, i, shift, ret;
@@ -658,7 +659,8 @@ static void qcow_close(BlockDriverState *bs)
error_free(s->migration_blocker);
}
static int qcow_create(const char *filename, QEMUOptionParameter *options)
static int qcow_create(const char *filename, QEMUOptionParameter *options,
Error **errp)
{
int header_size, backing_filename_len, l1_size, shift, i;
QCowHeader header;
@@ -666,6 +668,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
int64_t total_size = 0;
const char *backing_file = NULL;
int flags = 0;
Error *local_err = NULL;
int ret;
BlockDriverState *qcow_bs;
@@ -681,13 +684,17 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
options++;
}
ret = bdrv_create_file(filename, options);
ret = bdrv_create_file(filename, options, &local_err);
if (ret < 0) {
qerror_report_err(local_err);
error_free(local_err);
return ret;
}
ret = bdrv_file_open(&qcow_bs, filename, NULL, BDRV_O_RDWR);
ret = bdrv_file_open(&qcow_bs, filename, NULL, BDRV_O_RDWR, &local_err);
if (ret < 0) {
qerror_report_err(local_err);
error_free(local_err);
return ret;
}
+18
View File
@@ -202,6 +202,24 @@ void qcow2_cache_depends_on_flush(Qcow2Cache *c)
c->depends_on_flush = true;
}
int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
{
int ret, i;
ret = qcow2_cache_flush(bs, c);
if (ret < 0) {
return ret;
}
for (i = 0; i < c->size; i++) {
assert(c->entries[i].ref == 0);
c->entries[i].offset = 0;
c->entries[i].cache_hits = 0;
}
return 0;
}
static int qcow2_cache_find_entry_to_replace(Qcow2Cache *c)
{
int i;
+237 -4
View File
@@ -1338,7 +1338,7 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
* clusters.
*/
static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
unsigned int nb_clusters)
unsigned int nb_clusters, enum qcow2_discard_type type)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l2_table;
@@ -1367,7 +1367,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
l2_table[l2_index + i] = cpu_to_be64(0);
/* Then decrease the refcount */
qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
qcow2_free_any_clusters(bs, old_offset, 1, type);
}
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
@@ -1379,7 +1379,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
}
int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
int nb_sectors)
int nb_sectors, enum qcow2_discard_type type)
{
BDRVQcowState *s = bs->opaque;
uint64_t end_offset;
@@ -1402,7 +1402,7 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
/* Each L2 table is handled by its own loop iteration */
while (nb_clusters > 0) {
ret = discard_single_l2(bs, offset, nb_clusters);
ret = discard_single_l2(bs, offset, nb_clusters, type);
if (ret < 0) {
goto fail;
}
@@ -1497,3 +1497,236 @@ fail:
return ret;
}
/*
* Expands all zero clusters in a specific L1 table (or deallocates them, for
* non-backed non-pre-allocated zero clusters).
*
* expanded_clusters is a bitmap where every bit corresponds to one cluster in
* the image file; a bit gets set if the corresponding cluster has been used for
* zero expansion (i.e., has been filled with zeroes and is referenced from an
* L2 table). nb_clusters contains the total cluster count of the image file,
* i.e., the number of bits in expanded_clusters.
*/
static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
int l1_size, uint8_t *expanded_clusters,
uint64_t nb_clusters)
{
BDRVQcowState *s = bs->opaque;
bool is_active_l1 = (l1_table == s->l1_table);
uint64_t *l2_table = NULL;
int ret;
int i, j;
if (!is_active_l1) {
/* inactive L2 tables require a buffer to be stored in when loading
* them from disk */
l2_table = qemu_blockalign(bs, s->cluster_size);
}
for (i = 0; i < l1_size; i++) {
uint64_t l2_offset = l1_table[i] & L1E_OFFSET_MASK;
bool l2_dirty = false;
if (!l2_offset) {
/* unallocated */
continue;
}
if (is_active_l1) {
/* get active L2 tables from cache */
ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
(void **)&l2_table);
} else {
/* load inactive L2 tables from disk */
ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
(void *)l2_table, s->cluster_sectors);
}
if (ret < 0) {
goto fail;
}
for (j = 0; j < s->l2_size; j++) {
uint64_t l2_entry = be64_to_cpu(l2_table[j]);
int64_t offset = l2_entry & L2E_OFFSET_MASK, cluster_index;
int cluster_type = qcow2_get_cluster_type(l2_entry);
if (cluster_type == QCOW2_CLUSTER_NORMAL) {
cluster_index = offset >> s->cluster_bits;
assert((cluster_index >= 0) && (cluster_index < nb_clusters));
if (expanded_clusters[cluster_index / 8] &
(1 << (cluster_index % 8))) {
/* Probably a shared L2 table; this cluster was a zero
* cluster which has been expanded, its refcount
* therefore most likely requires an update. */
ret = qcow2_update_cluster_refcount(bs, cluster_index, 1,
QCOW2_DISCARD_NEVER);
if (ret < 0) {
goto fail;
}
/* Since we just increased the refcount, the COPIED flag may
* no longer be set. */
l2_table[j] = cpu_to_be64(l2_entry & ~QCOW_OFLAG_COPIED);
l2_dirty = true;
}
continue;
}
else if (qcow2_get_cluster_type(l2_entry) != QCOW2_CLUSTER_ZERO) {
continue;
}
if (!offset) {
/* not preallocated */
if (!bs->backing_hd) {
/* not backed; therefore we can simply deallocate the
* cluster */
l2_table[j] = 0;
l2_dirty = true;
continue;
}
offset = qcow2_alloc_clusters(bs, s->cluster_size);
if (offset < 0) {
ret = offset;
goto fail;
}
}
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,
offset, s->cluster_size);
if (ret < 0) {
qcow2_free_clusters(bs, offset, s->cluster_size,
QCOW2_DISCARD_ALWAYS);
goto fail;
}
ret = bdrv_write_zeroes(bs->file, offset / BDRV_SECTOR_SIZE,
s->cluster_sectors);
if (ret < 0) {
qcow2_free_clusters(bs, offset, s->cluster_size,
QCOW2_DISCARD_ALWAYS);
goto fail;
}
l2_table[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
l2_dirty = true;
cluster_index = offset >> s->cluster_bits;
assert((cluster_index >= 0) && (cluster_index < nb_clusters));
expanded_clusters[cluster_index / 8] |= 1 << (cluster_index % 8);
}
if (is_active_l1) {
if (l2_dirty) {
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
qcow2_cache_depends_on_flush(s->l2_table_cache);
}
ret = qcow2_cache_put(bs, s->l2_table_cache, (void **)&l2_table);
if (ret < 0) {
l2_table = NULL;
goto fail;
}
} else {
if (l2_dirty) {
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT &
~(QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2), l2_offset,
s->cluster_size);
if (ret < 0) {
goto fail;
}
ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
(void *)l2_table, s->cluster_sectors);
if (ret < 0) {
goto fail;
}
}
}
}
ret = 0;
fail:
if (l2_table) {
if (!is_active_l1) {
qemu_vfree(l2_table);
} else {
if (ret < 0) {
qcow2_cache_put(bs, s->l2_table_cache, (void **)&l2_table);
} else {
ret = qcow2_cache_put(bs, s->l2_table_cache,
(void **)&l2_table);
}
}
}
return ret;
}
/*
* For backed images, expands all zero clusters on the image. For non-backed
* images, deallocates all non-pre-allocated zero clusters (and claims the
* allocation for pre-allocated ones). This is important for downgrading to a
* qcow2 version which doesn't yet support metadata zero clusters.
*/
int qcow2_expand_zero_clusters(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l1_table = NULL;
int cluster_to_sector_bits = s->cluster_bits - BDRV_SECTOR_BITS;
uint64_t nb_clusters;
uint8_t *expanded_clusters;
int ret;
int i, j;
nb_clusters = (bs->total_sectors + (1 << cluster_to_sector_bits) - 1)
>> cluster_to_sector_bits;
expanded_clusters = g_malloc0((nb_clusters + 7) / 8);
ret = expand_zero_clusters_in_l1(bs, s->l1_table, s->l1_size,
expanded_clusters, nb_clusters);
if (ret < 0) {
goto fail;
}
/* Inactive L1 tables may point to active L2 tables - therefore it is
* necessary to flush the L2 table cache before trying to access the L2
* tables pointed to by inactive L1 entries (else we might try to expand
* zero clusters that have already been expanded); furthermore, it is also
* necessary to empty the L2 table cache, since it may contain tables which
* are now going to be modified directly on disk, bypassing the cache.
* qcow2_cache_empty() does both for us. */
ret = qcow2_cache_empty(bs, s->l2_table_cache);
if (ret < 0) {
goto fail;
}
for (i = 0; i < s->nb_snapshots; i++) {
int l1_sectors = (s->snapshots[i].l1_size * sizeof(uint64_t) +
BDRV_SECTOR_SIZE - 1) / BDRV_SECTOR_SIZE;
l1_table = g_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
ret = bdrv_read(bs->file, s->snapshots[i].l1_table_offset /
BDRV_SECTOR_SIZE, (void *)l1_table, l1_sectors);
if (ret < 0) {
goto fail;
}
for (j = 0; j < s->snapshots[i].l1_size; j++) {
be64_to_cpus(&l1_table[j]);
}
ret = expand_zero_clusters_in_l1(bs, l1_table, s->snapshots[i].l1_size,
expanded_clusters, nb_clusters);
if (ret < 0) {
goto fail;
}
}
ret = 0;
fail:
g_free(expanded_clusters);
g_free(l1_table);
return ret;
}
+15 -14
View File
@@ -601,10 +601,10 @@ fail:
* If the return value is non-negative, it is the new refcount of the cluster.
* If it is negative, it is -errno and indicates an error.
*/
static int update_cluster_refcount(BlockDriverState *bs,
int64_t cluster_index,
int addend,
enum qcow2_discard_type type)
int qcow2_update_cluster_refcount(BlockDriverState *bs,
int64_t cluster_index,
int addend,
enum qcow2_discard_type type)
{
BDRVQcowState *s = bs->opaque;
int ret;
@@ -733,8 +733,8 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
if (free_in_cluster == 0)
s->free_byte_offset = 0;
if ((offset & (s->cluster_size - 1)) != 0)
update_cluster_refcount(bs, offset >> s->cluster_bits, 1,
QCOW2_DISCARD_NEVER);
qcow2_update_cluster_refcount(bs, offset >> s->cluster_bits, 1,
QCOW2_DISCARD_NEVER);
} else {
offset = qcow2_alloc_clusters(bs, s->cluster_size);
if (offset < 0) {
@@ -744,8 +744,8 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
if ((cluster_offset + s->cluster_size) == offset) {
/* we are lucky: contiguous data */
offset = s->free_byte_offset;
update_cluster_refcount(bs, offset >> s->cluster_bits, 1,
QCOW2_DISCARD_NEVER);
qcow2_update_cluster_refcount(bs, offset >> s->cluster_bits, 1,
QCOW2_DISCARD_NEVER);
s->free_byte_offset += size;
} else {
s->free_byte_offset = offset;
@@ -754,8 +754,8 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
}
/* The cluster refcount was incremented, either by qcow2_alloc_clusters()
* or explicitly by update_cluster_refcount(). Refcount blocks must be
* flushed before the caller's L2 table updates.
* or explicitly by qcow2_update_cluster_refcount(). Refcount blocks must
* be flushed before the caller's L2 table updates.
*/
qcow2_cache_set_dependency(bs, s->l2_table_cache, s->refcount_block_cache);
return offset;
@@ -896,8 +896,9 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
break;
}
if (addend != 0) {
refcount = update_cluster_refcount(bs, cluster_index, addend,
QCOW2_DISCARD_SNAPSHOT);
refcount = qcow2_update_cluster_refcount(bs,
cluster_index, addend,
QCOW2_DISCARD_SNAPSHOT);
} else {
refcount = get_refcount(bs, cluster_index);
}
@@ -936,8 +937,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
if (addend != 0) {
refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend,
QCOW2_DISCARD_SNAPSHOT);
refcount = qcow2_update_cluster_refcount(bs, l2_offset >>
s->cluster_bits, addend, QCOW2_DISCARD_SNAPSHOT);
} else {
refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
}
+46 -16
View File
@@ -297,31 +297,47 @@ static void find_new_snapshot_id(BlockDriverState *bs,
snprintf(id_str, id_str_size, "%d", id_max + 1);
}
static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
static int find_snapshot_by_id_and_name(BlockDriverState *bs,
const char *id,
const char *name)
{
BDRVQcowState *s = bs->opaque;
int i;
for(i = 0; i < s->nb_snapshots; i++) {
if (!strcmp(s->snapshots[i].id_str, id_str))
return i;
if (id && name) {
for (i = 0; i < s->nb_snapshots; i++) {
if (!strcmp(s->snapshots[i].id_str, id) &&
!strcmp(s->snapshots[i].name, name)) {
return i;
}
}
} else if (id) {
for (i = 0; i < s->nb_snapshots; i++) {
if (!strcmp(s->snapshots[i].id_str, id)) {
return i;
}
}
} else if (name) {
for (i = 0; i < s->nb_snapshots; i++) {
if (!strcmp(s->snapshots[i].name, name)) {
return i;
}
}
}
return -1;
}
static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
static int find_snapshot_by_id_or_name(BlockDriverState *bs,
const char *id_or_name)
{
BDRVQcowState *s = bs->opaque;
int i, ret;
int ret;
ret = find_snapshot_by_id(bs, name);
if (ret >= 0)
ret = find_snapshot_by_id_and_name(bs, id_or_name, NULL);
if (ret >= 0) {
return ret;
for(i = 0; i < s->nb_snapshots; i++) {
if (!strcmp(s->snapshots[i].name, name))
return i;
}
return -1;
return find_snapshot_by_id_and_name(bs, NULL, id_or_name);
}
/* if no id is provided, a new one is constructed */
@@ -343,7 +359,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
}
/* Check that the ID is unique */
if (find_snapshot_by_id(bs, sn_info->id_str) >= 0) {
if (find_snapshot_by_id_and_name(bs, sn_info->id_str, NULL) >= 0) {
return -EEXIST;
}
@@ -416,6 +432,13 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
g_free(old_snapshot_list);
/* The VM state isn't needed any more in the active L1 table; in fact, it
* hurts by causing expensive COW for the next snapshot. */
qcow2_discard_clusters(bs, qcow2_vm_state_offset(s),
align_offset(sn->vm_state_size, s->cluster_size)
>> BDRV_SECTOR_BITS,
QCOW2_DISCARD_NEVER);
#ifdef DEBUG_ALLOC
{
BdrvCheckResult result = {0};
@@ -553,15 +576,19 @@ fail:
return ret;
}
int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
int qcow2_snapshot_delete(BlockDriverState *bs,
const char *snapshot_id,
const char *name,
Error **errp)
{
BDRVQcowState *s = bs->opaque;
QCowSnapshot sn;
int snapshot_index, ret;
/* Search the snapshot */
snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
snapshot_index = find_snapshot_by_id_and_name(bs, snapshot_id, name);
if (snapshot_index < 0) {
error_setg(errp, "Can't find the snapshot");
return -ENOENT;
}
sn = s->snapshots[snapshot_index];
@@ -573,6 +600,7 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
s->nb_snapshots--;
ret = qcow2_write_snapshots(bs);
if (ret < 0) {
error_setg(errp, "Failed to remove snapshot from snapshot list");
return ret;
}
@@ -590,6 +618,7 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
ret = qcow2_update_snapshot_refcount(bs, sn.l1_table_offset,
sn.l1_size, -1);
if (ret < 0) {
error_setg(errp, "Failed to free the cluster and L1 table");
return ret;
}
qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t),
@@ -598,6 +627,7 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
/* must update the copied flag on the current cluster offsets */
ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
if (ret < 0) {
error_setg(errp, "Failed to update snapshot status in disk");
return ret;
}
+290 -56
View File
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More