aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block.c8
-rw-r--r--block/io.c20
-rw-r--r--block/mirror.c2
-rw-r--r--block/qcow2-cache.c3
-rw-r--r--block/raw-posix.c3
-rw-r--r--block/snapshot.c2
-rw-r--r--blockjob.c20
-rw-r--r--include/block/blockjob.h8
-rw-r--r--migration/block.c2
9 files changed, 40 insertions, 28 deletions
diff --git a/block.c b/block.c
index 7e130cc528..5e80336e9f 100644
--- a/block.c
+++ b/block.c
@@ -1271,7 +1271,7 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
QemuOpts *opts = NULL;
QDict *snapshot_options;
BlockDriverState *bs_snapshot;
- Error *local_err;
+ Error *local_err = NULL;
int ret;
/* if snapshot, we create a temporary backing file and open it
@@ -1841,9 +1841,9 @@ void bdrv_close(BlockDriverState *bs)
if (bs->job) {
block_job_cancel_sync(bs->job);
}
- bdrv_drain_all(); /* complete I/O */
+ bdrv_drain(bs); /* complete I/O */
bdrv_flush(bs);
- bdrv_drain_all(); /* in case flush left pending I/O */
+ bdrv_drain(bs); /* in case flush left pending I/O */
notifier_list_notify(&bs->close_notifiers, bs);
if (bs->drv) {
@@ -3906,7 +3906,7 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
{
- bdrv_drain_all(); /* ensure there are no in-flight requests */
+ bdrv_drain(bs); /* ensure there are no in-flight requests */
bdrv_detach_aio_context(bs);
diff --git a/block/io.c b/block/io.c
index 305e0d952e..d4bc83b33b 100644
--- a/block/io.c
+++ b/block/io.c
@@ -236,12 +236,12 @@ static bool bdrv_requests_pending(BlockDriverState *bs)
/*
* Wait for pending requests to complete on a single BlockDriverState subtree
*
- * See the warning in bdrv_drain_all(). This function can only be called if
- * you are sure nothing can generate I/O because you have op blockers
- * installed.
- *
* Note that unlike bdrv_drain_all(), the caller must hold the BlockDriverState
* AioContext.
+ *
+ * Only this BlockDriverState's AioContext is run, so in-flight requests must
+ * not depend on events in other AioContexts. In that case, use
+ * bdrv_drain_all() instead.
*/
void bdrv_drain(BlockDriverState *bs)
{
@@ -260,12 +260,6 @@ void bdrv_drain(BlockDriverState *bs)
*
* This function does not flush data to disk, use bdrv_flush_all() for that
* after calling this function.
- *
- * Note that completion of an asynchronous I/O operation can trigger any
- * number of other I/O operations on other devices---for example a coroutine
- * can be arbitrarily complex and a constant flow of I/O can come until the
- * coroutine is complete. Because of this, it is not possible to have a
- * function to drain a single device's I/O queue.
*/
void bdrv_drain_all(void)
{
@@ -288,6 +282,12 @@ void bdrv_drain_all(void)
}
}
+ /* Note that completion of an asynchronous I/O operation can trigger any
+ * number of other I/O operations on other devices---for example a
+ * coroutine can submit an I/O request to another device in response to
+ * request completion. Therefore we must keep looping until there was no
+ * more activity rather than simply draining each device independently.
+ */
while (busy) {
busy = false;
diff --git a/block/mirror.c b/block/mirror.c
index 8888cea952..d409337c4a 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -708,6 +708,8 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
if (!s->dirty_bitmap) {
+ g_free(s->replaces);
+ block_job_release(bs);
return;
}
bdrv_set_enable_write_cache(s->target, true);
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index ed92a098c4..53b8afc3d3 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -281,9 +281,6 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
i = min_lru_index;
trace_qcow2_cache_get_replace_entry(qemu_coroutine_self(),
c == s->l2_table_cache, i);
- if (i < 0) {
- return i;
- }
ret = qcow2_cache_entry_flush(bs, c, i);
if (ret < 0) {
diff --git a/block/raw-posix.c b/block/raw-posix.c
index cbe6574bf4..855febed52 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -2430,7 +2430,8 @@ static int floppy_probe_device(const char *filename)
struct stat st;
if (strstart(filename, "/dev/fd", NULL) &&
- !strstart(filename, "/dev/fdset/", NULL)) {
+ !strstart(filename, "/dev/fdset/", NULL) &&
+ !strstart(filename, "/dev/fd/", NULL)) {
prio = 50;
}
diff --git a/block/snapshot.c b/block/snapshot.c
index 19395ae014..49e143e991 100644
--- a/block/snapshot.c
+++ b/block/snapshot.c
@@ -239,7 +239,7 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
}
/* drain all pending i/o before deleting snapshot */
- bdrv_drain_all();
+ bdrv_drain(bs);
if (drv->bdrv_snapshot_delete) {
return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
diff --git a/blockjob.c b/blockjob.c
index ec46fad2f1..62bb906634 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -66,10 +66,7 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
block_job_set_speed(job, speed, &local_err);
if (local_err) {
- bs->job = NULL;
- bdrv_op_unblock_all(bs, job->blocker);
- error_free(job->blocker);
- g_free(job);
+ block_job_release(bs);
error_propagate(errp, local_err);
return NULL;
}
@@ -77,18 +74,25 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
return job;
}
-void block_job_completed(BlockJob *job, int ret)
+void block_job_release(BlockDriverState *bs)
{
- BlockDriverState *bs = job->bs;
+ BlockJob *job = bs->job;
- assert(bs->job == job);
- job->cb(job->opaque, ret);
bs->job = NULL;
bdrv_op_unblock_all(bs, job->blocker);
error_free(job->blocker);
g_free(job);
}
+void block_job_completed(BlockJob *job, int ret)
+{
+ BlockDriverState *bs = job->bs;
+
+ assert(bs->job == job);
+ job->cb(job->opaque, ret);
+ block_job_release(bs);
+}
+
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
{
Error *local_err = NULL;
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
index 57d8ef13e2..dd9d5e6aad 100644
--- a/include/block/blockjob.h
+++ b/include/block/blockjob.h
@@ -166,6 +166,14 @@ void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns);
void block_job_yield(BlockJob *job);
/**
+ * block_job_release:
+ * @bs: The block device.
+ *
+ * Release job resources when an error occurred or job completed.
+ */
+void block_job_release(BlockDriverState *bs);
+
+/**
* block_job_completed:
* @job: The job being completed.
* @ret: The status code.
diff --git a/migration/block.c b/migration/block.c
index ddb59ccf87..ed865ed23b 100644
--- a/migration/block.c
+++ b/migration/block.c
@@ -457,7 +457,7 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
blk_mig_lock();
if (bmds_aio_inflight(bmds, sector)) {
blk_mig_unlock();
- bdrv_drain_all();
+ bdrv_drain(bmds->bs);
} else {
blk_mig_unlock();
}