}
static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
- uint64_t bytes)
+ uint64_t bytes, BdrvRequestFlags flags)
{
BDRVBackupTopState *s = bs->opaque;
- uint64_t end = QEMU_ALIGN_UP(offset + bytes, s->bcs->cluster_size);
- uint64_t off = QEMU_ALIGN_DOWN(offset, s->bcs->cluster_size);
+ uint64_t off, end;
+
+ if (flags & BDRV_REQ_WRITE_UNCHANGED) {
+ return 0;
+ }
+
+ off = QEMU_ALIGN_DOWN(offset, s->bcs->cluster_size);
+ end = QEMU_ALIGN_UP(offset + bytes, s->bcs->cluster_size);
return block_copy(s->bcs, off, end - off, NULL);
}
static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs,
int64_t offset, int bytes)
{
- int ret = backup_top_cbw(bs, offset, bytes);
+ int ret = backup_top_cbw(bs, offset, bytes, 0);
if (ret < 0) {
return ret;
}
static int coroutine_fn backup_top_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int bytes, BdrvRequestFlags flags)
{
- int ret = backup_top_cbw(bs, offset, bytes);
+ int ret = backup_top_cbw(bs, offset, bytes, flags);
if (ret < 0) {
return ret;
}
uint64_t bytes,
QEMUIOVector *qiov, int flags)
{
- if (!(flags & BDRV_REQ_WRITE_UNCHANGED)) {
- int ret = backup_top_cbw(bs, offset, bytes);
- if (ret < 0) {
- return ret;
- }
+ int ret = backup_top_cbw(bs, offset, bytes, flags);
+ if (ret < 0) {
+ return ret;
}
return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags);
BlockDriverState *top = bdrv_new_open_driver(&bdrv_backup_top_filter,
filter_node_name,
BDRV_O_RDWR, errp);
+ bool appended = false;
if (!top) {
return NULL;
}
+ state = top->opaque;
top->total_sectors = source->total_sectors;
- top->opaque = state = g_new0(BDRVBackupTopState, 1);
+ top->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
+ (BDRV_REQ_FUA & source->supported_write_flags);
+ top->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
+ ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
+ source->supported_zero_flags);
bdrv_ref(target);
state->target = bdrv_attach_child(top, target, "target", &child_file, errp);
bdrv_append(top, source, &local_err);
if (local_err) {
error_prepend(&local_err, "Cannot append backup-top filter: ");
- goto append_failed;
+ goto fail;
}
+ appended = true;
/*
* bdrv_append() finished successfully, now we can require permissions
if (local_err) {
error_prepend(&local_err,
"Cannot set permissions for backup-top filter: ");
- goto failed_after_append;
+ goto fail;
}
state->bcs = block_copy_state_new(top->backing, state->target,
cluster_size, write_flags, &local_err);
if (local_err) {
error_prepend(&local_err, "Cannot create block-copy-state: ");
- goto failed_after_append;
+ goto fail;
}
*bcs = state->bcs;
return top;
-failed_after_append:
- state->active = false;
- bdrv_backup_top_drop(top);
+fail:
+ if (appended) {
+ state->active = false;
+ bdrv_backup_top_drop(top);
+ } else {
+ bdrv_unref(top);
+ }
-append_failed:
bdrv_drained_end(source);
- bdrv_unref_child(top, state->target);
- bdrv_unref(top);
error_propagate(errp, local_err);
return NULL;
void bdrv_backup_top_drop(BlockDriverState *bs)
{
BDRVBackupTopState *s = bs->opaque;
- AioContext *aio_context = bdrv_get_aio_context(bs);
-
- aio_context_acquire(aio_context);
bdrv_drained_begin(bs);
bdrv_drained_end(bs);
bdrv_unref(bs);
-
- aio_context_release(aio_context);
}