aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block.c94
-rw-r--r--block/block-backend.c5
-rw-r--r--block/commit.c4
-rw-r--r--block/qapi.c20
-rw-r--r--block/throttle-groups.c28
-rw-r--r--block/vmdk.c44
-rw-r--r--block/vpc.c30
-rw-r--r--block/vvfat.c90
-rw-r--r--blockdev.c11
-rw-r--r--fsdev/qemu-fsdev-throttle.c2
-rw-r--r--hmp.c11
-rw-r--r--hw/core/qdev-properties.c32
-rw-r--r--hw/i386/pc_q35.c4
-rw-r--r--hw/ide/ahci.c10
-rw-r--r--hw/ide/ahci_internal.h359
-rw-r--r--hw/ide/ich.c2
-rw-r--r--hw/ide/qdev.c3
-rw-r--r--hw/mips/boston.c4
-rw-r--r--hw/scsi/scsi-disk.c5
-rw-r--r--include/hw/ide/ahci.h320
-rw-r--r--include/hw/qdev-properties.h3
-rw-r--r--include/migration/colo.h1
-rw-r--r--include/qemu/throttle.h2
-rw-r--r--include/sysemu/block-backend.h2
-rw-r--r--io/channel.c10
-rw-r--r--migration/colo.c5
-rw-r--r--migration/migration.c268
-rw-r--r--migration/rdma.c137
-rw-r--r--qapi/block-core.json9
-rw-r--r--qemu-img-cmds.hx4
-rw-r--r--qemu-img.c16
-rw-r--r--qemu-img.texi9
-rw-r--r--tests/ahci-test.c8
-rwxr-xr-xtests/qemu-iotests/06713
-rw-r--r--tests/qemu-iotests/067.out40
-rwxr-xr-xtests/qemu-iotests/0824
-rw-r--r--tests/qemu-iotests/082.out4
-rwxr-xr-xtests/qemu-iotests/0852
-rw-r--r--tests/qemu-iotests/111.out1
-rw-r--r--tests/qemu-iotests/1392
-rwxr-xr-xtests/qemu-iotests/1562
-rwxr-xr-xtests/qemu-iotests/1582
-rwxr-xr-xtests/qemu-iotests/186147
-rw-r--r--tests/qemu-iotests/186.out489
-rwxr-xr-xtests/qemu-iotests/1892
-rw-r--r--tests/qemu-iotests/group1
-rw-r--r--tests/test-throttle.c4
-rw-r--r--util/throttle.c18
48 files changed, 1683 insertions, 600 deletions
diff --git a/block.c b/block.c
index 98a9209371..2dd9262cd0 100644
--- a/block.c
+++ b/block.c
@@ -4396,55 +4396,65 @@ void bdrv_img_create(const char *filename, const char *fmt,
backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
- // The size for the image must always be specified, with one exception:
- // If we are using a backing file, we can obtain the size from there
+ /* The size for the image must always be specified, unless we have a backing
+ * file and we have not been forbidden from opening it. */
size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0);
- if (size == -1) {
- if (backing_file) {
- BlockDriverState *bs;
- char *full_backing = g_new0(char, PATH_MAX);
- int64_t size;
- int back_flags;
- QDict *backing_options = NULL;
-
- bdrv_get_full_backing_filename_from_filename(filename, backing_file,
- full_backing, PATH_MAX,
- &local_err);
- if (local_err) {
- g_free(full_backing);
- goto out;
- }
+ if (backing_file && !(flags & BDRV_O_NO_BACKING)) {
+ BlockDriverState *bs;
+ char *full_backing = g_new0(char, PATH_MAX);
+ int back_flags;
+ QDict *backing_options = NULL;
+
+ bdrv_get_full_backing_filename_from_filename(filename, backing_file,
+ full_backing, PATH_MAX,
+ &local_err);
+ if (local_err) {
+ g_free(full_backing);
+ goto out;
+ }
- /* backing files always opened read-only */
- back_flags = flags;
- back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
+ /* backing files always opened read-only */
+ back_flags = flags;
+ back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
- if (backing_fmt) {
- backing_options = qdict_new();
- qdict_put_str(backing_options, "driver", backing_fmt);
- }
+ if (backing_fmt) {
+ backing_options = qdict_new();
+ qdict_put_str(backing_options, "driver", backing_fmt);
+ }
- bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
- &local_err);
- g_free(full_backing);
- if (!bs) {
- goto out;
- }
- size = bdrv_getlength(bs);
- if (size < 0) {
- error_setg_errno(errp, -size, "Could not get size of '%s'",
- backing_file);
- bdrv_unref(bs);
- goto out;
+ bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
+ &local_err);
+ g_free(full_backing);
+ if (!bs && size != -1) {
+ /* Couldn't open BS, but we have a size, so it's nonfatal */
+ warn_reportf_err(local_err,
+ "Could not verify backing image. "
+ "This may become an error in future versions.\n");
+ local_err = NULL;
+ } else if (!bs) {
+ /* Couldn't open bs, do not have size */
+ error_append_hint(&local_err,
+ "Could not open backing image to determine size.\n");
+ goto out;
+ } else {
+ if (size == -1) {
+ /* Opened BS, have no size */
+ size = bdrv_getlength(bs);
+ if (size < 0) {
+ error_setg_errno(errp, -size, "Could not get size of '%s'",
+ backing_file);
+ bdrv_unref(bs);
+ goto out;
+ }
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort);
}
-
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort);
-
bdrv_unref(bs);
- } else {
- error_setg(errp, "Image creation needs a size parameter");
- goto out;
}
+ } /* (backing_file && !(flags & BDRV_O_NO_BACKING)) */
+
+ if (size == -1) {
+ error_setg(errp, "Image creation needs a size parameter");
+ goto out;
}
if (!quiet) {
diff --git a/block/block-backend.c b/block/block-backend.c
index fe3542b3f8..968438c149 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -83,7 +83,6 @@ static const AIOCBInfo block_backend_aiocb_info = {
static void drive_info_del(DriveInfo *dinfo);
static BlockBackend *bdrv_first_blk(BlockDriverState *bs);
-static char *blk_get_attached_dev_id(BlockBackend *blk);
/* All BlockBackends */
static QTAILQ_HEAD(, BlockBackend) block_backends =
@@ -343,7 +342,7 @@ void blk_unref(BlockBackend *blk)
* Behaves similarly to blk_next() but iterates over all BlockBackends, even the
* ones which are hidden (i.e. are not referenced by the monitor).
*/
-static BlockBackend *blk_all_next(BlockBackend *blk)
+BlockBackend *blk_all_next(BlockBackend *blk)
{
return blk ? QTAILQ_NEXT(blk, link)
: QTAILQ_FIRST(&block_backends);
@@ -726,7 +725,7 @@ void *blk_get_attached_dev(BlockBackend *blk)
/* Return the qdev ID, or if no ID is assigned the QOM path, of the block
* device attached to the BlockBackend. */
-static char *blk_get_attached_dev_id(BlockBackend *blk)
+char *blk_get_attached_dev_id(BlockBackend *blk)
{
DeviceState *dev;
diff --git a/block/commit.c b/block/commit.c
index 13143608f8..5cc910f567 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -90,7 +90,9 @@ static void commit_complete(BlockJob *job, void *opaque)
/* Make sure overlay_bs and top stay around until bdrv_set_backing_hd() */
bdrv_ref(top);
- bdrv_ref(overlay_bs);
+ if (overlay_bs) {
+ bdrv_ref(overlay_bs);
+ }
/* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
* the normal backing chain can be restored. */
diff --git a/block/qapi.c b/block/qapi.c
index 080eb8f115..95b2e2daa5 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -322,11 +322,21 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
{
BlockInfo *info = g_malloc0(sizeof(*info));
BlockDriverState *bs = blk_bs(blk);
+ char *qdev;
+
info->device = g_strdup(blk_name(blk));
info->type = g_strdup("unknown");
info->locked = blk_dev_is_medium_locked(blk);
info->removable = blk_dev_has_removable_media(blk);
+ qdev = blk_get_attached_dev_id(blk);
+ if (qdev && *qdev) {
+ info->has_qdev = true;
+ info->qdev = qdev;
+ } else {
+ g_free(qdev);
+ }
+
if (blk_dev_has_tray(blk)) {
info->has_tray_open = true;
info->tray_open = blk_dev_is_tray_open(blk);
@@ -462,8 +472,14 @@ BlockInfoList *qmp_query_block(Error **errp)
BlockBackend *blk;
Error *local_err = NULL;
- for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
- BlockInfoList *info = g_malloc0(sizeof(*info));
+ for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) {
+ BlockInfoList *info;
+
+ if (!*blk_name(blk) && !blk_get_attached_dev(blk)) {
+ continue;
+ }
+
+ info = g_malloc0(sizeof(*info));
bdrv_query_info(blk, &info->value, &local_err);
if (local_err) {
error_propagate(errp, local_err);
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index da2b490c38..890bfded3f 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -61,6 +61,7 @@ typedef struct ThrottleGroup {
QLIST_HEAD(, BlockBackendPublic) head;
BlockBackend *tokens[2];
bool any_timer_armed[2];
+ QEMUClockType clock_type;
/* These two are protected by the global throttle_groups_lock */
unsigned refcount;
@@ -98,6 +99,12 @@ ThrottleState *throttle_group_incref(const char *name)
if (!tg) {
tg = g_new0(ThrottleGroup, 1);
tg->name = g_strdup(name);
+ tg->clock_type = QEMU_CLOCK_REALTIME;
+
+ if (qtest_enabled()) {
+ /* For testing block IO throttling only */
+ tg->clock_type = QEMU_CLOCK_VIRTUAL;
+ }
qemu_mutex_init(&tg->lock);
throttle_init(&tg->ts);
QLIST_INIT(&tg->head);
@@ -310,7 +317,7 @@ static void schedule_next_request(BlockBackend *blk, bool is_write)
token = blk;
} else {
ThrottleTimers *tt = &blk_get_public(token)->throttle_timers;
- int64_t now = qemu_clock_get_ns(tt->clock_type);
+ int64_t now = qemu_clock_get_ns(tg->clock_type);
timer_mod(tt->timers[is_write], now);
tg->any_timer_armed[is_write] = true;
}
@@ -419,18 +426,10 @@ void throttle_group_restart_blk(BlockBackend *blk)
void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg)
{
BlockBackendPublic *blkp = blk_get_public(blk);
- ThrottleTimers *tt = &blkp->throttle_timers;
ThrottleState *ts = blkp->throttle_state;
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
qemu_mutex_lock(&tg->lock);
- /* throttle_config() cancels the timers */
- if (timer_pending(tt->timers[0])) {
- tg->any_timer_armed[0] = false;
- }
- if (timer_pending(tt->timers[1])) {
- tg->any_timer_armed[1] = false;
- }
- throttle_config(ts, tt, cfg);
+ throttle_config(ts, tg->clock_type, cfg);
qemu_mutex_unlock(&tg->lock);
throttle_group_restart_blk(blk);
@@ -497,13 +496,6 @@ void throttle_group_register_blk(BlockBackend *blk, const char *groupname)
BlockBackendPublic *blkp = blk_get_public(blk);
ThrottleState *ts = throttle_group_incref(groupname);
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
- int clock_type = QEMU_CLOCK_REALTIME;
-
- if (qtest_enabled()) {
- /* For testing block IO throttling only */
- clock_type = QEMU_CLOCK_VIRTUAL;
- }
-
blkp->throttle_state = ts;
qemu_mutex_lock(&tg->lock);
@@ -518,7 +510,7 @@ void throttle_group_register_blk(BlockBackend *blk, const char *groupname)
throttle_timers_init(&blkp->throttle_timers,
blk_get_aio_context(blk),
- clock_type,
+ tg->clock_type,
read_timer_cb,
write_timer_cb,
blk);
diff --git a/block/vmdk.c b/block/vmdk.c
index 24d71b5982..0fc97391a6 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -242,10 +242,11 @@ static void vmdk_free_last_extent(BlockDriverState *bs)
s->extents = g_renew(VmdkExtent, s->extents, s->num_extents);
}
-static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
+/* Return -ve errno, or 0 on success and write CID into *pcid. */
+static int vmdk_read_cid(BlockDriverState *bs, int parent, uint32_t *pcid)
{
char *desc;
- uint32_t cid = 0xffffffff;
+ uint32_t cid;
const char *p_name, *cid_str;
size_t cid_str_size;
BDRVVmdkState *s = bs->opaque;
@@ -254,8 +255,7 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
desc = g_malloc0(DESC_SIZE);
ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
if (ret < 0) {
- g_free(desc);
- return 0;
+ goto out;
}
if (parent) {
@@ -268,13 +268,21 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
desc[DESC_SIZE - 1] = '\0';
p_name = strstr(desc, cid_str);
- if (p_name != NULL) {
- p_name += cid_str_size;
- sscanf(p_name, "%" SCNx32, &cid);
+ if (p_name == NULL) {
+ ret = -EINVAL;
+ goto out;
}
+ p_name += cid_str_size;
+ if (sscanf(p_name, "%" SCNx32, &cid) != 1) {
+ ret = -EINVAL;
+ goto out;
+ }
+ *pcid = cid;
+ ret = 0;
+out:
g_free(desc);
- return cid;
+ return ret;
}
static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
@@ -322,7 +330,10 @@ static int vmdk_is_cid_valid(BlockDriverState *bs)
if (!s->cid_checked && bs->backing) {
BlockDriverState *p_bs = bs->backing->bs;
- cur_pcid = vmdk_read_cid(p_bs, 0);
+ if (vmdk_read_cid(p_bs, 0, &cur_pcid) != 0) {
+ /* read failure: report as not valid */
+ return 0;
+ }
if (s->parent_cid != cur_pcid) {
/* CID not valid */
return 0;
@@ -975,8 +986,14 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
if (ret) {
goto fail;
}
- s->cid = vmdk_read_cid(bs, 0);
- s->parent_cid = vmdk_read_cid(bs, 1);
+ ret = vmdk_read_cid(bs, 0, &s->cid);
+ if (ret) {
+ goto fail;
+ }
+ ret = vmdk_read_cid(bs, 1, &s->parent_cid);
+ if (ret) {
+ goto fail;
+ }
qemu_co_mutex_init(&s->lock);
/* Disable migration when VMDK images are used */
@@ -2008,8 +2025,11 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
ret = -EINVAL;
goto exit;
}
- parent_cid = vmdk_read_cid(blk_bs(blk), 0);
+ ret = vmdk_read_cid(blk_bs(blk), 0, &parent_cid);
blk_unref(blk);
+ if (ret) {
+ goto exit;
+ }
snprintf(parent_desc_line, BUF_SIZE,
"parentFileNameHint=\"%s\"", backing_file);
}
diff --git a/block/vpc.c b/block/vpc.c
index 8057d42a23..10e6519d78 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -460,17 +460,23 @@ static int vpc_reopen_prepare(BDRVReopenState *state,
/*
* Returns the absolute byte offset of the given sector in the image file.
* If the sector is not allocated, -1 is returned instead.
+ * If an error occurred trying to write an updated block bitmap back to
+ * the file, -2 is returned, and the error value is written to *err.
+ * This can only happen for a write operation.
*
* The parameter write must be 1 if the offset will be used for a write
* operation (the block bitmaps is updated then), 0 otherwise.
+ * If write is true then err must not be NULL.
*/
static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
- bool write)
+ bool write, int *err)
{
BDRVVPCState *s = bs->opaque;
uint64_t bitmap_offset, block_offset;
uint32_t pagetable_index, offset_in_block;
+ assert(!(write && err == NULL));
+
pagetable_index = offset / s->block_size;
offset_in_block = offset % s->block_size;
@@ -487,10 +493,15 @@ static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
correctness. */
if (write && (s->last_bitmap_offset != bitmap_offset)) {
uint8_t bitmap[s->bitmap_size];
+ int r;
s->last_bitmap_offset = bitmap_offset;
memset(bitmap, 0xff, s->bitmap_size);
- bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
+ r = bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
+ if (r < 0) {
+ *err = r;
+ return -2;
+ }
}
return block_offset;
@@ -561,7 +572,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t offset)
if (ret < 0)
goto fail;
- return get_image_offset(bs, offset, false);
+ return get_image_offset(bs, offset, false, NULL);
fail:
s->free_data_block_offset -= (s->block_size + s->bitmap_size);
@@ -601,7 +612,7 @@ vpc_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
qemu_iovec_init(&local_qiov, qiov->niov);
while (bytes > 0) {
- image_offset = get_image_offset(bs, offset, false);
+ image_offset = get_image_offset(bs, offset, false, NULL);
n_bytes = MIN(bytes, s->block_size - (offset % s->block_size));
if (image_offset == -1) {
@@ -650,7 +661,11 @@ vpc_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
qemu_iovec_init(&local_qiov, qiov->niov);
while (bytes > 0) {
- image_offset = get_image_offset(bs, offset, true);
+ image_offset = get_image_offset(bs, offset, true, &ret);
+ if (image_offset == -2) {
+ /* Failed to write block bitmap: can't proceed with write */
+ goto fail;
+ }
n_bytes = MIN(bytes, s->block_size - (offset % s->block_size));
if (image_offset == -1) {
@@ -702,7 +717,7 @@ static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
qemu_co_mutex_lock(&s->lock);
- offset = get_image_offset(bs, sector_num << BDRV_SECTOR_BITS, false);
+ offset = get_image_offset(bs, sector_num << BDRV_SECTOR_BITS, false, NULL);
start = offset;
allocated = (offset != -1);
*pnum = 0;
@@ -727,7 +742,8 @@ static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
if (nb_sectors == 0) {
break;
}
- offset = get_image_offset(bs, sector_num << BDRV_SECTOR_BITS, false);
+ offset = get_image_offset(bs, sector_num << BDRV_SECTOR_BITS, false,
+ NULL);
} while (offset == -1);
qemu_co_mutex_unlock(&s->lock);
diff --git a/block/vvfat.c b/block/vvfat.c
index 4dae790203..a9e207f7f0 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -71,6 +71,17 @@ void nonono(const char* file, int line, const char* msg) {
#endif
+/* bootsector OEM name. see related compatibility problems at:
+ * https://jdebp.eu/FGA/volume-boot-block-oem-name-field.html
+ * http://seasip.info/Misc/oemid.html
+ */
+#define BOOTSECTOR_OEM_NAME "MSWIN4.1"
+
+#define DIR_DELETED 0xe5
+#define DIR_KANJI DIR_DELETED
+#define DIR_KANJI_FAKE 0x05
+#define DIR_FREE 0x00
+
/* dynamic array functions */
typedef struct array_t {
char* pointer;
@@ -104,6 +115,7 @@ static inline int array_ensure_allocated(array_t* array, int index)
array->pointer = g_realloc(array->pointer, new_size);
if (!array->pointer)
return -1;
+ memset(array->pointer + array->size, 0, new_size - array->size);
array->size = new_size;
array->next = index + 1;
}
@@ -466,7 +478,7 @@ static direntry_t *create_long_filename(BDRVVVFATState *s, const char *filename)
static char is_free(const direntry_t* direntry)
{
- return direntry->name[0]==0xe5 || direntry->name[0]==0x00;
+ return direntry->name[0] == DIR_DELETED || direntry->name[0] == DIR_FREE;
}
static char is_volume_label(const direntry_t* direntry)
@@ -487,7 +499,7 @@ static char is_short_name(const direntry_t* direntry)
static char is_directory(const direntry_t* direntry)
{
- return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
+ return direntry->attributes & 0x10 && direntry->name[0] != DIR_DELETED;
}
static inline char is_dot(const direntry_t* direntry)
@@ -537,7 +549,7 @@ static direntry_t *create_short_filename(BDRVVVFATState *s,
const gchar *p, *last_dot = NULL;
gunichar c;
bool lossy_conversion = false;
- char tail[11];
+ char tail[8];
if (!entry) {
return NULL;
@@ -589,8 +601,8 @@ static direntry_t *create_short_filename(BDRVVVFATState *s,
}
}
- if (entry->name[0] == 0xe5) {
- entry->name[0] = 0x05;
+ if (entry->name[0] == DIR_KANJI) {
+ entry->name[0] = DIR_KANJI_FAKE;
}
/* numeric-tail generation */
@@ -602,7 +614,8 @@ static direntry_t *create_short_filename(BDRVVVFATState *s,
for (i = lossy_conversion ? 1 : 0; i < 999999; i++) {
direntry_t *entry1;
if (i > 0) {
- int len = sprintf(tail, "~%d", i);
+ int len = snprintf(tail, sizeof(tail), "~%u", (unsigned)i);
+ assert(len <= 7);
memcpy(entry->name + MIN(j, 8 - len), tail, len);
}
for (entry1 = array_get(&(s->directory), directory_start);
@@ -1023,7 +1036,7 @@ static int init_directories(BDRVVVFATState* s,
bootsector->jump[0]=0xeb;
bootsector->jump[1]=0x3e;
bootsector->jump[2]=0x90;
- memcpy(bootsector->name, "MSWIN4.1", 8);
+ memcpy(bootsector->name, BOOTSECTOR_OEM_NAME, 8);
bootsector->sector_size=cpu_to_le16(0x200);
bootsector->sectors_per_cluster=s->sectors_per_cluster;
bootsector->reserved_sectors=cpu_to_le16(1);
@@ -1658,6 +1671,7 @@ typedef struct {
* filename length is 0x3f * 13 bytes.
*/
unsigned char name[0x3f * 13 + 1];
+ gunichar2 name2[0x3f * 13 + 1];
int checksum, len;
int sequence_number;
} long_file_name;
@@ -1679,16 +1693,21 @@ static int parse_long_name(long_file_name* lfn,
return 1;
if (pointer[0] & 0x40) {
+ /* first entry; do some initialization */
lfn->sequence_number = pointer[0] & 0x3f;
lfn->checksum = pointer[13];
lfn->name[0] = 0;
lfn->name[lfn->sequence_number * 13] = 0;
- } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
+ } else if ((pointer[0] & 0x3f) != --lfn->sequence_number) {
+ /* not the expected sequence number */
return -1;
- else if (pointer[13] != lfn->checksum)
+ } else if (pointer[13] != lfn->checksum) {
+ /* not the expected checksum */
return -2;
- else if (pointer[12] || pointer[26] || pointer[27])
+ } else if (pointer[12] || pointer[26] || pointer[27]) {
+ /* invalid zero fields */
return -3;
+ }
offset = 13 * (lfn->sequence_number - 1);
for (i = 0, j = 1; i < 13; i++, j+=2) {
@@ -1697,16 +1716,29 @@ static int parse_long_name(long_file_name* lfn,
else if (j == 26)
j = 28;
- if (pointer[j+1] == 0)
- lfn->name[offset + i] = pointer[j];
- else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
- return -4;
- else
- lfn->name[offset + i] = 0;
+ if (pointer[j] == 0 && pointer[j + 1] == 0) {
+ /* end of long file name */
+ break;
+ }
+ gunichar2 c = (pointer[j + 1] << 8) + pointer[j];
+ lfn->name2[offset + i] = c;
}
- if (pointer[0] & 0x40)
- lfn->len = offset + strlen((char*)lfn->name + offset);
+ if (pointer[0] & 0x40) {
+ /* first entry; set len */
+ lfn->len = offset + i;
+ }
+ if ((pointer[0] & 0x3f) == 0x01) {
+ /* last entry; finalize entry */
+ glong olen;
+ gchar *utf8 = g_utf16_to_utf8(lfn->name2, lfn->len, NULL, &olen, NULL);
+ if (!utf8) {
+ return -4;
+ }
+ lfn->len = olen;
+ memcpy(lfn->name, utf8, olen + 1);
+ g_free(utf8);
+ }
return 0;
}
@@ -1722,12 +1754,14 @@ static int parse_short_name(BDRVVVFATState* s,
for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
for (i = 0; i <= j; i++) {
- if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
+ uint8_t c = direntry->name[i];
+ if (c != to_valid_short_char(c)) {
return -1;
- else if (s->downcase_short_names)
+ } else if (s->downcase_short_names) {
lfn->name[i] = qemu_tolower(direntry->name[i]);
- else
+ } else {
lfn->name[i] = direntry->name[i];
+ }
}
for (j = 2; j >= 0 && direntry->name[8 + j] == ' '; j--) {
@@ -1737,7 +1771,7 @@ static int parse_short_name(BDRVVVFATState* s,
lfn->name[i + j + 1] = '\0';
for (;j >= 0; j--) {
uint8_t c = direntry->name[8 + j];
- if (c <= ' ' || c > 0x7f) {
+ if (c != to_valid_short_char(c)) {
return -2;
} else if (s->downcase_short_names) {
lfn->name[i + j] = qemu_tolower(c);
@@ -1748,8 +1782,8 @@ static int parse_short_name(BDRVVVFATState* s,
} else
lfn->name[i + j + 1] = '\0';
- if (lfn->name[0] == 0x05) {
- lfn->name[0] = 0xe5;
+ if (lfn->name[0] == DIR_KANJI_FAKE) {
+ lfn->name[0] = DIR_KANJI;
}
lfn->len = strlen((char*)lfn->name);
@@ -2955,7 +2989,6 @@ DLOG(checkpoint());
/*
* Some sanity checks:
* - do not allow writing to the boot sector
- * - do not allow to write non-ASCII filenames
*/
if (sector_num < s->offset_to_fat)
@@ -2989,13 +3022,8 @@ DLOG(checkpoint());
direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
for (k = 0; k < (end - begin) * 0x10; k++) {
- /* do not allow non-ASCII filenames */
- if (parse_long_name(&lfn, direntries + k) < 0) {
- fprintf(stderr, "Warning: non-ASCII filename\n");
- return -1;
- }
/* no access to the direntry of a read-only file */
- else if (is_short_name(direntries+k) &&
+ if (is_short_name(direntries + k) &&
(direntries[k].attributes & 1)) {
if (memcmp(direntries + k,
array_get(&(s->directory), dir_index + k),
diff --git a/blockdev.c b/blockdev.c
index 7f53cc8bb3..6469f161df 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1710,7 +1710,8 @@ static void external_snapshot_prepare(BlkActionState *common,
}
flags = state->old_bs->open_flags;
- flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
+ flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_COPY_ON_READ);
+ flags |= BDRV_O_NO_BACKING;
/* create new image w/backing file */
mode = s->has_mode ? s->mode : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
@@ -1735,8 +1736,6 @@ static void external_snapshot_prepare(BlkActionState *common,
qdict_put_str(options, "node-name", snapshot_node_name);
}
qdict_put_str(options, "driver", format);
-
- flags |= BDRV_O_NO_BACKING;
}
state->new_bs = bdrv_open(new_image_file, snapshot_ref, options, flags,
@@ -3548,6 +3547,9 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
backing_mode = MIRROR_OPEN_BACKING_CHAIN;
}
+ /* Don't open backing image in create() */
+ flags |= BDRV_O_NO_BACKING;
+
if ((arg->sync == MIRROR_SYNC_MODE_FULL || !source)
&& arg->mode != NEW_IMAGE_MODE_EXISTING)
{
@@ -3587,8 +3589,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
/* Mirroring takes care of copy-on-write using the source's backing
* file.
*/
- target_bs = bdrv_open(arg->target, NULL, options,
- flags | BDRV_O_NO_BACKING, errp);
+ target_bs = bdrv_open(arg->target, NULL, options, flags, errp);
if (!target_bs) {
goto out;
}
diff --git a/fsdev/qemu-fsdev-throttle.c b/fsdev/qemu-fsdev-throttle.c
index 7ae4e86646..49eebb5412 100644
--- a/fsdev/qemu-fsdev-throttle.c
+++ b/fsdev/qemu-fsdev-throttle.c
@@ -86,7 +86,7 @@ void fsdev_throttle_init(FsThrottle *fst)
fsdev_throttle_read_timer_cb,
fsdev_throttle_write_timer_cb,
fst);
- throttle_config(&fst->ts, &fst->tt, &fst->cfg);
+ throttle_config(&fst->ts, QEMU_CLOCK_REALTIME, &fst->cfg);
qemu_co_queue_init(&fst->throttled_reqs[0]);
qemu_co_queue_init(&fst->throttled_reqs[1]);
}
diff --git a/hmp.c b/hmp.c
index b42ae59a29..bf1de747d5 100644
--- a/hmp.c
+++ b/hmp.c
@@ -401,16 +401,16 @@ static void print_block_info(Monitor *mon, BlockInfo *info,
assert(!info || !info->has_inserted || info->inserted == inserted);
- if (info) {
+ if (info && *info->device) {
monitor_printf(mon, "%s", info->device);
if (inserted && inserted->has_node_name) {
monitor_printf(mon, " (%s)", inserted->node_name);
}
} else {
- assert(inserted);
+ assert(info || inserted);
monitor_printf(mon, "%s",
- inserted->has_node_name
- ? inserted->node_name
+ inserted && inserted->has_node_name ? inserted->node_name
+ : info && info->has_qdev ? info->qdev
: "<anonymous>");
}
@@ -425,6 +425,9 @@ static void print_block_info(Monitor *mon, BlockInfo *info,
}
if (info) {
+ if (info->has_qdev) {
+ monitor_printf(mon, " Attached to: %s\n", info->qdev);
+ }
if (info->has_io_status && info->io_status != BLOCK_DEVICE_IO_STATUS_OK) {
monitor_printf(mon, " I/O status: %s\n",
BlockDeviceIoStatus_lookup[info->io_status]);
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 58a8f92d92..078fc5d239 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -404,6 +404,31 @@ static void set_uint64(Object *obj, Visitor *v, const char *name,
visit_type_uint64(v, name, ptr, errp);
}
+static void get_int64(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ int64_t *ptr = qdev_get_prop_ptr(dev, prop);
+
+ visit_type_int64(v, name, ptr, errp);
+}
+
+static void set_int64(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ int64_t *ptr = qdev_get_prop_ptr(dev, prop);
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+
+ visit_type_int64(v, name, ptr, errp);
+}
+
const PropertyInfo qdev_prop_uint64 = {
.name = "uint64",
.get = get_uint64,
@@ -411,6 +436,13 @@ const PropertyInfo qdev_prop_uint64 = {
.set_default_value = set_default_value_uint,
};
+const PropertyInfo qdev_prop_int64 = {
+ .name = "int64",
+ .get = get_int64,
+ .set = set_int64,
+ .set_default_value = set_default_value_int,
+};
+
/* --- string --- */
static void release_string(Object *obj, const char *name, void *opaque)
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 1653a47f0a..169a214d50 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -242,8 +242,8 @@ static void pc_q35_init(MachineState *machine)
true, "ich9-ahci");
idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0");
idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1");
- g_assert(MAX_SATA_PORTS == ICH_AHCI(ahci)->ahci.ports);
- ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports);
+ g_assert(MAX_SATA_PORTS == ahci_get_num_ports(ahci));
+ ide_drive_get(hd, ahci_get_num_ports(ahci));
ahci_ide_create_devs(ahci, hd);
} else {
idebus[0] = idebus[1] = NULL;
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 874d3fe280..406a1b5579 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -32,7 +32,7 @@
#include "sysemu/dma.h"
#include "hw/ide/internal.h"
#include "hw/ide/pci.h"
-#include "hw/ide/ahci.h"
+#include "hw/ide/ahci_internal.h"
#define DEBUG_AHCI 0
@@ -1833,6 +1833,14 @@ static void sysbus_ahci_register_types(void)
type_init(sysbus_ahci_register_types)
+int32_t ahci_get_num_ports(PCIDevice *dev)
+{
+ AHCIPCIState *d = ICH_AHCI(dev);
+ AHCIState *ahci = &d->ahci;
+
+ return ahci->ports;
+}
+
void ahci_ide_create_devs(PCIDevice *dev, DriveInfo **hd)
{
AHCIPCIState *d = ICH_AHCI(dev);
diff --git a/hw/ide/ahci_internal.h b/hw/ide/ahci_internal.h
new file mode 100644
index 0000000000..1e21169e79
--- /dev/null
+++ b/hw/ide/ahci_internal.h
@@ -0,0 +1,359 @@
+/*
+ * QEMU AHCI Emulation
+ *
+ * Copyright (c) 2010 qiaochong@loongson.cn
+ * Copyright (c) 2010 Roland Elek <elek.roland@gmail.com>
+ * Copyright (c) 2010 Sebastian Herbszt <herbszt@gmx.de>
+ * Copyright (c) 2010 Alexander Graf <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef HW_IDE_AHCI_INTERNAL_H
+#define HW_IDE_AHCI_INTERNAL_H
+
+#include "hw/ide/ahci.h"
+#include "hw/sysbus.h"
+
+#define AHCI_MEM_BAR_SIZE 0x1000
+#define AHCI_MAX_PORTS 32
+#define AHCI_MAX_SG 168 /* hardware max is 64K */
+#define AHCI_DMA_BOUNDARY 0xffffffff
+#define AHCI_USE_CLUSTERING 0
+#define AHCI_MAX_CMDS 32
+#define AHCI_CMD_SZ 32
+#define AHCI_CMD_SLOT_SZ (AHCI_MAX_CMDS * AHCI_CMD_SZ)
+#define AHCI_RX_FIS_SZ 256
+#define AHCI_CMD_TBL_CDB 0x40
+#define AHCI_CMD_TBL_HDR_SZ 0x80
+#define AHCI_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16))
+#define AHCI_CMD_TBL_AR_SZ (AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS)
+#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
+ AHCI_RX_FIS_SZ)
+
+#define AHCI_IRQ_ON_SG (1U << 31)
+#define AHCI_CMD_ATAPI (1 << 5)
+#define AHCI_CMD_WRITE (1 << 6)
+#define AHCI_CMD_PREFETCH (1 << 7)
+#define AHCI_CMD_RESET (1 << 8)
+#define AHCI_CMD_CLR_BUSY (1 << 10)
+
+#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */
+#define RX_FIS_SDB 0x58 /* offset of SDB FIS data */
+#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */
+
+/* global controller registers */
+#define HOST_CAP 0x00 /* host capabilities */
+#define HOST_CTL 0x04 /* global host control */
+#define HOST_IRQ_STAT 0x08 /* interrupt status */
+#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */
+#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */
+
+/* HOST_CTL bits */
+#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
+#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */
+#define HOST_CTL_AHCI_EN (1U << 31) /* AHCI enabled */
+
+/* HOST_CAP bits */
+#define HOST_CAP_SSC (1 << 14) /* Slumber capable */
+#define HOST_CAP_AHCI (1 << 18) /* AHCI only */
+#define HOST_CAP_CLO (1 << 24) /* Command List Override support */
+#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */
+#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */
+#define HOST_CAP_64 (1U << 31) /* PCI DAC (64-bit DMA) support */
+
+/* registers for each SATA port */
+#define PORT_LST_ADDR 0x00 /* command list DMA addr */
+#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */
+#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */
+#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */
+#define PORT_IRQ_STAT 0x10 /* interrupt status */
+#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */
+#define PORT_CMD 0x18 /* port command */
+#define PORT_TFDATA 0x20 /* taskfile data */
+#define PORT_SIG 0x24 /* device TF signature */
+#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */
+#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */
+#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */
+#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */
+#define PORT_CMD_ISSUE 0x38 /* command issue */
+#define PORT_RESERVED 0x3c /* reserved */
+
+/* PORT_IRQ_{STAT,MASK} bits */
+#define PORT_IRQ_COLD_PRES (1U << 31) /* cold presence detect */
+#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
+#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */
+#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
+#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */
+#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */
+#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */
+#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */
+
+#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */
+#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */
+#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */
+#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */
+#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */
+#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */
+#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */
+#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */
+#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */
+
+#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \
+ PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \
+ PORT_IRQ_UNK_FIS)
+#define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \
+ PORT_IRQ_HBUS_DATA_ERR)
+#define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \
+ PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \
+ PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS)
+
+/* PORT_CMD bits */
+#define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */
+#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */
+#define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */
+#define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */
+#define PORT_CMD_CLO (1 << 3) /* Command list override */
+#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */
+#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */
+#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */
+
+#define PORT_CMD_ICC_MASK (0xfU << 28) /* i/f ICC state mask */
+#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */
+#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */
+#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */
+
+#define PORT_CMD_RO_MASK 0x007dffe0 /* Which CMD bits are read only? */
+
+/* ap->flags bits */
+#define AHCI_FLAG_NO_NCQ (1 << 24)
+#define AHCI_FLAG_IGN_IRQ_IF_ERR (1 << 25) /* ignore IRQ_IF_ERR */
+#define AHCI_FLAG_HONOR_PI (1 << 26) /* honor PORTS_IMPL */
+#define AHCI_FLAG_IGN_SERR_INTERNAL (1 << 27) /* ignore SERR_INTERNAL */
+#define AHCI_FLAG_32BIT_ONLY (1 << 28) /* force 32bit */
+
+#define ATA_SRST (1 << 2) /* software reset */
+
+#define STATE_RUN 0
+#define STATE_RESET 1
+
+#define SATA_SCR_SSTATUS_DET_NODEV 0x0
+#define SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP 0x3
+
+#define SATA_SCR_SSTATUS_SPD_NODEV 0x00
+#define SATA_SCR_SSTATUS_SPD_GEN1 0x10
+
+#define SATA_SCR_SSTATUS_IPM_NODEV 0x000
+#define SATA_SCR_SSTATUS_IPM_ACTIVE 0X100
+
+#define AHCI_SCR_SCTL_DET 0xf
+
+#define SATA_FIS_TYPE_REGISTER_H2D 0x27
+#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80
+#define SATA_FIS_TYPE_REGISTER_D2H 0x34
+#define SATA_FIS_TYPE_PIO_SETUP 0x5f
+#define SATA_FIS_TYPE_SDB 0xA1
+
+#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f
+#define AHCI_CMD_HDR_PRDT_LEN 16
+
+#define SATA_SIGNATURE_CDROM 0xeb140101
+#define SATA_SIGNATURE_DISK 0x00000101
+
+#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20
+ /* Shouldn't this be 0x2c? */
+
+#define AHCI_PORT_REGS_START_ADDR 0x100
+#define AHCI_PORT_ADDR_OFFSET_MASK 0x7f
+#define AHCI_PORT_ADDR_OFFSET_LEN 0x80
+
+#define AHCI_NUM_COMMAND_SLOTS 31
+#define AHCI_SUPPORTED_SPEED 20
+#define AHCI_SUPPORTED_SPEED_GEN1 1
+#define AHCI_VERSION_1_0 0x10000
+
+#define AHCI_PROGMODE_MAJOR_REV_1 1
+
+#define AHCI_COMMAND_TABLE_ACMD 0x40
+
+#define AHCI_PRDT_SIZE_MASK 0x3fffff
+
+#define IDE_FEATURE_DMA 1
+
+#define READ_FPDMA_QUEUED 0x60
+#define WRITE_FPDMA_QUEUED 0x61
+#define NCQ_NON_DATA 0x63
+#define RECEIVE_FPDMA_QUEUED 0x65
+#define SEND_FPDMA_QUEUED 0x64
+
+#define NCQ_FIS_FUA_MASK 0x80
+#define NCQ_FIS_RARC_MASK 0x01
+
+#define RES_FIS_DSFIS 0x00
+#define RES_FIS_PSFIS 0x20
+#define RES_FIS_RFIS 0x40
+#define RES_FIS_SDBFIS 0x58
+#define RES_FIS_UFIS 0x60
+
+#define SATA_CAP_SIZE 0x8
+#define SATA_CAP_REV 0x2
+#define SATA_CAP_BAR 0x4
+
+typedef struct AHCIPortRegs {
+ uint32_t lst_addr;
+ uint32_t lst_addr_hi;
+ uint32_t fis_addr;
+ uint32_t fis_addr_hi;
+ uint32_t irq_stat;
+ uint32_t irq_mask;
+ uint32_t cmd;
+ uint32_t unused0;
+ uint32_t tfdata;
+ uint32_t sig;
+ uint32_t scr_stat;
+ uint32_t scr_ctl;
+ uint32_t scr_err;
+ uint32_t scr_act;
+ uint32_t cmd_issue;
+ uint32_t reserved;
+} AHCIPortRegs;
+
+typedef struct AHCICmdHdr {
+ uint16_t opts;
+ uint16_t prdtl;
+ uint32_t status;
+ uint64_t tbl_addr;
+ uint32_t reserved[4];
+} QEMU_PACKED AHCICmdHdr;
+
+typedef struct AHCI_SG {
+ uint64_t addr;
+ uint32_t reserved;
+ uint32_t flags_size;
+} QEMU_PACKED AHCI_SG;
+
+typedef struct NCQTransferState {
+ AHCIDevice *drive;
+ BlockAIOCB *aiocb;
+ AHCICmdHdr *cmdh;
+ QEMUSGList sglist;
+ BlockAcctCookie acct;
+ uint32_t sector_count;
+ uint64_t lba;
+ uint8_t tag;
+ uint8_t cmd;
+ uint8_t slot;
+ bool used;
+ bool halt;
+} NCQTransferState;
+
+struct AHCIDevice {
+ IDEDMA dma;
+ IDEBus port;
+ int port_no;
+ uint32_t port_state;
+ uint32_t finished;
+ AHCIPortRegs port_regs;
+ struct AHCIState *hba;
+ QEMUBH *check_bh;
+ uint8_t *lst;
+ uint8_t *res_fis;
+ bool done_atapi_packet;
+ int32_t busy_slot;
+ bool init_d2h_sent;
+ AHCICmdHdr *cur_cmd;
+ NCQTransferState ncq_tfs[AHCI_MAX_CMDS];
+};
+
+struct AHCIPCIState {
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
+ AHCIState ahci;
+};
+
+#define TYPE_ICH9_AHCI "ich9-ahci"
+
+#define ICH_AHCI(obj) \
+ OBJECT_CHECK(AHCIPCIState, (obj), TYPE_ICH9_AHCI)
+
+extern const VMStateDescription vmstate_ahci;
+
+#define VMSTATE_AHCI(_field, _state) { \
+ .name = (stringify(_field)), \
+ .size = sizeof(AHCIState), \
+ .vmsd = &vmstate_ahci, \
+ .flags = VMS_STRUCT, \
+ .offset = vmstate_offset_value(_state, _field, AHCIState), \
+}
+
+/**
+ * NCQFrame is the same as a Register H2D FIS (described in SATA 3.2),
+ * but some fields have been re-mapped and re-purposed, as seen in
+ * SATA 3.2 section 13.6.4.1 ("READ FPDMA QUEUED")
+ *
+ * cmd_fis[3], feature 7:0, becomes sector count 7:0.
+ * cmd_fis[7], device 7:0, uses bit 7 as the Force Unit Access bit.
+ * cmd_fis[11], feature 15:8, becomes sector count 15:8.
+ * cmd_fis[12], count 7:0, becomes the NCQ TAG (7:3) and RARC bit (0)
+ * cmd_fis[13], count 15:8, becomes the priority value (7:6)
+ * bytes 16-19 become an le32 "auxiliary" field.
+ */
+typedef struct NCQFrame {
+ uint8_t fis_type;
+ uint8_t c;
+ uint8_t command;
+ uint8_t sector_count_low; /* (feature 7:0) */
+ uint8_t lba0;
+ uint8_t lba1;
+ uint8_t lba2;
+ uint8_t fua; /* (device 7:0) */
+ uint8_t lba3;
+ uint8_t lba4;
+ uint8_t lba5;
+ uint8_t sector_count_high; /* (feature 15:8) */
+ uint8_t tag; /* (count 0:7) */
+ uint8_t prio; /* (count 15:8) */
+ uint8_t icc;
+ uint8_t control;
+ uint8_t aux0;
+ uint8_t aux1;
+ uint8_t aux2;
+ uint8_t aux3;
+} QEMU_PACKED NCQFrame;
+
+typedef struct SDBFIS {
+ uint8_t type;
+ uint8_t flags;
+ uint8_t status;
+ uint8_t error;
+ uint32_t payload;
+} QEMU_PACKED SDBFIS;
+
+void ahci_realize(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports);
+void ahci_init(AHCIState *s, DeviceState *qdev);
+void ahci_uninit(AHCIState *s);
+
+void ahci_reset(AHCIState *s);
+
+#define TYPE_SYSBUS_AHCI "sysbus-ahci"
+#define SYSBUS_AHCI(obj) OBJECT_CHECK(SysbusAHCIState, (obj), TYPE_SYSBUS_AHCI)
+
+#define TYPE_ALLWINNER_AHCI "allwinner-ahci"
+#define ALLWINNER_AHCI(obj) OBJECT_CHECK(AllwinnerAHCIState, (obj), \
+ TYPE_ALLWINNER_AHCI)
+
+#endif /* HW_IDE_AHCI_H */
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 989fca5e9f..9472a60cab 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -69,7 +69,7 @@
#include "sysemu/block-backend.h"
#include "sysemu/dma.h"
#include "hw/ide/pci.h"
-#include "hw/ide/ahci.h"
+#include "hw/ide/ahci_internal.h"
#define ICH9_MSI_CAP_OFFSET 0x80
#define ICH9_SATA_CAP_OFFSET 0xA8
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 299e592fa2..cc2f5bd280 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -164,6 +164,7 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
IDEState *s = bus->ifs + dev->unit;
Error *err = NULL;
+ int ret;
if (!dev->conf.blk) {
if (kind != IDE_CD) {
@@ -172,6 +173,8 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
} else {
/* Anonymous BlockBackend for an empty drive */
dev->conf.blk = blk_new(0, BLK_PERM_ALL);
+ ret = blk_attach_dev(dev->conf.blk, &dev->qdev);
+ assert(ret == 0);
}
}
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
index 7985c60dde..776ee283e1 100644
--- a/hw/mips/boston.c
+++ b/hw/mips/boston.c
@@ -538,8 +538,8 @@ static void boston_mach_init(MachineState *machine)
ahci = pci_create_simple_multifunction(&PCI_BRIDGE(&pcie2->root)->sec_bus,
PCI_DEVFN(0, 0),
true, TYPE_ICH9_AHCI);
- g_assert(ARRAY_SIZE(hd) == ICH_AHCI(ahci)->ahci.ports);
- ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports);
+ g_assert(ARRAY_SIZE(hd) == ahci_get_num_ports(ahci));
+ ide_drive_get(hd, ahci_get_num_ports(ahci));
ahci_ide_create_devs(ahci, hd);
if (machine->firmware) {
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index a53f058621..5f1e5e8070 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -2384,9 +2384,14 @@ static void scsi_hd_realize(SCSIDevice *dev, Error **errp)
static void scsi_cd_realize(SCSIDevice *dev, Error **errp)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+ int ret;
if (!dev->conf.blk) {
+ /* Anonymous BlockBackend for an empty drive. As we put it into
+ * dev->conf, qdev takes care of detaching on unplug. */
dev->conf.blk = blk_new(0, BLK_PERM_ALL);
+ ret = blk_attach_dev(dev->conf.blk, &dev->qdev);
+ assert(ret == 0);
}
s->qdev.blocksize = 2048;
diff --git a/include/hw/ide/ahci.h b/include/hw/ide/ahci.h
index 0ca7c65820..5a06537e6b 100644
--- a/include/hw/ide/ahci.h
+++ b/include/hw/ide/ahci.h
@@ -26,189 +26,7 @@
#include "hw/sysbus.h"
-#define AHCI_MEM_BAR_SIZE 0x1000
-#define AHCI_MAX_PORTS 32
-#define AHCI_MAX_SG 168 /* hardware max is 64K */
-#define AHCI_DMA_BOUNDARY 0xffffffff
-#define AHCI_USE_CLUSTERING 0
-#define AHCI_MAX_CMDS 32
-#define AHCI_CMD_SZ 32
-#define AHCI_CMD_SLOT_SZ (AHCI_MAX_CMDS * AHCI_CMD_SZ)
-#define AHCI_RX_FIS_SZ 256
-#define AHCI_CMD_TBL_CDB 0x40
-#define AHCI_CMD_TBL_HDR_SZ 0x80
-#define AHCI_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16))
-#define AHCI_CMD_TBL_AR_SZ (AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS)
-#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
- AHCI_RX_FIS_SZ)
-
-#define AHCI_IRQ_ON_SG (1U << 31)
-#define AHCI_CMD_ATAPI (1 << 5)
-#define AHCI_CMD_WRITE (1 << 6)
-#define AHCI_CMD_PREFETCH (1 << 7)
-#define AHCI_CMD_RESET (1 << 8)
-#define AHCI_CMD_CLR_BUSY (1 << 10)
-
-#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */
-#define RX_FIS_SDB 0x58 /* offset of SDB FIS data */
-#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */
-
-/* global controller registers */
-#define HOST_CAP 0x00 /* host capabilities */
-#define HOST_CTL 0x04 /* global host control */
-#define HOST_IRQ_STAT 0x08 /* interrupt status */
-#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */
-#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */
-
-/* HOST_CTL bits */
-#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
-#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */
-#define HOST_CTL_AHCI_EN (1U << 31) /* AHCI enabled */
-
-/* HOST_CAP bits */
-#define HOST_CAP_SSC (1 << 14) /* Slumber capable */
-#define HOST_CAP_AHCI (1 << 18) /* AHCI only */
-#define HOST_CAP_CLO (1 << 24) /* Command List Override support */
-#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */
-#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */
-#define HOST_CAP_64 (1U << 31) /* PCI DAC (64-bit DMA) support */
-
-/* registers for each SATA port */
-#define PORT_LST_ADDR 0x00 /* command list DMA addr */
-#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */
-#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */
-#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */
-#define PORT_IRQ_STAT 0x10 /* interrupt status */
-#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */
-#define PORT_CMD 0x18 /* port command */
-#define PORT_TFDATA 0x20 /* taskfile data */
-#define PORT_SIG 0x24 /* device TF signature */
-#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */
-#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */
-#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */
-#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */
-#define PORT_CMD_ISSUE 0x38 /* command issue */
-#define PORT_RESERVED 0x3c /* reserved */
-
-/* PORT_IRQ_{STAT,MASK} bits */
-#define PORT_IRQ_COLD_PRES (1U << 31) /* cold presence detect */
-#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
-#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */
-#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
-#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */
-#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */
-#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */
-#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */
-
-#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */
-#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */
-#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */
-#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */
-#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */
-#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */
-#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */
-#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */
-#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */
-
-#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \
- PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \
- PORT_IRQ_UNK_FIS)
-#define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \
- PORT_IRQ_HBUS_DATA_ERR)
-#define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \
- PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \
- PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS)
-
-/* PORT_CMD bits */
-#define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */
-#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */
-#define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */
-#define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */
-#define PORT_CMD_CLO (1 << 3) /* Command list override */
-#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */
-#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */
-#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */
-
-#define PORT_CMD_ICC_MASK (0xfU << 28) /* i/f ICC state mask */
-#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */
-#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */
-#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */
-
-#define PORT_CMD_RO_MASK 0x007dffe0 /* Which CMD bits are read only? */
-
-/* ap->flags bits */
-#define AHCI_FLAG_NO_NCQ (1 << 24)
-#define AHCI_FLAG_IGN_IRQ_IF_ERR (1 << 25) /* ignore IRQ_IF_ERR */
-#define AHCI_FLAG_HONOR_PI (1 << 26) /* honor PORTS_IMPL */
-#define AHCI_FLAG_IGN_SERR_INTERNAL (1 << 27) /* ignore SERR_INTERNAL */
-#define AHCI_FLAG_32BIT_ONLY (1 << 28) /* force 32bit */
-
-#define ATA_SRST (1 << 2) /* software reset */
-
-#define STATE_RUN 0
-#define STATE_RESET 1
-
-#define SATA_SCR_SSTATUS_DET_NODEV 0x0
-#define SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP 0x3
-
-#define SATA_SCR_SSTATUS_SPD_NODEV 0x00
-#define SATA_SCR_SSTATUS_SPD_GEN1 0x10
-
-#define SATA_SCR_SSTATUS_IPM_NODEV 0x000
-#define SATA_SCR_SSTATUS_IPM_ACTIVE 0X100
-
-#define AHCI_SCR_SCTL_DET 0xf
-
-#define SATA_FIS_TYPE_REGISTER_H2D 0x27
-#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80
-#define SATA_FIS_TYPE_REGISTER_D2H 0x34
-#define SATA_FIS_TYPE_PIO_SETUP 0x5f
-#define SATA_FIS_TYPE_SDB 0xA1
-
-#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f
-#define AHCI_CMD_HDR_PRDT_LEN 16
-
-#define SATA_SIGNATURE_CDROM 0xeb140101
-#define SATA_SIGNATURE_DISK 0x00000101
-
-#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20
- /* Shouldn't this be 0x2c? */
-
-#define AHCI_PORT_REGS_START_ADDR 0x100
-#define AHCI_PORT_ADDR_OFFSET_MASK 0x7f
-#define AHCI_PORT_ADDR_OFFSET_LEN 0x80
-
-#define AHCI_NUM_COMMAND_SLOTS 31
-#define AHCI_SUPPORTED_SPEED 20
-#define AHCI_SUPPORTED_SPEED_GEN1 1
-#define AHCI_VERSION_1_0 0x10000
-
-#define AHCI_PROGMODE_MAJOR_REV_1 1
-
-#define AHCI_COMMAND_TABLE_ACMD 0x40
-
-#define AHCI_PRDT_SIZE_MASK 0x3fffff
-
-#define IDE_FEATURE_DMA 1
-
-#define READ_FPDMA_QUEUED 0x60
-#define WRITE_FPDMA_QUEUED 0x61
-#define NCQ_NON_DATA 0x63
-#define RECEIVE_FPDMA_QUEUED 0x65
-#define SEND_FPDMA_QUEUED 0x64
-
-#define NCQ_FIS_FUA_MASK 0x80
-#define NCQ_FIS_RARC_MASK 0x01
-
-#define RES_FIS_DSFIS 0x00
-#define RES_FIS_PSFIS 0x20
-#define RES_FIS_RFIS 0x40
-#define RES_FIS_SDBFIS 0x58
-#define RES_FIS_UFIS 0x60
-
-#define SATA_CAP_SIZE 0x8
-#define SATA_CAP_REV 0x2
-#define SATA_CAP_BAR 0x4
+typedef struct AHCIDevice AHCIDevice;
typedef struct AHCIControlRegs {
uint32_t cap;
@@ -218,74 +36,6 @@ typedef struct AHCIControlRegs {
uint32_t version;
} AHCIControlRegs;
-typedef struct AHCIPortRegs {
- uint32_t lst_addr;
- uint32_t lst_addr_hi;
- uint32_t fis_addr;
- uint32_t fis_addr_hi;
- uint32_t irq_stat;
- uint32_t irq_mask;
- uint32_t cmd;
- uint32_t unused0;
- uint32_t tfdata;
- uint32_t sig;
- uint32_t scr_stat;
- uint32_t scr_ctl;
- uint32_t scr_err;
- uint32_t scr_act;
- uint32_t cmd_issue;
- uint32_t reserved;
-} AHCIPortRegs;
-
-typedef struct AHCICmdHdr {
- uint16_t opts;
- uint16_t prdtl;
- uint32_t status;
- uint64_t tbl_addr;
- uint32_t reserved[4];
-} QEMU_PACKED AHCICmdHdr;
-
-typedef struct AHCI_SG {
- uint64_t addr;
- uint32_t reserved;
- uint32_t flags_size;
-} QEMU_PACKED AHCI_SG;
-
-typedef struct AHCIDevice AHCIDevice;
-
-typedef struct NCQTransferState {
- AHCIDevice *drive;
- BlockAIOCB *aiocb;
- AHCICmdHdr *cmdh;
- QEMUSGList sglist;
- BlockAcctCookie acct;
- uint32_t sector_count;
- uint64_t lba;
- uint8_t tag;
- uint8_t cmd;
- uint8_t slot;
- bool used;
- bool halt;
-} NCQTransferState;
-
-struct AHCIDevice {
- IDEDMA dma;
- IDEBus port;
- int port_no;
- uint32_t port_state;
- uint32_t finished;
- AHCIPortRegs port_regs;
- struct AHCIState *hba;
- QEMUBH *check_bh;
- uint8_t *lst;
- uint8_t *res_fis;
- bool done_atapi_packet;
- int32_t busy_slot;
- bool init_d2h_sent;
- AHCICmdHdr *cur_cmd;
- NCQTransferState ncq_tfs[AHCI_MAX_CMDS];
-};
-
typedef struct AHCIState {
DeviceState *container;
@@ -300,78 +50,14 @@ typedef struct AHCIState {
AddressSpace *as;
} AHCIState;
-typedef struct AHCIPCIState {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- AHCIState ahci;
-} AHCIPCIState;
+typedef struct AHCIPCIState AHCIPCIState;
#define TYPE_ICH9_AHCI "ich9-ahci"
#define ICH_AHCI(obj) \
OBJECT_CHECK(AHCIPCIState, (obj), TYPE_ICH9_AHCI)
-extern const VMStateDescription vmstate_ahci;
-
-#define VMSTATE_AHCI(_field, _state) { \
- .name = (stringify(_field)), \
- .size = sizeof(AHCIState), \
- .vmsd = &vmstate_ahci, \
- .flags = VMS_STRUCT, \
- .offset = vmstate_offset_value(_state, _field, AHCIState), \
-}
-
-/**
- * NCQFrame is the same as a Register H2D FIS (described in SATA 3.2),
- * but some fields have been re-mapped and re-purposed, as seen in
- * SATA 3.2 section 13.6.4.1 ("READ FPDMA QUEUED")
- *
- * cmd_fis[3], feature 7:0, becomes sector count 7:0.
- * cmd_fis[7], device 7:0, uses bit 7 as the Force Unit Access bit.
- * cmd_fis[11], feature 15:8, becomes sector count 15:8.
- * cmd_fis[12], count 7:0, becomes the NCQ TAG (7:3) and RARC bit (0)
- * cmd_fis[13], count 15:8, becomes the priority value (7:6)
- * bytes 16-19 become an le32 "auxiliary" field.
- */
-typedef struct NCQFrame {
- uint8_t fis_type;
- uint8_t c;
- uint8_t command;
- uint8_t sector_count_low; /* (feature 7:0) */
- uint8_t lba0;
- uint8_t lba1;
- uint8_t lba2;
- uint8_t fua; /* (device 7:0) */
- uint8_t lba3;
- uint8_t lba4;
- uint8_t lba5;
- uint8_t sector_count_high; /* (feature 15:8) */
- uint8_t tag; /* (count 0:7) */
- uint8_t prio; /* (count 15:8) */
- uint8_t icc;
- uint8_t control;
- uint8_t aux0;
- uint8_t aux1;
- uint8_t aux2;
- uint8_t aux3;
-} QEMU_PACKED NCQFrame;
-
-typedef struct SDBFIS {
- uint8_t type;
- uint8_t flags;
- uint8_t status;
- uint8_t error;
- uint32_t payload;
-} QEMU_PACKED SDBFIS;
-
-void ahci_realize(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports);
-void ahci_init(AHCIState *s, DeviceState *qdev);
-void ahci_uninit(AHCIState *s);
-
-void ahci_reset(AHCIState *s);
-
+int32_t ahci_get_num_ports(PCIDevice *dev);
void ahci_ide_create_devs(PCIDevice *dev, DriveInfo **hd);
#define TYPE_SYSBUS_AHCI "sysbus-ahci"
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 39297961f3..e2321f1cc1 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -13,6 +13,7 @@ extern const PropertyInfo qdev_prop_uint16;
extern const PropertyInfo qdev_prop_uint32;
extern const PropertyInfo qdev_prop_int32;
extern const PropertyInfo qdev_prop_uint64;
+extern const PropertyInfo qdev_prop_int64;
extern const PropertyInfo qdev_prop_size;
extern const PropertyInfo qdev_prop_string;
extern const PropertyInfo qdev_prop_chr;
@@ -157,6 +158,8 @@ extern const PropertyInfo qdev_prop_link;
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_int32, int32_t)
#define DEFINE_PROP_UINT64(_n, _s, _f, _d) \
DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_uint64, uint64_t)
+#define DEFINE_PROP_INT64(_n, _s, _f, _d) \
+ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_int64, int64_t)
#define DEFINE_PROP_SIZE(_n, _s, _f, _d) \
DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_size, uint64_t)
#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \
diff --git a/include/migration/colo.h b/include/migration/colo.h
index be6beba301..ff9874ea16 100644
--- a/include/migration/colo.h
+++ b/include/migration/colo.h
@@ -15,7 +15,6 @@
#include "qemu-common.h"
-bool colo_supported(void);
void colo_info_init(void);
void migrate_start_colo_process(MigrationState *s);
diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
index 9109657609..d056008c18 100644
--- a/include/qemu/throttle.h
+++ b/include/qemu/throttle.h
@@ -139,7 +139,7 @@ bool throttle_enabled(ThrottleConfig *cfg);
bool throttle_is_valid(ThrottleConfig *cfg, Error **errp);
void throttle_config(ThrottleState *ts,
- ThrottleTimers *tt,
+ QEMUClockType clock_type,
ThrottleConfig *cfg);
void throttle_get_config(ThrottleState *ts, ThrottleConfig *cfg);
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index d9ea0cdb0f..4a3730596b 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -100,6 +100,7 @@ void blk_remove_all_bs(void);
const char *blk_name(const BlockBackend *blk);
BlockBackend *blk_by_name(const char *name);
BlockBackend *blk_next(BlockBackend *blk);
+BlockBackend *blk_all_next(BlockBackend *blk);
bool monitor_add_blk(BlockBackend *blk, const char *name, Error **errp);
void monitor_remove_blk(BlockBackend *blk);
@@ -126,6 +127,7 @@ int blk_attach_dev(BlockBackend *blk, DeviceState *dev);
void blk_attach_dev_legacy(BlockBackend *blk, void *dev);
void blk_detach_dev(BlockBackend *blk, void *dev);
void *blk_get_attached_dev(BlockBackend *blk);
+char *blk_get_attached_dev_id(BlockBackend *blk);
BlockBackend *blk_by_dev(void *dev);
BlockBackend *blk_by_qdev_id(const char *id, Error **errp);
void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque);
diff --git a/io/channel.c b/io/channel.c
index cdf74540c1..1cfb8b33a2 100644
--- a/io/channel.c
+++ b/io/channel.c
@@ -279,15 +279,9 @@ static void qio_channel_set_aio_fd_handlers(QIOChannel *ioc)
void qio_channel_attach_aio_context(QIOChannel *ioc,
AioContext *ctx)
{
- AioContext *old_ctx;
- if (ioc->ctx == ctx) {
- return;
- }
-
- old_ctx = ioc->ctx ? ioc->ctx : iohandler_get_aio_context();
- qio_channel_set_aio_fd_handler(ioc, old_ctx, NULL, NULL, NULL);
+ assert(!ioc->read_coroutine);
+ assert(!ioc->write_coroutine);
ioc->ctx = ctx;
- qio_channel_set_aio_fd_handlers(ioc);
}
void qio_channel_detach_aio_context(QIOChannel *ioc)
diff --git a/migration/colo.c b/migration/colo.c
index ef35f00c9a..a4255432ac 100644
--- a/migration/colo.c
+++ b/migration/colo.c
@@ -29,11 +29,6 @@ static bool vmstate_loading;
#define COLO_BUFFER_BASE_SIZE (4 * 1024 * 1024)
-bool colo_supported(void)
-{
- return true;
-}
-
bool migration_in_colo_state(void)
{
MigrationState *s = migrate_get_current();
diff --git a/migration/migration.c b/migration/migration.c
index a0db40d364..76153914d1 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -102,14 +102,22 @@ enum mig_rp_message_type {
static MigrationState *current_migration;
+static bool migration_object_check(MigrationState *ms, Error **errp);
+
void migration_object_init(void)
{
MachineState *ms = MACHINE(qdev_get_machine());
+ Error *err = NULL;
/* This can only be called once. */
assert(!current_migration);
current_migration = MIGRATION_OBJ(object_new(TYPE_MIGRATION));
+ if (!migration_object_check(current_migration, &err)) {
+ error_report_err(err);
+ exit(1);
+ }
+
/*
* We cannot really do this in migration_instance_init() since at
* that time global properties are not yet applied, then this
@@ -348,6 +356,7 @@ static void process_incoming_migration_co(void *opaque)
migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
MIGRATION_STATUS_FAILED);
error_report("load of migration failed: %s", strerror(-ret));
+ qemu_fclose(mis->from_src_file);
exit(EXIT_FAILURE);
}
mis->bh = qemu_bh_new(process_incoming_migration_bh, mis);
@@ -403,9 +412,6 @@ MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
continue;
}
#endif
- if (i == MIGRATION_CAPABILITY_X_COLO && !colo_supported()) {
- continue;
- }
if (head == NULL) {
head = g_malloc0(sizeof(*caps));
caps = head;
@@ -582,51 +588,49 @@ MigrationInfo *qmp_query_migrate(Error **errp)
return info;
}
-void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
- Error **errp)
+/**
+ * @migration_caps_check - check capability validity
+ *
+ * @cap_list: old capability list, array of bool
+ * @params: new capabilities to be applied soon
+ * @errp: set *errp if the check failed, with reason
+ *
+ * Returns true if check passed, otherwise false.
+ */
+static bool migrate_caps_check(bool *cap_list,
+ MigrationCapabilityStatusList *params,
+ Error **errp)
{
- MigrationState *s = migrate_get_current();
MigrationCapabilityStatusList *cap;
- bool old_postcopy_cap = migrate_postcopy_ram();
+ bool old_postcopy_cap;
- if (migration_is_setup_or_active(s->state)) {
- error_setg(errp, QERR_MIGRATION_ACTIVE);
- return;
- }
+ old_postcopy_cap = cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM];
for (cap = params; cap; cap = cap->next) {
+ cap_list[cap->value->capability] = cap->value->state;
+ }
+
#ifndef CONFIG_LIVE_BLOCK_MIGRATION
- if (cap->value->capability == MIGRATION_CAPABILITY_BLOCK
- && cap->value->state) {
- error_setg(errp, "QEMU compiled without old-style (blk/-b, inc/-i) "
- "block migration");
- error_append_hint(errp, "Use drive_mirror+NBD instead.\n");
- continue;
- }
-#endif
- if (cap->value->capability == MIGRATION_CAPABILITY_X_COLO) {
- if (!colo_supported()) {
- error_setg(errp, "COLO is not currently supported, please"
- " configure with --enable-colo option in order to"
- " support COLO feature");
- continue;
- }
- }
- s->enabled_capabilities[cap->value->capability] = cap->value->state;
+ if (cap_list[MIGRATION_CAPABILITY_BLOCK]) {
+ error_setg(errp, "QEMU compiled without old-style (blk/-b, inc/-i) "
+ "block migration");
+ error_append_hint(errp, "Use drive_mirror+NBD instead.\n");
+ return false;
}
+#endif
- if (migrate_postcopy_ram()) {
- if (migrate_use_compression()) {
+ if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
+ if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) {
/* The decompression threads asynchronously write into RAM
* rather than use the atomic copies needed to avoid
* userfaulting. It should be possible to fix the decompression
* threads for compatibility in future.
*/
- error_report("Postcopy is not currently compatible with "
- "compression");
- s->enabled_capabilities[MIGRATION_CAPABILITY_POSTCOPY_RAM] =
- false;
+ error_setg(errp, "Postcopy is not currently compatible "
+ "with compression");
+ return false;
}
+
/* This check is reasonably expensive, so only when it's being
* set the first time, also it's only the destination that needs
* special support.
@@ -636,96 +640,141 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
/* postcopy_ram_supported_by_host will have emitted a more
* detailed message
*/
- error_report("Postcopy is not supported");
- s->enabled_capabilities[MIGRATION_CAPABILITY_POSTCOPY_RAM] =
- false;
+ error_setg(errp, "Postcopy is not supported");
+ return false;
}
}
+
+ return true;
}
-void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
+void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
+ Error **errp)
{
MigrationState *s = migrate_get_current();
+ MigrationCapabilityStatusList *cap;
+ if (migration_is_setup_or_active(s->state)) {
+ error_setg(errp, QERR_MIGRATION_ACTIVE);
+ return;
+ }
+
+ if (!migrate_caps_check(s->enabled_capabilities, params, errp)) {
+ return;
+ }
+
+ for (cap = params; cap; cap = cap->next) {
+ s->enabled_capabilities[cap->value->capability] = cap->value->state;
+ }
+}
+
+/*
+ * Check whether the parameters are valid. Error will be put into errp
+ * (if provided). Return true if valid, otherwise false.
+ */
+static bool migrate_params_check(MigrationParameters *params, Error **errp)
+{
if (params->has_compress_level &&
(params->compress_level < 0 || params->compress_level > 9)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "compress_level",
"is invalid, it should be in the range of 0 to 9");
- return;
+ return false;
}
+
if (params->has_compress_threads &&
(params->compress_threads < 1 || params->compress_threads > 255)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"compress_threads",
"is invalid, it should be in the range of 1 to 255");
- return;
+ return false;
}
+
if (params->has_decompress_threads &&
(params->decompress_threads < 1 || params->decompress_threads > 255)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"decompress_threads",
"is invalid, it should be in the range of 1 to 255");
- return;
+ return false;
}
+
if (params->has_cpu_throttle_initial &&
(params->cpu_throttle_initial < 1 ||
params->cpu_throttle_initial > 99)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"cpu_throttle_initial",
"an integer in the range of 1 to 99");
- return;
+ return false;
}
+
if (params->has_cpu_throttle_increment &&
(params->cpu_throttle_increment < 1 ||
params->cpu_throttle_increment > 99)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"cpu_throttle_increment",
"an integer in the range of 1 to 99");
- return;
+ return false;
}
+
if (params->has_max_bandwidth &&
(params->max_bandwidth < 0 || params->max_bandwidth > SIZE_MAX)) {
error_setg(errp, "Parameter 'max_bandwidth' expects an integer in the"
" range of 0 to %zu bytes/second", SIZE_MAX);
- return;
+ return false;
}
+
if (params->has_downtime_limit &&
(params->downtime_limit < 0 ||
params->downtime_limit > MAX_MIGRATE_DOWNTIME)) {
error_setg(errp, "Parameter 'downtime_limit' expects an integer in "
"the range of 0 to %d milliseconds",
MAX_MIGRATE_DOWNTIME);
- return;
+ return false;
}
+
if (params->has_x_checkpoint_delay && (params->x_checkpoint_delay < 0)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"x_checkpoint_delay",
"is invalid, it should be positive");
+ return false;
}
+ return true;
+}
+
+static void migrate_params_apply(MigrationParameters *params)
+{
+ MigrationState *s = migrate_get_current();
+
if (params->has_compress_level) {
s->parameters.compress_level = params->compress_level;
}
+
if (params->has_compress_threads) {
s->parameters.compress_threads = params->compress_threads;
}
+
if (params->has_decompress_threads) {
s->parameters.decompress_threads = params->decompress_threads;
}
+
if (params->has_cpu_throttle_initial) {
s->parameters.cpu_throttle_initial = params->cpu_throttle_initial;
}
+
if (params->has_cpu_throttle_increment) {
s->parameters.cpu_throttle_increment = params->cpu_throttle_increment;
}
+
if (params->has_tls_creds) {
g_free(s->parameters.tls_creds);
s->parameters.tls_creds = g_strdup(params->tls_creds);
}
+
if (params->has_tls_hostname) {
g_free(s->parameters.tls_hostname);
s->parameters.tls_hostname = g_strdup(params->tls_hostname);
}
+
if (params->has_max_bandwidth) {
s->parameters.max_bandwidth = params->max_bandwidth;
if (s->to_dst_file) {
@@ -733,6 +782,7 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
s->parameters.max_bandwidth / XFER_LIMIT_RATIO);
}
}
+
if (params->has_downtime_limit) {
s->parameters.downtime_limit = params->downtime_limit;
}
@@ -743,11 +793,22 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
colo_checkpoint_notify(s);
}
}
+
if (params->has_block_incremental) {
s->parameters.block_incremental = params->block_incremental;
}
}
+void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
+{
+ if (!migrate_params_check(params, errp)) {
+ /* Invalid parameter */
+ return;
+ }
+
+ migrate_params_apply(params);
+}
+
void qmp_migrate_start_postcopy(Error **errp)
{
@@ -781,14 +842,27 @@ void migrate_set_state(int *state, int old_state, int new_state)
}
}
-void migrate_set_block_enabled(bool value, Error **errp)
+static MigrationCapabilityStatusList *migrate_cap_add(
+ MigrationCapabilityStatusList *list,
+ MigrationCapability index,
+ bool state)
{
MigrationCapabilityStatusList *cap;
cap = g_new0(MigrationCapabilityStatusList, 1);
cap->value = g_new0(MigrationCapabilityStatus, 1);
- cap->value->capability = MIGRATION_CAPABILITY_BLOCK;
- cap->value->state = value;
+ cap->value->capability = index;
+ cap->value->state = state;
+ cap->next = list;
+
+ return cap;
+}
+
+void migrate_set_block_enabled(bool value, Error **errp)
+{
+ MigrationCapabilityStatusList *cap;
+
+ cap = migrate_cap_add(NULL, MIGRATION_CAPABILITY_BLOCK, value);
qmp_migrate_set_capabilities(cap, errp);
qapi_free_MigrationCapabilityStatusList(cap);
}
@@ -2001,6 +2075,9 @@ void migration_global_dump(Monitor *mon)
ms->send_configuration, ms->send_section_footer);
}
+#define DEFINE_PROP_MIG_CAP(name, x) \
+ DEFINE_PROP_BOOL(name, MigrationState, enabled_capabilities[x], false)
+
static Property migration_properties[] = {
DEFINE_PROP_BOOL("store-global-state", MigrationState,
store_global_state, true),
@@ -2009,6 +2086,45 @@ static Property migration_properties[] = {
send_configuration, true),
DEFINE_PROP_BOOL("send-section-footer", MigrationState,
send_section_footer, true),
+
+ /* Migration parameters */
+ DEFINE_PROP_INT64("x-compress-level", MigrationState,
+ parameters.compress_level,
+ DEFAULT_MIGRATE_COMPRESS_LEVEL),
+ DEFINE_PROP_INT64("x-compress-threads", MigrationState,
+ parameters.compress_threads,
+ DEFAULT_MIGRATE_COMPRESS_THREAD_COUNT),
+ DEFINE_PROP_INT64("x-decompress-threads", MigrationState,
+ parameters.decompress_threads,
+ DEFAULT_MIGRATE_DECOMPRESS_THREAD_COUNT),
+ DEFINE_PROP_INT64("x-cpu-throttle-initial", MigrationState,
+ parameters.cpu_throttle_initial,
+ DEFAULT_MIGRATE_CPU_THROTTLE_INITIAL),
+ DEFINE_PROP_INT64("x-cpu-throttle-increment", MigrationState,
+ parameters.cpu_throttle_increment,
+ DEFAULT_MIGRATE_CPU_THROTTLE_INCREMENT),
+ DEFINE_PROP_INT64("x-max-bandwidth", MigrationState,
+ parameters.max_bandwidth, MAX_THROTTLE),
+ DEFINE_PROP_INT64("x-downtime-limit", MigrationState,
+ parameters.downtime_limit,
+ DEFAULT_MIGRATE_SET_DOWNTIME),
+ DEFINE_PROP_INT64("x-checkpoint-delay", MigrationState,
+ parameters.x_checkpoint_delay,
+ DEFAULT_MIGRATE_X_CHECKPOINT_DELAY),
+
+ /* Migration capabilities */
+ DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE),
+ DEFINE_PROP_MIG_CAP("x-rdma-pin-all", MIGRATION_CAPABILITY_RDMA_PIN_ALL),
+ DEFINE_PROP_MIG_CAP("x-auto-converge", MIGRATION_CAPABILITY_AUTO_CONVERGE),
+ DEFINE_PROP_MIG_CAP("x-zero-blocks", MIGRATION_CAPABILITY_ZERO_BLOCKS),
+ DEFINE_PROP_MIG_CAP("x-compress", MIGRATION_CAPABILITY_COMPRESS),
+ DEFINE_PROP_MIG_CAP("x-events", MIGRATION_CAPABILITY_EVENTS),
+ DEFINE_PROP_MIG_CAP("x-postcopy-ram", MIGRATION_CAPABILITY_POSTCOPY_RAM),
+ DEFINE_PROP_MIG_CAP("x-colo", MIGRATION_CAPABILITY_X_COLO),
+ DEFINE_PROP_MIG_CAP("x-release-ram", MIGRATION_CAPABILITY_RELEASE_RAM),
+ DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK),
+ DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH),
+
DEFINE_PROP_END_OF_LIST(),
};
@@ -2023,22 +2139,54 @@ static void migration_class_init(ObjectClass *klass, void *data)
static void migration_instance_init(Object *obj)
{
MigrationState *ms = MIGRATION_OBJ(obj);
+ MigrationParameters *params = &ms->parameters;
ms->state = MIGRATION_STATUS_NONE;
ms->xbzrle_cache_size = DEFAULT_MIGRATE_CACHE_SIZE;
ms->mbps = -1;
- ms->parameters = (MigrationParameters) {
- .compress_level = DEFAULT_MIGRATE_COMPRESS_LEVEL,
- .compress_threads = DEFAULT_MIGRATE_COMPRESS_THREAD_COUNT,
- .decompress_threads = DEFAULT_MIGRATE_DECOMPRESS_THREAD_COUNT,
- .cpu_throttle_initial = DEFAULT_MIGRATE_CPU_THROTTLE_INITIAL,
- .cpu_throttle_increment = DEFAULT_MIGRATE_CPU_THROTTLE_INCREMENT,
- .max_bandwidth = MAX_THROTTLE,
- .downtime_limit = DEFAULT_MIGRATE_SET_DOWNTIME,
- .x_checkpoint_delay = DEFAULT_MIGRATE_X_CHECKPOINT_DELAY,
- };
- ms->parameters.tls_creds = g_strdup("");
- ms->parameters.tls_hostname = g_strdup("");
+
+ params->tls_hostname = g_strdup("");
+ params->tls_creds = g_strdup("");
+
+ /* Set has_* up only for parameter checks */
+ params->has_compress_level = true;
+ params->has_compress_threads = true;
+ params->has_decompress_threads = true;
+ params->has_cpu_throttle_initial = true;
+ params->has_cpu_throttle_increment = true;
+ params->has_max_bandwidth = true;
+ params->has_downtime_limit = true;
+ params->has_x_checkpoint_delay = true;
+ params->has_block_incremental = true;
+}
+
+/*
+ * Return true if check pass, false otherwise. Error will be put
+ * inside errp if provided.
+ */
+static bool migration_object_check(MigrationState *ms, Error **errp)
+{
+ MigrationCapabilityStatusList *head = NULL;
+ /* Assuming all off */
+ bool cap_list[MIGRATION_CAPABILITY__MAX] = { 0 }, ret;
+ int i;
+
+ if (!migrate_params_check(&ms->parameters, errp)) {
+ return false;
+ }
+
+ for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
+ if (ms->enabled_capabilities[i]) {
+ head = migrate_cap_add(head, i, true);
+ }
+ }
+
+ ret = migrate_caps_check(cap_list, head, errp);
+
+ /* It works with head == NULL */
+ qapi_free_MigrationCapabilityStatusList(head);
+
+ return ret;
}
static const TypeInfo migration_type = {
diff --git a/migration/rdma.c b/migration/rdma.c
index c6bc607a03..ca56594328 100644
--- a/migration/rdma.c
+++ b/migration/rdma.c
@@ -165,20 +165,6 @@ enum {
RDMA_CONTROL_UNREGISTER_FINISHED, /* unpinning finished */
};
-static const char *control_desc[] = {
- [RDMA_CONTROL_NONE] = "NONE",
- [RDMA_CONTROL_ERROR] = "ERROR",
- [RDMA_CONTROL_READY] = "READY",
- [RDMA_CONTROL_QEMU_FILE] = "QEMU FILE",
- [RDMA_CONTROL_RAM_BLOCKS_REQUEST] = "RAM BLOCKS REQUEST",
- [RDMA_CONTROL_RAM_BLOCKS_RESULT] = "RAM BLOCKS RESULT",
- [RDMA_CONTROL_COMPRESS] = "COMPRESS",
- [RDMA_CONTROL_REGISTER_REQUEST] = "REGISTER REQUEST",
- [RDMA_CONTROL_REGISTER_RESULT] = "REGISTER RESULT",
- [RDMA_CONTROL_REGISTER_FINISHED] = "REGISTER FINISHED",
- [RDMA_CONTROL_UNREGISTER_REQUEST] = "UNREGISTER REQUEST",
- [RDMA_CONTROL_UNREGISTER_FINISHED] = "UNREGISTER FINISHED",
-};
/*
* Memory and MR structures used to represent an IB Send/Recv work request.
@@ -251,6 +237,30 @@ typedef struct QEMU_PACKED RDMADestBlock {
uint32_t padding;
} RDMADestBlock;
+static const char *control_desc(unsigned int rdma_control)
+{
+ static const char *strs[] = {
+ [RDMA_CONTROL_NONE] = "NONE",
+ [RDMA_CONTROL_ERROR] = "ERROR",
+ [RDMA_CONTROL_READY] = "READY",
+ [RDMA_CONTROL_QEMU_FILE] = "QEMU FILE",
+ [RDMA_CONTROL_RAM_BLOCKS_REQUEST] = "RAM BLOCKS REQUEST",
+ [RDMA_CONTROL_RAM_BLOCKS_RESULT] = "RAM BLOCKS RESULT",
+ [RDMA_CONTROL_COMPRESS] = "COMPRESS",
+ [RDMA_CONTROL_REGISTER_REQUEST] = "REGISTER REQUEST",
+ [RDMA_CONTROL_REGISTER_RESULT] = "REGISTER RESULT",
+ [RDMA_CONTROL_REGISTER_FINISHED] = "REGISTER FINISHED",
+ [RDMA_CONTROL_UNREGISTER_REQUEST] = "UNREGISTER REQUEST",
+ [RDMA_CONTROL_UNREGISTER_FINISHED] = "UNREGISTER FINISHED",
+ };
+
+ if (rdma_control > RDMA_CONTROL_UNREGISTER_FINISHED) {
+ return "??BAD CONTROL VALUE??";
+ }
+
+ return strs[rdma_control];
+}
+
static uint64_t htonll(uint64_t v)
{
union { uint32_t lv[2]; uint64_t llv; } u;
@@ -1466,6 +1476,56 @@ static uint64_t qemu_rdma_poll(RDMAContext *rdma, uint64_t *wr_id_out,
return 0;
}
+/* Wait for activity on the completion channel.
+ * Returns 0 on success, none-0 on error.
+ */
+static int qemu_rdma_wait_comp_channel(RDMAContext *rdma)
+{
+ /*
+ * Coroutine doesn't start until migration_fd_process_incoming()
+ * so don't yield unless we know we're running inside of a coroutine.
+ */
+ if (rdma->migration_started_on_destination) {
+ yield_until_fd_readable(rdma->comp_channel->fd);
+ } else {
+ /* This is the source side, we're in a separate thread
+ * or destination prior to migration_fd_process_incoming()
+ * we can't yield; so we have to poll the fd.
+ * But we need to be able to handle 'cancel' or an error
+ * without hanging forever.
+ */
+ while (!rdma->error_state && !rdma->received_error) {
+ GPollFD pfds[1];
+ pfds[0].fd = rdma->comp_channel->fd;
+ pfds[0].events = G_IO_IN | G_IO_HUP | G_IO_ERR;
+ /* 0.1s timeout, should be fine for a 'cancel' */
+ switch (qemu_poll_ns(pfds, 1, 100 * 1000 * 1000)) {
+ case 1: /* fd active */
+ return 0;
+
+ case 0: /* Timeout, go around again */
+ break;
+
+ default: /* Error of some type -
+ * I don't trust errno from qemu_poll_ns
+ */
+ error_report("%s: poll failed", __func__);
+ return -EPIPE;
+ }
+
+ if (migrate_get_current()->state == MIGRATION_STATUS_CANCELLING) {
+ /* Bail out and let the cancellation happen */
+ return -EPIPE;
+ }
+ }
+ }
+
+ if (rdma->received_error) {
+ return -EPIPE;
+ }
+ return rdma->error_state;
+}
+
/*
* Block until the next work request has completed.
*
@@ -1513,22 +1573,21 @@ static int qemu_rdma_block_for_wrid(RDMAContext *rdma, int wrid_requested,
}
while (1) {
- /*
- * Coroutine doesn't start until migration_fd_process_incoming()
- * so don't yield unless we know we're running inside of a coroutine.
- */
- if (rdma->migration_started_on_destination) {
- yield_until_fd_readable(rdma->comp_channel->fd);
+ ret = qemu_rdma_wait_comp_channel(rdma);
+ if (ret) {
+ goto err_block_for_wrid;
}
- if (ibv_get_cq_event(rdma->comp_channel, &cq, &cq_ctx)) {
+ ret = ibv_get_cq_event(rdma->comp_channel, &cq, &cq_ctx);
+ if (ret) {
perror("ibv_get_cq_event");
goto err_block_for_wrid;
}
num_cq_events++;
- if (ibv_req_notify_cq(cq, 0)) {
+ ret = -ibv_req_notify_cq(cq, 0);
+ if (ret) {
goto err_block_for_wrid;
}
@@ -1564,6 +1623,8 @@ err_block_for_wrid:
if (num_cq_events) {
ibv_ack_cq_events(cq, num_cq_events);
}
+
+ rdma->error_state = ret;
return ret;
}
@@ -1590,7 +1651,7 @@ static int qemu_rdma_post_send_control(RDMAContext *rdma, uint8_t *buf,
.num_sge = 1,
};
- trace_qemu_rdma_post_send_control(control_desc[head->type]);
+ trace_qemu_rdma_post_send_control(control_desc(head->type));
/*
* We don't actually need to do a memcpy() in here if we used
@@ -1669,16 +1730,16 @@ static int qemu_rdma_exchange_get_response(RDMAContext *rdma,
network_to_control((void *) rdma->wr_data[idx].control);
memcpy(head, rdma->wr_data[idx].control, sizeof(RDMAControlHeader));
- trace_qemu_rdma_exchange_get_response_start(control_desc[expecting]);
+ trace_qemu_rdma_exchange_get_response_start(control_desc(expecting));
if (expecting == RDMA_CONTROL_NONE) {
- trace_qemu_rdma_exchange_get_response_none(control_desc[head->type],
+ trace_qemu_rdma_exchange_get_response_none(control_desc(head->type),
head->type);
} else if (head->type != expecting || head->type == RDMA_CONTROL_ERROR) {
error_report("Was expecting a %s (%d) control message"
", but got: %s (%d), length: %d",
- control_desc[expecting], expecting,
- control_desc[head->type], head->type, head->len);
+ control_desc(expecting), expecting,
+ control_desc(head->type), head->type, head->len);
if (head->type == RDMA_CONTROL_ERROR) {
rdma->received_error = true;
}
@@ -1788,7 +1849,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head,
}
}
- trace_qemu_rdma_exchange_send_waiting(control_desc[resp->type]);
+ trace_qemu_rdma_exchange_send_waiting(control_desc(resp->type));
ret = qemu_rdma_exchange_get_response(rdma, resp,
resp->type, RDMA_WRID_DATA);
@@ -1800,7 +1861,7 @@ static int qemu_rdma_exchange_send(RDMAContext *rdma, RDMAControlHeader *head,
if (resp_idx) {
*resp_idx = RDMA_WRID_DATA;
}
- trace_qemu_rdma_exchange_send_received(control_desc[resp->type]);
+ trace_qemu_rdma_exchange_send_received(control_desc(resp->type));
}
rdma->control_ready_expected = 1;
@@ -2208,7 +2269,9 @@ static void qemu_rdma_cleanup(RDMAContext *rdma)
int ret, idx;
if (rdma->cm_id && rdma->connected) {
- if (rdma->error_state && !rdma->received_error) {
+ if ((rdma->error_state ||
+ migrate_get_current()->state == MIGRATION_STATUS_CANCELLING) &&
+ !rdma->received_error) {
RDMAControlHeader head = { .len = 0,
.type = RDMA_CONTROL_ERROR,
.repeat = 1,
@@ -2365,6 +2428,12 @@ static int qemu_rdma_connect(RDMAContext *rdma, Error **errp)
caps_to_network(&cap);
+ ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY);
+ if (ret) {
+ ERROR(errp, "posting second control recv");
+ goto err_rdma_source_connect;
+ }
+
ret = rdma_connect(rdma->cm_id, &conn_param);
if (ret) {
perror("rdma_connect");
@@ -2405,12 +2474,6 @@ static int qemu_rdma_connect(RDMAContext *rdma, Error **errp)
rdma_ack_cm_event(cm_event);
- ret = qemu_rdma_post_recv_control(rdma, RDMA_WRID_READY);
- if (ret) {
- ERROR(errp, "posting second control recv!");
- goto err_rdma_source_connect;
- }
-
rdma->control_ready_expected = 1;
rdma->nb_sent = 0;
return 0;
@@ -3350,7 +3413,7 @@ static int qemu_rdma_registration_handle(QEMUFile *f, void *opaque)
ret = -EIO;
goto out;
default:
- error_report("Unknown control message %s", control_desc[head.type]);
+ error_report("Unknown control message %s", control_desc(head.type));
ret = -EIO;
goto out;
}
diff --git a/qapi/block-core.json b/qapi/block-core.json
index c437aa50ef..ff8e2ba0cb 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -457,6 +457,9 @@
#
# @device: The device name associated with the virtual device.
#
+# @qdev: The qdev ID, or if no ID is assigned, the QOM path of the block
+# device. (since 2.10)
+#
# @type: This field is returned only for compatibility reasons, it should
# not be used (always returns 'unknown')
#
@@ -482,7 +485,7 @@
# Since: 0.14.0
##
{ 'struct': 'BlockInfo',
- 'data': {'device': 'str', 'type': 'str', 'removable': 'bool',
+ 'data': {'device': 'str', '*qdev': 'str', 'type': 'str', 'removable': 'bool',
'locked': 'bool', '*inserted': 'BlockDeviceInfo',
'*tray_open': 'bool', '*io-status': 'BlockDeviceIoStatus',
'*dirty-bitmaps': ['BlockDirtyInfo'] } }
@@ -577,6 +580,7 @@
# }
# }
# },
+# "qdev": "ide_disk",
# "type":"unknown"
# },
# {
@@ -584,12 +588,15 @@
# "device":"ide1-cd0",
# "locked":false,
# "removable":true,
+# "qdev": "/machine/unattached/device[23]",
+# "tray_open": false,
# "type":"unknown"
# },
# {
# "device":"floppy0",
# "locked":false,
# "removable":true,
+# "qdev": "/machine/unattached/device[20]",
# "type":"unknown"
# },
# {
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index ac5946bc4f..3763f13625 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -22,9 +22,9 @@ STEXI
ETEXI
DEF("create", img_create,
- "create [-q] [--object objectdef] [-f fmt] [-b backing_file] [-F backing_fmt] [-o options] filename [size]")
+ "create [-q] [--object objectdef] [-f fmt] [-b backing_file] [-F backing_fmt] [-u] [-o options] filename [size]")
STEXI
-@item create [--object @var{objectdef}] [-q] [-f @var{fmt}] [-b @var{backing_file}] [-F @var{backing_fmt}] [-o @var{options}] @var{filename} [@var{size}]
+@item create [--object @var{objectdef}] [-q] [-f @var{fmt}] [-b @var{backing_file}] [-F @var{backing_fmt}] [-u] [-o @var{options}] @var{filename} [@var{size}]
ETEXI
DEF("commit", img_commit,
diff --git a/qemu-img.c b/qemu-img.c
index 182e697f81..eb32b93e90 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -150,9 +150,11 @@ static void QEMU_NORETURN help(void)
" 'snapshot_id_or_name' is deprecated, use 'snapshot_param'\n"
" instead\n"
" '-c' indicates that target image must be compressed (qcow format only)\n"
- " '-u' enables unsafe rebasing. It is assumed that old and new backing file\n"
- " match exactly. The image doesn't need a working backing file before\n"
- " rebasing in this case (useful for renaming the backing file)\n"
+ " '-u' allows unsafe backing chains. For rebasing, it is assumed that old and\n"
+ " new backing file match exactly. The image doesn't need a working\n"
+ " backing file before rebasing in this case (useful for renaming the\n"
+ " backing file). For image creation, allow creating without attempting\n"
+ " to open the backing file.\n"
" '-h' with or without a command shows this help and lists the supported formats\n"
" '-p' show progress of command (only certain commands)\n"
" '-q' use Quiet mode - do not print any output (except errors)\n"
@@ -429,6 +431,7 @@ static int img_create(int argc, char **argv)
char *options = NULL;
Error *local_err = NULL;
bool quiet = false;
+ int flags = 0;
for(;;) {
static const struct option long_options[] = {
@@ -436,7 +439,7 @@ static int img_create(int argc, char **argv)
{"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":F:b:f:ho:q",
+ c = getopt_long(argc, argv, ":F:b:f:ho:qu",
long_options, NULL);
if (c == -1) {
break;
@@ -476,6 +479,9 @@ static int img_create(int argc, char **argv)
case 'q':
quiet = true;
break;
+ case 'u':
+ flags |= BDRV_O_NO_BACKING;
+ break;
case OPTION_OBJECT: {
QemuOpts *opts;
opts = qemu_opts_parse_noisily(&qemu_object_opts,
@@ -528,7 +534,7 @@ static int img_create(int argc, char **argv)
}
bdrv_img_create(filename, fmt, base_filename, base_fmt,
- options, img_size, 0, quiet, &local_err);
+ options, img_size, flags, quiet, &local_err);
if (local_err) {
error_reportf_err(local_err, "%s: ", filename);
goto fail;
diff --git a/qemu-img.texi b/qemu-img.texi
index f11f6036ad..72dabd6b3e 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -233,7 +233,7 @@ If @code{-r} is specified, exit codes representing the image state refer to the
state after (the attempt at) repairing it. That is, a successful @code{-r all}
will yield the exit code 0, independently of the image state before.
-@item create [-f @var{fmt}] [-b @var{backing_file}] [-F @var{backing_fmt}] [-o @var{options}] @var{filename} [@var{size}]
+@item create [-f @var{fmt}] [-b @var{backing_file}] [-F @var{backing_fmt}] [-u] [-o @var{options}] @var{filename} [@var{size}]
Create the new disk image @var{filename} of size @var{size} and format
@var{fmt}. Depending on the file format, you can add one or more @var{options}
@@ -244,6 +244,13 @@ only the differences from @var{backing_file}. No size needs to be specified in
this case. @var{backing_file} will never be modified unless you use the
@code{commit} monitor command (or qemu-img commit).
+Note that a given backing file will be opened to check that it is valid. Use
+the @code{-u} option to enable unsafe backing file mode, which means that the
+image will be created even if the associated backing file cannot be opened. A
+matching backing file must be created or additional options be used to make the
+backing file specification valid when you want to use an image created this
+way.
+
The size can also be specified using the @var{size} option with @code{-o},
it doesn't need to be specified separately in this case.
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index ef17629345..999121bb7c 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -1132,9 +1132,9 @@ static void test_migrate_sanity(void)
AHCIQState *src, *dst;
char *uri = g_strdup_printf("unix:%s", mig_socket);
- src = ahci_boot("-m 1024 -M q35 "
+ src = ahci_boot("-m 384 -M q35 "
"-drive if=ide,file=%s,format=%s ", tmp_path, imgfmt);
- dst = ahci_boot("-m 1024 -M q35 "
+ dst = ahci_boot("-m 384 -M q35 "
"-drive if=ide,file=%s,format=%s "
"-incoming %s", tmp_path, imgfmt, uri);
@@ -1157,10 +1157,10 @@ static void ahci_migrate_simple(uint8_t cmd_read, uint8_t cmd_write)
unsigned char *rx = g_malloc0(bufsize);
char *uri = g_strdup_printf("unix:%s", mig_socket);
- src = ahci_boot_and_enable("-m 1024 -M q35 "
+ src = ahci_boot_and_enable("-m 384 -M q35 "
"-drive if=ide,format=%s,file=%s ",
imgfmt, tmp_path);
- dst = ahci_boot("-m 1024 -M q35 "
+ dst = ahci_boot("-m 384 -M q35 "
"-drive if=ide,format=%s,file=%s "
"-incoming %s", imgfmt, tmp_path, uri);
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067
index 38d23fce6b..5d4ca4bc61 100755
--- a/tests/qemu-iotests/067
+++ b/tests/qemu-iotests/067
@@ -137,6 +137,19 @@ run_qemu <<EOF
{ "execute": "quit" }
EOF
+echo
+echo === Empty drive with -device and device_del ===
+echo
+
+run_qemu -device virtio-scsi-pci -device scsi-cd,id=cd0 <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "query-block" }
+{ "execute": "device_del", "arguments": { "id": "cd0" } }
+{ "execute": "system_reset" }
+{ "execute": "query-block" }
+{ "execute": "quit" }
+EOF
+
# success, all done
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out
index 782eae27a0..bd70557ddc 100644
--- a/tests/qemu-iotests/067.out
+++ b/tests/qemu-iotests/067.out
@@ -57,6 +57,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
"file": "TEST_DIR/t.qcow2",
"encryption_key_missing": false
},
+ "qdev": "/machine/peripheral/virtio0/virtio-backend",
"type": "unknown"
}
]
@@ -415,4 +416,43 @@ Testing:
"return": {
}
}
+
+=== Empty drive with -device and device_del ===
+
+Testing: -device virtio-scsi-pci -device scsi-cd,id=cd0
+{
+ QMP_VERSION
+}
+{
+ "return": {
+ }
+}
+{
+ "return": [
+ {
+ "device": "",
+ "locked": false,
+ "removable": true,
+ "qdev": "cd0",
+ "tray_open": false,
+ "type": "unknown"
+ }
+ ]
+}
+{
+ "return": {
+ }
+}
+{
+ "return": {
+ }
+}
+{
+ "return": [
+ ]
+}
+{
+ "return": {
+ }
+}
*** done
diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082
index ad1d9fadc1..d5c83d45ed 100755
--- a/tests/qemu-iotests/082
+++ b/tests/qemu-iotests/082
@@ -85,8 +85,8 @@ run_qemu_img create -f $IMGFMT -o cluster_size=4k -o help "$TEST_IMG" $size
run_qemu_img create -f $IMGFMT -o cluster_size=4k -o \? "$TEST_IMG" $size
# Looks like a help option, but is part of the backing file name
-run_qemu_img create -f $IMGFMT -o backing_file="$TEST_IMG",,help "$TEST_IMG" $size
-run_qemu_img create -f $IMGFMT -o backing_file="$TEST_IMG",,\? "$TEST_IMG" $size
+run_qemu_img create -f $IMGFMT -u -o backing_file="$TEST_IMG",,help "$TEST_IMG" $size
+run_qemu_img create -f $IMGFMT -u -o backing_file="$TEST_IMG",,\? "$TEST_IMG" $size
# Try to trick qemu-img into creating escaped commas
run_qemu_img create -f $IMGFMT -o backing_file="$TEST_IMG", -o help "$TEST_IMG" $size
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
index dbed67f2ba..1527fbe1b7 100644
--- a/tests/qemu-iotests/082.out
+++ b/tests/qemu-iotests/082.out
@@ -210,10 +210,10 @@ lazy_refcounts Postpone refcount updates
refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
-Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M
+Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 128M
+Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 128M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,? cluster_size=65536 lazy_refcounts=off refcount_bits=16
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2, -o help TEST_DIR/t.qcow2 128M
diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085
index b97adcd8db..71efe50d34 100755
--- a/tests/qemu-iotests/085
+++ b/tests/qemu-iotests/085
@@ -104,7 +104,7 @@ function add_snapshot_image()
{
base_image="${TEST_DIR}/$((${1}-1))-${snapshot_virt0}"
snapshot_file="${TEST_DIR}/${1}-${snapshot_virt0}"
- _make_test_img -b "${base_image}" "$size"
+ _make_test_img -u -b "${base_image}" "$size"
mv "${TEST_IMG}" "${snapshot_file}"
do_blockdev_add "$1" "'backing': '', " "${snapshot_file}"
}
diff --git a/tests/qemu-iotests/111.out b/tests/qemu-iotests/111.out
index 683c01a679..5279c462fc 100644
--- a/tests/qemu-iotests/111.out
+++ b/tests/qemu-iotests/111.out
@@ -1,3 +1,4 @@
QA output created by 111
qemu-img: TEST_DIR/t.IMGFMT: Could not open 'TEST_DIR/t.IMGFMT.inexistent': No such file or directory
+Could not open backing image to determine size.
*** done
diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139
index 175d8f0008..9ff51d9647 100644
--- a/tests/qemu-iotests/139
+++ b/tests/qemu-iotests/139
@@ -65,7 +65,7 @@ class TestBlockdevDel(iotests.QMPTestCase):
# Add a BlockDriverState that will be used as overlay for the base_img BDS
def addBlockDriverStateOverlay(self, node):
self.checkBlockDriverState(node, False)
- iotests.qemu_img('create', '-f', iotests.imgfmt,
+ iotests.qemu_img('create', '-u', '-f', iotests.imgfmt,
'-b', base_img, new_img, '1M')
opts = {'driver': iotests.imgfmt,
'node-name': node,
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
index d799b73e1e..2c4a06e2d8 100755
--- a/tests/qemu-iotests/156
+++ b/tests/qemu-iotests/156
@@ -66,7 +66,7 @@ _send_qemu_cmd $QEMU_HANDLE \
'return'
# Create snapshot
-TEST_IMG="$TEST_IMG.overlay" _make_test_img -b "$TEST_IMG" 1M
+TEST_IMG="$TEST_IMG.overlay" _make_test_img -u -b "$TEST_IMG" 1M
_send_qemu_cmd $QEMU_HANDLE \
"{ 'execute': 'blockdev-snapshot-sync',
'arguments': { 'device': 'source',
diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158
index 823c12002e..24ac600a4a 100755
--- a/tests/qemu-iotests/158
+++ b/tests/qemu-iotests/158
@@ -66,7 +66,7 @@ echo "== verify pattern =="
$QEMU_IO --object $SECRET -c "read -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir
echo "== create overlay =="
-_make_test_img --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" -b "$TEST_IMG_BASE" $size
+_make_test_img -u --object $SECRET -o "encryption=on,encrypt.key-secret=sec0" -b "$TEST_IMG_BASE" $size
echo
echo "== writing part of a cluster =="
diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186
new file mode 100755
index 0000000000..ab83ee402a
--- /dev/null
+++ b/tests/qemu-iotests/186
@@ -0,0 +1,147 @@
+#!/bin/bash
+#
+# Test 'info block' with all kinds of configurations
+#
+# Copyright (C) 2017 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=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then
+ _notrun "Requires a PC machine"
+fi
+
+function do_run_qemu()
+{
+ echo Testing: "$@"
+
+ (
+ if ! test -t 0; then
+ while read cmd; do
+ echo $cmd
+ done
+ fi
+ echo quit
+ ) | $QEMU -S -nodefaults -display none -device virtio-scsi-pci -monitor stdio "$@"
+ echo
+}
+
+function check_info_block()
+{
+ echo "info block" |
+ QEMU_OPTIONS="" do_run_qemu "$@" | _filter_win32 | _filter_hmp |
+ _filter_qemu | _filter_generated_node_ids
+}
+
+
+size=64M
+_make_test_img $size
+
+removable="floppy ide-cd scsi-cd"
+fixed="ide-hd scsi-hd virtio-blk-pci"
+
+echo
+echo "=== Empty drives ==="
+echo
+
+for dev in $removable; do
+ check_info_block -device $dev
+ check_info_block -device $dev,id=qdev_id
+done
+
+echo
+echo "=== -blockdev/-device=<node-name> ==="
+echo
+
+for dev in $fixed $removable; do
+ check_info_block -blockdev driver=null-co,node-name=null -device $dev,drive=null
+ check_info_block -blockdev driver=null-co,node-name=null -device $dev,drive=null,id=qdev_id
+done
+
+echo
+echo "=== -drive if=none/-device=<node-name> ==="
+echo
+
+# This creates two BlockBackends that will show up in 'info block'!
+# A monitor-owned one from -drive, and anonymous one from -device
+for dev in $fixed $removable; do
+ check_info_block -drive if=none,driver=null-co,node-name=null -device $dev,drive=null,id=qdev_id
+done
+
+echo
+echo "=== -drive if=none/-device=<bb-name> (with medium) ==="
+echo
+
+for dev in $fixed $removable; do
+ check_info_block -drive if=none,driver=null-co,node-name=null -device $dev,drive=none0
+ check_info_block -drive if=none,driver=null-co,node-name=null -device $dev,drive=none0,id=qdev_id
+done
+
+echo
+echo "=== -drive if=none/-device=<bb-name> (without medium) ==="
+echo
+
+check_info_block -drive if=none
+
+for dev in $removable; do
+ check_info_block -drive if=none -device $dev,drive=none0
+ check_info_block -drive if=none -device $dev,drive=none0,id=qdev_id
+done
+
+echo
+echo "=== -drive if=... ==="
+echo
+
+check_info_block -drive if=floppy
+check_info_block -drive if=floppy,driver=null-co
+
+check_info_block -drive if=ide,driver=null-co
+check_info_block -drive if=ide,media=cdrom
+check_info_block -drive if=ide,driver=null-co,media=cdrom
+
+check_info_block -drive if=scsi,driver=null-co
+check_info_block -drive if=scsi,media=cdrom
+check_info_block -drive if=scsi,driver=null-co,media=cdrom
+
+check_info_block -drive if=virtio,driver=null-co
+
+check_info_block -drive if=pflash,driver=null-co,size=1M
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/186.out b/tests/qemu-iotests/186.out
new file mode 100644
index 0000000000..b963b12d64
--- /dev/null
+++ b/tests/qemu-iotests/186.out
@@ -0,0 +1,489 @@
+QA output created by 186
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+
+=== Empty drives ===
+
+Testing: -device floppy
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+/machine/peripheral-anon/device[1]: [not inserted]
+ Attached to: /machine/peripheral-anon/device[1]
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -device floppy,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+qdev_id: [not inserted]
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -device ide-cd
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+/machine/peripheral-anon/device[1]: [not inserted]
+ Attached to: /machine/peripheral-anon/device[1]
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -device ide-cd,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+qdev_id: [not inserted]
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -device scsi-cd
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+/machine/peripheral-anon/device[1]: [not inserted]
+ Attached to: /machine/peripheral-anon/device[1]
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -device scsi-cd,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+qdev_id: [not inserted]
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+(qemu) quit
+
+
+=== -blockdev/-device=<node-name> ===
+
+Testing: -blockdev driver=null-co,node-name=null -device ide-hd,drive=null
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+null: null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -blockdev driver=null-co,node-name=null -device ide-hd,drive=null,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+null: null-co:// (null-co)
+ Attached to: qdev_id
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -blockdev driver=null-co,node-name=null -device scsi-hd,drive=null
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+null: null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -blockdev driver=null-co,node-name=null -device scsi-hd,drive=null,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+null: null-co:// (null-co)
+ Attached to: qdev_id
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -blockdev driver=null-co,node-name=null -device virtio-blk-pci,drive=null
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+null: null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]/virtio-backend
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -blockdev driver=null-co,node-name=null -device virtio-blk-pci,drive=null,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+null: null-co:// (null-co)
+ Attached to: /machine/peripheral/qdev_id/virtio-backend
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -blockdev driver=null-co,node-name=null -device floppy,drive=null
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+null: null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -blockdev driver=null-co,node-name=null -device floppy,drive=null,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+null: null-co:// (null-co)
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -blockdev driver=null-co,node-name=null -device ide-cd,drive=null
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+null: null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -blockdev driver=null-co,node-name=null -device ide-cd,drive=null,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+null: null-co:// (null-co)
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -blockdev driver=null-co,node-name=null -device scsi-cd,drive=null
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+null: null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -blockdev driver=null-co,node-name=null -device scsi-cd,drive=null,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+null: null-co:// (null-co)
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+
+=== -drive if=none/-device=<node-name> ===
+
+Testing: -drive if=none,driver=null-co,node-name=null -device ide-hd,drive=null,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+
+null: null-co:// (null-co)
+ Attached to: qdev_id
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device scsi-hd,drive=null,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+
+null: null-co:// (null-co)
+ Attached to: qdev_id
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device virtio-blk-pci,drive=null,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+
+null: null-co:// (null-co)
+ Attached to: /machine/peripheral/qdev_id/virtio-backend
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device floppy,drive=null,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+
+null: null-co:// (null-co)
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device ide-cd,drive=null,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+
+null: null-co:// (null-co)
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device scsi-cd,drive=null,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+
+null: null-co:// (null-co)
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+
+=== -drive if=none/-device=<bb-name> (with medium) ===
+
+Testing: -drive if=none,driver=null-co,node-name=null -device ide-hd,drive=none0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device ide-hd,drive=none0,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Attached to: qdev_id
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device scsi-hd,drive=none0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device scsi-hd,drive=none0,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Attached to: qdev_id
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device virtio-blk-pci,drive=none0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]/virtio-backend
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device virtio-blk-pci,drive=none0,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Attached to: /machine/peripheral/qdev_id/virtio-backend
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device floppy,drive=none0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device floppy,drive=none0,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device ide-cd,drive=none0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device ide-cd,drive=none0,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device scsi-cd,drive=none0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=none,driver=null-co,node-name=null -device scsi-cd,drive=none0,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0 (null): null-co:// (null-co)
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+
+=== -drive if=none/-device=<bb-name> (without medium) ===
+
+Testing: -drive if=none
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0: [not inserted]
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -drive if=none -device floppy,drive=none0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0: [not inserted]
+ Attached to: /machine/peripheral-anon/device[1]
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -drive if=none -device floppy,drive=none0,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0: [not inserted]
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -drive if=none -device ide-cd,drive=none0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0: [not inserted]
+ Attached to: /machine/peripheral-anon/device[1]
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -drive if=none -device ide-cd,drive=none0,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0: [not inserted]
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -drive if=none -device scsi-cd,drive=none0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0: [not inserted]
+ Attached to: /machine/peripheral-anon/device[1]
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -drive if=none -device scsi-cd,drive=none0,id=qdev_id
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+none0: [not inserted]
+ Attached to: qdev_id
+ Removable device: not locked, tray closed
+(qemu) quit
+
+
+=== -drive if=... ===
+
+Testing: -drive if=floppy
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+floppy0: [not inserted]
+ Attached to: /machine/unattached/device[17]
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -drive if=floppy,driver=null-co
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+floppy0 (NODE_NAME): null-co:// (null-co)
+ Attached to: /machine/unattached/device[17]
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=ide,driver=null-co
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+ide0-hd0 (NODE_NAME): null-co:// (null-co)
+ Attached to: /machine/unattached/device[18]
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=ide,media=cdrom
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+ide0-cd0: [not inserted]
+ Attached to: /machine/unattached/device[18]
+ Removable device: not locked, tray closed
+(qemu) quit
+
+Testing: -drive if=ide,driver=null-co,media=cdrom
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+ide0-cd0 (NODE_NAME): null-co:// (null-co, read-only)
+ Attached to: /machine/unattached/device[18]
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+warning: qemu-system-x86_64: -drive if=scsi,driver=null-co: bus=0,unit=0 is deprecated with this machine type
+Testing: -drive if=scsi,driver=null-co
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+scsi0-hd0 (NODE_NAME): null-co:// (null-co)
+ Attached to: /machine/unattached/device[27]/scsi.0/legacy[0]
+ Cache mode: writeback
+(qemu) quit
+
+warning: qemu-system-x86_64: -drive if=scsi,media=cdrom: bus=0,unit=0 is deprecated with this machine type
+Testing: -drive if=scsi,media=cdrom
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+scsi0-cd0: [not inserted]
+ Attached to: /machine/unattached/device[27]/scsi.0/legacy[0]
+ Removable device: not locked, tray closed
+(qemu) quit
+
+warning: qemu-system-x86_64: -drive if=scsi,driver=null-co,media=cdrom: bus=0,unit=0 is deprecated with this machine type
+Testing: -drive if=scsi,driver=null-co,media=cdrom
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+scsi0-cd0 (NODE_NAME): null-co:// (null-co, read-only)
+ Attached to: /machine/unattached/device[27]/scsi.0/legacy[0]
+ Removable device: not locked, tray closed
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=virtio,driver=null-co
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+virtio0 (NODE_NAME): null-co:// (null-co)
+ Attached to: /machine/peripheral-anon/device[1]/virtio-backend
+ Cache mode: writeback
+(qemu) quit
+
+Testing: -drive if=pflash,driver=null-co,size=1M
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) info block
+pflash0 (NODE_NAME): json:{"driver": "null-co", "size": "1M"} (null-co)
+ Attached to: /machine/unattached/device[2]
+ Cache mode: writeback
+(qemu) quit
+
+*** done
diff --git a/tests/qemu-iotests/189 b/tests/qemu-iotests/189
index 54ad980a4e..e695475722 100755
--- a/tests/qemu-iotests/189
+++ b/tests/qemu-iotests/189
@@ -66,7 +66,7 @@ echo "== verify pattern =="
$QEMU_IO --object $SECRET0 -c "read -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir
echo "== create overlay =="
-_make_test_img --object $SECRET1 -o "encrypt.format=luks,encrypt.key-secret=sec1,encrypt.iter-time=10" -b "$TEST_IMG_BASE" $size
+_make_test_img --object $SECRET1 -o "encrypt.format=luks,encrypt.key-secret=sec1,encrypt.iter-time=10" -u -b "$TEST_IMG_BASE" $size
echo
echo "== writing part of a cluster =="
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 2aba585287..0961f8cc4e 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -181,5 +181,6 @@
182 rw auto quick
183 rw auto migration
185 rw auto
+186 rw auto
188 rw auto quick
189 rw auto quick
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
index a9201b1fea..768f11dfed 100644
--- a/tests/test-throttle.c
+++ b/tests/test-throttle.c
@@ -228,7 +228,7 @@ static void test_config_functions(void)
read_timer_cb, write_timer_cb, &ts);
/* structure reset by throttle_init previous_leak should be null */
g_assert(!ts.previous_leak);
- throttle_config(&ts, &tt, &orig_cfg);
+ throttle_config(&ts, QEMU_CLOCK_VIRTUAL, &orig_cfg);
/* has previous leak been initialized by throttle_config ? */
g_assert(ts.previous_leak);
@@ -486,7 +486,7 @@ static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
throttle_init(&ts);
throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
read_timer_cb, write_timer_cb, &ts);
- throttle_config(&ts, &tt, &cfg);
+ throttle_config(&ts, QEMU_CLOCK_VIRTUAL, &cfg);
/* account a read */
throttle_account(&ts, false, size);
diff --git a/util/throttle.c b/util/throttle.c
index 3570ed25fc..b2a52b8b34 100644
--- a/util/throttle.c
+++ b/util/throttle.c
@@ -388,22 +388,14 @@ static void throttle_unfix_bucket(LeakyBucket *bkt)
}
}
-/* take care of canceling a timer */
-static void throttle_cancel_timer(QEMUTimer *timer)
-{
- assert(timer != NULL);
-
- timer_del(timer);
-}
-
/* Used to configure the throttle
*
* @ts: the throttle state we are working on
- * @tt: the throttle timers we use in this aio context
+ * @clock_type: the group's clock_type
* @cfg: the config to set
*/
void throttle_config(ThrottleState *ts,
- ThrottleTimers *tt,
+ QEMUClockType clock_type,
ThrottleConfig *cfg)
{
int i;
@@ -414,11 +406,7 @@ void throttle_config(ThrottleState *ts,
throttle_fix_bucket(&ts->cfg.buckets[i]);
}
- ts->previous_leak = qemu_clock_get_ns(tt->clock_type);
-
- for (i = 0; i < 2; i++) {
- throttle_cancel_timer(tt->timers[i]);
- }
+ ts->previous_leak = qemu_clock_get_ns(clock_type);
}
/* used to get config