aboutsummaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2018-01-11 22:01:17 +0200
committerMichael S. Tsirkin <mst@redhat.com>2018-01-11 22:03:50 +0200
commitacc95bc85036c443da8bf7159a77edf9f00dcd80 (patch)
tree21965c6e60a2e29664b7685e52feacdb6a86e0bd /block
parent880b1ffe6ec2f0ae25cc4175716227ad275e8b8a (diff)
parent997eba28a3ed5400a80f754bf3a1c8044b75b9ff (diff)
Merge remote-tracking branch 'origin/master' into HEAD
Resolve conflicts around apb. Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'block')
-rw-r--r--block/backup.c118
-rw-r--r--block/commit.c8
-rw-r--r--block/curl.c24
-rw-r--r--block/dirty-bitmap.c5
-rw-r--r--block/dmg.h1
-rw-r--r--block/io.c164
-rw-r--r--block/iscsi.c51
-rw-r--r--block/nbd.c1
-rw-r--r--block/null.c3
-rw-r--r--block/qcow2.c51
-rw-r--r--block/qcow2.h3
-rw-r--r--block/replication.c6
-rw-r--r--block/sheepdog.c169
13 files changed, 343 insertions, 261 deletions
diff --git a/block/backup.c b/block/backup.c
index 99e6bcc748..4a16a37229 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -40,11 +40,12 @@ typedef struct BackupBlockJob {
BlockdevOnError on_target_error;
CoRwlock flush_rwlock;
uint64_t bytes_read;
- unsigned long *done_bitmap;
int64_t cluster_size;
bool compress;
NotifierWithReturn before_write;
QLIST_HEAD(, CowRequest) inflight_reqs;
+
+ HBitmap *copy_bitmap;
} BackupBlockJob;
/* See if in-flight requests overlap and wait for them to complete */
@@ -109,10 +110,11 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
cow_request_begin(&cow_request, job, start, end);
for (; start < end; start += job->cluster_size) {
- if (test_bit(start / job->cluster_size, job->done_bitmap)) {
+ if (!hbitmap_get(job->copy_bitmap, start / job->cluster_size)) {
trace_backup_do_cow_skip(job, start);
continue; /* already copied */
}
+ hbitmap_reset(job->copy_bitmap, start / job->cluster_size, 1);
trace_backup_do_cow_process(job, start);
@@ -132,6 +134,7 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
if (error_is_read) {
*error_is_read = true;
}
+ hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1);
goto out;
}
@@ -148,11 +151,10 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
if (error_is_read) {
*error_is_read = false;
}
+ hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1);
goto out;
}
- set_bit(start / job->cluster_size, job->done_bitmap);
-
/* Publish progress, guest I/O counts as progress too. Note that the
* offset field is an opaque progress value, it is not a disk offset.
*/
@@ -260,7 +262,7 @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
}
len = DIV_ROUND_UP(backup_job->common.len, backup_job->cluster_size);
- bitmap_zero(backup_job->done_bitmap, len);
+ hbitmap_set(backup_job->copy_bitmap, 0, len);
}
void backup_wait_for_overlapping_requests(BlockJob *job, int64_t offset,
@@ -360,64 +362,68 @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job)
static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
{
+ int ret;
bool error_is_read;
- int ret = 0;
- int clusters_per_iter;
- uint32_t granularity;
- int64_t offset;
int64_t cluster;
- int64_t end;
- int64_t last_cluster = -1;
- BdrvDirtyBitmapIter *dbi;
+ HBitmapIter hbi;
- granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap);
- clusters_per_iter = MAX((granularity / job->cluster_size), 1);
- dbi = bdrv_dirty_iter_new(job->sync_bitmap);
+ hbitmap_iter_init(&hbi, job->copy_bitmap, 0);
+ while ((cluster = hbitmap_iter_next(&hbi)) != -1) {
+ do {
+ if (yield_and_check(job)) {
+ return 0;
+ }
+ ret = backup_do_cow(job, cluster * job->cluster_size,
+ job->cluster_size, &error_is_read, false);
+ if (ret < 0 && backup_error_action(job, error_is_read, -ret) ==
+ BLOCK_ERROR_ACTION_REPORT)
+ {
+ return ret;
+ }
+ } while (ret < 0);
+ }
+
+ return 0;
+}
- /* Find the next dirty sector(s) */
- while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) {
- cluster = offset / job->cluster_size;
+/* init copy_bitmap from sync_bitmap */
+static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
+{
+ BdrvDirtyBitmapIter *dbi;
+ int64_t offset;
+ int64_t end = DIV_ROUND_UP(bdrv_dirty_bitmap_size(job->sync_bitmap),
+ job->cluster_size);
- /* Fake progress updates for any clusters we skipped */
- if (cluster != last_cluster + 1) {
- job->common.offset += ((cluster - last_cluster - 1) *
- job->cluster_size);
+ dbi = bdrv_dirty_iter_new(job->sync_bitmap);
+ while ((offset = bdrv_dirty_iter_next(dbi)) != -1) {
+ int64_t cluster = offset / job->cluster_size;
+ int64_t next_cluster;
+
+ offset += bdrv_dirty_bitmap_granularity(job->sync_bitmap);
+ if (offset >= bdrv_dirty_bitmap_size(job->sync_bitmap)) {
+ hbitmap_set(job->copy_bitmap, cluster, end - cluster);
+ break;
}
- for (end = cluster + clusters_per_iter; cluster < end; cluster++) {
- do {
- if (yield_and_check(job)) {
- goto out;
- }
- ret = backup_do_cow(job, cluster * job->cluster_size,
- job->cluster_size, &error_is_read,
- false);
- if ((ret < 0) &&
- backup_error_action(job, error_is_read, -ret) ==
- BLOCK_ERROR_ACTION_REPORT) {
- goto out;
- }
- } while (ret < 0);
+ offset = bdrv_dirty_bitmap_next_zero(job->sync_bitmap, offset);
+ if (offset == -1) {
+ hbitmap_set(job->copy_bitmap, cluster, end - cluster);
+ break;
}
- /* If the bitmap granularity is smaller than the backup granularity,
- * we need to advance the iterator pointer to the next cluster. */
- if (granularity < job->cluster_size) {
- bdrv_set_dirty_iter(dbi, cluster * job->cluster_size);
+ next_cluster = DIV_ROUND_UP(offset, job->cluster_size);
+ hbitmap_set(job->copy_bitmap, cluster, next_cluster - cluster);
+ if (next_cluster >= end) {
+ break;
}
- last_cluster = cluster - 1;
+ bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size);
}
- /* Play some final catchup with the progress meter */
- end = DIV_ROUND_UP(job->common.len, job->cluster_size);
- if (last_cluster + 1 < end) {
- job->common.offset += ((end - last_cluster - 1) * job->cluster_size);
- }
+ job->common.offset = job->common.len -
+ hbitmap_count(job->copy_bitmap) * job->cluster_size;
-out:
bdrv_dirty_iter_free(dbi);
- return ret;
}
static void coroutine_fn backup_run(void *opaque)
@@ -425,19 +431,27 @@ static void coroutine_fn backup_run(void *opaque)
BackupBlockJob *job = opaque;
BackupCompleteData *data;
BlockDriverState *bs = blk_bs(job->common.blk);
- int64_t offset;
+ int64_t offset, nb_clusters;
int ret = 0;
QLIST_INIT(&job->inflight_reqs);
qemu_co_rwlock_init(&job->flush_rwlock);
- job->done_bitmap = bitmap_new(DIV_ROUND_UP(job->common.len,
- job->cluster_size));
+ nb_clusters = DIV_ROUND_UP(job->common.len, job->cluster_size);
+ job->copy_bitmap = hbitmap_alloc(nb_clusters, 0);
+ if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
+ backup_incremental_init_copy_bitmap(job);
+ } else {
+ hbitmap_set(job->copy_bitmap, 0, nb_clusters);
+ }
+
job->before_write.notify = backup_before_write_notify;
bdrv_add_before_write_notifier(bs, &job->before_write);
if (job->sync_mode == MIRROR_SYNC_MODE_NONE) {
+ /* All bits are set in copy_bitmap to allow any cluster to be copied.
+ * This does not actually require them to be copied. */
while (!block_job_is_cancelled(&job->common)) {
/* Yield until the job is cancelled. We just let our before_write
* notify callback service CoW requests. */
@@ -512,7 +526,7 @@ static void coroutine_fn backup_run(void *opaque)
/* wait until pending backup_do_cow() calls have completed */
qemu_co_rwlock_wrlock(&job->flush_rwlock);
qemu_co_rwlock_unlock(&job->flush_rwlock);
- g_free(job->done_bitmap);
+ hbitmap_free(job->copy_bitmap);
data = g_malloc(sizeof(*data));
data->ret = ret;
diff --git a/block/commit.c b/block/commit.c
index c5327551ce..bb6c904704 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -277,7 +277,6 @@ void commit_start(const char *job_id, BlockDriverState *bs,
const char *filter_node_name, Error **errp)
{
CommitBlockJob *s;
- BlockReopenQueue *reopen_queue = NULL;
int orig_base_flags;
BlockDriverState *iter;
BlockDriverState *commit_top_bs = NULL;
@@ -299,12 +298,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
/* convert base to r/w, if necessary */
orig_base_flags = bdrv_get_flags(base);
if (!(orig_base_flags & BDRV_O_RDWR)) {
- reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
- orig_base_flags | BDRV_O_RDWR);
- }
-
- if (reopen_queue) {
- bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
+ bdrv_reopen(base, orig_base_flags | BDRV_O_RDWR, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
goto fail;
diff --git a/block/curl.c b/block/curl.c
index 2a244e2439..35cf417f59 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -89,6 +89,8 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
struct BDRVCURLState;
+static bool libcurl_initialized;
+
typedef struct CURLAIOCB {
Coroutine *co;
QEMUIOVector *qiov;
@@ -686,14 +688,23 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
double d;
const char *secretid;
const char *protocol_delimiter;
+ int ret;
- static int inited = 0;
if (flags & BDRV_O_RDWR) {
error_setg(errp, "curl block device does not support writes");
return -EROFS;
}
+ if (!libcurl_initialized) {
+ ret = curl_global_init(CURL_GLOBAL_ALL);
+ if (ret) {
+ error_setg(errp, "libcurl initialization failed with %d", ret);
+ return -EIO;
+ }
+ libcurl_initialized = true;
+ }
+
qemu_mutex_init(&s->mutex);
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
@@ -772,11 +783,6 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
}
}
- if (!inited) {
- curl_global_init(CURL_GLOBAL_ALL);
- inited = 1;
- }
-
DPRINTF("CURL: Opening %s\n", file);
QSIMPLEQ_INIT(&s->free_state_waitq);
s->aio_context = bdrv_get_aio_context(bs);
@@ -851,6 +857,9 @@ out_noclean:
qemu_mutex_destroy(&s->mutex);
g_free(s->cookie);
g_free(s->url);
+ g_free(s->username);
+ g_free(s->proxyusername);
+ g_free(s->proxypassword);
qemu_opts_del(opts);
return -EINVAL;
}
@@ -949,6 +958,9 @@ static void curl_close(BlockDriverState *bs)
g_free(s->cookie);
g_free(s->url);
+ g_free(s->username);
+ g_free(s->proxyusername);
+ g_free(s->proxypassword);
}
static int64_t curl_getlength(BlockDriverState *bs)
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index bd04e991b1..7879d13ddb 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -715,3 +715,8 @@ char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp)
{
return hbitmap_sha256(bitmap->bitmap, errp);
}
+
+int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset)
+{
+ return hbitmap_next_zero(bitmap->bitmap, offset);
+}
diff --git a/block/dmg.h b/block/dmg.h
index b592d6fa8b..2ecf239ba5 100644
--- a/block/dmg.h
+++ b/block/dmg.h
@@ -26,7 +26,6 @@
#ifndef BLOCK_DMG_H
#define BLOCK_DMG_H
-#include "qemu/osdep.h"
#include "qemu-common.h"
#include "block/block_int.h"
#include <zlib.h>
diff --git a/block/io.c b/block/io.c
index 6773926fc1..7ea402352e 100644
--- a/block/io.c
+++ b/block/io.c
@@ -40,22 +40,28 @@
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)
+void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
{
BdrvChild *c, *next;
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
+ if (c == ignore) {
+ continue;
+ }
if (c->role->drained_begin) {
c->role->drained_begin(c);
}
}
}
-void bdrv_parent_drained_end(BlockDriverState *bs)
+void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
{
BdrvChild *c, *next;
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
+ if (c == ignore) {
+ continue;
+ }
if (c->role->drained_end) {
c->role->drained_end(c);
}
@@ -134,29 +140,13 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
assert(old >= 1);
}
-/* Check if any requests are in-flight (including throttled requests) */
-bool bdrv_requests_pending(BlockDriverState *bs)
-{
- BdrvChild *child;
-
- if (atomic_read(&bs->in_flight)) {
- return true;
- }
-
- QLIST_FOREACH(child, &bs->children, next) {
- if (bdrv_requests_pending(child->bs)) {
- return true;
- }
- }
-
- return false;
-}
-
typedef struct {
Coroutine *co;
BlockDriverState *bs;
bool done;
bool begin;
+ bool recursive;
+ BdrvChild *parent;
} BdrvCoDrainData;
static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
@@ -175,8 +165,10 @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
bdrv_wakeup(bs);
}
-static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
+/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
+static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive)
{
+ BdrvChild *child, *tmp;
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) ||
@@ -187,16 +179,19 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
data.co = qemu_coroutine_create(bdrv_drain_invoke_entry, &data);
bdrv_coroutine_enter(bs, data.co);
BDRV_POLL_WHILE(bs, !data.done);
+
+ if (recursive) {
+ QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
+ bdrv_drain_invoke(child->bs, begin, true);
+ }
+ }
}
-static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
+static bool bdrv_drain_recurse(BlockDriverState *bs)
{
BdrvChild *child, *tmp;
bool waited;
- /* Ensure any pending metadata writes are submitted to bs->file. */
- bdrv_drain_invoke(bs, begin);
-
/* Wait for drained requests to finish */
waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0);
@@ -215,7 +210,7 @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
*/
bdrv_ref(bs);
}
- waited |= bdrv_drain_recurse(bs, begin);
+ waited |= bdrv_drain_recurse(bs);
if (in_main_loop) {
bdrv_unref(bs);
}
@@ -224,6 +219,11 @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
return waited;
}
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
+ BdrvChild *parent);
+static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
+ BdrvChild *parent);
+
static void bdrv_co_drain_bh_cb(void *opaque)
{
BdrvCoDrainData *data = opaque;
@@ -232,9 +232,9 @@ static void bdrv_co_drain_bh_cb(void *opaque)
bdrv_dec_in_flight(bs);
if (data->begin) {
- bdrv_drained_begin(bs);
+ bdrv_do_drained_begin(bs, data->recursive, data->parent);
} else {
- bdrv_drained_end(bs);
+ bdrv_do_drained_end(bs, data->recursive, data->parent);
}
data->done = true;
@@ -242,7 +242,8 @@ static void bdrv_co_drain_bh_cb(void *opaque)
}
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
- bool begin)
+ bool begin, bool recursive,
+ BdrvChild *parent)
{
BdrvCoDrainData data;
@@ -256,6 +257,8 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
.bs = bs,
.done = false,
.begin = begin,
+ .recursive = recursive,
+ .parent = parent,
};
bdrv_inc_in_flight(bs);
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs),
@@ -267,35 +270,97 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
assert(data.done);
}
-void bdrv_drained_begin(BlockDriverState *bs)
+void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
+ BdrvChild *parent)
{
+ BdrvChild *child, *next;
+
if (qemu_in_coroutine()) {
- bdrv_co_yield_to_drain(bs, true);
+ bdrv_co_yield_to_drain(bs, true, recursive, parent);
return;
}
+ /* Stop things in parent-to-child order */
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
aio_disable_external(bdrv_get_aio_context(bs));
- bdrv_parent_drained_begin(bs);
}
- bdrv_drain_recurse(bs, true);
+ bdrv_parent_drained_begin(bs, parent);
+ bdrv_drain_invoke(bs, true, false);
+ bdrv_drain_recurse(bs);
+
+ if (recursive) {
+ bs->recursive_quiesce_counter++;
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
+ bdrv_do_drained_begin(child->bs, true, child);
+ }
+ }
}
-void bdrv_drained_end(BlockDriverState *bs)
+void bdrv_drained_begin(BlockDriverState *bs)
{
+ bdrv_do_drained_begin(bs, false, NULL);
+}
+
+void bdrv_subtree_drained_begin(BlockDriverState *bs)
+{
+ bdrv_do_drained_begin(bs, true, NULL);
+}
+
+void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
+ BdrvChild *parent)
+{
+ BdrvChild *child, *next;
+ int old_quiesce_counter;
+
if (qemu_in_coroutine()) {
- bdrv_co_yield_to_drain(bs, false);
+ bdrv_co_yield_to_drain(bs, false, recursive, parent);
return;
}
assert(bs->quiesce_counter > 0);
- if (atomic_fetch_dec(&bs->quiesce_counter) > 1) {
- return;
+ old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
+
+ /* Re-enable things in child-to-parent order */
+ bdrv_drain_invoke(bs, false, false);
+ bdrv_parent_drained_end(bs, parent);
+ if (old_quiesce_counter == 1) {
+ aio_enable_external(bdrv_get_aio_context(bs));
}
- bdrv_parent_drained_end(bs);
- bdrv_drain_recurse(bs, false);
- aio_enable_external(bdrv_get_aio_context(bs));
+ if (recursive) {
+ bs->recursive_quiesce_counter--;
+ QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
+ bdrv_do_drained_end(child->bs, true, child);
+ }
+ }
+}
+
+void bdrv_drained_end(BlockDriverState *bs)
+{
+ bdrv_do_drained_end(bs, false, NULL);
+}
+
+void bdrv_subtree_drained_end(BlockDriverState *bs)
+{
+ bdrv_do_drained_end(bs, true, NULL);
+}
+
+void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
+{
+ int i;
+
+ for (i = 0; i < new_parent->recursive_quiesce_counter; i++) {
+ bdrv_do_drained_begin(child->bs, true, child);
+ }
+}
+
+void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent)
+{
+ int i;
+
+ for (i = 0; i < old_parent->recursive_quiesce_counter; i++) {
+ bdrv_do_drained_end(child->bs, true, child);
+ }
}
/*
@@ -342,14 +407,20 @@ void bdrv_drain_all_begin(void)
BdrvNextIterator it;
GSList *aio_ctxs = NULL, *ctx;
- block_job_pause_all();
+ /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread
+ * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on
+ * nodes in several different AioContexts, so make sure we're in the main
+ * context. */
+ assert(qemu_get_current_aio_context() == qemu_get_aio_context());
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
AioContext *aio_context = bdrv_get_aio_context(bs);
+ /* Stop things in parent-to-child order */
aio_context_acquire(aio_context);
- bdrv_parent_drained_begin(bs);
aio_disable_external(aio_context);
+ bdrv_parent_drained_begin(bs, NULL);
+ bdrv_drain_invoke(bs, true, true);
aio_context_release(aio_context);
if (!g_slist_find(aio_ctxs, aio_context)) {
@@ -372,7 +443,7 @@ void bdrv_drain_all_begin(void)
aio_context_acquire(aio_context);
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
if (aio_context == bdrv_get_aio_context(bs)) {
- waited |= bdrv_drain_recurse(bs, true);
+ waited |= bdrv_drain_recurse(bs);
}
}
aio_context_release(aio_context);
@@ -390,14 +461,13 @@ void bdrv_drain_all_end(void)
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
AioContext *aio_context = bdrv_get_aio_context(bs);
+ /* Re-enable things in child-to-parent order */
aio_context_acquire(aio_context);
+ bdrv_drain_invoke(bs, false, true);
+ bdrv_parent_drained_end(bs, NULL);
aio_enable_external(aio_context);
- bdrv_parent_drained_end(bs);
- bdrv_drain_recurse(bs, false);
aio_context_release(aio_context);
}
-
- block_job_resume_all();
}
void bdrv_drain_all(void)
diff --git a/block/iscsi.c b/block/iscsi.c
index 4683f3b244..5c0a9e55b6 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -2,7 +2,7 @@
* QEMU Block driver for iSCSI images
*
* Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
- * Copyright (c) 2012-2016 Peter Lieven <pl@kamp.de>
+ * Copyright (c) 2012-2017 Peter Lieven <pl@kamp.de>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -104,6 +104,7 @@ typedef struct IscsiTask {
IscsiLun *iscsilun;
QEMUTimer retry_timer;
int err_code;
+ char *err_str;
} IscsiTask;
typedef struct IscsiAIOCB {
@@ -265,7 +266,7 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
}
}
iTask->err_code = iscsi_translate_sense(&task->sense);
- error_report("iSCSI Failure: %s", iscsi_get_error(iscsi));
+ iTask->err_str = g_strdup(iscsi_get_error(iscsi));
}
out:
@@ -629,6 +630,8 @@ retry:
if (iTask.status != SCSI_STATUS_GOOD) {
iscsi_allocmap_set_invalid(iscsilun, sector_num, nb_sectors);
+ error_report("iSCSI WRITE10/16 failed at lba %" PRIu64 ": %s", lba,
+ iTask.err_str);
r = iTask.err_code;
goto out_unlock;
}
@@ -637,6 +640,7 @@ retry:
out_unlock:
qemu_mutex_unlock(&iscsilun->mutex);
+ g_free(iTask.err_str);
return r;
}
@@ -651,10 +655,9 @@ static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
struct scsi_get_lba_status *lbas = NULL;
struct scsi_lba_status_descriptor *lbasd = NULL;
struct IscsiTask iTask;
+ uint64_t lba;
int64_t ret;
- iscsi_co_init_iscsitask(iscsilun, &iTask);
-
if (!is_sector_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
ret = -EINVAL;
goto out;
@@ -670,11 +673,13 @@ static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
goto out;
}
+ lba = sector_qemu2lun(sector_num, iscsilun);
+
+ iscsi_co_init_iscsitask(iscsilun, &iTask);
qemu_mutex_lock(&iscsilun->mutex);
retry:
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
- sector_qemu2lun(sector_num, iscsilun),
- 8 + 16, iscsi_co_generic_cb,
+ lba, 8 + 16, iscsi_co_generic_cb,
&iTask) == NULL) {
ret = -ENOMEM;
goto out_unlock;
@@ -701,6 +706,8 @@ retry:
* because the device is busy or the cmd is not
* supported) we pretend all blocks are allocated
* for backwards compatibility */
+ error_report("iSCSI GET_LBA_STATUS failed at lba %" PRIu64 ": %s",
+ lba, iTask.err_str);
goto out_unlock;
}
@@ -738,6 +745,7 @@ retry:
}
out_unlock:
qemu_mutex_unlock(&iscsilun->mutex);
+ g_free(iTask.err_str);
out:
if (iTask.task != NULL) {
scsi_free_scsi_task(iTask.task);
@@ -756,6 +764,7 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
struct IscsiTask iTask;
uint64_t lba;
uint32_t num_sectors;
+ int r = 0;
if (!is_sector_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
return -EINVAL;
@@ -853,19 +862,23 @@ retry:
iTask.complete = 0;
goto retry;
}
- qemu_mutex_unlock(&iscsilun->mutex);
if (iTask.status != SCSI_STATUS_GOOD) {
- return iTask.err_code;
+ error_report("iSCSI READ10/16 failed at lba %" PRIu64 ": %s",
+ lba, iTask.err_str);
+ r = iTask.err_code;
}
- return 0;
+ qemu_mutex_unlock(&iscsilun->mutex);
+ g_free(iTask.err_str);
+ return r;
}
static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
{
IscsiLun *iscsilun = bs->opaque;
struct IscsiTask iTask;
+ int r = 0;
iscsi_co_init_iscsitask(iscsilun, &iTask);
qemu_mutex_lock(&iscsilun->mutex);
@@ -892,13 +905,15 @@ retry:
iTask.complete = 0;
goto retry;
}
- qemu_mutex_unlock(&iscsilun->mutex);
if (iTask.status != SCSI_STATUS_GOOD) {
- return iTask.err_code;
+ error_report("iSCSI SYNCHRONIZECACHE10 failed: %s", iTask.err_str);
+ r = iTask.err_code;
}
- return 0;
+ qemu_mutex_unlock(&iscsilun->mutex);
+ g_free(iTask.err_str);
+ return r;
}
#ifdef __linux__
@@ -1128,6 +1143,9 @@ retry:
goto retry;
}
+ iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS,
+ bytes >> BDRV_SECTOR_BITS);
+
if (iTask.status == SCSI_STATUS_CHECK_CONDITION) {
/* the target might fail with a check condition if it
is not happy with the alignment of the UNMAP request
@@ -1136,15 +1154,15 @@ retry:
}
if (iTask.status != SCSI_STATUS_GOOD) {
+ error_report("iSCSI UNMAP failed at lba %" PRIu64 ": %s",
+ list.lba, iTask.err_str);
r = iTask.err_code;
goto out_unlock;
}
- iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS,
- bytes >> BDRV_SECTOR_BITS);
-
out_unlock:
qemu_mutex_unlock(&iscsilun->mutex);
+ g_free(iTask.err_str);
return r;
}
@@ -1241,6 +1259,8 @@ retry:
if (iTask.status != SCSI_STATUS_GOOD) {
iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS,
bytes >> BDRV_SECTOR_BITS);
+ error_report("iSCSI WRITESAME10/16 failed at lba %" PRIu64 ": %s",
+ lba, iTask.err_str);
r = iTask.err_code;
goto out_unlock;
}
@@ -1255,6 +1275,7 @@ retry:
out_unlock:
qemu_mutex_unlock(&iscsilun->mutex);
+ g_free(iTask.err_str);
return r;
}
diff --git a/block/nbd.c b/block/nbd.c
index a50d24b50a..8b8ba56cdd 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -388,6 +388,7 @@ static QemuOptsList nbd_runtime_opts = {
.type = QEMU_OPT_STRING,
.help = "ID of the TLS credentials to use",
},
+ { /* end of list */ }
},
};
diff --git a/block/null.c b/block/null.c
index dd9c13f9ba..0cdabaa440 100644
--- a/block/null.c
+++ b/block/null.c
@@ -110,8 +110,7 @@ static coroutine_fn int null_co_common(BlockDriverState *bs)
BDRVNullState *s = bs->opaque;
if (s->latency_ns) {
- co_aio_sleep_ns(bdrv_get_aio_context(bs), QEMU_CLOCK_REALTIME,
- s->latency_ns);
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, s->latency_ns);
}
return 0;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index 1914a940e5..4348b2c0c5 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1672,34 +1672,12 @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
return status;
}
-/* handle reading after the end of the backing file */
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
- int64_t offset, int bytes)
-{
- uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE;
- int n1;
-
- if ((offset + bytes) <= bs_size) {
- return bytes;
- }
-
- if (offset >= bs_size) {
- n1 = 0;
- } else {
- n1 = bs_size - offset;
- }
-
- qemu_iovec_memset(qiov, n1, 0, bytes - n1);
-
- return n1;
-}
-
static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
uint64_t bytes, QEMUIOVector *qiov,
int flags)
{
BDRVQcow2State *s = bs->opaque;
- int offset_in_cluster, n1;
+ int offset_in_cluster;
int ret;
unsigned int cur_bytes; /* number of bytes in current iteration */
uint64_t cluster_offset = 0;
@@ -1734,26 +1712,13 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
case QCOW2_CLUSTER_UNALLOCATED:
if (bs->backing) {
- /* read from the base image */
- n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov,
- offset, cur_bytes);
- if (n1 > 0) {
- QEMUIOVector local_qiov;
-
- qemu_iovec_init(&local_qiov, hd_qiov.niov);
- qemu_iovec_concat(&local_qiov, &hd_qiov, 0, n1);
-
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
- qemu_co_mutex_unlock(&s->lock);
- ret = bdrv_co_preadv(bs->backing, offset, n1,
- &local_qiov, 0);
- qemu_co_mutex_lock(&s->lock);
-
- qemu_iovec_destroy(&local_qiov);
-
- if (ret < 0) {
- goto fail;
- }
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
+ qemu_co_mutex_unlock(&s->lock);
+ ret = bdrv_co_preadv(bs->backing, offset, cur_bytes,
+ &hd_qiov, 0);
+ qemu_co_mutex_lock(&s->lock);
+ if (ret < 0) {
+ goto fail;
}
} else {
/* Note: in this case, no need to wait */
diff --git a/block/qcow2.h b/block/qcow2.h
index 6f0ff15dd0..46c8cf44ec 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -528,9 +528,6 @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset)
}
/* qcow2.c functions */
-int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
- int64_t sector_num, int nb_sectors);
-
int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
int refcount_order, bool generous_increase,
uint64_t *refblock_count);
diff --git a/block/replication.c b/block/replication.c
index e41e293d2b..b1ea3caa4b 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -394,6 +394,9 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
new_secondary_flags = s->orig_secondary_flags;
}
+ bdrv_subtree_drained_begin(s->hidden_disk->bs);
+ bdrv_subtree_drained_begin(s->secondary_disk->bs);
+
if (orig_hidden_flags != new_hidden_flags) {
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL,
new_hidden_flags);
@@ -409,6 +412,9 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
reopen_queue, &local_err);
error_propagate(errp, local_err);
}
+
+ bdrv_subtree_drained_end(s->hidden_disk->bs);
+ bdrv_subtree_drained_end(s->secondary_disk->bs);
}
static void backup_job_cleanup(BlockDriverState *bs)
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 696a71442a..f684477328 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -400,7 +400,7 @@ typedef struct BDRVSheepdogReopenState {
int cache_flags;
} BDRVSheepdogReopenState;
-static const char * sd_strerror(int err)
+static const char *sd_strerror(int err)
{
int i;
@@ -776,8 +776,7 @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
if (s->fd < 0) {
DPRINTF("Wait for connection to be established\n");
error_report_err(local_err);
- co_aio_sleep_ns(bdrv_get_aio_context(s->bs), QEMU_CLOCK_REALTIME,
- 1000000000ULL);
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000000ULL);
}
};
@@ -1632,7 +1631,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
if (!tag) {
tag = "";
}
- if (tag && strlen(tag) >= SD_MAX_VDI_TAG_LEN) {
+ if (strlen(tag) >= SD_MAX_VDI_TAG_LEN) {
error_setg(errp, "value of parameter 'tag' is too long");
ret = -EINVAL;
goto err_no_fd;
@@ -3078,111 +3077,111 @@ static QemuOptsList sd_create_opts = {
};
static BlockDriver bdrv_sheepdog = {
- .format_name = "sheepdog",
- .protocol_name = "sheepdog",
- .instance_size = sizeof(BDRVSheepdogState),
- .bdrv_parse_filename = sd_parse_filename,
- .bdrv_file_open = sd_open,
- .bdrv_reopen_prepare = sd_reopen_prepare,
- .bdrv_reopen_commit = sd_reopen_commit,
- .bdrv_reopen_abort = sd_reopen_abort,
- .bdrv_close = sd_close,
- .bdrv_create = sd_create,
- .bdrv_has_zero_init = bdrv_has_zero_init_1,
- .bdrv_getlength = sd_getlength,
+ .format_name = "sheepdog",
+ .protocol_name = "sheepdog",
+ .instance_size = sizeof(BDRVSheepdogState),
+ .bdrv_parse_filename = sd_parse_filename,
+ .bdrv_file_open = sd_open,
+ .bdrv_reopen_prepare = sd_reopen_prepare,
+ .bdrv_reopen_commit = sd_reopen_commit,
+ .bdrv_reopen_abort = sd_reopen_abort,
+ .bdrv_close = sd_close,
+ .bdrv_create = sd_create,
+ .bdrv_has_zero_init = bdrv_has_zero_init_1,
+ .bdrv_getlength = sd_getlength,
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
- .bdrv_truncate = sd_truncate,
+ .bdrv_truncate = sd_truncate,
- .bdrv_co_readv = sd_co_readv,
- .bdrv_co_writev = sd_co_writev,
- .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
- .bdrv_co_pdiscard = sd_co_pdiscard,
- .bdrv_co_get_block_status = sd_co_get_block_status,
+ .bdrv_co_readv = sd_co_readv,
+ .bdrv_co_writev = sd_co_writev,
+ .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
+ .bdrv_co_pdiscard = sd_co_pdiscard,
+ .bdrv_co_get_block_status = sd_co_get_block_status,
- .bdrv_snapshot_create = sd_snapshot_create,
- .bdrv_snapshot_goto = sd_snapshot_goto,
- .bdrv_snapshot_delete = sd_snapshot_delete,
- .bdrv_snapshot_list = sd_snapshot_list,
+ .bdrv_snapshot_create = sd_snapshot_create,
+ .bdrv_snapshot_goto = sd_snapshot_goto,
+ .bdrv_snapshot_delete = sd_snapshot_delete,
+ .bdrv_snapshot_list = sd_snapshot_list,
- .bdrv_save_vmstate = sd_save_vmstate,
- .bdrv_load_vmstate = sd_load_vmstate,
+ .bdrv_save_vmstate = sd_save_vmstate,
+ .bdrv_load_vmstate = sd_load_vmstate,
- .bdrv_detach_aio_context = sd_detach_aio_context,
- .bdrv_attach_aio_context = sd_attach_aio_context,
+ .bdrv_detach_aio_context = sd_detach_aio_context,
+ .bdrv_attach_aio_context = sd_attach_aio_context,
- .create_opts = &sd_create_opts,
+ .create_opts = &sd_create_opts,
};
static BlockDriver bdrv_sheepdog_tcp = {
- .format_name = "sheepdog",
- .protocol_name = "sheepdog+tcp",
- .instance_size = sizeof(BDRVSheepdogState),
- .bdrv_parse_filename = sd_parse_filename,
- .bdrv_file_open = sd_open,
- .bdrv_reopen_prepare = sd_reopen_prepare,
- .bdrv_reopen_commit = sd_reopen_commit,
- .bdrv_reopen_abort = sd_reopen_abort,
- .bdrv_close = sd_close,
- .bdrv_create = sd_create,
- .bdrv_has_zero_init = bdrv_has_zero_init_1,
- .bdrv_getlength = sd_getlength,
+ .format_name = "sheepdog",
+ .protocol_name = "sheepdog+tcp",
+ .instance_size = sizeof(BDRVSheepdogState),
+ .bdrv_parse_filename = sd_parse_filename,
+ .bdrv_file_open = sd_open,
+ .bdrv_reopen_prepare = sd_reopen_prepare,
+ .bdrv_reopen_commit = sd_reopen_commit,
+ .bdrv_reopen_abort = sd_reopen_abort,
+ .bdrv_close = sd_close,
+ .bdrv_create = sd_create,
+ .bdrv_has_zero_init = bdrv_has_zero_init_1,
+ .bdrv_getlength = sd_getlength,
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
- .bdrv_truncate = sd_truncate,
+ .bdrv_truncate = sd_truncate,
- .bdrv_co_readv = sd_co_readv,
- .bdrv_co_writev = sd_co_writev,
- .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
- .bdrv_co_pdiscard = sd_co_pdiscard,
- .bdrv_co_get_block_status = sd_co_get_block_status,
+ .bdrv_co_readv = sd_co_readv,
+ .bdrv_co_writev = sd_co_writev,
+ .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
+ .bdrv_co_pdiscard = sd_co_pdiscard,
+ .bdrv_co_get_block_status = sd_co_get_block_status,
- .bdrv_snapshot_create = sd_snapshot_create,
- .bdrv_snapshot_goto = sd_snapshot_goto,
- .bdrv_snapshot_delete = sd_snapshot_delete,
- .bdrv_snapshot_list = sd_snapshot_list,
+ .bdrv_snapshot_create = sd_snapshot_create,
+ .bdrv_snapshot_goto = sd_snapshot_goto,
+ .bdrv_snapshot_delete = sd_snapshot_delete,
+ .bdrv_snapshot_list = sd_snapshot_list,
- .bdrv_save_vmstate = sd_save_vmstate,
- .bdrv_load_vmstate = sd_load_vmstate,
+ .bdrv_save_vmstate = sd_save_vmstate,
+ .bdrv_load_vmstate = sd_load_vmstate,
- .bdrv_detach_aio_context = sd_detach_aio_context,
- .bdrv_attach_aio_context = sd_attach_aio_context,
+ .bdrv_detach_aio_context = sd_detach_aio_context,
+ .bdrv_attach_aio_context = sd_attach_aio_context,
- .create_opts = &sd_create_opts,
+ .create_opts = &sd_create_opts,
};
static BlockDriver bdrv_sheepdog_unix = {
- .format_name = "sheepdog",
- .protocol_name = "sheepdog+unix",
- .instance_size = sizeof(BDRVSheepdogState),
- .bdrv_parse_filename = sd_parse_filename,
- .bdrv_file_open = sd_open,
- .bdrv_reopen_prepare = sd_reopen_prepare,
- .bdrv_reopen_commit = sd_reopen_commit,
- .bdrv_reopen_abort = sd_reopen_abort,
- .bdrv_close = sd_close,
- .bdrv_create = sd_create,
- .bdrv_has_zero_init = bdrv_has_zero_init_1,
- .bdrv_getlength = sd_getlength,
+ .format_name = "sheepdog",
+ .protocol_name = "sheepdog+unix",
+ .instance_size = sizeof(BDRVSheepdogState),
+ .bdrv_parse_filename = sd_parse_filename,
+ .bdrv_file_open = sd_open,
+ .bdrv_reopen_prepare = sd_reopen_prepare,
+ .bdrv_reopen_commit = sd_reopen_commit,
+ .bdrv_reopen_abort = sd_reopen_abort,
+ .bdrv_close = sd_close,
+ .bdrv_create = sd_create,
+ .bdrv_has_zero_init = bdrv_has_zero_init_1,
+ .bdrv_getlength = sd_getlength,
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
- .bdrv_truncate = sd_truncate,
+ .bdrv_truncate = sd_truncate,
- .bdrv_co_readv = sd_co_readv,
- .bdrv_co_writev = sd_co_writev,
- .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
- .bdrv_co_pdiscard = sd_co_pdiscard,
- .bdrv_co_get_block_status = sd_co_get_block_status,
+ .bdrv_co_readv = sd_co_readv,
+ .bdrv_co_writev = sd_co_writev,
+ .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
+ .bdrv_co_pdiscard = sd_co_pdiscard,
+ .bdrv_co_get_block_status = sd_co_get_block_status,
- .bdrv_snapshot_create = sd_snapshot_create,
- .bdrv_snapshot_goto = sd_snapshot_goto,
- .bdrv_snapshot_delete = sd_snapshot_delete,
- .bdrv_snapshot_list = sd_snapshot_list,
+ .bdrv_snapshot_create = sd_snapshot_create,
+ .bdrv_snapshot_goto = sd_snapshot_goto,
+ .bdrv_snapshot_delete = sd_snapshot_delete,
+ .bdrv_snapshot_list = sd_snapshot_list,
- .bdrv_save_vmstate = sd_save_vmstate,
- .bdrv_load_vmstate = sd_load_vmstate,
+ .bdrv_save_vmstate = sd_save_vmstate,
+ .bdrv_load_vmstate = sd_load_vmstate,
- .bdrv_detach_aio_context = sd_detach_aio_context,
- .bdrv_attach_aio_context = sd_attach_aio_context,
+ .bdrv_detach_aio_context = sd_detach_aio_context,
+ .bdrv_attach_aio_context = sd_attach_aio_context,
- .create_opts = &sd_create_opts,
+ .create_opts = &sd_create_opts,
};
static void bdrv_sheepdog_init(void)