diff options
Diffstat (limited to 'block')
| -rw-r--r-- | block/backup.c | 71 | ||||
| -rw-r--r-- | block/block-backend.c | 123 | ||||
| -rw-r--r-- | block/commit.c | 53 | ||||
| -rw-r--r-- | block/io.c | 97 | ||||
| -rw-r--r-- | block/mirror.c | 100 | ||||
| -rw-r--r-- | block/parallels.c | 4 | ||||
| -rw-r--r-- | block/snapshot.c | 55 | ||||
| -rw-r--r-- | block/stream.c | 15 | ||||
| -rw-r--r-- | block/vvfat.c | 8 |
9 files changed, 258 insertions, 268 deletions
diff --git a/block/backup.c b/block/backup.c index fec45e8212..feeb9f8bf2 100644 --- a/block/backup.c +++ b/block/backup.c @@ -36,7 +36,7 @@ typedef struct CowRequest { typedef struct BackupBlockJob { BlockJob common; - BlockDriverState *target; + BlockBackend *target; /* bitmap for sync=incremental */ BdrvDirtyBitmap *sync_bitmap; MirrorSyncMode sync_mode; @@ -47,6 +47,7 @@ typedef struct BackupBlockJob { uint64_t sectors_read; unsigned long *done_bitmap; int64_t cluster_size; + NotifierWithReturn before_write; QLIST_HEAD(, CowRequest) inflight_reqs; } BackupBlockJob; @@ -93,12 +94,12 @@ static void cow_request_end(CowRequest *req) qemu_co_queue_restart_all(&req->wait_queue); } -static int coroutine_fn backup_do_cow(BlockDriverState *bs, +static int coroutine_fn backup_do_cow(BackupBlockJob *job, int64_t sector_num, int nb_sectors, bool *error_is_read, bool is_write_notifier) { - BackupBlockJob *job = (BackupBlockJob *)bs->job; + BlockBackend *blk = job->common.blk; CowRequest cow_request; struct iovec iov; QEMUIOVector bounce_qiov; @@ -131,20 +132,15 @@ static int coroutine_fn backup_do_cow(BlockDriverState *bs, start * sectors_per_cluster); if (!bounce_buffer) { - bounce_buffer = qemu_blockalign(bs, job->cluster_size); + bounce_buffer = blk_blockalign(blk, job->cluster_size); } iov.iov_base = bounce_buffer; iov.iov_len = n * BDRV_SECTOR_SIZE; qemu_iovec_init_external(&bounce_qiov, &iov, 1); - if (is_write_notifier) { - ret = bdrv_co_readv_no_serialising(bs, - start * sectors_per_cluster, - n, &bounce_qiov); - } else { - ret = bdrv_co_readv(bs, start * sectors_per_cluster, n, - &bounce_qiov); - } + ret = blk_co_preadv(blk, start * job->cluster_size, + bounce_qiov.size, &bounce_qiov, + is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0); if (ret < 0) { trace_backup_do_cow_read_fail(job, start, ret); if (error_is_read) { @@ -154,13 +150,11 @@ static int coroutine_fn backup_do_cow(BlockDriverState *bs, } if (buffer_is_zero(iov.iov_base, iov.iov_len)) { - ret = bdrv_co_write_zeroes(job->target, - start * sectors_per_cluster, - n, BDRV_REQ_MAY_UNMAP); + ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size, + bounce_qiov.size, BDRV_REQ_MAY_UNMAP); } else { - ret = bdrv_co_writev(job->target, - start * sectors_per_cluster, n, - &bounce_qiov); + ret = blk_co_pwritev(job->target, start * job->cluster_size, + bounce_qiov.size, &bounce_qiov, 0); } if (ret < 0) { trace_backup_do_cow_write_fail(job, start, ret); @@ -197,14 +191,16 @@ static int coroutine_fn backup_before_write_notify( NotifierWithReturn *notifier, void *opaque) { + BackupBlockJob *job = container_of(notifier, BackupBlockJob, before_write); BdrvTrackedRequest *req = opaque; int64_t sector_num = req->offset >> BDRV_SECTOR_BITS; int nb_sectors = req->bytes >> BDRV_SECTOR_BITS; + assert(req->bs == blk_bs(job->common.blk)); assert((req->offset & (BDRV_SECTOR_SIZE - 1)) == 0); assert((req->bytes & (BDRV_SECTOR_SIZE - 1)) == 0); - return backup_do_cow(req->bs, sector_num, nb_sectors, NULL, true); + return backup_do_cow(job, sector_num, nb_sectors, NULL, true); } static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp) @@ -221,7 +217,7 @@ static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp) static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret) { BdrvDirtyBitmap *bm; - BlockDriverState *bs = job->common.bs; + BlockDriverState *bs = blk_bs(job->common.blk); if (ret < 0 || block_job_is_cancelled(&job->common)) { /* Merge the successor back into the parent, delete nothing. */ @@ -279,7 +275,7 @@ static void backup_complete(BlockJob *job, void *opaque) BackupBlockJob *s = container_of(job, BackupBlockJob, common); BackupCompleteData *data = opaque; - bdrv_unref(s->target); + blk_unref(s->target); block_job_completed(job, data->ret); g_free(data); @@ -321,7 +317,6 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job) int64_t end; int64_t last_cluster = -1; int64_t sectors_per_cluster = cluster_size_sectors(job); - BlockDriverState *bs = job->common.bs; HBitmapIter hbi; granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap); @@ -343,7 +338,7 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job) if (yield_and_check(job)) { return ret; } - ret = backup_do_cow(bs, cluster * sectors_per_cluster, + ret = backup_do_cow(job, cluster * sectors_per_cluster, sectors_per_cluster, &error_is_read, false); if ((ret < 0) && @@ -376,11 +371,8 @@ static void coroutine_fn backup_run(void *opaque) { BackupBlockJob *job = opaque; BackupCompleteData *data; - BlockDriverState *bs = job->common.bs; - BlockDriverState *target = job->target; - NotifierWithReturn before_write = { - .notify = backup_before_write_notify, - }; + BlockDriverState *bs = blk_bs(job->common.blk); + BlockBackend *target = job->target; int64_t start, end; int64_t sectors_per_cluster = cluster_size_sectors(job); int ret = 0; @@ -393,7 +385,8 @@ static void coroutine_fn backup_run(void *opaque) job->done_bitmap = bitmap_new(end); - bdrv_add_before_write_notifier(bs, &before_write); + 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) { while (!block_job_is_cancelled(&job->common)) { @@ -445,7 +438,7 @@ static void coroutine_fn backup_run(void *opaque) } } /* FULL sync mode we copy the whole drive. */ - ret = backup_do_cow(bs, start * sectors_per_cluster, + ret = backup_do_cow(job, start * sectors_per_cluster, sectors_per_cluster, &error_is_read, false); if (ret < 0) { /* Depending on error action, fail now or retry cluster */ @@ -461,14 +454,14 @@ static void coroutine_fn backup_run(void *opaque) } } - notifier_with_return_remove(&before_write); + notifier_with_return_remove(&job->before_write); /* 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); - bdrv_op_unblock_all(target, job->common.blocker); + bdrv_op_unblock_all(blk_bs(target), job->common.blocker); data = g_malloc(sizeof(*data)); data->ret = ret; @@ -485,6 +478,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target, { int64_t len; BlockDriverInfo bdi; + BackupBlockJob *job = NULL; int ret; assert(bs); @@ -542,15 +536,16 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target, goto error; } - BackupBlockJob *job = block_job_create(&backup_job_driver, bs, speed, - cb, opaque, errp); + job = block_job_create(&backup_job_driver, bs, speed, cb, opaque, errp); if (!job) { goto error; } + job->target = blk_new(); + blk_insert_bs(job->target, target); + job->on_source_error = on_source_error; job->on_target_error = on_target_error; - job->target = target; job->sync_mode = sync_mode; job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_INCREMENTAL ? sync_bitmap : NULL; @@ -558,7 +553,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target, /* If there is no backing file on the target, we cannot rely on COW if our * backup cluster size is smaller than the target cluster size. Even for * targets with a backing file, try to avoid COW if possible. */ - ret = bdrv_get_info(job->target, &bdi); + ret = bdrv_get_info(target, &bdi); if (ret < 0 && !target->backing) { error_setg_errno(errp, -ret, "Couldn't determine the cluster size of the target image, " @@ -584,4 +579,8 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target, if (sync_bitmap) { bdrv_reclaim_dirty_bitmap(bs, sync_bitmap, NULL); } + if (job) { + blk_unref(job->target); + block_job_unref(&job->common); + } } diff --git a/block/block-backend.c b/block/block-backend.c index 6928d61de4..34500e6080 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -19,6 +19,7 @@ #include "sysemu/sysemu.h" #include "qapi-event.h" #include "qemu/id.h" +#include "trace.h" /* Number of coroutines to reserve per attached device model */ #define COROUTINE_POOL_RESERVATION 64 @@ -119,12 +120,14 @@ static const BdrvChildRole child_root = { * Store an error through @errp on failure, unless it's null. * Return the new BlockBackend on success, null on failure. */ -BlockBackend *blk_new(Error **errp) +BlockBackend *blk_new(void) { BlockBackend *blk; blk = g_new0(BlockBackend, 1); blk->refcnt = 1; + blk_set_enable_write_cache(blk, true); + qemu_co_queue_init(&blk->public.throttled_reqs[0]); qemu_co_queue_init(&blk->public.throttled_reqs[1]); @@ -136,27 +139,7 @@ BlockBackend *blk_new(Error **errp) } /* - * Create a new BlockBackend with a new BlockDriverState attached. - * Otherwise just like blk_new(), which see. - */ -BlockBackend *blk_new_with_bs(Error **errp) -{ - BlockBackend *blk; - BlockDriverState *bs; - - blk = blk_new(errp); - if (!blk) { - return NULL; - } - - bs = bdrv_new_root(); - blk->root = bdrv_root_attach_child(bs, "root", &child_root); - blk->root->opaque = blk; - return blk; -} - -/* - * Calls blk_new_with_bs() and then calls bdrv_open() on the BlockDriverState. + * Creates a new BlockBackend, opens a new BlockDriverState, and connects both. * * Just as with bdrv_open(), after having called this function the reference to * @options belongs to the block layer (even on failure). @@ -171,21 +154,16 @@ BlockBackend *blk_new_open(const char *filename, const char *reference, QDict *options, int flags, Error **errp) { BlockBackend *blk; - int ret; - - blk = blk_new_with_bs(errp); - if (!blk) { - QDECREF(options); - return NULL; - } + BlockDriverState *bs; - ret = bdrv_open(&blk->root->bs, filename, reference, options, flags, errp); - if (ret < 0) { + blk = blk_new(); + bs = bdrv_open(filename, reference, options, flags, errp); + if (!bs) { blk_unref(blk); return NULL; } - blk_set_enable_write_cache(blk, true); + blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk); return blk; } @@ -286,25 +264,11 @@ BlockBackend *blk_next(BlockBackend *blk) : QTAILQ_FIRST(&monitor_block_backends); } -struct BdrvNextIterator { - enum { - BDRV_NEXT_BACKEND_ROOTS, - BDRV_NEXT_MONITOR_OWNED, - } phase; - BlockBackend *blk; - BlockDriverState *bs; -}; - /* Iterates over all top-level BlockDriverStates, i.e. BDSs that are owned by * the monitor or attached to a BlockBackend */ -BdrvNextIterator *bdrv_next(BdrvNextIterator *it, BlockDriverState **bs) +BlockDriverState *bdrv_next(BdrvNextIterator *it) { - if (!it) { - it = g_new(BdrvNextIterator, 1); - *it = (BdrvNextIterator) { - .phase = BDRV_NEXT_BACKEND_ROOTS, - }; - } + BlockDriverState *bs; /* First, return all root nodes of BlockBackends. In order to avoid * returning a BDS twice when multiple BBs refer to it, we only return it @@ -312,11 +276,11 @@ BdrvNextIterator *bdrv_next(BdrvNextIterator *it, BlockDriverState **bs) if (it->phase == BDRV_NEXT_BACKEND_ROOTS) { do { it->blk = blk_all_next(it->blk); - *bs = it->blk ? blk_bs(it->blk) : NULL; - } while (it->blk && (*bs == NULL || bdrv_first_blk(*bs) != it->blk)); + bs = it->blk ? blk_bs(it->blk) : NULL; + } while (it->blk && (bs == NULL || bdrv_first_blk(bs) != it->blk)); - if (*bs) { - return it; + if (bs) { + return bs; } it->phase = BDRV_NEXT_MONITOR_OWNED; } @@ -326,10 +290,19 @@ BdrvNextIterator *bdrv_next(BdrvNextIterator *it, BlockDriverState **bs) * by the above block already */ do { it->bs = bdrv_next_monitor_owned(it->bs); - *bs = it->bs; - } while (*bs && bdrv_has_blk(*bs)); + bs = it->bs; + } while (bs && bdrv_has_blk(bs)); - return *bs ? it : NULL; + return bs; +} + +BlockDriverState *bdrv_first(BdrvNextIterator *it) +{ + *it = (BdrvNextIterator) { + .phase = BDRV_NEXT_BACKEND_ROOTS, + }; + + return bdrv_next(it); } /* @@ -509,8 +482,7 @@ void blk_remove_bs(BlockBackend *blk) void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs) { bdrv_ref(bs); - blk->root = bdrv_root_attach_child(bs, "root", &child_root); - blk->root->opaque = blk; + blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk); notifier_list_notify(&blk->insert_bs_notifiers, blk); if (blk->public.throttle_state) { @@ -770,11 +742,15 @@ static int blk_check_request(BlockBackend *blk, int64_t sector_num, nb_sectors * BDRV_SECTOR_SIZE); } -static int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, - unsigned int bytes, QEMUIOVector *qiov, - BdrvRequestFlags flags) +int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, + unsigned int bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags) { - int ret = blk_check_byte_request(blk, offset, bytes); + int ret; + + trace_blk_co_preadv(blk, blk_bs(blk), offset, bytes, flags); + + ret = blk_check_byte_request(blk, offset, bytes); if (ret < 0) { return ret; } @@ -787,12 +763,14 @@ static int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, return bdrv_co_preadv(blk_bs(blk), offset, bytes, qiov, flags); } -static int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset, - unsigned int bytes, QEMUIOVector *qiov, - BdrvRequestFlags flags) +int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset, + unsigned int bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags) { int ret; + trace_blk_co_pwritev(blk, blk_bs(blk), offset, bytes, flags); + ret = blk_check_byte_request(blk, offset, bytes); if (ret < 0) { return ret; @@ -885,8 +863,8 @@ int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf, return ret; } -int blk_write_zeroes(BlockBackend *blk, int64_t offset, - int count, BdrvRequestFlags flags) +int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset, + int count, BdrvRequestFlags flags) { return blk_prw(blk, offset, NULL, count, blk_write_entry, flags | BDRV_REQ_ZERO_WRITE); @@ -1001,9 +979,9 @@ static void blk_aio_write_entry(void *opaque) blk_aio_complete(acb); } -BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t offset, - int count, BdrvRequestFlags flags, - BlockCompletionFunc *cb, void *opaque) +BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset, + int count, BdrvRequestFlags flags, + BlockCompletionFunc *cb, void *opaque) { return blk_aio_prwv(blk, offset, count, NULL, blk_aio_write_entry, flags | BDRV_REQ_ZERO_WRITE, cb, opaque); @@ -1492,8 +1470,8 @@ void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk, return qemu_aio_get(aiocb_info, blk_bs(blk), cb, opaque); } -int coroutine_fn blk_co_write_zeroes(BlockBackend *blk, int64_t offset, - int count, BdrvRequestFlags flags) +int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, + int count, BdrvRequestFlags flags) { return blk_co_pwritev(blk, offset, count, NULL, flags | BDRV_REQ_ZERO_WRITE); @@ -1704,6 +1682,9 @@ static void blk_root_drained_begin(BdrvChild *child) { BlockBackend *blk = child->opaque; + /* Note that blk->root may not be accessible here yet if we are just + * attaching to a BlockDriverState that is drained. Use child instead. */ + if (blk->public.io_limits_disabled++ == 0) { throttle_group_restart_blk(blk); } diff --git a/block/commit.c b/block/commit.c index f308c8c6f0..8a00e1146c 100644 --- a/block/commit.c +++ b/block/commit.c @@ -36,28 +36,36 @@ typedef struct CommitBlockJob { BlockJob common; RateLimit limit; BlockDriverState *active; - BlockDriverState *top; - BlockDriverState *base; + BlockBackend *top; + BlockBackend *base; BlockdevOnError on_error; int base_flags; int orig_overlay_flags; char *backing_file_str; } CommitBlockJob; -static int coroutine_fn commit_populate(BlockDriverState *bs, - BlockDriverState *base, +static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base, int64_t sector_num, int nb_sectors, void *buf) { int ret = 0; + QEMUIOVector qiov; + struct iovec iov = { + .iov_base = buf, + .iov_len = nb_sectors * BDRV_SECTOR_SIZE, + }; - ret = bdrv_read(bs, sector_num, buf, nb_sectors); - if (ret) { + qemu_iovec_init_external(&qiov, &iov, 1); + + ret = blk_co_preadv(bs, sector_num * BDRV_SECTOR_SIZE, + qiov.size, &qiov, 0); + if (ret < 0) { return ret; } - ret = bdrv_write(base, sector_num, buf, nb_sectors); - if (ret) { + ret = blk_co_pwritev(base, sector_num * BDRV_SECTOR_SIZE, + qiov.size, &qiov, 0); + if (ret < 0) { return ret; } @@ -73,8 +81,8 @@ static void commit_complete(BlockJob *job, void *opaque) CommitBlockJob *s = container_of(job, CommitBlockJob, common); CommitCompleteData *data = opaque; BlockDriverState *active = s->active; - BlockDriverState *top = s->top; - BlockDriverState *base = s->base; + BlockDriverState *top = blk_bs(s->top); + BlockDriverState *base = blk_bs(s->base); BlockDriverState *overlay_bs; int ret = data->ret; @@ -94,6 +102,8 @@ static void commit_complete(BlockJob *job, void *opaque) bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL); } g_free(s->backing_file_str); + blk_unref(s->top); + blk_unref(s->base); block_job_completed(&s->common, ret); g_free(data); } @@ -102,8 +112,6 @@ static void coroutine_fn commit_run(void *opaque) { CommitBlockJob *s = opaque; CommitCompleteData *data; - BlockDriverState *top = s->top; - BlockDriverState *base = s->base; int64_t sector_num, end; int ret = 0; int n = 0; @@ -111,27 +119,27 @@ static void coroutine_fn commit_run(void *opaque) int bytes_written = 0; int64_t base_len; - ret = s->common.len = bdrv_getlength(top); + ret = s->common.len = blk_getlength(s->top); if (s->common.len < 0) { goto out; } - ret = base_len = bdrv_getlength(base); + ret = base_len = blk_getlength(s->base); if (base_len < 0) { goto out; } if (base_len < s->common.len) { - ret = bdrv_truncate(base, s->common.len); + ret = blk_truncate(s->base, s->common.len); if (ret) { goto out; } } end = s->common.len >> BDRV_SECTOR_BITS; - buf = qemu_blockalign(top, COMMIT_BUFFER_SIZE); + buf = blk_blockalign(s->top, COMMIT_BUFFER_SIZE); for (sector_num = 0; sector_num < end; sector_num += n) { uint64_t delay_ns = 0; @@ -146,7 +154,8 @@ wait: break; } /* Copy if allocated above the base */ - ret = bdrv_is_allocated_above(top, base, sector_num, + ret = bdrv_is_allocated_above(blk_bs(s->top), blk_bs(s->base), + sector_num, COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n); copy = (ret == 1); @@ -158,7 +167,7 @@ wait: goto wait; } } - ret = commit_populate(top, base, sector_num, n, buf); + ret = commit_populate(s->top, s->base, sector_num, n, buf); bytes_written += n * BDRV_SECTOR_SIZE; } if (ret < 0) { @@ -253,8 +262,12 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, return; } - s->base = base; - s->top = top; + s->base = blk_new(); + blk_insert_bs(s->base, base); + + s->top = blk_new(); + blk_insert_bs(s->top, top); + s->active = bs; s->base_flags = orig_base_flags; diff --git a/block/io.c b/block/io.c index 60a6bd8bdb..2d832aa532 100644 --- a/block/io.c +++ b/block/io.c @@ -225,6 +225,34 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs) assert(data.done); } +void bdrv_drained_begin(BlockDriverState *bs) +{ + if (!bs->quiesce_counter++) { + aio_disable_external(bdrv_get_aio_context(bs)); + bdrv_parent_drained_begin(bs); + } + + bdrv_io_unplugged_begin(bs); + bdrv_drain_recurse(bs); + if (qemu_in_coroutine()) { + bdrv_co_yield_to_drain(bs); + } else { + bdrv_drain_poll(bs); + } + bdrv_io_unplugged_end(bs); +} + +void bdrv_drained_end(BlockDriverState *bs) +{ + assert(bs->quiesce_counter > 0); + if (--bs->quiesce_counter > 0) { + return; + } + + bdrv_parent_drained_end(bs); + aio_enable_external(bdrv_get_aio_context(bs)); +} + /* * Wait for pending requests to complete on a single BlockDriverState subtree, * and suspend block driver's internal I/O until next request arrives. @@ -238,26 +266,15 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs) */ void coroutine_fn bdrv_co_drain(BlockDriverState *bs) { - bdrv_parent_drained_begin(bs); - bdrv_io_unplugged_begin(bs); - bdrv_drain_recurse(bs); - bdrv_co_yield_to_drain(bs); - bdrv_io_unplugged_end(bs); - bdrv_parent_drained_end(bs); + assert(qemu_in_coroutine()); + bdrv_drained_begin(bs); + bdrv_drained_end(bs); } void bdrv_drain(BlockDriverState *bs) { - bdrv_parent_drained_begin(bs); - bdrv_io_unplugged_begin(bs); - bdrv_drain_recurse(bs); - if (qemu_in_coroutine()) { - bdrv_co_yield_to_drain(bs); - } else { - bdrv_drain_poll(bs); - } - bdrv_io_unplugged_end(bs); - bdrv_parent_drained_end(bs); + bdrv_drained_begin(bs); + bdrv_drained_end(bs); } /* @@ -271,10 +288,10 @@ void bdrv_drain_all(void) /* Always run first iteration so any pending completion BHs run */ bool busy = true; BlockDriverState *bs; - BdrvNextIterator *it = NULL; + BdrvNextIterator it; GSList *aio_ctxs = NULL, *ctx; - while ((it = bdrv_next(it, &bs))) { + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); @@ -302,10 +319,9 @@ void bdrv_drain_all(void) for (ctx = aio_ctxs; ctx != NULL; ctx = ctx->next) { AioContext *aio_context = ctx->data; - it = NULL; aio_context_acquire(aio_context); - while ((it = bdrv_next(it, &bs))) { + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { if (aio_context == bdrv_get_aio_context(bs)) { if (bdrv_requests_pending(bs)) { busy = true; @@ -318,8 +334,7 @@ void bdrv_drain_all(void) } } - it = NULL; - while ((it = bdrv_next(it, &bs))) { + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); @@ -1093,24 +1108,6 @@ int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num, return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov, 0); } -int coroutine_fn bdrv_co_readv_no_serialising(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) -{ - trace_bdrv_co_readv_no_serialising(bs, sector_num, nb_sectors); - - return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov, - BDRV_REQ_NO_SERIALISING); -} - -int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) -{ - trace_bdrv_co_copy_on_readv(bs, sector_num, nb_sectors); - - return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov, - BDRV_REQ_COPY_ON_READ); -} - #define MAX_WRITE_ZEROES_BOUNCE_BUFFER 32768 static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs, @@ -2543,23 +2540,3 @@ void bdrv_io_unplugged_end(BlockDriverState *bs) } } } - -void bdrv_drained_begin(BlockDriverState *bs) -{ - if (!bs->quiesce_counter++) { - aio_disable_external(bdrv_get_aio_context(bs)); - } - bdrv_parent_drained_begin(bs); - bdrv_drain(bs); -} - -void bdrv_drained_end(BlockDriverState *bs) -{ - bdrv_parent_drained_end(bs); - - assert(bs->quiesce_counter > 0); - if (--bs->quiesce_counter > 0) { - return; - } - aio_enable_external(bdrv_get_aio_context(bs)); -} diff --git a/block/mirror.c b/block/mirror.c index b9986d8218..80fd3c7469 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -20,7 +20,6 @@ #include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" #include "qemu/bitmap.h" -#include "qemu/error-report.h" #define SLICE_TIME 100000000ULL /* ns */ #define MAX_IN_FLIGHT 16 @@ -36,7 +35,7 @@ typedef struct MirrorBuffer { typedef struct MirrorBlockJob { BlockJob common; RateLimit limit; - BlockDriverState *target; + BlockBackend *target; BlockDriverState *base; /* The name of the graph node to replace */ char *replaces; @@ -157,7 +156,8 @@ static void mirror_read_complete(void *opaque, int ret) mirror_iteration_done(op, ret); return; } - bdrv_aio_writev(s->target, op->sector_num, &op->qiov, op->nb_sectors, + blk_aio_pwritev(s->target, op->sector_num * BDRV_SECTOR_SIZE, &op->qiov, + op->nb_sectors * BDRV_SECTOR_SIZE, mirror_write_complete, op); } @@ -186,7 +186,7 @@ static int mirror_cow_align(MirrorBlockJob *s, need_cow |= !test_bit((*sector_num + *nb_sectors - 1) / chunk_sectors, s->cow_bitmap); if (need_cow) { - bdrv_round_to_clusters(s->target, *sector_num, *nb_sectors, + bdrv_round_to_clusters(blk_bs(s->target), *sector_num, *nb_sectors, &align_sector_num, &align_nb_sectors); } @@ -224,7 +224,7 @@ static inline void mirror_wait_for_io(MirrorBlockJob *s) static int mirror_do_read(MirrorBlockJob *s, int64_t sector_num, int nb_sectors) { - BlockDriverState *source = s->common.bs; + BlockBackend *source = s->common.blk; int sectors_per_chunk, nb_chunks; int ret = nb_sectors; MirrorOp *op; @@ -274,7 +274,8 @@ static int mirror_do_read(MirrorBlockJob *s, int64_t sector_num, s->sectors_in_flight += nb_sectors; trace_mirror_one_iteration(s, sector_num, nb_sectors); - bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors, + blk_aio_preadv(source, sector_num * BDRV_SECTOR_SIZE, &op->qiov, + nb_sectors * BDRV_SECTOR_SIZE, mirror_read_complete, op); return ret; } @@ -296,10 +297,11 @@ static void mirror_do_zero_or_discard(MirrorBlockJob *s, s->in_flight++; s->sectors_in_flight += nb_sectors; if (is_discard) { - bdrv_aio_discard(s->target, sector_num, op->nb_sectors, - mirror_write_complete, op); + blk_aio_discard(s->target, sector_num, op->nb_sectors, + mirror_write_complete, op); } else { - bdrv_aio_write_zeroes(s->target, sector_num, op->nb_sectors, + blk_aio_pwrite_zeroes(s->target, sector_num * BDRV_SECTOR_SIZE, + op->nb_sectors * BDRV_SECTOR_SIZE, s->unmap ? BDRV_REQ_MAY_UNMAP : 0, mirror_write_complete, op); } @@ -307,7 +309,7 @@ static void mirror_do_zero_or_discard(MirrorBlockJob *s, static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) { - BlockDriverState *source = s->common.bs; + BlockDriverState *source = blk_bs(s->common.blk); int64_t sector_num, first_chunk; uint64_t delay_ns = 0; /* At least the first dirty chunk is mirrored in one iteration. */ @@ -384,7 +386,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) } else if (ret >= 0 && !(ret & BDRV_BLOCK_DATA)) { int64_t target_sector_num; int target_nb_sectors; - bdrv_round_to_clusters(s->target, sector_num, io_sectors, + bdrv_round_to_clusters(blk_bs(s->target), sector_num, io_sectors, &target_sector_num, &target_nb_sectors); if (target_sector_num == sector_num && target_nb_sectors == io_sectors) { @@ -449,7 +451,8 @@ static void mirror_exit(BlockJob *job, void *opaque) MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); MirrorExitData *data = opaque; AioContext *replace_aio_context = NULL; - BlockDriverState *src = s->common.bs; + BlockDriverState *src = blk_bs(s->common.blk); + BlockDriverState *target_bs = blk_bs(s->target); /* Make sure that the source BDS doesn't go away before we called * block_job_completed(). */ @@ -461,26 +464,25 @@ static void mirror_exit(BlockJob *job, void *opaque) } if (s->should_complete && data->ret == 0) { - BlockDriverState *to_replace = s->common.bs; + BlockDriverState *to_replace = src; if (s->to_replace) { to_replace = s->to_replace; } - /* This was checked in mirror_start_job(), but meanwhile one of the - * nodes could have been newly attached to a BlockBackend. */ - if (bdrv_has_blk(to_replace) && bdrv_has_blk(s->target)) { - error_report("block job: Can't create node with two BlockBackends"); - data->ret = -EINVAL; - goto out; + if (bdrv_get_flags(target_bs) != bdrv_get_flags(to_replace)) { + bdrv_reopen(target_bs, bdrv_get_flags(to_replace), NULL); } - if (bdrv_get_flags(s->target) != bdrv_get_flags(to_replace)) { - bdrv_reopen(s->target, bdrv_get_flags(to_replace), NULL); - } - bdrv_replace_in_backing_chain(to_replace, s->target); - } + /* The mirror job has no requests in flight any more, but we need to + * drain potential other users of the BDS before changing the graph. */ + bdrv_drained_begin(target_bs); + bdrv_replace_in_backing_chain(to_replace, target_bs); + bdrv_drained_end(target_bs); -out: + /* We just changed the BDS the job BB refers to */ + blk_remove_bs(job->blk); + blk_insert_bs(job->blk, src); + } if (s->to_replace) { bdrv_op_unblock_all(s->to_replace, s->replace_blocker); error_free(s->replace_blocker); @@ -490,8 +492,8 @@ out: aio_context_release(replace_aio_context); } g_free(s->replaces); - bdrv_op_unblock_all(s->target, s->common.blocker); - bdrv_unref(s->target); + bdrv_op_unblock_all(target_bs, s->common.blocker); + blk_unref(s->target); block_job_completed(&s->common, data->ret); g_free(data); bdrv_drained_end(src); @@ -505,7 +507,8 @@ static void coroutine_fn mirror_run(void *opaque) { MirrorBlockJob *s = opaque; MirrorExitData *data; - BlockDriverState *bs = s->common.bs; + BlockDriverState *bs = blk_bs(s->common.blk); + BlockDriverState *target_bs = blk_bs(s->target); int64_t sector_num, end, length; uint64_t last_pause_ns; BlockDriverInfo bdi; @@ -541,18 +544,18 @@ static void coroutine_fn mirror_run(void *opaque) * the destination do COW. Instead, we copy sectors around the * dirty data if needed. We need a bitmap to do that. */ - bdrv_get_backing_filename(s->target, backing_filename, + bdrv_get_backing_filename(target_bs, backing_filename, sizeof(backing_filename)); - if (!bdrv_get_info(s->target, &bdi) && bdi.cluster_size) { + if (!bdrv_get_info(target_bs, &bdi) && bdi.cluster_size) { target_cluster_size = bdi.cluster_size; } - if (backing_filename[0] && !s->target->backing + if (backing_filename[0] && !target_bs->backing && s->granularity < target_cluster_size) { s->buf_size = MAX(s->buf_size, target_cluster_size); s->cow_bitmap = bitmap_new(length); } s->target_cluster_sectors = target_cluster_size >> BDRV_SECTOR_BITS; - s->max_iov = MIN(s->common.bs->bl.max_iov, s->target->bl.max_iov); + s->max_iov = MIN(bs->bl.max_iov, target_bs->bl.max_iov); end = s->bdev_length / BDRV_SECTOR_SIZE; s->buf = qemu_try_blockalign(bs, s->buf_size); @@ -567,7 +570,7 @@ static void coroutine_fn mirror_run(void *opaque) if (!s->is_none_mode) { /* First part, loop on the sectors and initialize the dirty bitmap. */ BlockDriverState *base = s->base; - bool mark_all_dirty = s->base == NULL && !bdrv_has_zero_init(s->target); + bool mark_all_dirty = s->base == NULL && !bdrv_has_zero_init(target_bs); for (sector_num = 0; sector_num < end; ) { /* Just to make sure we are not exceeding int limit. */ @@ -637,7 +640,7 @@ static void coroutine_fn mirror_run(void *opaque) should_complete = false; if (s->in_flight == 0 && cnt == 0) { trace_mirror_before_flush(s); - ret = bdrv_flush(s->target); + ret = blk_flush(s->target); if (ret < 0) { if (mirror_error_action(s, false, -ret) == BLOCK_ERROR_ACTION_REPORT) { @@ -715,7 +718,7 @@ immediate_exit: data->ret = ret; /* Before we switch to target in mirror_exit, make sure data doesn't * change. */ - bdrv_drained_begin(s->common.bs); + bdrv_drained_begin(bs); if (qemu_get_aio_context() == bdrv_get_aio_context(bs)) { /* FIXME: virtio host notifiers run on iohandler_ctx, therefore the * above bdrv_drained_end isn't enough to quiesce it. This is ugly, we @@ -742,7 +745,8 @@ static void mirror_complete(BlockJob *job, Error **errp) Error *local_err = NULL; int ret; - ret = bdrv_open_backing_file(s->target, NULL, "backing", &local_err); + ret = bdrv_open_backing_file(blk_bs(s->target), NULL, "backing", + &local_err); if (ret < 0) { error_propagate(errp, local_err); return; @@ -804,7 +808,6 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, bool is_none_mode, BlockDriverState *base) { MirrorBlockJob *s; - BlockDriverState *replaced_bs; if (granularity == 0) { granularity = bdrv_get_default_bitmap_granularity(target); @@ -821,30 +824,17 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, buf_size = DEFAULT_MIRROR_BUF_SIZE; } - /* We can't support this case as long as the block layer can't handle - * multiple BlockBackends per BlockDriverState. */ - if (replaces) { - replaced_bs = bdrv_lookup_bs(replaces, replaces, errp); - if (replaced_bs == NULL) { - return; - } - } else { - replaced_bs = bs; - } - if (bdrv_has_blk(replaced_bs) && bdrv_has_blk(target)) { - error_setg(errp, "Can't create node with two BlockBackends"); - return; - } - s = block_job_create(driver, bs, speed, cb, opaque, errp); if (!s) { return; } + s->target = blk_new(); + blk_insert_bs(s->target, target); + s->replaces = g_strdup(replaces); s->on_source_error = on_source_error; s->on_target_error = on_target_error; - s->target = target; s->is_none_mode = is_none_mode; s->base = base; s->granularity = granularity; @@ -854,11 +844,12 @@ 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); + blk_unref(s->target); block_job_unref(&s->common); return; } - bdrv_op_block_all(s->target, s->common.blocker); + bdrv_op_block_all(target, s->common.blocker); s->common.co = qemu_coroutine_create(mirror_run); trace_mirror_start(bs, s, s->common.co, opaque); @@ -931,7 +922,6 @@ void commit_active_start(BlockDriverState *bs, BlockDriverState *base, } } - bdrv_ref(base); mirror_start_job(bs, base, NULL, speed, 0, 0, on_error, on_error, false, cb, opaque, &local_err, &commit_active_job_driver, false, base); diff --git a/block/parallels.c b/block/parallels.c index 88cfacebe3..99fc0f77ef 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -517,8 +517,8 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp) if (ret < 0) { goto exit; } - ret = blk_write_zeroes(file, BDRV_SECTOR_SIZE, - (bat_sectors - 1) << BDRV_SECTOR_BITS, 0); + ret = blk_pwrite_zeroes(file, BDRV_SECTOR_SIZE, + (bat_sectors - 1) << BDRV_SECTOR_BITS, 0); if (ret < 0) { goto exit; } diff --git a/block/snapshot.c b/block/snapshot.c index 3917ec5c91..6e6e34fcf4 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -374,9 +374,9 @@ bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs) { bool ok = true; BlockDriverState *bs; - BdrvNextIterator *it = NULL; + BdrvNextIterator it; - while (ok && (it = bdrv_next(it, &bs))) { + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); @@ -384,8 +384,12 @@ bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs) ok = bdrv_can_snapshot(bs); } aio_context_release(ctx); + if (!ok) { + goto fail; + } } +fail: *first_bad_bs = bs; return ok; } @@ -395,20 +399,27 @@ int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs, { int ret = 0; BlockDriverState *bs; - BdrvNextIterator *it = NULL; + BdrvNextIterator it; QEMUSnapshotInfo sn1, *snapshot = &sn1; - while (ret == 0 && (it = bdrv_next(it, &bs))) { + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); if (bdrv_can_snapshot(bs) && bdrv_snapshot_find(bs, snapshot, name) >= 0) { ret = bdrv_snapshot_delete_by_id_or_name(bs, name, err); + if (ret < 0) { + goto fail; + } } aio_context_release(ctx); + if (ret < 0) { + goto fail; + } } +fail: *first_bad_bs = bs; return ret; } @@ -418,9 +429,9 @@ int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs) { int err = 0; BlockDriverState *bs; - BdrvNextIterator *it = NULL; + BdrvNextIterator it; - while (err == 0 && (it = bdrv_next(it, &bs))) { + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); @@ -428,8 +439,12 @@ int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs) err = bdrv_snapshot_goto(bs, name); } aio_context_release(ctx); + if (err < 0) { + goto fail; + } } +fail: *first_bad_bs = bs; return err; } @@ -439,9 +454,9 @@ int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs) QEMUSnapshotInfo sn; int err = 0; BlockDriverState *bs; - BdrvNextIterator *it = NULL; + BdrvNextIterator it; - while (err == 0 && (it = bdrv_next(it, &bs))) { + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); @@ -449,8 +464,12 @@ int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs) err = bdrv_snapshot_find(bs, &sn, name); } aio_context_release(ctx); + if (err < 0) { + goto fail; + } } +fail: *first_bad_bs = bs; return err; } @@ -462,9 +481,9 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn, { int err = 0; BlockDriverState *bs; - BdrvNextIterator *it = NULL; + BdrvNextIterator it; - while (err == 0 && (it = bdrv_next(it, &bs))) { + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); @@ -476,24 +495,32 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn, err = bdrv_snapshot_create(bs, sn); } aio_context_release(ctx); + if (err < 0) { + goto fail; + } } +fail: *first_bad_bs = bs; return err; } BlockDriverState *bdrv_all_find_vmstate_bs(void) { - bool not_found = true; BlockDriverState *bs; - BdrvNextIterator *it = NULL; + BdrvNextIterator it; - while (not_found && (it = bdrv_next(it, &bs))) { + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *ctx = bdrv_get_aio_context(bs); + bool found; aio_context_acquire(ctx); - not_found = !bdrv_can_snapshot(bs); + found = bdrv_can_snapshot(bs); aio_context_release(ctx); + + if (found) { + break; + } } return bs; } diff --git a/block/stream.c b/block/stream.c index 40aa32212e..c0efbda34e 100644 --- a/block/stream.c +++ b/block/stream.c @@ -39,7 +39,7 @@ typedef struct StreamBlockJob { char *backing_file_str; } StreamBlockJob; -static int coroutine_fn stream_populate(BlockDriverState *bs, +static int coroutine_fn stream_populate(BlockBackend *blk, int64_t sector_num, int nb_sectors, void *buf) { @@ -52,7 +52,8 @@ static int coroutine_fn stream_populate(BlockDriverState *bs, qemu_iovec_init_external(&qiov, &iov, 1); /* Copy-on-read the unallocated clusters */ - return bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, &qiov); + return blk_co_preadv(blk, sector_num * BDRV_SECTOR_SIZE, qiov.size, &qiov, + BDRV_REQ_COPY_ON_READ); } typedef struct { @@ -64,6 +65,7 @@ static void stream_complete(BlockJob *job, void *opaque) { StreamBlockJob *s = container_of(job, StreamBlockJob, common); StreamCompleteData *data = opaque; + BlockDriverState *bs = blk_bs(job->blk); BlockDriverState *base = s->base; if (!block_job_is_cancelled(&s->common) && data->reached_end && @@ -75,8 +77,8 @@ static void stream_complete(BlockJob *job, void *opaque) base_fmt = base->drv->format_name; } } - data->ret = bdrv_change_backing_file(job->bs, base_id, base_fmt); - bdrv_set_backing_hd(job->bs, base); + data->ret = bdrv_change_backing_file(bs, base_id, base_fmt); + bdrv_set_backing_hd(bs, base); } g_free(s->backing_file_str); @@ -88,7 +90,8 @@ static void coroutine_fn stream_run(void *opaque) { StreamBlockJob *s = opaque; StreamCompleteData *data; - BlockDriverState *bs = s->common.bs; + BlockBackend *blk = s->common.blk; + BlockDriverState *bs = blk_bs(blk); BlockDriverState *base = s->base; int64_t sector_num = 0; int64_t end = -1; @@ -159,7 +162,7 @@ wait: goto wait; } } - ret = stream_populate(bs, sector_num, n, buf); + ret = stream_populate(blk, sector_num, n, buf); } if (ret < 0) { BlockErrorAction action = diff --git a/block/vvfat.c b/block/vvfat.c index 3e484a1dcc..a39dbe67e2 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2998,12 +2998,12 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp) goto err; } - s->qcow = NULL; options = qdict_new(); qdict_put(options, "driver", qstring_from_str("qcow")); - ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, options, - BDRV_O_RDWR | BDRV_O_NO_FLUSH, errp); - if (ret < 0) { + s->qcow = bdrv_open(s->qcow_filename, NULL, options, + BDRV_O_RDWR | BDRV_O_NO_FLUSH, errp); + if (!s->qcow) { + ret = -EINVAL; goto err; } |