qemu-img: Implement commit like QMP

qemu-img should use QMP commands whenever possible in order to ensure
feature completeness of both online and offline image operations. As
qemu-img itself has no access to QMP (since this would basically require
just everything being linked into qemu-img), imitate QMP's
implementation of block-commit by using commit_active_start() and then
waiting for the block job to finish.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1414159063-25977-9-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Max Reitz 2014-10-24 15:57:37 +02:00 committed by Stefan Hajnoczi
parent b21c76529d
commit d4a3238af5
2 changed files with 60 additions and 21 deletions

View File

@ -9,7 +9,7 @@ block-obj-y += block-backend.o snapshot.o qapi.o
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
block-obj-$(CONFIG_POSIX) += raw-posix.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
block-obj-y += null.o
block-obj-y += null.o mirror.o
block-obj-y += nbd.o nbd-client.o sheepdog.o
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
@ -23,7 +23,6 @@ block-obj-y += accounting.o
common-obj-y += stream.o
common-obj-y += commit.o
common-obj-y += mirror.o
common-obj-y += backup.o
iscsi.o-cflags := $(LIBISCSI_CFLAGS)

View File

@ -31,6 +31,7 @@
#include "sysemu/sysemu.h"
#include "sysemu/block-backend.h"
#include "block/block_int.h"
#include "block/blockjob.h"
#include "block/qapi.h"
#include <getopt.h>
@ -722,13 +723,43 @@ fail:
return ret;
}
typedef struct CommonBlockJobCBInfo {
BlockDriverState *bs;
Error **errp;
} CommonBlockJobCBInfo;
static void common_block_job_cb(void *opaque, int ret)
{
CommonBlockJobCBInfo *cbi = opaque;
if (ret < 0) {
error_setg_errno(cbi->errp, -ret, "Block job failed");
}
/* Drop this block job's reference */
bdrv_unref(cbi->bs);
}
static void run_block_job(BlockJob *job, Error **errp)
{
AioContext *aio_context = bdrv_get_aio_context(job->bs);
do {
aio_poll(aio_context, true);
} while (!job->ready);
block_job_complete_sync(job, errp);
}
static int img_commit(int argc, char **argv)
{
int c, ret, flags;
const char *filename, *fmt, *cache;
BlockBackend *blk;
BlockDriverState *bs;
BlockDriverState *bs, *base_bs;
bool quiet = false;
Error *local_err = NULL;
CommonBlockJobCBInfo cbi;
fmt = NULL;
cache = BDRV_DEFAULT_CACHE;
@ -771,29 +802,38 @@ static int img_commit(int argc, char **argv)
}
bs = blk_bs(blk);
ret = bdrv_commit(bs);
switch(ret) {
case 0:
qprintf(quiet, "Image committed.\n");
break;
case -ENOENT:
error_report("No disk inserted");
break;
case -EACCES:
error_report("Image is read-only");
break;
case -ENOTSUP:
error_report("Image is already committed");
break;
default:
error_report("Error while committing image");
break;
/* This is different from QMP, which by default uses the deepest file in the
* backing chain (i.e., the very base); however, the traditional behavior of
* qemu-img commit is using the immediate backing file. */
base_bs = bs->backing_hd;
if (!base_bs) {
error_setg(&local_err, "Image does not have a backing file");
goto done;
}
cbi = (CommonBlockJobCBInfo){
.errp = &local_err,
.bs = bs,
};
commit_active_start(bs, base_bs, 0, BLOCKDEV_ON_ERROR_REPORT,
common_block_job_cb, &cbi, &local_err);
if (local_err) {
goto done;
}
run_block_job(bs->job, &local_err);
done:
blk_unref(blk);
if (ret) {
if (local_err) {
qerror_report_err(local_err);
error_free(local_err);
return 1;
}
qprintf(quiet, "Image committed.\n");
return 0;
}