1
0
mirror of https://gitlab.com/qemu-project/qemu synced 2024-07-03 08:19:15 +00:00

qapi: blockdev-backup: add discard-source parameter

Add a parameter that enables discard-after-copy. That is mostly useful
in "push backup with fleecing" scheme, when source is snapshot-access
format driver node, based on copy-before-write filter snapshot-access
API:

[guest]      [snapshot-access] ~~ blockdev-backup ~~> [backup target]
   |            |
   | root       | file
   v            v
[copy-before-write]
   |             |
   | file        | target
   v             v
[active disk]   [temp.img]

In this case discard-after-copy does two things:

 - discard data in temp.img to save disk space
 - avoid further copy-before-write operation in discarded area

Note that we have to declare WRITE permission on source in
copy-before-write filter, for discard to work. Still we can't take it
unconditionally, as it will break normal backup from RO source. So, we
have to add a parameter and pass it thorough bdrv_open flags.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Fiona Ebner <f.ebner@proxmox.com>
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
Acked-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20240313152822.626493-5-vsementsov@yandex-team.ru>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
This commit is contained in:
Vladimir Sementsov-Ogievskiy 2024-03-13 18:28:21 +03:00
parent 006e845b5a
commit 0fd05c8d80
10 changed files with 37 additions and 8 deletions

View File

@ -356,7 +356,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockDriverState *target, int64_t speed, BlockDriverState *target, int64_t speed,
MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap, MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
BitmapSyncMode bitmap_mode, BitmapSyncMode bitmap_mode,
bool compress, bool compress, bool discard_source,
const char *filter_node_name, const char *filter_node_name,
BackupPerf *perf, BackupPerf *perf,
BlockdevOnError on_source_error, BlockdevOnError on_source_error,
@ -457,7 +457,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
goto error; goto error;
} }
cbw = bdrv_cbw_append(bs, target, filter_node_name, &bcs, errp); cbw = bdrv_cbw_append(bs, target, filter_node_name, discard_source,
&bcs, errp);
if (!cbw) { if (!cbw) {
goto error; goto error;
} }

View File

