mirror of https://github.com/xqemu/xqemu.git
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:
parent
b21c76529d
commit
d4a3238af5
|
@ -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_WIN32) += raw-win32.o win32-aio.o
|
||||||
block-obj-$(CONFIG_POSIX) += raw-posix.o
|
block-obj-$(CONFIG_POSIX) += raw-posix.o
|
||||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.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-y += nbd.o nbd-client.o sheepdog.o
|
||||||
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
||||||
|
@ -23,7 +23,6 @@ block-obj-y += accounting.o
|
||||||
|
|
||||||
common-obj-y += stream.o
|
common-obj-y += stream.o
|
||||||
common-obj-y += commit.o
|
common-obj-y += commit.o
|
||||||
common-obj-y += mirror.o
|
|
||||||
common-obj-y += backup.o
|
common-obj-y += backup.o
|
||||||
|
|
||||||
iscsi.o-cflags := $(LIBISCSI_CFLAGS)
|
iscsi.o-cflags := $(LIBISCSI_CFLAGS)
|
||||||
|
|
78
qemu-img.c
78
qemu-img.c
|
@ -31,6 +31,7 @@
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "sysemu/block-backend.h"
|
#include "sysemu/block-backend.h"
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
|
#include "block/blockjob.h"
|
||||||
#include "block/qapi.h"
|
#include "block/qapi.h"
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
|
@ -722,13 +723,43 @@ fail:
|
||||||
return ret;
|
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)
|
static int img_commit(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int c, ret, flags;
|
int c, ret, flags;
|
||||||
const char *filename, *fmt, *cache;
|
const char *filename, *fmt, *cache;
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs, *base_bs;
|
||||||
bool quiet = false;
|
bool quiet = false;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
CommonBlockJobCBInfo cbi;
|
||||||
|
|
||||||
fmt = NULL;
|
fmt = NULL;
|
||||||
cache = BDRV_DEFAULT_CACHE;
|
cache = BDRV_DEFAULT_CACHE;
|
||||||
|
@ -771,29 +802,38 @@ static int img_commit(int argc, char **argv)
|
||||||
}
|
}
|
||||||
bs = blk_bs(blk);
|
bs = blk_bs(blk);
|
||||||
|
|
||||||
ret = bdrv_commit(bs);
|
/* This is different from QMP, which by default uses the deepest file in the
|
||||||
switch(ret) {
|
* backing chain (i.e., the very base); however, the traditional behavior of
|
||||||
case 0:
|
* qemu-img commit is using the immediate backing file. */
|
||||||
qprintf(quiet, "Image committed.\n");
|
base_bs = bs->backing_hd;
|
||||||
break;
|
if (!base_bs) {
|
||||||
case -ENOENT:
|
error_setg(&local_err, "Image does not have a backing file");
|
||||||
error_report("No disk inserted");
|
goto done;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
blk_unref(blk);
|
||||||
if (ret) {
|
|
||||||
|
if (local_err) {
|
||||||
|
qerror_report_err(local_err);
|
||||||
|
error_free(local_err);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qprintf(quiet, "Image committed.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue