mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches: - block: Fix forbidden use of polling in drained_end - block: Don't wait for I/O throttling while exiting QEMU - iotests: Use read-zeroes for the null driver to be Valgrind-friendly # gpg: Signature made Fri 19 Jul 2019 14:30:14 BST # gpg: using RSA key 7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full] # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: iotests: Test quitting with job on throttled node vl: Drain before (block) job cancel when quitting iotests: Test commit with a filter on the chain iotests: Add @has_quit to vm.shutdown() block: Loop unsafely in bdrv*drained_end() tests: Extend commit by drained_end test block: Do not poll in bdrv_do_drained_end() tests: Lock AioContexts in test-block-iothread block: Make bdrv_parent_drained_[^_]*() static block: Add @drained_end_counter tests: Add job commit by drained_end test block: Introduce BdrvChild.parent_quiesce_counter iotests: Set read-zeroes on in null block driver for Valgrind Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -911,10 +911,11 @@ static bool bdrv_child_cb_drained_poll(BdrvChild *child)
|
||||
return bdrv_drain_poll(bs, false, NULL, false);
|
||||
}
|
||||
|
||||
static void bdrv_child_cb_drained_end(BdrvChild *child)
|
||||
static void bdrv_child_cb_drained_end(BdrvChild *child,
|
||||
int *drained_end_counter)
|
||||
{
|
||||
BlockDriverState *bs = child->opaque;
|
||||
bdrv_drained_end(bs);
|
||||
bdrv_drained_end_no_poll(bs, drained_end_counter);
|
||||
}
|
||||
|
||||
static void bdrv_child_cb_attach(BdrvChild *child)
|
||||
@@ -2251,24 +2252,19 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
|
||||
if (child->role->detach) {
|
||||
child->role->detach(child);
|
||||
}
|
||||
if (old_bs->quiesce_counter && child->role->drained_end) {
|
||||
int num = old_bs->quiesce_counter;
|
||||
if (child->role->parent_is_bds) {
|
||||
num -= bdrv_drain_all_count;
|
||||
}
|
||||
assert(num >= 0);
|
||||
for (i = 0; i < num; i++) {
|
||||
child->role->drained_end(child);
|
||||
}
|
||||
while (child->parent_quiesce_counter) {
|
||||
bdrv_parent_drained_end_single(child);
|
||||
}
|
||||
QLIST_REMOVE(child, next_parent);
|
||||
} else {
|
||||
assert(child->parent_quiesce_counter == 0);
|
||||
}
|
||||
|
||||
child->bs = new_bs;
|
||||
|
||||
if (new_bs) {
|
||||
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
|
||||
if (new_bs->quiesce_counter && child->role->drained_begin) {
|
||||
if (new_bs->quiesce_counter) {
|
||||
int num = new_bs->quiesce_counter;
|
||||
if (child->role->parent_is_bds) {
|
||||
num -= bdrv_drain_all_count;
|
||||
@@ -5928,9 +5924,11 @@ static void bdrv_attach_aio_context(BlockDriverState *bs,
|
||||
void bdrv_set_aio_context_ignore(BlockDriverState *bs,
|
||||
AioContext *new_context, GSList **ignore)
|
||||
{
|
||||
AioContext *old_context = bdrv_get_aio_context(bs);
|
||||
AioContext *current_context = qemu_get_current_aio_context();
|
||||
BdrvChild *child;
|
||||
|
||||
if (bdrv_get_aio_context(bs) == new_context) {
|
||||
if (old_context == new_context) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5954,13 +5952,31 @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs,
|
||||
|
||||
bdrv_detach_aio_context(bs);
|
||||
|
||||
/* This function executes in the old AioContext so acquire the new one in
|
||||
* case it runs in a different thread.
|
||||
*/
|
||||
aio_context_acquire(new_context);
|
||||
/* Acquire the new context, if necessary */
|
||||
if (current_context != new_context) {
|
||||
aio_context_acquire(new_context);
|
||||
}
|
||||
|
||||
bdrv_attach_aio_context(bs, new_context);
|
||||
|
||||
/*
|
||||
* If this function was recursively called from
|
||||
* bdrv_set_aio_context_ignore(), there may be nodes in the
|
||||
* subtree that have not yet been moved to the new AioContext.
|
||||
* Release the old one so bdrv_drained_end() can poll them.
|
||||
*/
|
||||
if (current_context != old_context) {
|
||||
aio_context_release(old_context);
|
||||
}
|
||||
|
||||
bdrv_drained_end(bs);
|
||||
aio_context_release(new_context);
|
||||
|
||||
if (current_context != old_context) {
|
||||
aio_context_acquire(old_context);
|
||||
}
|
||||
if (current_context != new_context) {
|
||||
aio_context_release(new_context);
|
||||
}
|
||||
}
|
||||
|
||||
static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx,
|
||||
|
||||
@@ -121,7 +121,7 @@ static void blk_root_inherit_options(int *child_flags, QDict *child_options,
|
||||
}
|
||||
static void blk_root_drained_begin(BdrvChild *child);
|
||||
static bool blk_root_drained_poll(BdrvChild *child);
|
||||
static void blk_root_drained_end(BdrvChild *child);
|
||||
static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter);
|
||||
|
||||
static void blk_root_change_media(BdrvChild *child, bool load);
|
||||
static void blk_root_resize(BdrvChild *child);
|
||||
@@ -1249,7 +1249,7 @@ int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf,
|
||||
|
||||
blk_root_drained_begin(blk->root);
|
||||
ret = blk_pread(blk, offset, buf, count);
|
||||
blk_root_drained_end(blk->root);
|
||||
blk_root_drained_end(blk->root, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2236,7 +2236,7 @@ static bool blk_root_drained_poll(BdrvChild *child)
|
||||
return !!blk->in_flight;
|
||||
}
|
||||
|
||||
static void blk_root_drained_end(BdrvChild *child)
|
||||
static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter)
|
||||
{
|
||||
BlockBackend *blk = child->opaque;
|
||||
assert(blk->quiesce_counter);
|
||||
|
||||
+99
-35
@@ -42,8 +42,8 @@ static void bdrv_parent_cb_resize(BlockDriverState *bs);
|
||||
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int bytes, BdrvRequestFlags flags);
|
||||
|
||||
void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
|
||||
bool ignore_bds_parents)
|
||||
static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
|
||||
bool ignore_bds_parents)
|
||||
{
|
||||
BdrvChild *c, *next;
|
||||
|
||||
@@ -55,18 +55,34 @@ void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
|
||||
bool ignore_bds_parents)
|
||||
static void bdrv_parent_drained_end_single_no_poll(BdrvChild *c,
|
||||
int *drained_end_counter)
|
||||
{
|
||||
BdrvChild *c, *next;
|
||||
assert(c->parent_quiesce_counter > 0);
|
||||
c->parent_quiesce_counter--;
|
||||
if (c->role->drained_end) {
|
||||
c->role->drained_end(c, drained_end_counter);
|
||||
}
|
||||
}
|
||||
|
||||
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
|
||||
void bdrv_parent_drained_end_single(BdrvChild *c)
|
||||
{
|
||||
int drained_end_counter = 0;
|
||||
bdrv_parent_drained_end_single_no_poll(c, &drained_end_counter);
|
||||
BDRV_POLL_WHILE(c->bs, atomic_read(&drained_end_counter) > 0);
|
||||
}
|
||||
|
||||
static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
|
||||
bool ignore_bds_parents,
|
||||
int *drained_end_counter)
|
||||
{
|
||||
BdrvChild *c;
|
||||
|
||||
QLIST_FOREACH(c, &bs->parents, next_parent) {
|
||||
if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) {
|
||||
continue;
|
||||
}
|
||||
if (c->role->drained_end) {
|
||||
c->role->drained_end(c);
|
||||
}
|
||||
bdrv_parent_drained_end_single_no_poll(c, drained_end_counter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +112,7 @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
|
||||
|
||||
void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll)
|
||||
{
|
||||
c->parent_quiesce_counter++;
|
||||
if (c->role->drained_begin) {
|
||||
c->role->drained_begin(c);
|
||||
}
|
||||
@@ -186,6 +203,7 @@ typedef struct {
|
||||
bool poll;
|
||||
BdrvChild *parent;
|
||||
bool ignore_bds_parents;
|
||||
int *drained_end_counter;
|
||||
} BdrvCoDrainData;
|
||||
|
||||
static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
|
||||
@@ -203,13 +221,16 @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
|
||||
atomic_mb_set(&data->done, true);
|
||||
bdrv_dec_in_flight(bs);
|
||||
|
||||
if (data->begin) {
|
||||
g_free(data);
|
||||
if (!data->begin) {
|
||||
atomic_dec(data->drained_end_counter);
|
||||
}
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
|
||||
static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
|
||||
static void bdrv_drain_invoke(BlockDriverState *bs, bool begin,
|
||||
int *drained_end_counter)
|
||||
{
|
||||
BdrvCoDrainData *data;
|
||||
|
||||
@@ -222,19 +243,19 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
|
||||
*data = (BdrvCoDrainData) {
|
||||
.bs = bs,
|
||||
.done = false,
|
||||
.begin = begin
|
||||
.begin = begin,
|
||||
.drained_end_counter = drained_end_counter,
|
||||
};
|
||||
|
||||
if (!begin) {
|
||||
atomic_inc(drained_end_counter);
|
||||
}
|
||||
|
||||
/* Make sure the driver callback completes during the polling phase for
|
||||
* drain_begin. */
|
||||
bdrv_inc_in_flight(bs);
|
||||
data->co = qemu_coroutine_create(bdrv_drain_invoke_entry, data);
|
||||
aio_co_schedule(bdrv_get_aio_context(bs), data->co);
|
||||
|
||||
if (!begin) {
|
||||
BDRV_POLL_WHILE(bs, !data->done);
|
||||
g_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */
|
||||
@@ -273,7 +294,8 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
|
||||
BdrvChild *parent, bool ignore_bds_parents,
|
||||
bool poll);
|
||||
static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
|
||||
BdrvChild *parent, bool ignore_bds_parents);
|
||||
BdrvChild *parent, bool ignore_bds_parents,
|
||||
int *drained_end_counter);
|
||||
|
||||
static void bdrv_co_drain_bh_cb(void *opaque)
|
||||
{
|
||||
@@ -296,11 +318,14 @@ static void bdrv_co_drain_bh_cb(void *opaque)
|
||||
}
|
||||
bdrv_dec_in_flight(bs);
|
||||
if (data->begin) {
|
||||
assert(!data->drained_end_counter);
|
||||
bdrv_do_drained_begin(bs, data->recursive, data->parent,
|
||||
data->ignore_bds_parents, data->poll);
|
||||
} else {
|
||||
assert(!data->poll);
|
||||
bdrv_do_drained_end(bs, data->recursive, data->parent,
|
||||
data->ignore_bds_parents);
|
||||
data->ignore_bds_parents,
|
||||
data->drained_end_counter);
|
||||
}
|
||||
if (ctx == co_ctx) {
|
||||
aio_context_release(ctx);
|
||||
@@ -318,7 +343,8 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
|
||||
bool begin, bool recursive,
|
||||
BdrvChild *parent,
|
||||
bool ignore_bds_parents,
|
||||
bool poll)
|
||||
bool poll,
|
||||
int *drained_end_counter)
|
||||
{
|
||||
BdrvCoDrainData data;
|
||||
|
||||
@@ -335,7 +361,9 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
|
||||
.parent = parent,
|
||||
.ignore_bds_parents = ignore_bds_parents,
|
||||
.poll = poll,
|
||||
.drained_end_counter = drained_end_counter,
|
||||
};
|
||||
|
||||
if (bs) {
|
||||
bdrv_inc_in_flight(bs);
|
||||
}
|
||||
@@ -359,7 +387,7 @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
bdrv_parent_drained_begin(bs, parent, ignore_bds_parents);
|
||||
bdrv_drain_invoke(bs, true);
|
||||
bdrv_drain_invoke(bs, true, NULL);
|
||||
}
|
||||
|
||||
static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
|
||||
@@ -370,7 +398,7 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
|
||||
|
||||
if (qemu_in_coroutine()) {
|
||||
bdrv_co_yield_to_drain(bs, true, recursive, parent, ignore_bds_parents,
|
||||
poll);
|
||||
poll, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -410,22 +438,40 @@ void bdrv_subtree_drained_begin(BlockDriverState *bs)
|
||||
bdrv_do_drained_begin(bs, true, NULL, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function does not poll, nor must any of its recursively called
|
||||
* functions. The *drained_end_counter pointee will be incremented
|
||||
* once for every background operation scheduled, and decremented once
|
||||
* the operation settles. Therefore, the pointer must remain valid
|
||||
* until the pointee reaches 0. That implies that whoever sets up the
|
||||
* pointee has to poll until it is 0.
|
||||
*
|
||||
* We use atomic operations to access *drained_end_counter, because
|
||||
* (1) when called from bdrv_set_aio_context_ignore(), the subgraph of
|
||||
* @bs may contain nodes in different AioContexts,
|
||||
* (2) bdrv_drain_all_end() uses the same counter for all nodes,
|
||||
* regardless of which AioContext they are in.
|
||||
*/
|
||||
static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
|
||||
BdrvChild *parent, bool ignore_bds_parents)
|
||||
BdrvChild *parent, bool ignore_bds_parents,
|
||||
int *drained_end_counter)
|
||||
{
|
||||
BdrvChild *child, *next;
|
||||
BdrvChild *child;
|
||||
int old_quiesce_counter;
|
||||
|
||||
assert(drained_end_counter != NULL);
|
||||
|
||||
if (qemu_in_coroutine()) {
|
||||
bdrv_co_yield_to_drain(bs, false, recursive, parent, ignore_bds_parents,
|
||||
false);
|
||||
false, drained_end_counter);
|
||||
return;
|
||||
}
|
||||
assert(bs->quiesce_counter > 0);
|
||||
|
||||
/* Re-enable things in child-to-parent order */
|
||||
bdrv_drain_invoke(bs, false);
|
||||
bdrv_parent_drained_end(bs, parent, ignore_bds_parents);
|
||||
bdrv_drain_invoke(bs, false, drained_end_counter);
|
||||
bdrv_parent_drained_end(bs, parent, ignore_bds_parents,
|
||||
drained_end_counter);
|
||||
|
||||
old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
|
||||
if (old_quiesce_counter == 1) {
|
||||
@@ -435,20 +481,30 @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
|
||||
if (recursive) {
|
||||
assert(!ignore_bds_parents);
|
||||
bs->recursive_quiesce_counter--;
|
||||
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
|
||||
bdrv_do_drained_end(child->bs, true, child, ignore_bds_parents);
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
bdrv_do_drained_end(child->bs, true, child, ignore_bds_parents,
|
||||
drained_end_counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_drained_end(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_do_drained_end(bs, false, NULL, false);
|
||||
int drained_end_counter = 0;
|
||||
bdrv_do_drained_end(bs, false, NULL, false, &drained_end_counter);
|
||||
BDRV_POLL_WHILE(bs, atomic_read(&drained_end_counter) > 0);
|
||||
}
|
||||
|
||||
void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter)
|
||||
{
|
||||
bdrv_do_drained_end(bs, false, NULL, false, drained_end_counter);
|
||||
}
|
||||
|
||||
void bdrv_subtree_drained_end(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_do_drained_end(bs, true, NULL, false);
|
||||
int drained_end_counter = 0;
|
||||
bdrv_do_drained_end(bs, true, NULL, false, &drained_end_counter);
|
||||
BDRV_POLL_WHILE(bs, atomic_read(&drained_end_counter) > 0);
|
||||
}
|
||||
|
||||
void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
|
||||
@@ -462,11 +518,15 @@ void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
|
||||
|
||||
void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent)
|
||||
{
|
||||
int drained_end_counter = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < old_parent->recursive_quiesce_counter; i++) {
|
||||
bdrv_do_drained_end(child->bs, true, child, false);
|
||||
bdrv_do_drained_end(child->bs, true, child, false,
|
||||
&drained_end_counter);
|
||||
}
|
||||
|
||||
BDRV_POLL_WHILE(child->bs, atomic_read(&drained_end_counter) > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -535,7 +595,7 @@ void bdrv_drain_all_begin(void)
|
||||
BlockDriverState *bs = NULL;
|
||||
|
||||
if (qemu_in_coroutine()) {
|
||||
bdrv_co_yield_to_drain(NULL, true, false, NULL, true, true);
|
||||
bdrv_co_yield_to_drain(NULL, true, false, NULL, true, true, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -566,15 +626,19 @@ void bdrv_drain_all_begin(void)
|
||||
void bdrv_drain_all_end(void)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
int drained_end_counter = 0;
|
||||
|
||||
while ((bs = bdrv_next_all_states(bs))) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
bdrv_do_drained_end(bs, false, NULL, true);
|
||||
bdrv_do_drained_end(bs, false, NULL, true, &drained_end_counter);
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
|
||||
AIO_WAIT_WHILE(NULL, atomic_read(&drained_end_counter) > 0);
|
||||
|
||||
assert(bdrv_drain_all_count > 0);
|
||||
bdrv_drain_all_count--;
|
||||
}
|
||||
|
||||
+1
-1
@@ -135,7 +135,7 @@ static bool child_job_drained_poll(BdrvChild *c)
|
||||
}
|
||||
}
|
||||
|
||||
static void child_job_drained_end(BdrvChild *c)
|
||||
static void child_job_drained_end(BdrvChild *c, int *drained_end_counter)
|
||||
{
|
||||
BlockJob *job = c->opaque;
|
||||
job_resume(&job->job);
|
||||
|
||||
+28
-14
@@ -600,15 +600,6 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
|
||||
void bdrv_io_plug(BlockDriverState *bs);
|
||||
void bdrv_io_unplug(BlockDriverState *bs);
|
||||
|
||||
/**
|
||||
* bdrv_parent_drained_begin:
|
||||
*
|
||||
* Begin a quiesced section of all users of @bs. This is part of
|
||||
* bdrv_drained_begin.
|
||||
*/
|
||||
void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
|
||||
bool ignore_bds_parents);
|
||||
|
||||
/**
|
||||
* bdrv_parent_drained_begin_single:
|
||||
*
|
||||
@@ -618,13 +609,14 @@ void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
|
||||
void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll);
|
||||
|
||||
/**
|
||||
* bdrv_parent_drained_end:
|
||||
* bdrv_parent_drained_end_single:
|
||||
*
|
||||
* End a quiesced section of all users of @bs. This is part of
|
||||
* bdrv_drained_end.
|
||||
* End a quiesced section for the parent of @c.
|
||||
*
|
||||
* This polls @bs's AioContext until all scheduled sub-drained_ends
|
||||
* have settled, which may result in graph changes.
|
||||
*/
|
||||
void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
|
||||
bool ignore_bds_parents);
|
||||
void bdrv_parent_drained_end_single(BdrvChild *c);
|
||||
|
||||
/**
|
||||
* bdrv_drain_poll:
|
||||
@@ -672,9 +664,31 @@ void bdrv_subtree_drained_begin(BlockDriverState *bs);
|
||||
* bdrv_drained_end:
|
||||
*
|
||||
* End a quiescent section started by bdrv_drained_begin().
|
||||
*
|
||||
* This polls @bs's AioContext until all scheduled sub-drained_ends
|
||||
* have settled. On one hand, that may result in graph changes. On
|
||||
* the other, this requires that all involved nodes (@bs and all of
|
||||
* its parents) are in the same AioContext, and that the caller has
|
||||
* acquired it.
|
||||
* If there are any nodes that are in different contexts from @bs,
|
||||
* these contexts must not be acquired.
|
||||
*/
|
||||
void bdrv_drained_end(BlockDriverState *bs);
|
||||
|
||||
/**
|
||||
* bdrv_drained_end_no_poll:
|
||||
*
|
||||
* Same as bdrv_drained_end(), but do not poll for the subgraph to
|
||||
* actually become unquiesced. Therefore, no graph changes will occur
|
||||
* with this function.
|
||||
*
|
||||
* *drained_end_counter is incremented for every background operation
|
||||
* that is scheduled, and will be decremented for every operation once
|
||||
* it settles. The caller must poll until it reaches 0. The counter
|
||||
* should be accessed using atomic operations only.
|
||||
*/
|
||||
void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter);
|
||||
|
||||
/**
|
||||
* End a quiescent section started by bdrv_subtree_drained_begin().
|
||||
*/
|
||||
|
||||
@@ -664,11 +664,15 @@ struct BdrvChildRole {
|
||||
* These functions must not change the graph (and therefore also must not
|
||||
* call aio_poll(), which could change the graph indirectly).
|
||||
*
|
||||
* If drained_end() schedules background operations, it must atomically
|
||||
* increment *drained_end_counter for each such operation and atomically
|
||||
* decrement it once the operation has settled.
|
||||
*
|
||||
* Note that this can be nested. If drained_begin() was called twice, new
|
||||
* I/O is allowed only after drained_end() was called twice, too.
|
||||
*/
|
||||
void (*drained_begin)(BdrvChild *child);
|
||||
void (*drained_end)(BdrvChild *child);
|
||||
void (*drained_end)(BdrvChild *child, int *drained_end_counter);
|
||||
|
||||
/*
|
||||
* Returns whether the parent has pending requests for the child. This
|
||||
@@ -729,6 +733,15 @@ struct BdrvChild {
|
||||
*/
|
||||
bool frozen;
|
||||
|
||||
/*
|
||||
* How many times the parent of this child has been drained
|
||||
* (through role->drained_*).
|
||||
* Usually, this is equal to bs->quiesce_counter (potentially
|
||||
* reduced by bdrv_drain_all_count). It may differ while the
|
||||
* child is entering or leaving a drained section.
|
||||
*/
|
||||
int parent_quiesce_counter;
|
||||
|
||||
QLIST_ENTRY(BdrvChild) next;
|
||||
QLIST_ENTRY(BdrvChild) next_parent;
|
||||
};
|
||||
|
||||
@@ -329,13 +329,14 @@ class QEMUMachine(object):
|
||||
self._load_io_log()
|
||||
self._post_shutdown()
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self, has_quit=False):
|
||||
"""
|
||||
Terminate the VM and clean up
|
||||
"""
|
||||
if self.is_running():
|
||||
try:
|
||||
self._qmp.cmd('quit')
|
||||
if not has_quit:
|
||||
self._qmp.cmd('quit')
|
||||
self._qmp.close()
|
||||
except:
|
||||
self._popen.kill()
|
||||
|
||||
+39
-1
@@ -92,9 +92,10 @@ class TestSingleDrive(ImageCommitTestCase):
|
||||
|
||||
self.vm.add_device("scsi-hd,id=scsi0,drive=drive0")
|
||||
self.vm.launch()
|
||||
self.has_quit = False
|
||||
|
||||
def tearDown(self):
|
||||
self.vm.shutdown()
|
||||
self.vm.shutdown(has_quit=self.has_quit)
|
||||
os.remove(test_img)
|
||||
os.remove(mid_img)
|
||||
os.remove(backing_img)
|
||||
@@ -109,6 +110,43 @@ class TestSingleDrive(ImageCommitTestCase):
|
||||
self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed"))
|
||||
self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed"))
|
||||
|
||||
def test_commit_with_filter_and_quit(self):
|
||||
result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
# Add a filter outside of the backing chain
|
||||
result = self.vm.qmp('blockdev-add', driver='throttle', node_name='filter', throttle_group='tg', file='mid')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('block-commit', device='drive0')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
# Quit immediately, thus forcing a simultaneous cancel of the
|
||||
# block job and a bdrv_drain_all()
|
||||
result = self.vm.qmp('quit')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.has_quit = True
|
||||
|
||||
# Same as above, but this time we add the filter after starting the job
|
||||
def test_commit_plus_filter_and_quit(self):
|
||||
result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('block-commit', device='drive0')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
# Add a filter outside of the backing chain
|
||||
result = self.vm.qmp('blockdev-add', driver='throttle', node_name='filter', throttle_group='tg', file='mid')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
# Quit immediately, thus forcing a simultaneous cancel of the
|
||||
# block job and a bdrv_drain_all()
|
||||
result = self.vm.qmp('quit')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.has_quit = True
|
||||
|
||||
def test_device_not_found(self):
|
||||
result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % mid_img)
|
||||
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
...........................................
|
||||
...............................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 43 tests
|
||||
Ran 47 tests
|
||||
|
||||
OK
|
||||
|
||||
@@ -251,11 +251,11 @@ echo
|
||||
# Cannot use the test image because cache=none might not work on the host FS
|
||||
# Use cdrom so that we won't get errors about missing media
|
||||
|
||||
run_qemu -drive driver=null-co,cache=none
|
||||
run_qemu -drive driver=null-co,cache=directsync
|
||||
run_qemu -drive driver=null-co,cache=writeback
|
||||
run_qemu -drive driver=null-co,cache=writethrough
|
||||
run_qemu -drive driver=null-co,cache=unsafe
|
||||
run_qemu -drive driver=null-co,read-zeroes=on,cache=none
|
||||
run_qemu -drive driver=null-co,read-zeroes=on,cache=directsync
|
||||
run_qemu -drive driver=null-co,read-zeroes=on,cache=writeback
|
||||
run_qemu -drive driver=null-co,read-zeroes=on,cache=writethrough
|
||||
run_qemu -drive driver=null-co,read-zeroes=on,cache=unsafe
|
||||
run_qemu -drive driver=null-co,cache=invalid_value
|
||||
|
||||
# Can't test direct=on here because O_DIRECT might not be supported on this FS
|
||||
|
||||
@@ -245,23 +245,23 @@ QEMU X.Y.Z monitor - type 'help' for more information
|
||||
|
||||
=== Cache modes ===
|
||||
|
||||
Testing: -drive driver=null-co,cache=none
|
||||
Testing: -drive driver=null-co,read-zeroes=on,cache=none
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive driver=null-co,cache=directsync
|
||||
Testing: -drive driver=null-co,read-zeroes=on,cache=directsync
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive driver=null-co,cache=writeback
|
||||
Testing: -drive driver=null-co,read-zeroes=on,cache=writeback
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive driver=null-co,cache=writethrough
|
||||
Testing: -drive driver=null-co,read-zeroes=on,cache=writethrough
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive driver=null-co,cache=unsafe
|
||||
Testing: -drive driver=null-co,read-zeroes=on,cache=unsafe
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) quit
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class ThrottleTestCase(iotests.QMPTestCase):
|
||||
def setUp(self):
|
||||
self.vm = iotests.VM()
|
||||
for i in range(0, self.max_drives):
|
||||
self.vm.add_drive(self.test_img)
|
||||
self.vm.add_drive(self.test_img, "file.read-zeroes=on")
|
||||
self.vm.launch()
|
||||
|
||||
def tearDown(self):
|
||||
@@ -273,7 +273,8 @@ class ThrottleTestGroupNames(iotests.QMPTestCase):
|
||||
def setUp(self):
|
||||
self.vm = iotests.VM()
|
||||
for i in range(0, self.max_drives):
|
||||
self.vm.add_drive(self.test_img, "throttling.iops-total=100")
|
||||
self.vm.add_drive(self.test_img,
|
||||
"throttling.iops-total=100,file.read-zeroes=on")
|
||||
self.vm.launch()
|
||||
|
||||
def tearDown(self):
|
||||
@@ -378,10 +379,10 @@ class ThrottleTestRemovableMedia(iotests.QMPTestCase):
|
||||
def test_removable_media(self):
|
||||
# Add a couple of dummy nodes named cd0 and cd1
|
||||
result = self.vm.qmp("blockdev-add", driver="null-aio",
|
||||
node_name="cd0")
|
||||
read_zeroes=True, node_name="cd0")
|
||||
self.assert_qmp(result, 'return', {})
|
||||
result = self.vm.qmp("blockdev-add", driver="null-aio",
|
||||
node_name="cd1")
|
||||
read_zeroes=True, node_name="cd1")
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
# Attach a CD drive with cd0 inserted
|
||||
|
||||
@@ -74,6 +74,7 @@ sector = "%d"
|
||||
(self.account_invalid and "on" or "off"))
|
||||
drive_args.append("stats-account-failed=%s" %
|
||||
(self.account_failed and "on" or "off"))
|
||||
drive_args.append("file.image.read-zeroes=on")
|
||||
self.create_blkdebug_file()
|
||||
self.vm = iotests.VM().add_drive('blkdebug:%s:%s' %
|
||||
(blkdebug_file, self.test_img),
|
||||
|
||||
+10
-10
@@ -86,8 +86,8 @@ 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
|
||||
check_info_block -blockdev driver=null-co,read-zeroes=on,node-name=null -device $dev,drive=null
|
||||
check_info_block -blockdev driver=null-co,read-zeroes=on,node-name=null -device $dev,drive=null,id=qdev_id
|
||||
done
|
||||
|
||||
echo
|
||||
@@ -97,7 +97,7 @@ 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
|
||||
check_info_block -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device $dev,drive=null,id=qdev_id
|
||||
done
|
||||
|
||||
echo
|
||||
@@ -105,8 +105,8 @@ 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
|
||||
check_info_block -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device $dev,drive=none0
|
||||
check_info_block -drive if=none,driver=null-co,read-zeroes=on,node-name=null -device $dev,drive=none0,id=qdev_id
|
||||
done
|
||||
|
||||
echo
|
||||
@@ -125,15 +125,15 @@ echo "=== -drive if=... ==="
|
||||
echo
|
||||
|
||||
check_info_block -drive if=floppy
|
||||
check_info_block -drive if=floppy,driver=null-co
|
||||
check_info_block -drive if=floppy,driver=null-co,read-zeroes=on
|
||||
|
||||
check_info_block -drive if=ide,driver=null-co
|
||||
check_info_block -drive if=ide,driver=null-co,read-zeroes=on
|
||||
check_info_block -drive if=ide,media=cdrom
|
||||
check_info_block -drive if=ide,driver=null-co,media=cdrom
|
||||
check_info_block -drive if=ide,driver=null-co,read-zeroes=on,media=cdrom
|
||||
|
||||
check_info_block -drive if=virtio,driver=null-co
|
||||
check_info_block -drive if=virtio,driver=null-co,read-zeroes=on
|
||||
|
||||
check_info_block -drive if=pflash,driver=null-co,size=1M
|
||||
check_info_block -drive if=pflash,driver=null-co,read-zeroes=on,size=1M
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
|
||||
+76
-76
@@ -54,103 +54,103 @@ qdev_id: [not inserted]
|
||||
|
||||
=== -blockdev/-device=<node-name> ===
|
||||
|
||||
Testing: -blockdev driver=null-co,node-name=null -device ide-hd,drive=null
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,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)
|
||||
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
Testing: -blockdev driver=null-co,node-name=null -device ide-hd,drive=null,id=qdev_id
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,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)
|
||||
null: json:{"read-zeroes": true, "driver": "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
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,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)
|
||||
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
Testing: -blockdev driver=null-co,node-name=null -device scsi-hd,drive=null,id=qdev_id
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,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)
|
||||
null: json:{"read-zeroes": true, "driver": "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
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,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)
|
||||
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
Testing: -blockdev driver=null-co,node-name=null -device virtio-blk-pci,drive=null,id=qdev_id
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,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)
|
||||
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
Testing: -blockdev driver=null-co,node-name=null -device floppy,drive=null
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,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)
|
||||
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
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
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,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)
|
||||
null: json:{"read-zeroes": true, "driver": "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
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,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)
|
||||
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
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
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,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)
|
||||
null: json:{"read-zeroes": true, "driver": "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
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,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)
|
||||
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
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
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,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)
|
||||
null: json:{"read-zeroes": true, "driver": "null-co"} (null-co)
|
||||
Attached to: qdev_id
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback
|
||||
@@ -159,76 +159,76 @@ null: null-co:// (null-co)
|
||||
|
||||
=== -drive if=none/-device=<node-name> ===
|
||||
|
||||
Testing: -drive if=none,driver=null-co,node-name=null -device ide-hd,drive=null,id=qdev_id
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback
|
||||
|
||||
null: null-co:// (null-co)
|
||||
null: json:{"read-zeroes": "on", "driver": "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
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback
|
||||
|
||||
null: null-co:// (null-co)
|
||||
null: json:{"read-zeroes": "on", "driver": "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
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback
|
||||
|
||||
null: null-co:// (null-co)
|
||||
null: json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive if=none,driver=null-co,node-name=null -device floppy,drive=null,id=qdev_id
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback
|
||||
|
||||
null: null-co:// (null-co)
|
||||
null: json:{"read-zeroes": "on", "driver": "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
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback
|
||||
|
||||
null: null-co:// (null-co)
|
||||
null: json:{"read-zeroes": "on", "driver": "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
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback
|
||||
|
||||
null: null-co:// (null-co)
|
||||
null: json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: qdev_id
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback
|
||||
@@ -237,103 +237,103 @@ null: null-co:// (null-co)
|
||||
|
||||
=== -drive if=none/-device=<bb-name> (with medium) ===
|
||||
|
||||
Testing: -drive if=none,driver=null-co,node-name=null -device ide-hd,drive=none0
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive if=none,driver=null-co,node-name=null -device ide-hd,drive=none0,id=qdev_id
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "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
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive if=none,driver=null-co,node-name=null -device scsi-hd,drive=none0,id=qdev_id
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "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
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive if=none,driver=null-co,node-name=null -device virtio-blk-pci,drive=none0,id=qdev_id
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive if=none,driver=null-co,node-name=null -device floppy,drive=none0
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
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
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "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
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
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
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "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
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
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
|
||||
Testing: -drive if=none,driver=null-co,read-zeroes=on,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)
|
||||
none0 (null): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: qdev_id
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback
|
||||
@@ -408,19 +408,19 @@ floppy0: [not inserted]
|
||||
Removable device: not locked, tray closed
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive if=floppy,driver=null-co
|
||||
Testing: -drive if=floppy,driver=null-co,read-zeroes=on
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) info block
|
||||
floppy0 (NODE_NAME): null-co:// (null-co)
|
||||
floppy0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive if=ide,driver=null-co
|
||||
Testing: -drive if=ide,driver=null-co,read-zeroes=on
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) info block
|
||||
ide0-hd0 (NODE_NAME): null-co:// (null-co)
|
||||
ide0-hd0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
@@ -433,27 +433,27 @@ ide0-cd0: [not inserted]
|
||||
Removable device: not locked, tray closed
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive if=ide,driver=null-co,media=cdrom
|
||||
Testing: -drive if=ide,driver=null-co,read-zeroes=on,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)
|
||||
ide0-cd0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co"} (null-co, read-only)
|
||||
Attached to: PATH
|
||||
Removable device: not locked, tray closed
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive if=virtio,driver=null-co
|
||||
Testing: -drive if=virtio,driver=null-co,read-zeroes=on
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) info block
|
||||
virtio0 (NODE_NAME): null-co:// (null-co)
|
||||
virtio0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co"} (null-co)
|
||||
Attached to: PATH
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
Testing: -drive if=pflash,driver=null-co,size=1M
|
||||
Testing: -drive if=pflash,driver=null-co,read-zeroes=on,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)
|
||||
pflash0 (NODE_NAME): json:{"read-zeroes": "on", "driver": "null-co", "size": "1M"} (null-co)
|
||||
Attached to: PATH
|
||||
Cache mode: writeback
|
||||
(qemu) quit
|
||||
|
||||
+53
-2
@@ -27,9 +27,9 @@
|
||||
# Creator/Owner: Max Reitz <mreitz@redhat.com>
|
||||
|
||||
import iotests
|
||||
from iotests import log
|
||||
from iotests import log, qemu_img, qemu_io_silent
|
||||
|
||||
iotests.verify_platform(['linux'])
|
||||
iotests.verify_image_format(supported_fmts=['qcow2', 'raw'])
|
||||
|
||||
|
||||
# Launches the VM, adds two null-co nodes (source and target), and
|
||||
@@ -136,3 +136,54 @@ with iotests.VM() as vm:
|
||||
|
||||
log(vm.event_wait('BLOCK_JOB_CANCELLED'),
|
||||
filters=[iotests.filter_qmp_event])
|
||||
|
||||
log('')
|
||||
log('=== Cancel mirror job from throttled node by quitting ===')
|
||||
log('')
|
||||
|
||||
with iotests.VM() as vm, \
|
||||
iotests.FilePath('src.img') as src_img_path:
|
||||
|
||||
assert qemu_img('create', '-f', iotests.imgfmt, src_img_path, '64M') == 0
|
||||
assert qemu_io_silent('-f', iotests.imgfmt, src_img_path,
|
||||
'-c', 'write -P 42 0M 64M') == 0
|
||||
|
||||
vm.launch()
|
||||
|
||||
ret = vm.qmp('object-add', qom_type='throttle-group', id='tg',
|
||||
props={'x-bps-read': 4096})
|
||||
assert ret['return'] == {}
|
||||
|
||||
ret = vm.qmp('blockdev-add',
|
||||
node_name='source',
|
||||
driver=iotests.imgfmt,
|
||||
file={
|
||||
'driver': 'file',
|
||||
'filename': src_img_path
|
||||
})
|
||||
assert ret['return'] == {}
|
||||
|
||||
ret = vm.qmp('blockdev-add',
|
||||
node_name='throttled-source',
|
||||
driver='throttle',
|
||||
throttle_group='tg',
|
||||
file='source')
|
||||
assert ret['return'] == {}
|
||||
|
||||
ret = vm.qmp('blockdev-add',
|
||||
node_name='target',
|
||||
driver='null-co',
|
||||
size=(64 * 1048576))
|
||||
assert ret['return'] == {}
|
||||
|
||||
ret = vm.qmp('blockdev-mirror',
|
||||
job_id='mirror',
|
||||
device='throttled-source',
|
||||
target='target',
|
||||
sync='full')
|
||||
assert ret['return'] == {}
|
||||
|
||||
log(vm.qmp('quit'))
|
||||
|
||||
with iotests.Timeout(5, 'Timeout waiting for VM to quit'):
|
||||
vm.shutdown(has_quit=True)
|
||||
|
||||
@@ -28,3 +28,7 @@ Cancelling job
|
||||
Cancelling job
|
||||
{"return": {}}
|
||||
{"data": {"device": "mirror", "len": 1048576, "offset": 1048576, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
|
||||
|
||||
=== Cancel mirror job from throttled node by quitting ===
|
||||
|
||||
{"return": {}}
|
||||
|
||||
@@ -57,7 +57,7 @@ echo
|
||||
echo '=== blockstats with -drive if=virtio ==='
|
||||
echo
|
||||
|
||||
run_qemu -drive driver=null-co,if=virtio <<EOF
|
||||
run_qemu -drive driver=null-co,read-zeroes=on,if=virtio <<EOF
|
||||
{ "execute": "qmp_capabilities" }
|
||||
{ "execute": "query-blockstats"}
|
||||
{ "execute": "quit" }
|
||||
@@ -87,7 +87,7 @@ echo
|
||||
echo '=== blockstats with -blockdev and -device ==='
|
||||
echo
|
||||
|
||||
run_qemu -blockdev driver=null-co,node-name=null -device virtio-blk,drive=null,id=virtio0 <<EOF
|
||||
run_qemu -blockdev driver=null-co,read-zeroes=on,node-name=null -device virtio-blk,drive=null,id=virtio0 <<EOF
|
||||
{ "execute": "qmp_capabilities" }
|
||||
{ "execute": "query-blockstats"}
|
||||
{ "execute": "quit" }
|
||||
|
||||
@@ -2,7 +2,7 @@ QA output created by 227
|
||||
|
||||
=== blockstats with -drive if=virtio ===
|
||||
|
||||
Testing: -drive driver=null-co,if=virtio
|
||||
Testing: -drive driver=null-co,read-zeroes=on,if=virtio
|
||||
{
|
||||
QMP_VERSION
|
||||
}
|
||||
@@ -150,7 +150,7 @@ Testing: -blockdev driver=null-co,node-name=null
|
||||
|
||||
=== blockstats with -blockdev and -device ===
|
||||
|
||||
Testing: -blockdev driver=null-co,node-name=null -device virtio-blk,drive=null,id=virtio0
|
||||
Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device virtio-blk,drive=null,id=virtio0
|
||||
{
|
||||
QMP_VERSION
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ else:
|
||||
vm = iotests.VM()
|
||||
vm.launch()
|
||||
|
||||
log(vm.qmp('blockdev-add', node_name='hd0', driver='null-co'))
|
||||
log(vm.qmp('blockdev-add', node_name='hd0', driver='null-co', read_zeroes=True))
|
||||
log(vm.qmp('object-add', qom_type='iothread', id='iothread0'))
|
||||
log(vm.qmp('device_add', id='scsi0', driver=virtio_scsi_device, iothread='iothread0'))
|
||||
log(vm.qmp('device_add', id='scsi-hd0', driver='scsi-hd', drive='hd0'))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user