@ -137,6 +137,7 @@ typedef struct BlockCopyState {
CoMutex lock; CoMutex lock;
int64_t in_flight_bytes; int64_t in_flight_bytes;
BlockCopyMethod method; BlockCopyMethod method;
bool discard_source;
BlockReqList reqs; BlockReqList reqs;
QLIST_HEAD(, BlockCopyCallState) calls; QLIST_HEAD(, BlockCopyCallState) calls;
/* /*
@ -353,6 +354,7 @@ static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
BlockDriverState *copy_bitmap_bs, BlockDriverState *copy_bitmap_bs,
const BdrvDirtyBitmap *bitmap, const BdrvDirtyBitmap *bitmap,
bool discard_source,
Error **errp) Error **errp)
{ {
ERRP_GUARD(); ERRP_GUARD();
@ -418,6 +420,7 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
cluster_size), cluster_size),
}; };
s->discard_source = discard_source;
block_copy_set_copy_opts(s, false, false); block_copy_set_copy_opts(s, false, false);
ratelimit_init(&s->rate_limit); ratelimit_init(&s->rate_limit);
@ -589,6 +592,12 @@ static coroutine_fn int block_copy_task_entry(AioTask *task)
co_put_to_shres(s->mem, t->req.bytes); co_put_to_shres(s->mem, t->req.bytes);
block_copy_task_end(t, ret); block_copy_task_end(t, ret);
if (s->discard_source && ret == 0) {
int64_t nbytes =
MIN(t->req.offset + t->req.bytes, s->len) - t->req.offset;
bdrv_co_pdiscard(s->source, t->req.offset, nbytes);
}
return ret; return ret;
} }

View File

@ -44,6 +44,7 @@ typedef struct BDRVCopyBeforeWriteState {
BdrvChild *target; BdrvChild *target;
OnCbwError on_cbw_error; OnCbwError on_cbw_error;
uint32_t cbw_timeout_ns; uint32_t cbw_timeout_ns;
bool discard_source;
/* /*
* @lock: protects access to @access_bitmap, @done_bitmap and * @lock: protects access to @access_bitmap, @done_bitmap and
@ -357,6 +358,8 @@ cbw_child_perm(BlockDriverState *bs, BdrvChild *c, BdrvChildRole role,
uint64_t perm, uint64_t shared, uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared) uint64_t *nperm, uint64_t *nshared)
{ {
BDRVCopyBeforeWriteState *s = bs->opaque;
if (!(role & BDRV_CHILD_FILTERED)) { if (!(role & BDRV_CHILD_FILTERED)) {
/* /*
* Target child * Target child
@ -381,6 +384,10 @@ cbw_child_perm(BlockDriverState *bs, BdrvChild *c, BdrvChildRole role,
* start * start
*/ */
*nperm = *nperm | BLK_PERM_CONSISTENT_READ; *nperm = *nperm | BLK_PERM_CONSISTENT_READ;
if (s->discard_source) {
*nperm = *nperm | BLK_PERM_WRITE;
}
*nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); *nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
} }
} }
@ -468,7 +475,9 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
bs->file->bs->supported_zero_flags); bs->file->bs->supported_zero_flags);
s->bcs = block_copy_state_new(bs->file, s->target, bs, bitmap, errp); s->discard_source = flags & BDRV_O_CBW_DISCARD_SOURCE;
s->bcs = block_copy_state_new(bs->file, s->target, bs, bitmap,
flags & BDRV_O_CBW_DISCARD_SOURCE, errp);
if (!s->bcs) { if (!s->bcs) {
error_prepend(errp, "Cannot create block-copy-state: "); error_prepend(errp, "Cannot create block-copy-state: ");
return -EINVAL; return -EINVAL;
@ -535,12 +544,14 @@ static BlockDriver bdrv_cbw_filter = {
BlockDriverState *bdrv_cbw_append(BlockDriverState *source, BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
BlockDriverState *target, BlockDriverState *target,
const char *filter_node_name, const char *filter_node_name,
bool discard_source,
BlockCopyState **bcs, BlockCopyState **bcs,
Error **errp) Error **errp)
{ {
BDRVCopyBeforeWriteState *state; BDRVCopyBeforeWriteState *state;
BlockDriverState *top; BlockDriverState *top;
QDict *opts; QDict *opts;
int flags = BDRV_O_RDWR | (discard_source ? BDRV_O_CBW_DISCARD_SOURCE : 0);
assert(source->total_sectors == target->total_sectors); assert(source->total_sectors == target->total_sectors);
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
@ -553,7 +564,7 @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
qdict_put_str(opts, "file", bdrv_get_node_name(source)); qdict_put_str(opts, "file", bdrv_get_node_name(source));
qdict_put_str(opts, "target", bdrv_get_node_name(target)); qdict_put_str(opts, "target", bdrv_get_node_name(target));
top = bdrv_insert_node(source, opts, BDRV_O_RDWR, errp); top = bdrv_insert_node(source, opts, flags, errp);
if (!top) { if (!top) {
return NULL; return NULL;
} }

View File

@ -39,6 +39,7 @@
BlockDriverState *bdrv_cbw_append(BlockDriverState *source, BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
BlockDriverState *target, BlockDriverState *target,
const char *filter_node_name, const char *filter_node_name,
bool discard_source,
BlockCopyState **bcs, BlockCopyState **bcs,
Error **errp); Error **errp);
void bdrv_cbw_drop(BlockDriverState *bs); void bdrv_cbw_drop(BlockDriverState *bs);

View File

@ -582,8 +582,8 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
s->backup_job = backup_job_create( s->backup_job = backup_job_create(
NULL, s->secondary_disk->bs, s->hidden_disk->bs, NULL, s->secondary_disk->bs, s->hidden_disk->bs,
0, MIRROR_SYNC_MODE_NONE, NULL, 0, false, NULL, 0, MIRROR_SYNC_MODE_NONE, NULL, 0, false, false,
&perf, NULL, &perf,
BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL, BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL,
backup_job_completed, bs, NULL, &local_err); backup_job_completed, bs, NULL, &local_err);

View File

@ -2728,7 +2728,7 @@ static BlockJob *do_backup_common(BackupCommon *backup,
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
backup->sync, bmap, backup->bitmap_mode, backup->sync, bmap, backup->bitmap_mode,
backup->compress, backup->compress, backup->discard_source,
backup->filter_node_name, backup->filter_node_name,
&perf, &perf,
backup->on_source_error, backup->on_source_error,

View File

@ -243,6 +243,8 @@ typedef enum {
read-write fails */ read-write fails */
#define BDRV_O_IO_URING 0x40000 /* use io_uring instead of the thread pool */ #define BDRV_O_IO_URING 0x40000 /* use io_uring instead of the thread pool */
#define BDRV_O_CBW_DISCARD_SOURCE 0x80000 /* for copy-before-write filter */
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH) #define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH)

View File

@ -27,6 +27,7 @@ typedef struct BlockCopyCallState BlockCopyCallState;
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
BlockDriverState *copy_bitmap_bs, BlockDriverState *copy_bitmap_bs,
const BdrvDirtyBitmap *bitmap, const BdrvDirtyBitmap *bitmap,
bool discard_source,
Error **errp); Error **errp);
/* Function should be called prior any actual copy request */ /* Function should be called prior any actual copy request */

View File

@ -193,7 +193,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
MirrorSyncMode sync_mode, MirrorSyncMode sync_mode,
BdrvDirtyBitmap *sync_bitmap, BdrvDirtyBitmap *sync_bitmap,
BitmapSyncMode bitmap_mode, BitmapSyncMode bitmap_mode,
bool compress, bool compress, bool discard_source,
const char *filter_node_name, const char *filter_node_name,
BackupPerf *perf, BackupPerf *perf,
BlockdevOnError on_source_error, BlockdevOnError on_source_error,

View File

@ -1610,6 +1610,9 @@
# node specified by @drive. If this option is not given, a node # node specified by @drive. If this option is not given, a node
# name is autogenerated. (Since: 4.2) # name is autogenerated. (Since: 4.2)
# #
# @discard-source: Discard blocks on source which have already been
# copied to the target. (Since 9.1)
#
# @x-perf: Performance options. (Since 6.0) # @x-perf: Performance options. (Since 6.0)
# #
# Features: # Features:
@ -1631,6 +1634,7 @@
'*on-target-error': 'BlockdevOnError', '*on-target-error': 'BlockdevOnError',
'*auto-finalize': 'bool', '*auto-dismiss': 'bool', '*auto-finalize': 'bool', '*auto-dismiss': 'bool',
'*filter-node-name': 'str', '*filter-node-name': 'str',
'*discard-source': 'bool',
'*x-perf': { 'type': 'BackupPerf', '*x-perf': { 'type': 'BackupPerf',
'features': [ 'unstable' ] } } } 'features': [ 'unstable' ] } } }