mirror of https://github.com/xemu-project/xemu.git
Block pull request
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJTbSUxAAoJEJykq7OBq3PIh+EH/1pfLspteDS4hlTZZ8D5r+iN AEmemUQpMDGawLHQSJcK3xgNWSz5ei3HxLuXz9+5f3ZhP+ECsrTnf+60uzHkdd6j axG1viAHEBtX0ZumTdo0XY6FtCZmCRqRz8nfqxs1Q3O7UtZaDqLf1m/BNguw5K8G VHtuPAVidTWcS6QT6CoEdJ4coA3F8ZuK1viTU2nsBE28lqB99ZG9Zkr2pOCXXra2 5d6OIZYyc+PNW2HuNZTmma41aVoYJnT797qr2cLbZ3q38ykwmWU6cNrLsf+O91yT wnsCG6g1MdQb9mwVp0spPU/X/IuKbRg449XOzY9Ko4HmuSn1Inf6gUIBMigecjQ= =wmRq -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging Block pull request # gpg: Signature made Fri 09 May 2014 19:57:53 BST using RSA key ID 81AB73C8 # gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>" # gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>" * remotes/stefanha/tags/block-pull-request: glib: fix g_poll early timeout on windows block: qemu-iotests - test for live migration block: qemu-iotests - update 085 to use common.qemu block: qemu-iotests - add common.qemu, for bash-controlled qemu tests block/raw-posix: Try both FIEMAP and SEEK_HOLE gluster: Correctly propagate errors when volume isn't accessible vl.c: remove init_clocks call from main block: Fix open flags with BDRV_O_SNAPSHOT qemu-iotests: Test converting to streamOptimized from small cluster size vmdk: Implement .bdrv_get_info() vmdk: Implement .bdrv_write_compressed qemu-img: Convert by cluster size if target is compressed block/iscsi: bump year in copyright notice block/nfs: Check for NULL server part qemu-img: sort block formats in help message iotests: Use configured python qcow2: Fix alloc_clusters_noref() overflow detection Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
1b5498f687
34
block.c
34
block.c
|
@ -774,6 +774,16 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
|
||||||
bs->copy_on_read--;
|
bs->copy_on_read--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the flags that a temporary snapshot should get, based on the
|
||||||
|
* originally requested flags (the originally requested image will have flags
|
||||||
|
* like a backing file)
|
||||||
|
*/
|
||||||
|
static int bdrv_temp_snapshot_flags(int flags)
|
||||||
|
{
|
||||||
|
return (flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the flags that bs->file should get, based on the given flags for
|
* Returns the flags that bs->file should get, based on the given flags for
|
||||||
* the parent BDS
|
* the parent BDS
|
||||||
|
@ -787,11 +797,6 @@ static int bdrv_inherited_flags(int flags)
|
||||||
* so we can enable both unconditionally on lower layers. */
|
* so we can enable both unconditionally on lower layers. */
|
||||||
flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP;
|
flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP;
|
||||||
|
|
||||||
/* The backing file of a temporary snapshot is read-only */
|
|
||||||
if (flags & BDRV_O_SNAPSHOT) {
|
|
||||||
flags &= ~BDRV_O_RDWR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear flags that only apply to the top layer */
|
/* Clear flags that only apply to the top layer */
|
||||||
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
|
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
|
||||||
|
|
||||||
|
@ -817,11 +822,6 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
||||||
{
|
{
|
||||||
int open_flags = flags | BDRV_O_CACHE_WB;
|
int open_flags = flags | BDRV_O_CACHE_WB;
|
||||||
|
|
||||||
/* The backing file of a temporary snapshot is read-only */
|
|
||||||
if (flags & BDRV_O_SNAPSHOT) {
|
|
||||||
open_flags &= ~BDRV_O_RDWR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear flags that are internal to the block layer before opening the
|
* Clear flags that are internal to the block layer before opening the
|
||||||
* image.
|
* image.
|
||||||
|
@ -1206,7 +1206,7 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
|
void bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
||||||
{
|
{
|
||||||
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
||||||
char *tmp_filename = g_malloc0(PATH_MAX + 1);
|
char *tmp_filename = g_malloc0(PATH_MAX + 1);
|
||||||
|
@ -1262,8 +1262,7 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
|
||||||
bs_snapshot = bdrv_new("", &error_abort);
|
bs_snapshot = bdrv_new("", &error_abort);
|
||||||
|
|
||||||
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
||||||
(bs->open_flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY,
|
flags, bdrv_qcow2, &local_err);
|
||||||
bdrv_qcow2, &local_err);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1298,6 +1297,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||||
BlockDriverState *file = NULL, *bs;
|
BlockDriverState *file = NULL, *bs;
|
||||||
const char *drvname;
|
const char *drvname;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
int snapshot_flags = 0;
|
||||||
|
|
||||||
assert(pbs);
|
assert(pbs);
|
||||||
|
|
||||||
|
@ -1358,6 +1358,10 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||||
if (flags & BDRV_O_RDWR) {
|
if (flags & BDRV_O_RDWR) {
|
||||||
flags |= BDRV_O_ALLOW_RDWR;
|
flags |= BDRV_O_ALLOW_RDWR;
|
||||||
}
|
}
|
||||||
|
if (flags & BDRV_O_SNAPSHOT) {
|
||||||
|
snapshot_flags = bdrv_temp_snapshot_flags(flags);
|
||||||
|
flags = bdrv_backing_flags(flags);
|
||||||
|
}
|
||||||
|
|
||||||
assert(file == NULL);
|
assert(file == NULL);
|
||||||
ret = bdrv_open_image(&file, filename, options, "file",
|
ret = bdrv_open_image(&file, filename, options, "file",
|
||||||
|
@ -1417,8 +1421,8 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||||
|
|
||||||
/* For snapshot=on, create a temporary qcow2 overlay. bs points to the
|
/* For snapshot=on, create a temporary qcow2 overlay. bs points to the
|
||||||
* temporary snapshot afterwards. */
|
* temporary snapshot afterwards. */
|
||||||
if (flags & BDRV_O_SNAPSHOT) {
|
if (snapshot_flags) {
|
||||||
bdrv_append_temp_snapshot(bs, &local_err);
|
bdrv_append_temp_snapshot(bs, snapshot_flags, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto close_and_fail;
|
goto close_and_fail;
|
||||||
|
|
|
@ -207,6 +207,11 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename,
|
||||||
"volume=%s image=%s transport=%s", gconf->server,
|
"volume=%s image=%s transport=%s", gconf->server,
|
||||||
gconf->port, gconf->volname, gconf->image,
|
gconf->port, gconf->volname, gconf->image,
|
||||||
gconf->transport);
|
gconf->transport);
|
||||||
|
|
||||||
|
/* glfs_init sometimes doesn't set errno although docs suggest that */
|
||||||
|
if (errno == 0)
|
||||||
|
errno = EINVAL;
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
return glfs;
|
return glfs;
|
||||||
|
@ -482,7 +487,7 @@ static int qemu_gluster_create(const char *filename,
|
||||||
|
|
||||||
glfs = qemu_gluster_init(gconf, filename, errp);
|
glfs = qemu_gluster_init(gconf, filename, errp);
|
||||||
if (!glfs) {
|
if (!glfs) {
|
||||||
ret = -EINVAL;
|
ret = -errno;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* QEMU Block driver for iSCSI images
|
* QEMU Block driver for iSCSI images
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
* Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||||
* Copyright (c) 2012-2013 Peter Lieven <pl@kamp.de>
|
* Copyright (c) 2012-2014 Peter Lieven <pl@kamp.de>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -256,6 +256,10 @@ static int64_t nfs_client_open(NFSClient *client, const char *filename,
|
||||||
error_setg(errp, "Invalid URL specified");
|
error_setg(errp, "Invalid URL specified");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
if (!uri->server) {
|
||||||
|
error_setg(errp, "Invalid URL specified");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
strp = strrchr(uri->path, '/');
|
strp = strrchr(uri->path, '/');
|
||||||
if (strp == NULL) {
|
if (strp == NULL) {
|
||||||
error_setg(errp, "Invalid URL specified");
|
error_setg(errp, "Invalid URL specified");
|
||||||
|
|
|
@ -656,7 +656,9 @@ retry:
|
||||||
|
|
||||||
/* Make sure that all offsets in the "allocated" range are representable
|
/* Make sure that all offsets in the "allocated" range are representable
|
||||||
* in an int64_t */
|
* in an int64_t */
|
||||||
if (s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits)) {
|
if (s->free_cluster_index > 0 &&
|
||||||
|
s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits))
|
||||||
|
{
|
||||||
return -EFBIG;
|
return -EFBIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,9 @@ typedef struct BDRVRawState {
|
||||||
bool has_discard:1;
|
bool has_discard:1;
|
||||||
bool has_write_zeroes:1;
|
bool has_write_zeroes:1;
|
||||||
bool discard_zeroes:1;
|
bool discard_zeroes:1;
|
||||||
|
#ifdef CONFIG_FIEMAP
|
||||||
|
bool skip_fiemap;
|
||||||
|
#endif
|
||||||
} BDRVRawState;
|
} BDRVRawState;
|
||||||
|
|
||||||
typedef struct BDRVRawReopenState {
|
typedef struct BDRVRawReopenState {
|
||||||
|
@ -1272,6 +1275,83 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int64_t try_fiemap(BlockDriverState *bs, off_t start, off_t *data,
|
||||||
|
off_t *hole, int nb_sectors, int *pnum)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_FIEMAP
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
int64_t ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
||||||
|
struct {
|
||||||
|
struct fiemap fm;
|
||||||
|
struct fiemap_extent fe;
|
||||||
|
} f;
|
||||||
|
|
||||||
|
if (s->skip_fiemap) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.fm.fm_start = start;
|
||||||
|
f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
|
f.fm.fm_flags = 0;
|
||||||
|
f.fm.fm_extent_count = 1;
|
||||||
|
f.fm.fm_reserved = 0;
|
||||||
|
if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) {
|
||||||
|
s->skip_fiemap = true;
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f.fm.fm_mapped_extents == 0) {
|
||||||
|
/* No extents found, data is beyond f.fm.fm_start + f.fm.fm_length.
|
||||||
|
* f.fm.fm_start + f.fm.fm_length must be clamped to the file size!
|
||||||
|
*/
|
||||||
|
off_t length = lseek(s->fd, 0, SEEK_END);
|
||||||
|
*hole = f.fm.fm_start;
|
||||||
|
*data = MIN(f.fm.fm_start + f.fm.fm_length, length);
|
||||||
|
} else {
|
||||||
|
*data = f.fe.fe_logical;
|
||||||
|
*hole = f.fe.fe_logical + f.fe.fe_length;
|
||||||
|
if (f.fe.fe_flags & FIEMAP_EXTENT_UNWRITTEN) {
|
||||||
|
ret |= BDRV_BLOCK_ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return -ENOTSUP;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t try_seek_hole(BlockDriverState *bs, off_t start, off_t *data,
|
||||||
|
off_t *hole, int *pnum)
|
||||||
|
{
|
||||||
|
#if defined SEEK_HOLE && defined SEEK_DATA
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
|
||||||
|
*hole = lseek(s->fd, start, SEEK_HOLE);
|
||||||
|
if (*hole == -1) {
|
||||||
|
/* -ENXIO indicates that sector_num was past the end of the file.
|
||||||
|
* There is a virtual hole there. */
|
||||||
|
assert(errno != -ENXIO);
|
||||||
|
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*hole > start) {
|
||||||
|
*data = start;
|
||||||
|
} else {
|
||||||
|
/* On a hole. We need another syscall to find its end. */
|
||||||
|
*data = lseek(s->fd, start, SEEK_DATA);
|
||||||
|
if (*data == -1) {
|
||||||
|
*data = lseek(s->fd, 0, SEEK_END);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
||||||
|
#else
|
||||||
|
return -ENOTSUP;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns true iff the specified sector is present in the disk image. Drivers
|
* Returns true iff the specified sector is present in the disk image. Drivers
|
||||||
* not implementing the functionality are assumed to not support backing files,
|
* not implementing the functionality are assumed to not support backing files,
|
||||||
|
@ -1288,10 +1368,10 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
|
||||||
* beyond the end of the disk image it will be clamped.
|
* beyond the end of the disk image it will be clamped.
|
||||||
*/
|
*/
|
||||||
static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||||
int64_t sector_num,
|
int64_t sector_num,
|
||||||
int nb_sectors, int *pnum)
|
int nb_sectors, int *pnum)
|
||||||
{
|
{
|
||||||
off_t start, data, hole;
|
off_t start, data = 0, hole = 0;
|
||||||
int64_t ret;
|
int64_t ret;
|
||||||
|
|
||||||
ret = fd_open(bs);
|
ret = fd_open(bs);
|
||||||
|
@ -1300,71 +1380,18 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||||
}
|
}
|
||||||
|
|
||||||
start = sector_num * BDRV_SECTOR_SIZE;
|
start = sector_num * BDRV_SECTOR_SIZE;
|
||||||
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
|
||||||
|
|
||||||
#ifdef CONFIG_FIEMAP
|
ret = try_fiemap(bs, start, &data, &hole, nb_sectors, pnum);
|
||||||
|
if (ret < 0) {
|
||||||
BDRVRawState *s = bs->opaque;
|
ret = try_seek_hole(bs, start, &data, &hole, pnum);
|
||||||
struct {
|
if (ret < 0) {
|
||||||
struct fiemap fm;
|
/* Assume everything is allocated. */
|
||||||
struct fiemap_extent fe;
|
data = 0;
|
||||||
} f;
|
hole = start + nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
|
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
|
||||||
f.fm.fm_start = start;
|
|
||||||
f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE;
|
|
||||||
f.fm.fm_flags = 0;
|
|
||||||
f.fm.fm_extent_count = 1;
|
|
||||||
f.fm.fm_reserved = 0;
|
|
||||||
if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) {
|
|
||||||
/* Assume everything is allocated. */
|
|
||||||
*pnum = nb_sectors;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f.fm.fm_mapped_extents == 0) {
|
|
||||||
/* No extents found, data is beyond f.fm.fm_start + f.fm.fm_length.
|
|
||||||
* f.fm.fm_start + f.fm.fm_length must be clamped to the file size!
|
|
||||||
*/
|
|
||||||
off_t length = lseek(s->fd, 0, SEEK_END);
|
|
||||||
hole = f.fm.fm_start;
|
|
||||||
data = MIN(f.fm.fm_start + f.fm.fm_length, length);
|
|
||||||
} else {
|
|
||||||
data = f.fe.fe_logical;
|
|
||||||
hole = f.fe.fe_logical + f.fe.fe_length;
|
|
||||||
if (f.fe.fe_flags & FIEMAP_EXTENT_UNWRITTEN) {
|
|
||||||
ret |= BDRV_BLOCK_ZERO;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined SEEK_HOLE && defined SEEK_DATA
|
|
||||||
|
|
||||||
BDRVRawState *s = bs->opaque;
|
|
||||||
|
|
||||||
hole = lseek(s->fd, start, SEEK_HOLE);
|
|
||||||
if (hole == -1) {
|
|
||||||
/* -ENXIO indicates that sector_num was past the end of the file.
|
|
||||||
* There is a virtual hole there. */
|
|
||||||
assert(errno != -ENXIO);
|
|
||||||
|
|
||||||
/* Most likely EINVAL. Assume everything is allocated. */
|
|
||||||
*pnum = nb_sectors;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hole > start) {
|
|
||||||
data = start;
|
|
||||||
} else {
|
|
||||||
/* On a hole. We need another syscall to find its end. */
|
|
||||||
data = lseek(s->fd, start, SEEK_DATA);
|
|
||||||
if (data == -1) {
|
|
||||||
data = lseek(s->fd, 0, SEEK_END);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
data = 0;
|
|
||||||
hole = start + nb_sectors * BDRV_SECTOR_SIZE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (data <= start) {
|
if (data <= start) {
|
||||||
/* On a data extent, compute sectors to the end of the extent. */
|
/* On a data extent, compute sectors to the end of the extent. */
|
||||||
*pnum = MIN(nb_sectors, (hole - start) / BDRV_SECTOR_SIZE);
|
*pnum = MIN(nb_sectors, (hole - start) / BDRV_SECTOR_SIZE);
|
||||||
|
|
35
block/vmdk.c
35
block/vmdk.c
|
@ -1496,6 +1496,19 @@ static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vmdk_write_compressed(BlockDriverState *bs,
|
||||||
|
int64_t sector_num,
|
||||||
|
const uint8_t *buf,
|
||||||
|
int nb_sectors)
|
||||||
|
{
|
||||||
|
BDRVVmdkState *s = bs->opaque;
|
||||||
|
if (s->num_extents == 1 && s->extents[0].compressed) {
|
||||||
|
return vmdk_write(bs, sector_num, buf, nb_sectors, false, false);
|
||||||
|
} else {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs,
|
static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs,
|
||||||
int64_t sector_num,
|
int64_t sector_num,
|
||||||
int nb_sectors,
|
int nb_sectors,
|
||||||
|
@ -2063,6 +2076,26 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs)
|
||||||
return spec_info;
|
return spec_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
BDRVVmdkState *s = bs->opaque;
|
||||||
|
assert(s->num_extents);
|
||||||
|
bdi->needs_compressed_writes = s->extents[0].compressed;
|
||||||
|
if (!s->extents[0].flat) {
|
||||||
|
bdi->cluster_size = s->extents[0].cluster_sectors << BDRV_SECTOR_BITS;
|
||||||
|
}
|
||||||
|
/* See if we have multiple extents but they have different cases */
|
||||||
|
for (i = 1; i < s->num_extents; i++) {
|
||||||
|
if (bdi->needs_compressed_writes != s->extents[i].compressed ||
|
||||||
|
(bdi->cluster_size && bdi->cluster_size !=
|
||||||
|
s->extents[i].cluster_sectors << BDRV_SECTOR_BITS)) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static QEMUOptionParameter vmdk_create_options[] = {
|
static QEMUOptionParameter vmdk_create_options[] = {
|
||||||
{
|
{
|
||||||
.name = BLOCK_OPT_SIZE,
|
.name = BLOCK_OPT_SIZE,
|
||||||
|
@ -2109,6 +2142,7 @@ static BlockDriver bdrv_vmdk = {
|
||||||
.bdrv_reopen_prepare = vmdk_reopen_prepare,
|
.bdrv_reopen_prepare = vmdk_reopen_prepare,
|
||||||
.bdrv_read = vmdk_co_read,
|
.bdrv_read = vmdk_co_read,
|
||||||
.bdrv_write = vmdk_co_write,
|
.bdrv_write = vmdk_co_write,
|
||||||
|
.bdrv_write_compressed = vmdk_write_compressed,
|
||||||
.bdrv_co_write_zeroes = vmdk_co_write_zeroes,
|
.bdrv_co_write_zeroes = vmdk_co_write_zeroes,
|
||||||
.bdrv_close = vmdk_close,
|
.bdrv_close = vmdk_close,
|
||||||
.bdrv_create = vmdk_create,
|
.bdrv_create = vmdk_create,
|
||||||
|
@ -2118,6 +2152,7 @@ static BlockDriver bdrv_vmdk = {
|
||||||
.bdrv_has_zero_init = vmdk_has_zero_init,
|
.bdrv_has_zero_init = vmdk_has_zero_init,
|
||||||
.bdrv_get_specific_info = vmdk_get_specific_info,
|
.bdrv_get_specific_info = vmdk_get_specific_info,
|
||||||
.bdrv_refresh_limits = vmdk_refresh_limits,
|
.bdrv_refresh_limits = vmdk_refresh_limits,
|
||||||
|
.bdrv_get_info = vmdk_get_info,
|
||||||
|
|
||||||
.create_options = vmdk_create_options,
|
.create_options = vmdk_create_options,
|
||||||
};
|
};
|
||||||
|
|
|
@ -4771,6 +4771,12 @@ if test "$gcov" = "yes" ; then
|
||||||
echo "GCOV=$gcov_tool" >> $config_host_mak
|
echo "GCOV=$gcov_tool" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
iotests_common_env="tests/qemu-iotests/common.env"
|
||||||
|
|
||||||
|
echo "# Automatically generated by configure - do not modify" > $iotests_common_env
|
||||||
|
echo >> $iotests_common_env
|
||||||
|
echo "PYTHON='$python'" >> $iotests_common_env
|
||||||
|
|
||||||
# use included Linux headers
|
# use included Linux headers
|
||||||
if test "$linux" = "yes" ; then
|
if test "$linux" = "yes" ; then
|
||||||
mkdir -p linux-headers
|
mkdir -p linux-headers
|
||||||
|
|
|
@ -34,6 +34,10 @@ typedef struct BlockDriverInfo {
|
||||||
* opened with BDRV_O_UNMAP flag for this to work.
|
* opened with BDRV_O_UNMAP flag for this to work.
|
||||||
*/
|
*/
|
||||||
bool can_write_zeroes_with_unmap;
|
bool can_write_zeroes_with_unmap;
|
||||||
|
/*
|
||||||
|
* True if this block driver only supports compressed writes
|
||||||
|
*/
|
||||||
|
bool needs_compressed_writes;
|
||||||
} BlockDriverInfo;
|
} BlockDriverInfo;
|
||||||
|
|
||||||
typedef struct BlockFragInfo {
|
typedef struct BlockFragInfo {
|
||||||
|
@ -191,7 +195,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
|
||||||
QDict *options, const char *bdref_key, int flags,
|
QDict *options, const char *bdref_key, int flags,
|
||||||
bool allow_none, Error **errp);
|
bool allow_none, Error **errp);
|
||||||
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
|
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
|
||||||
void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp);
|
void bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp);
|
||||||
int bdrv_open(BlockDriverState **pbs, const char *filename,
|
int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||||
const char *reference, QDict *options, int flags,
|
const char *reference, QDict *options, int flags,
|
||||||
BlockDriver *drv, Error **errp);
|
BlockDriver *drv, Error **errp);
|
||||||
|
|
|
@ -24,7 +24,14 @@ static inline guint g_timeout_add_seconds(guint interval, GSourceFunc function,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !GLIB_CHECK_VERSION(2, 20, 0)
|
#ifdef _WIN32
|
||||||
|
/*
|
||||||
|
* g_poll has a problem on Windows when using
|
||||||
|
* timeouts < 10ms, so use wrapper.
|
||||||
|
*/
|
||||||
|
#define g_poll(fds, nfds, timeout) g_poll_fixed(fds, nfds, timeout)
|
||||||
|
gint g_poll_fixed(GPollFD *fds, guint nfds, gint timeout);
|
||||||
|
#elif !GLIB_CHECK_VERSION(2, 20, 0)
|
||||||
/*
|
/*
|
||||||
* Glib before 2.20.0 doesn't implement g_poll, so wrap it to compile properly
|
* Glib before 2.20.0 doesn't implement g_poll, so wrap it to compile properly
|
||||||
* on older systems.
|
* on older systems.
|
||||||
|
|
29
qemu-img.c
29
qemu-img.c
|
@ -32,6 +32,7 @@
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "block/qapi.h"
|
#include "block/qapi.h"
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
#define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION \
|
#define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION \
|
||||||
", Copyright (c) 2004-2008 Fabrice Bellard\n"
|
", Copyright (c) 2004-2008 Fabrice Bellard\n"
|
||||||
|
@ -55,9 +56,25 @@ typedef enum OutputFormat {
|
||||||
#define BDRV_O_FLAGS BDRV_O_CACHE_WB
|
#define BDRV_O_FLAGS BDRV_O_CACHE_WB
|
||||||
#define BDRV_DEFAULT_CACHE "writeback"
|
#define BDRV_DEFAULT_CACHE "writeback"
|
||||||
|
|
||||||
static void format_print(void *opaque, const char *name)
|
static gint compare_data(gconstpointer a, gconstpointer b, gpointer user)
|
||||||
{
|
{
|
||||||
printf(" %s", name);
|
return g_strcmp0(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_format(gpointer data, gpointer user)
|
||||||
|
{
|
||||||
|
printf(" %s", (char *)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_format_to_seq(void *opaque, const char *fmt_name)
|
||||||
|
{
|
||||||
|
GSequence *seq = opaque;
|
||||||
|
|
||||||
|
if (!g_sequence_lookup(seq, (gpointer)fmt_name,
|
||||||
|
compare_data, NULL)) {
|
||||||
|
g_sequence_insert_sorted(seq, (gpointer)fmt_name,
|
||||||
|
compare_data, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)
|
static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)
|
||||||
|
@ -142,10 +159,15 @@ static void QEMU_NORETURN help(void)
|
||||||
" '-f' first image format\n"
|
" '-f' first image format\n"
|
||||||
" '-F' second image format\n"
|
" '-F' second image format\n"
|
||||||
" '-s' run in Strict mode - fail on different image size or sector allocation\n";
|
" '-s' run in Strict mode - fail on different image size or sector allocation\n";
|
||||||
|
GSequence *seq;
|
||||||
|
|
||||||
printf("%s\nSupported formats:", help_msg);
|
printf("%s\nSupported formats:", help_msg);
|
||||||
bdrv_iterate_format(format_print, NULL);
|
seq = g_sequence_new(NULL);
|
||||||
|
bdrv_iterate_format(add_format_to_seq, seq);
|
||||||
|
g_sequence_foreach(seq, print_format, NULL);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
g_sequence_free(seq);
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1480,6 +1502,7 @@ static int img_convert(int argc, char **argv)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
compress = compress || bdi.needs_compressed_writes;
|
||||||
cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;
|
cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,6 +126,9 @@ static void qemu_clock_init(QEMUClockType type)
|
||||||
{
|
{
|
||||||
QEMUClock *clock = qemu_clock_ptr(type);
|
QEMUClock *clock = qemu_clock_ptr(type);
|
||||||
|
|
||||||
|
/* Assert that the clock of type TYPE has not been initialized yet. */
|
||||||
|
assert(main_loop_tlg.tl[type] == NULL);
|
||||||
|
|
||||||
clock->type = type;
|
clock->type = type;
|
||||||
clock->enabled = true;
|
clock->enabled = true;
|
||||||
clock->last = INT64_MIN;
|
clock->last = INT64_MIN;
|
||||||
|
|
|
@ -35,6 +35,7 @@ _cleanup()
|
||||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
# get standard environment, filters and checks
|
# get standard environment, filters and checks
|
||||||
|
. ./common.env
|
||||||
. ./common.rc
|
. ./common.rc
|
||||||
. ./common.filter
|
. ./common.filter
|
||||||
. ./common.pattern
|
. ./common.pattern
|
||||||
|
@ -56,22 +57,22 @@ for IMGOPTS in "compat=0.10" "compat=1.1"; do
|
||||||
echo === Create image with unknown header extension ===
|
echo === Create image with unknown header extension ===
|
||||||
echo
|
echo
|
||||||
_make_test_img 64M
|
_make_test_img 64M
|
||||||
./qcow2.py "$TEST_IMG" add-header-ext 0x12345678 "This is a test header extension"
|
$PYTHON qcow2.py "$TEST_IMG" add-header-ext 0x12345678 "This is a test header extension"
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
_check_test_img
|
_check_test_img
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo === Rewrite header with no backing file ===
|
echo === Rewrite header with no backing file ===
|
||||||
echo
|
echo
|
||||||
$QEMU_IMG rebase -u -b "" "$TEST_IMG"
|
$QEMU_IMG rebase -u -b "" "$TEST_IMG"
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
_check_test_img
|
_check_test_img
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo === Add a backing file and format ===
|
echo === Add a backing file and format ===
|
||||||
echo
|
echo
|
||||||
$QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device "$TEST_IMG"
|
$QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device "$TEST_IMG"
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
done
|
done
|
||||||
|
|
||||||
# success, all done
|
# success, all done
|
||||||
|
|
|
@ -38,6 +38,7 @@ _cleanup()
|
||||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
# get standard environment, filters and checks
|
# get standard environment, filters and checks
|
||||||
|
. ./common.env
|
||||||
. ./common.rc
|
. ./common.rc
|
||||||
. ./common.filter
|
. ./common.filter
|
||||||
. ./common.pattern
|
. ./common.pattern
|
||||||
|
@ -53,15 +54,15 @@ IMGOPTS="compat=1.1"
|
||||||
echo === Create image with unknown autoclear feature bit ===
|
echo === Create image with unknown autoclear feature bit ===
|
||||||
echo
|
echo
|
||||||
_make_test_img 64M
|
_make_test_img 64M
|
||||||
./qcow2.py "$TEST_IMG" set-feature-bit autoclear 63
|
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 63
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo === Repair image ===
|
echo === Repair image ===
|
||||||
echo
|
echo
|
||||||
_check_test_img -r all
|
_check_test_img -r all
|
||||||
|
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
|
|
||||||
# success, all done
|
# success, all done
|
||||||
echo "*** done"
|
echo "*** done"
|
||||||
|
|
|
@ -38,6 +38,7 @@ _cleanup()
|
||||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
# get standard environment, filters and checks
|
# get standard environment, filters and checks
|
||||||
|
. ./common.env
|
||||||
. ./common.rc
|
. ./common.rc
|
||||||
. ./common.filter
|
. ./common.filter
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ _make_test_img $size
|
||||||
$QEMU_IO -c "write -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -c "write -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
# The dirty bit must not be set
|
# The dirty bit must not be set
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
_check_test_img
|
_check_test_img
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
@ -73,7 +74,7 @@ $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
|
||||||
ulimit -c "$old_ulimit"
|
ulimit -c "$old_ulimit"
|
||||||
|
|
||||||
# The dirty bit must be set
|
# The dirty bit must be set
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
_check_test_img
|
_check_test_img
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
@ -82,7 +83,7 @@ echo "== Read-only access must still work =="
|
||||||
$QEMU_IO -r -c "read -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -r -c "read -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
# The dirty bit must be set
|
# The dirty bit must be set
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "== Repairing the image file must succeed =="
|
echo "== Repairing the image file must succeed =="
|
||||||
|
@ -90,7 +91,7 @@ echo "== Repairing the image file must succeed =="
|
||||||
_check_test_img -r all
|
_check_test_img -r all
|
||||||
|
|
||||||
# The dirty bit must not be set
|
# The dirty bit must not be set
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "== Data should still be accessible after repair =="
|
echo "== Data should still be accessible after repair =="
|
||||||
|
@ -109,12 +110,12 @@ $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
|
||||||
ulimit -c "$old_ulimit"
|
ulimit -c "$old_ulimit"
|
||||||
|
|
||||||
# The dirty bit must be set
|
# The dirty bit must be set
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
|
|
||||||
$QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
# The dirty bit must not be set
|
# The dirty bit must not be set
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "== Creating an image file with lazy_refcounts=off =="
|
echo "== Creating an image file with lazy_refcounts=off =="
|
||||||
|
@ -128,7 +129,7 @@ $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
|
||||||
ulimit -c "$old_ulimit"
|
ulimit -c "$old_ulimit"
|
||||||
|
|
||||||
# The dirty bit must not be set since lazy_refcounts=off
|
# The dirty bit must not be set since lazy_refcounts=off
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
_check_test_img
|
_check_test_img
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
@ -144,8 +145,8 @@ $QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
|
||||||
$QEMU_IMG commit "$TEST_IMG"
|
$QEMU_IMG commit "$TEST_IMG"
|
||||||
|
|
||||||
# The dirty bit must not be set
|
# The dirty bit must not be set
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
./qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features
|
||||||
|
|
||||||
_check_test_img
|
_check_test_img
|
||||||
TEST_IMG="$TEST_IMG".base _check_test_img
|
TEST_IMG="$TEST_IMG".base _check_test_img
|
||||||
|
|
|
@ -233,6 +233,10 @@ echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG",
|
||||||
|
|
||||||
$QEMU_IO -c "read -P 0x22 0 4k" "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -c "read -P 0x22 0 4k" "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
|
echo -e 'qemu-io ide0-hd0 "write -P 0x33 0 4k"\ncommit ide0-hd0' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io
|
||||||
|
|
||||||
|
$QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
# success, all done
|
# success, all done
|
||||||
echo "*** done"
|
echo "*** done"
|
||||||
rm -f $seq.full
|
rm -f $seq.full
|
||||||
|
|
|
@ -356,6 +356,16 @@ wrote 4096/4096 bytes at offset 0
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
|
read 4096/4096 bytes at offset 0
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on
|
||||||
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
|
(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x3[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4k"[K
|
||||||
|
wrote 4096/4096 bytes at offset 0
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit i[K[D[D[D[D[D[D[D[Dcommit id[K[D[D[D[D[D[D[D[D[Dcommit ide[K[D[D[D[D[D[D[D[D[D[Dcommit ide0[K[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd0[K
|
||||||
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
read 4096/4096 bytes at offset 0
|
read 4096/4096 bytes at offset 0
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
*** done
|
*** done
|
||||||
|
|
|
@ -35,6 +35,7 @@ _cleanup()
|
||||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
# get standard environment, filters and checks
|
# get standard environment, filters and checks
|
||||||
|
. ./common.env
|
||||||
. ./common.rc
|
. ./common.rc
|
||||||
. ./common.filter
|
. ./common.filter
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ _make_test_img $((1024*1024))T
|
||||||
echo
|
echo
|
||||||
echo "creating too large image (1 EB) using qcow2.py"
|
echo "creating too large image (1 EB) using qcow2.py"
|
||||||
_make_test_img 4G
|
_make_test_img 4G
|
||||||
./qcow2.py "$TEST_IMG" set-header size $((1024 ** 6))
|
$PYTHON qcow2.py "$TEST_IMG" set-header size $((1024 ** 6))
|
||||||
_check_test_img
|
_check_test_img
|
||||||
|
|
||||||
# success, all done
|
# success, all done
|
||||||
|
|
|
@ -103,6 +103,13 @@ IMGOPTS="subformat=monolithicSparse" _make_test_img 100G
|
||||||
truncate -s 10M $TEST_IMG
|
truncate -s 10M $TEST_IMG
|
||||||
_img_info
|
_img_info
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== Converting to streamOptimized from image with small cluster size==="
|
||||||
|
TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 IMGOPTS="cluster_size=4096" _make_test_img 1G
|
||||||
|
$QEMU_IO -c "write -P 0xa 0 512" "$TEST_IMG.qcow2" | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "write -P 0xb 10240 512" "$TEST_IMG.qcow2" | _filter_qemu_io
|
||||||
|
$QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2" "$TEST_IMG" 2>&1
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "=== Testing version 3 ==="
|
echo "=== Testing version 3 ==="
|
||||||
_use_sample_img iotest-version3.vmdk.bz2
|
_use_sample_img iotest-version3.vmdk.bz2
|
||||||
|
|
|
@ -2046,10 +2046,18 @@ RW 12582912 VMFS "dummy.IMGFMT" 1
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400
|
||||||
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': File truncated, expecting at least 13172736 bytes
|
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': File truncated, expecting at least 13172736 bytes
|
||||||
|
|
||||||
|
=== Converting to streamOptimized from image with small cluster size===
|
||||||
|
Formatting 'TEST_DIR/t.vmdk.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
wrote 512/512 bytes at offset 0
|
||||||
|
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 512/512 bytes at offset 10240
|
||||||
|
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
||||||
=== Testing version 3 ===
|
=== Testing version 3 ===
|
||||||
image: TEST_DIR/iotest-version3.IMGFMT
|
image: TEST_DIR/iotest-version3.IMGFMT
|
||||||
file format: IMGFMT
|
file format: IMGFMT
|
||||||
virtual size: 1.0G (1073741824 bytes)
|
virtual size: 1.0G (1073741824 bytes)
|
||||||
|
cluster_size: 65536
|
||||||
|
|
||||||
=== Testing 4TB monolithicFlat creation and IO ===
|
=== Testing 4TB monolithicFlat creation and IO ===
|
||||||
Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104
|
Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104
|
||||||
|
|
|
@ -35,6 +35,7 @@ _cleanup()
|
||||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
# get standard environment, filters and checks
|
# get standard environment, filters and checks
|
||||||
|
. ./common.env
|
||||||
. ./common.rc
|
. ./common.rc
|
||||||
. ./common.filter
|
. ./common.filter
|
||||||
|
|
||||||
|
@ -68,13 +69,13 @@ poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x03\x00\x00"
|
||||||
_check_test_img
|
_check_test_img
|
||||||
|
|
||||||
# The corrupt bit should not be set anyway
|
# The corrupt bit should not be set anyway
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
|
|
||||||
# Try to write something, thereby forcing the corrupt bit to be set
|
# Try to write something, thereby forcing the corrupt bit to be set
|
||||||
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
|
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
|
||||||
|
|
||||||
# The corrupt bit must now be set
|
# The corrupt bit must now be set
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
|
|
||||||
# Try to open the image R/W (which should fail)
|
# Try to open the image R/W (which should fail)
|
||||||
$QEMU_IO -c "$OPEN_RW" -c "read 0 512" 2>&1 | _filter_qemu_io \
|
$QEMU_IO -c "$OPEN_RW" -c "read 0 512" 2>&1 | _filter_qemu_io \
|
||||||
|
@ -99,19 +100,19 @@ poke_file "$TEST_IMG" "$(($rb_offset+8))" "\x00\x01"
|
||||||
# Redirect new data cluster onto refcount block
|
# Redirect new data cluster onto refcount block
|
||||||
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x02\x00\x00"
|
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x02\x00\x00"
|
||||||
_check_test_img
|
_check_test_img
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
|
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
|
|
||||||
# Try to fix it
|
# Try to fix it
|
||||||
_check_test_img -r all
|
_check_test_img -r all
|
||||||
|
|
||||||
# The corrupt bit should be cleared
|
# The corrupt bit should be cleared
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
|
|
||||||
# Look if it's really really fixed
|
# Look if it's really really fixed
|
||||||
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
|
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "=== Testing cluster data reference into inactive L2 table ==="
|
echo "=== Testing cluster data reference into inactive L2 table ==="
|
||||||
|
@ -124,13 +125,13 @@ $QEMU_IO -c "$OPEN_RW" -c "write -P 2 0 512" | _filter_qemu_io
|
||||||
poke_file "$TEST_IMG" "$l2_offset_after_snapshot" \
|
poke_file "$TEST_IMG" "$l2_offset_after_snapshot" \
|
||||||
"\x80\x00\x00\x00\x00\x04\x00\x00"
|
"\x80\x00\x00\x00\x00\x04\x00\x00"
|
||||||
_check_test_img
|
_check_test_img
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
$QEMU_IO -c "$OPEN_RW" -c "write -P 3 0 512" | _filter_qemu_io
|
$QEMU_IO -c "$OPEN_RW" -c "write -P 3 0 512" | _filter_qemu_io
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
_check_test_img -r all
|
_check_test_img -r all
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
$QEMU_IO -c "$OPEN_RW" -c "write -P 4 0 512" | _filter_qemu_io
|
$QEMU_IO -c "$OPEN_RW" -c "write -P 4 0 512" | _filter_qemu_io
|
||||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||||
|
|
||||||
# Check data
|
# Check data
|
||||||
$QEMU_IO -c "$OPEN_RO" -c "read -P 4 0 512" | _filter_qemu_io
|
$QEMU_IO -c "$OPEN_RO" -c "read -P 4 0 512" | _filter_qemu_io
|
||||||
|
|
|
@ -35,6 +35,7 @@ _cleanup()
|
||||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
# get standard environment, filters and checks
|
# get standard environment, filters and checks
|
||||||
|
. ./common.env
|
||||||
. ./common.rc
|
. ./common.rc
|
||||||
. ./common.filter
|
. ./common.filter
|
||||||
|
|
||||||
|
@ -48,9 +49,9 @@ echo "=== Testing version downgrade with zero expansion ==="
|
||||||
echo
|
echo
|
||||||
IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
|
IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
|
||||||
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
|
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
|
||||||
_check_test_img
|
_check_test_img
|
||||||
|
|
||||||
|
@ -59,9 +60,9 @@ echo "=== Testing dirty version downgrade ==="
|
||||||
echo
|
echo
|
||||||
IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
|
IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
|
||||||
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush -c abort "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush -c abort "$TEST_IMG" | _filter_qemu_io
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
|
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
$QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
|
||||||
_check_test_img
|
_check_test_img
|
||||||
|
|
||||||
|
@ -69,11 +70,11 @@ echo
|
||||||
echo "=== Testing version downgrade with unknown compat/autoclear flags ==="
|
echo "=== Testing version downgrade with unknown compat/autoclear flags ==="
|
||||||
echo
|
echo
|
||||||
IMGOPTS="compat=1.1" _make_test_img 64M
|
IMGOPTS="compat=1.1" _make_test_img 64M
|
||||||
./qcow2.py "$TEST_IMG" set-feature-bit compatible 42
|
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit compatible 42
|
||||||
./qcow2.py "$TEST_IMG" set-feature-bit autoclear 42
|
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 42
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
|
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
_check_test_img
|
_check_test_img
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
@ -81,9 +82,9 @@ echo "=== Testing version upgrade and resize ==="
|
||||||
echo
|
echo
|
||||||
IMGOPTS="compat=0.10" _make_test_img 64M
|
IMGOPTS="compat=0.10" _make_test_img 64M
|
||||||
$QEMU_IO -c "write -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -c "write -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
$QEMU_IMG amend -o "compat=1.1,lazy_refcounts=on,size=128M" "$TEST_IMG"
|
$QEMU_IMG amend -o "compat=1.1,lazy_refcounts=on,size=128M" "$TEST_IMG"
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
$QEMU_IO -c "read -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -c "read -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io
|
||||||
_check_test_img
|
_check_test_img
|
||||||
|
|
||||||
|
@ -92,9 +93,9 @@ echo "=== Testing dirty lazy_refcounts=off ==="
|
||||||
echo
|
echo
|
||||||
IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
|
IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
|
||||||
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush -c abort "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush -c abort "$TEST_IMG" | _filter_qemu_io
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
$QEMU_IMG amend -o "lazy_refcounts=off" "$TEST_IMG"
|
$QEMU_IMG amend -o "lazy_refcounts=off" "$TEST_IMG"
|
||||||
./qcow2.py "$TEST_IMG" dump-header
|
$PYTHON qcow2.py "$TEST_IMG" dump-header
|
||||||
$QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
|
||||||
_check_test_img
|
_check_test_img
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python
|
||||||
#
|
#
|
||||||
# Test for additional information emitted by qemu-img info on qcow2
|
# Test for additional information emitted by qemu-img info on qcow2
|
||||||
# images
|
# images
|
||||||
|
|
|
@ -29,6 +29,7 @@ tmp=/tmp/$$
|
||||||
status=1 # failure is the default!
|
status=1 # failure is the default!
|
||||||
|
|
||||||
# get standard environment, filters and checks
|
# get standard environment, filters and checks
|
||||||
|
. ./common.env
|
||||||
. ./common.rc
|
. ./common.rc
|
||||||
. ./common.filter
|
. ./common.filter
|
||||||
|
|
||||||
|
@ -81,7 +82,7 @@ EOF
|
||||||
nbd_url="nbd:127.0.0.1:$port:exportname=foo"
|
nbd_url="nbd:127.0.0.1:$port:exportname=foo"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
./nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" 2>&1 >/dev/null &
|
$PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" 2>&1 >/dev/null &
|
||||||
wait_for_tcp_port "127.0.0.1:$port"
|
wait_for_tcp_port "127.0.0.1:$port"
|
||||||
$QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | filter_nbd
|
$QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | filter_nbd
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,6 @@ echo "QA output created by $seq"
|
||||||
|
|
||||||
here=`pwd`
|
here=`pwd`
|
||||||
status=1 # failure is the default!
|
status=1 # failure is the default!
|
||||||
qemu_pid=
|
|
||||||
|
|
||||||
QMP_IN="${TEST_DIR}/qmp-in-$$"
|
|
||||||
QMP_OUT="${TEST_DIR}/qmp-out-$$"
|
|
||||||
|
|
||||||
snapshot_virt0="snapshot-v0.qcow2"
|
snapshot_virt0="snapshot-v0.qcow2"
|
||||||
snapshot_virt1="snapshot-v1.qcow2"
|
snapshot_virt1="snapshot-v1.qcow2"
|
||||||
|
@ -42,10 +38,7 @@ MAX_SNAPSHOTS=10
|
||||||
|
|
||||||
_cleanup()
|
_cleanup()
|
||||||
{
|
{
|
||||||
kill -KILL ${qemu_pid}
|
_cleanup_qemu
|
||||||
wait ${qemu_pid} 2>/dev/null # silent kill
|
|
||||||
|
|
||||||
rm -f "${QMP_IN}" "${QMP_OUT}"
|
|
||||||
for i in $(seq 1 ${MAX_SNAPSHOTS})
|
for i in $(seq 1 ${MAX_SNAPSHOTS})
|
||||||
do
|
do
|
||||||
rm -f "${TEST_DIR}/${i}-${snapshot_virt0}"
|
rm -f "${TEST_DIR}/${i}-${snapshot_virt0}"
|
||||||
|
@ -59,43 +52,12 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
# get standard environment, filters and checks
|
# get standard environment, filters and checks
|
||||||
. ./common.rc
|
. ./common.rc
|
||||||
. ./common.filter
|
. ./common.filter
|
||||||
|
. ./common.qemu
|
||||||
|
|
||||||
_supported_fmt qcow2
|
_supported_fmt qcow2
|
||||||
_supported_proto file
|
_supported_proto file
|
||||||
_supported_os Linux
|
_supported_os Linux
|
||||||
|
|
||||||
# Wait for expected QMP response from QEMU. Will time out
|
|
||||||
# after 10 seconds, which counts as failure.
|
|
||||||
#
|
|
||||||
# $1 is the string to expect
|
|
||||||
#
|
|
||||||
# If $silent is set to anything but an empty string, then
|
|
||||||
# response is not echoed out.
|
|
||||||
function timed_wait_for()
|
|
||||||
{
|
|
||||||
while read -t 10 resp <&5
|
|
||||||
do
|
|
||||||
if [ "${silent}" == "" ]; then
|
|
||||||
echo "${resp}" | _filter_testdir | _filter_qemu
|
|
||||||
fi
|
|
||||||
grep -q "${1}" < <(echo ${resp})
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "Timeout waiting for ${1}"
|
|
||||||
exit 1 # Timeout means the test failed
|
|
||||||
}
|
|
||||||
|
|
||||||
# Sends QMP command to QEMU, and waits for the expected response
|
|
||||||
#
|
|
||||||
# ${1}: String of the QMP command to send
|
|
||||||
# ${2}: String that the QEMU response should contain
|
|
||||||
function send_qmp_cmd()
|
|
||||||
{
|
|
||||||
echo "${1}" >&6
|
|
||||||
timed_wait_for "${2}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ${1}: unique identifier for the snapshot filename
|
# ${1}: unique identifier for the snapshot filename
|
||||||
function create_single_snapshot()
|
function create_single_snapshot()
|
||||||
|
@ -104,7 +66,7 @@ function create_single_snapshot()
|
||||||
'arguments': { 'device': 'virtio0',
|
'arguments': { 'device': 'virtio0',
|
||||||
'snapshot-file':'"${TEST_DIR}/${1}-${snapshot_virt0}"',
|
'snapshot-file':'"${TEST_DIR}/${1}-${snapshot_virt0}"',
|
||||||
'format': 'qcow2' } }"
|
'format': 'qcow2' } }"
|
||||||
send_qmp_cmd "${cmd}" "return"
|
_send_qemu_cmd $h "${cmd}" "return"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ${1}: unique identifier for the snapshot filename
|
# ${1}: unique identifier for the snapshot filename
|
||||||
|
@ -120,14 +82,11 @@ function create_group_snapshot()
|
||||||
'snapshot-file': '"${TEST_DIR}/${1}-${snapshot_virt1}"' } } ]
|
'snapshot-file': '"${TEST_DIR}/${1}-${snapshot_virt1}"' } } ]
|
||||||
} }"
|
} }"
|
||||||
|
|
||||||
send_qmp_cmd "${cmd}" "return"
|
_send_qemu_cmd $h "${cmd}" "return"
|
||||||
}
|
}
|
||||||
|
|
||||||
size=128M
|
size=128M
|
||||||
|
|
||||||
mkfifo "${QMP_IN}"
|
|
||||||
mkfifo "${QMP_OUT}"
|
|
||||||
|
|
||||||
_make_test_img $size
|
_make_test_img $size
|
||||||
mv "${TEST_IMG}" "${TEST_IMG}.orig"
|
mv "${TEST_IMG}" "${TEST_IMG}.orig"
|
||||||
_make_test_img $size
|
_make_test_img $size
|
||||||
|
@ -136,23 +95,15 @@ echo
|
||||||
echo === Running QEMU ===
|
echo === Running QEMU ===
|
||||||
echo
|
echo
|
||||||
|
|
||||||
"${QEMU}" -nographic -monitor none -serial none -qmp stdio\
|
qemu_comm_method="qmp"
|
||||||
-drive file="${TEST_IMG}.orig",if=virtio\
|
_launch_qemu -drive file="${TEST_IMG}.orig",if=virtio -drive file="${TEST_IMG}",if=virtio
|
||||||
-drive file="${TEST_IMG}",if=virtio 2>&1 >"${QMP_OUT}" <"${QMP_IN}"&
|
h=$QEMU_HANDLE
|
||||||
qemu_pid=$!
|
|
||||||
|
|
||||||
# redirect fifos to file descriptors, to keep from blocking
|
|
||||||
exec 5<"${QMP_OUT}"
|
|
||||||
exec 6>"${QMP_IN}"
|
|
||||||
|
|
||||||
# Don't print response, since it has version information in it
|
|
||||||
silent=yes timed_wait_for "capabilities"
|
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo === Sending capabilities ===
|
echo === Sending capabilities ===
|
||||||
echo
|
echo
|
||||||
|
|
||||||
send_qmp_cmd "{ 'execute': 'qmp_capabilities' }" "return"
|
_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return"
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo === Create a single snapshot on virtio0 ===
|
echo === Create a single snapshot on virtio0 ===
|
||||||
|
@ -165,16 +116,16 @@ echo
|
||||||
echo === Invalid command - missing device and nodename ===
|
echo === Invalid command - missing device and nodename ===
|
||||||
echo
|
echo
|
||||||
|
|
||||||
send_qmp_cmd "{ 'execute': 'blockdev-snapshot-sync',
|
_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync',
|
||||||
'arguments': { 'snapshot-file':'"${TEST_DIR}"/1-${snapshot_virt0}',
|
'arguments': { 'snapshot-file':'"${TEST_DIR}/1-${snapshot_virt0}"',
|
||||||
'format': 'qcow2' } }" "error"
|
'format': 'qcow2' } }" "error"
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo === Invalid command - missing snapshot-file ===
|
echo === Invalid command - missing snapshot-file ===
|
||||||
echo
|
echo
|
||||||
|
|
||||||
send_qmp_cmd "{ 'execute': 'blockdev-snapshot-sync',
|
_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync',
|
||||||
'arguments': { 'device': 'virtio0',
|
'arguments': { 'device': 'virtio0',
|
||||||
'format': 'qcow2' } }" "error"
|
'format': 'qcow2' } }" "error"
|
||||||
echo
|
echo
|
||||||
echo
|
echo
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Live migration test
|
||||||
|
#
|
||||||
|
# Performs a migration from one VM to another via monitor commands
|
||||||
|
#
|
||||||
|
# Copyright (C) 2014 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=jcody@redhat.com
|
||||||
|
|
||||||
|
seq=`basename $0`
|
||||||
|
echo "QA output created by $seq"
|
||||||
|
|
||||||
|
here=`pwd`
|
||||||
|
status=1 # failure is the default!
|
||||||
|
|
||||||
|
MIG_FIFO="${TEST_DIR}/migrate"
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
rm -f "${MIG_FIFO}"
|
||||||
|
_cleanup_qemu
|
||||||
|
_cleanup_test_img
|
||||||
|
}
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common.rc
|
||||||
|
. ./common.filter
|
||||||
|
. ./common.qemu
|
||||||
|
|
||||||
|
_supported_fmt qcow2
|
||||||
|
_supported_proto file
|
||||||
|
_supported_os Linux
|
||||||
|
|
||||||
|
size=1G
|
||||||
|
|
||||||
|
_make_test_img $size
|
||||||
|
|
||||||
|
mkfifo "${MIG_FIFO}"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === Starting QEMU VM1 ===
|
||||||
|
echo
|
||||||
|
|
||||||
|
qemu_comm_method="monitor"
|
||||||
|
_launch_qemu -drive file="${TEST_IMG}",cache=none,id=disk
|
||||||
|
h1=$QEMU_HANDLE
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === Starting QEMU VM2 ===
|
||||||
|
echo
|
||||||
|
_launch_qemu -drive file="${TEST_IMG}",cache=none,id=disk \
|
||||||
|
-incoming "exec: cat '${MIG_FIFO}'"
|
||||||
|
h2=$QEMU_HANDLE
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === VM 1: Migrate from VM1 to VM2 ===
|
||||||
|
echo
|
||||||
|
|
||||||
|
silent=yes
|
||||||
|
_send_qemu_cmd $h1 'qemu-io disk "write -P 0x22 0 4M"' "(qemu)"
|
||||||
|
echo "vm1: qemu-io disk write complete"
|
||||||
|
_send_qemu_cmd $h1 "migrate \"exec: cat > '${MIG_FIFO}'\"" "(qemu)"
|
||||||
|
echo "vm1: live migration started"
|
||||||
|
qemu_cmd_repeat=20 _send_qemu_cmd $h1 "info migrate" "completed"
|
||||||
|
echo "vm1: live migration completed"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === VM 2: Post-migration, write to disk, verify running ===
|
||||||
|
echo
|
||||||
|
|
||||||
|
_send_qemu_cmd $h2 'qemu-io disk "write 4M 1M"' "(qemu)"
|
||||||
|
echo "vm2: qemu-io disk write complete"
|
||||||
|
qemu_cmd_repeat=20 _send_qemu_cmd $h2 "info status" "running"
|
||||||
|
echo "vm2: qemu process running successfully"
|
||||||
|
|
||||||
|
echo "vm2: flush io, and quit"
|
||||||
|
_send_qemu_cmd $h2 'qemu-io disk flush' "(qemu)"
|
||||||
|
_send_qemu_cmd $h2 'quit' ""
|
||||||
|
|
||||||
|
echo "Check image pattern"
|
||||||
|
${QEMU_IO} -c "read -P 0x22 0 4M" "${TEST_IMG}" | _filter_testdir | _filter_qemu_io
|
||||||
|
|
||||||
|
echo "Running 'qemu-img check -r all \$TEST_IMG'"
|
||||||
|
"${QEMU_IMG}" check -r all "${TEST_IMG}" 2>&1 | _filter_testdir | _filter_qemu
|
||||||
|
|
||||||
|
echo "*** done"
|
||||||
|
rm -f $seq.full
|
||||||
|
status=0
|
|
@ -0,0 +1,28 @@
|
||||||
|
QA output created by 091
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
|
=== Starting QEMU VM1 ===
|
||||||
|
|
||||||
|
|
||||||
|
=== Starting QEMU VM2 ===
|
||||||
|
|
||||||
|
|
||||||
|
=== VM 1: Migrate from VM1 to VM2 ===
|
||||||
|
|
||||||
|
vm1: qemu-io disk write complete
|
||||||
|
vm1: live migration started
|
||||||
|
vm1: live migration completed
|
||||||
|
|
||||||
|
=== VM 2: Post-migration, write to disk, verify running ===
|
||||||
|
|
||||||
|
vm2: qemu-io disk write complete
|
||||||
|
vm2: qemu process running successfully
|
||||||
|
vm2: flush io, and quit
|
||||||
|
Check image pattern
|
||||||
|
read 4194304/4194304 bytes at offset 0
|
||||||
|
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
Running 'qemu-img check -r all $TEST_IMG'
|
||||||
|
No errors were found on the image.
|
||||||
|
80/16384 = 0.49% allocated, 0.00% fragmented, 0.00% compressed clusters
|
||||||
|
Image end offset: 5570560
|
||||||
|
*** done
|
|
@ -34,6 +34,13 @@ timestamp=${TIMESTAMP:=false}
|
||||||
# generic initialization
|
# generic initialization
|
||||||
iam=check
|
iam=check
|
||||||
|
|
||||||
|
# we need common.env
|
||||||
|
if ! . ./common.env
|
||||||
|
then
|
||||||
|
echo "$iam: failed to source common.env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# we need common.config
|
# we need common.config
|
||||||
if ! . ./common.config
|
if ! . ./common.config
|
||||||
then
|
then
|
||||||
|
@ -215,9 +222,16 @@ do
|
||||||
|
|
||||||
start=`_wallclock`
|
start=`_wallclock`
|
||||||
$timestamp && echo -n " ["`date "+%T"`"]"
|
$timestamp && echo -n " ["`date "+%T"`"]"
|
||||||
[ ! -x $seq ] && chmod u+x $seq # ensure we can run it
|
|
||||||
|
if [ "$(head -n 1 $seq)" == "#!/usr/bin/env python" ]; then
|
||||||
|
run_command="$PYTHON $seq"
|
||||||
|
else
|
||||||
|
[ ! -x $seq ] && chmod u+x $seq # ensure we can run it
|
||||||
|
run_command="./$seq"
|
||||||
|
fi
|
||||||
|
|
||||||
MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \
|
MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \
|
||||||
./$seq >$tmp.out 2>&1
|
$run_command >$tmp.out 2>&1
|
||||||
sts=$?
|
sts=$?
|
||||||
$timestamp && _timestamp
|
$timestamp && _timestamp
|
||||||
stop=`_wallclock`
|
stop=`_wallclock`
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# This allows for launching of multiple QEMU instances, with independent
|
||||||
|
# communication possible to each instance.
|
||||||
|
#
|
||||||
|
# Each instance can choose, at launch, to use either the QMP or the
|
||||||
|
# HMP (monitor) interface.
|
||||||
|
#
|
||||||
|
# All instances are cleaned up via _cleanup_qemu, including killing the
|
||||||
|
# running qemu instance.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2014 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/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
QEMU_COMM_TIMEOUT=10
|
||||||
|
|
||||||
|
QEMU_FIFO_IN="${TEST_DIR}/qmp-in-$$"
|
||||||
|
QEMU_FIFO_OUT="${TEST_DIR}/qmp-out-$$"
|
||||||
|
|
||||||
|
QEMU_PID=
|
||||||
|
_QEMU_HANDLE=0
|
||||||
|
QEMU_HANDLE=0
|
||||||
|
|
||||||
|
# If bash version is >= 4.1, these will be overwritten and dynamic
|
||||||
|
# file descriptor values assigned.
|
||||||
|
_out_fd=3
|
||||||
|
_in_fd=4
|
||||||
|
|
||||||
|
# Wait for expected QMP response from QEMU. Will time out
|
||||||
|
# after 10 seconds, which counts as failure.
|
||||||
|
#
|
||||||
|
# Override QEMU_COMM_TIMEOUT for a timeout different than the
|
||||||
|
# default 10 seconds
|
||||||
|
#
|
||||||
|
# $1: The handle to use
|
||||||
|
# $2+ All remaining arguments comprise the string to search for
|
||||||
|
# in the response.
|
||||||
|
#
|
||||||
|
# If $silent is set to anything but an empty string, then
|
||||||
|
# response is not echoed out.
|
||||||
|
function _timed_wait_for()
|
||||||
|
{
|
||||||
|
local h=${1}
|
||||||
|
shift
|
||||||
|
|
||||||
|
QEMU_STATUS[$h]=0
|
||||||
|
while read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]}
|
||||||
|
do
|
||||||
|
if [ -z "${silent}" ]; then
|
||||||
|
echo "${resp}" | _filter_testdir | _filter_qemu \
|
||||||
|
| _filter_qemu_io | _filter_qmp
|
||||||
|
fi
|
||||||
|
grep -q "${*}" < <(echo ${resp})
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
QEMU_STATUS[$h]=-1
|
||||||
|
if [ -z "${qemu_error_no_exit}" ]; then
|
||||||
|
echo "Timeout waiting for ${*} on handle ${h}"
|
||||||
|
exit 1 # Timeout means the test failed
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Sends QMP or HMP command to QEMU, and waits for the expected response
|
||||||
|
#
|
||||||
|
# $1: QEMU handle to use
|
||||||
|
# $2: String of the QMP command to send
|
||||||
|
# ${@: -1} (Last string passed)
|
||||||
|
# String that the QEMU response should contain. If it is a null
|
||||||
|
# string, do not wait for a response
|
||||||
|
#
|
||||||
|
# Set qemu_cmd_repeat to the number of times to repeat the cmd
|
||||||
|
# until either timeout, or a response. If it is not set, or <=0,
|
||||||
|
# then the command is only sent once.
|
||||||
|
#
|
||||||
|
# If $qemu_error_no_exit is set, then even if the expected response
|
||||||
|
# is not seen, we will not exit. $QEMU_STATUS[$1] will be set it -1 in
|
||||||
|
# that case.
|
||||||
|
function _send_qemu_cmd()
|
||||||
|
{
|
||||||
|
local h=${1}
|
||||||
|
local count=1
|
||||||
|
local cmd=
|
||||||
|
local use_error=${qemu_error_no_exit}
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [ ${qemu_cmd_repeat} -gt 0 ] 2>/dev/null; then
|
||||||
|
count=${qemu_cmd_repeat}
|
||||||
|
use_error="no"
|
||||||
|
fi
|
||||||
|
# This array element extraction is done to accomodate pathnames with spaces
|
||||||
|
cmd=${@: 1:${#@}-1}
|
||||||
|
shift $(($# - 1))
|
||||||
|
|
||||||
|
while [ ${count} -gt 0 ]
|
||||||
|
do
|
||||||
|
echo "${cmd}" >&${QEMU_IN[${h}]}
|
||||||
|
if [ -n "${1}" ]; then
|
||||||
|
qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}"
|
||||||
|
if [ ${QEMU_STATUS[$h]} -eq 0 ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
let count--;
|
||||||
|
done
|
||||||
|
if [ ${QEMU_STATUS[$h]} -ne 0 ] && [ -z "${qemu_error_no_exit}" ]; then
|
||||||
|
echo "Timeout waiting for ${1} on handle ${h}"
|
||||||
|
exit 1 #Timeout means the test failed
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Launch a QEMU process.
|
||||||
|
#
|
||||||
|
# Input parameters:
|
||||||
|
# $qemu_comm_method: set this variable to 'monitor' (case insensitive)
|
||||||
|
# to use the QEMU HMP monitor for communication.
|
||||||
|
# Otherwise, the default of QMP is used.
|
||||||
|
# Returns:
|
||||||
|
# $QEMU_HANDLE: set to a handle value to communicate with this QEMU instance.
|
||||||
|
#
|
||||||
|
function _launch_qemu()
|
||||||
|
{
|
||||||
|
local comm=
|
||||||
|
local fifo_out=
|
||||||
|
local fifo_in=
|
||||||
|
|
||||||
|
if (shopt -s nocasematch; [[ "${qemu_comm_method}" == "monitor" ]])
|
||||||
|
then
|
||||||
|
comm="-monitor stdio"
|
||||||
|
else
|
||||||
|
local qemu_comm_method="qmp"
|
||||||
|
comm="-monitor none -qmp stdio"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fifo_out=${QEMU_FIFO_OUT}_${_QEMU_HANDLE}
|
||||||
|
fifo_in=${QEMU_FIFO_IN}_${_QEMU_HANDLE}
|
||||||
|
mkfifo "${fifo_out}"
|
||||||
|
mkfifo "${fifo_in}"
|
||||||
|
|
||||||
|
"${QEMU}" -nographic -serial none ${comm} -machine accel=qtest "${@}" 2>&1 \
|
||||||
|
>"${fifo_out}" \
|
||||||
|
<"${fifo_in}" &
|
||||||
|
QEMU_PID[${_QEMU_HANDLE}]=$!
|
||||||
|
|
||||||
|
if [[ "${BASH_VERSINFO[0]}" -ge "5" ||
|
||||||
|
("${BASH_VERSINFO[0]}" -ge "4" && "${BASH_VERSINFO[1]}" -ge "1") ]]
|
||||||
|
then
|
||||||
|
# bash >= 4.1 required for automatic fd
|
||||||
|
exec {_out_fd}<"${fifo_out}"
|
||||||
|
exec {_in_fd}>"${fifo_in}"
|
||||||
|
else
|
||||||
|
let _out_fd++
|
||||||
|
let _in_fd++
|
||||||
|
eval "exec ${_out_fd}<'${fifo_out}'"
|
||||||
|
eval "exec ${_in_fd}>'${fifo_in}'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
QEMU_OUT[${_QEMU_HANDLE}]=${_out_fd}
|
||||||
|
QEMU_IN[${_QEMU_HANDLE}]=${_in_fd}
|
||||||
|
QEMU_STATUS[${_QEMU_HANDLE}]=0
|
||||||
|
|
||||||
|
if [ "${qemu_comm_method}" == "qmp" ]
|
||||||
|
then
|
||||||
|
# Don't print response, since it has version information in it
|
||||||
|
silent=yes _timed_wait_for ${_QEMU_HANDLE} "capabilities"
|
||||||
|
fi
|
||||||
|
QEMU_HANDLE=${_QEMU_HANDLE}
|
||||||
|
let _QEMU_HANDLE++
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Silenty kills the QEMU process
|
||||||
|
function _cleanup_qemu()
|
||||||
|
{
|
||||||
|
# QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices
|
||||||
|
for i in "${!QEMU_OUT[@]}"
|
||||||
|
do
|
||||||
|
kill -KILL ${QEMU_PID[$i]} 2>/dev/null
|
||||||
|
wait ${QEMU_PID[$i]} 2>/dev/null # silent kill
|
||||||
|
rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}"
|
||||||
|
eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors
|
||||||
|
eval "exec ${QEMU_OUT[$i]}<&-"
|
||||||
|
done
|
||||||
|
}
|
|
@ -96,3 +96,4 @@
|
||||||
087 rw auto
|
087 rw auto
|
||||||
088 rw auto
|
088 rw auto
|
||||||
090 rw auto quick
|
090 rw auto quick
|
||||||
|
091 rw auto
|
||||||
|
|
|
@ -238,3 +238,115 @@ char *qemu_get_exec_dir(void)
|
||||||
{
|
{
|
||||||
return g_strdup(exec_dir);
|
return g_strdup(exec_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* g_poll has a problem on Windows when using
|
||||||
|
* timeouts < 10ms, in glib/gpoll.c:
|
||||||
|
*
|
||||||
|
* // If not, and we have a significant timeout, poll again with
|
||||||
|
* // timeout then. Note that this will return indication for only
|
||||||
|
* // one event, or only for messages. We ignore timeouts less than
|
||||||
|
* // ten milliseconds as they are mostly pointless on Windows, the
|
||||||
|
* // MsgWaitForMultipleObjectsEx() call will timeout right away
|
||||||
|
* // anyway.
|
||||||
|
*
|
||||||
|
* if (retval == 0 && (timeout == INFINITE || timeout >= 10))
|
||||||
|
* retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, timeout);
|
||||||
|
*
|
||||||
|
* So whenever g_poll is called with timeout < 10ms it does
|
||||||
|
* a quick poll instead of wait, this causes significant performance
|
||||||
|
* degradation of QEMU, thus we should use WaitForMultipleObjectsEx
|
||||||
|
* directly
|
||||||
|
*/
|
||||||
|
gint g_poll_fixed(GPollFD *fds, guint nfds, gint timeout)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
|
||||||
|
gint nhandles = 0;
|
||||||
|
int num_completed = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < nfds; i++) {
|
||||||
|
gint j;
|
||||||
|
|
||||||
|
if (fds[i].fd <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* don't add same handle several times
|
||||||
|
*/
|
||||||
|
for (j = 0; j < nhandles; j++) {
|
||||||
|
if (handles[j] == (HANDLE)fds[i].fd) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == nhandles) {
|
||||||
|
if (nhandles == MAXIMUM_WAIT_OBJECTS) {
|
||||||
|
fprintf(stderr, "Too many handles to wait for!\n");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
handles[nhandles++] = (HANDLE)fds[i].fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nfds; ++i) {
|
||||||
|
fds[i].revents = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout == -1) {
|
||||||
|
timeout = INFINITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nhandles == 0) {
|
||||||
|
if (timeout == INFINITE) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
SleepEx(timeout, TRUE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
DWORD res;
|
||||||
|
gint j;
|
||||||
|
|
||||||
|
res = WaitForMultipleObjectsEx(nhandles, handles, FALSE,
|
||||||
|
timeout, TRUE);
|
||||||
|
|
||||||
|
if (res == WAIT_FAILED) {
|
||||||
|
for (i = 0; i < nfds; ++i) {
|
||||||
|
fds[i].revents = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
} else if ((res == WAIT_TIMEOUT) || (res == WAIT_IO_COMPLETION) ||
|
||||||
|
((int)res < (int)WAIT_OBJECT_0) ||
|
||||||
|
(res >= (WAIT_OBJECT_0 + nhandles))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nfds; ++i) {
|
||||||
|
if (handles[res - WAIT_OBJECT_0] == (HANDLE)fds[i].fd) {
|
||||||
|
fds[i].revents = fds[i].events;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++num_completed;
|
||||||
|
|
||||||
|
if (nhandles <= 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* poll the rest of the handles
|
||||||
|
*/
|
||||||
|
for (j = res - WAIT_OBJECT_0 + 1; j < nhandles; j++) {
|
||||||
|
handles[j - 1] = handles[j];
|
||||||
|
}
|
||||||
|
--nhandles;
|
||||||
|
|
||||||
|
timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_completed;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue