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:
Peter Maydell 2014-05-13 10:35:46 +01:00
commit 1b5498f687
32 changed files with 758 additions and 192 deletions

34
block.c
View File

@ -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;

View File

@ -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;
} }

View File

@ -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

View File

@ -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");

View File

@ -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;
} }

View File

@ -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);

View File

@ -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,
}; };

6
configure vendored
View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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;
} }

View File

@ -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;

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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) qququiquit (qemu) qququiquit
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) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x3qemu-io ide0-hd0 "write -P 0x33qemu-io ide0-hd0 "write -P 0x33 qemu-io ide0-hd0 "write -P 0x33 0qemu-io ide0-hd0 "write -P 0x33 0 qemu-io ide0-hd0 "write -P 0x33 0 4qemu-io ide0-hd0 "write -P 0x33 0 4kqemu-io ide0-hd0 "write -P 0x33 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) ccocomcommcommicommitcommit commit icommit idcommit idecommit ide0commit ide0-commit ide0-hcommit ide0-hdcommit ide0-hd0
(qemu) qququiquit
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

105
tests/qemu-iotests/091 Executable file
View File

@ -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

View File

@ -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

View File

@ -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`

View File

@ -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
}

View File

@ -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

View File

@ -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;
}

1
vl.c
View File

@ -3024,7 +3024,6 @@ int main(int argc, char **argv, char **envp)
runstate_init(); runstate_init();
init_clocks();
rtc_clock = QEMU_CLOCK_HOST; rtc_clock = QEMU_CLOCK_HOST;
qemu_init_auxval(envp); qemu_init_auxval(envp);