Lines Matching +full:block +full:- +full:copy
2 * copy-before-write filter driver
4 * The driver performs Copy-Before-Write (CBW) operation: it is injected above
7 * Copyright (c) 2018-2021 Virtuozzo International GmbH.
10 * Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com>
22 * You should have received a copy of the GNU General Public License
29 #include "sysemu/block-backend.h"
32 #include "block/block_int.h"
33 #include "block/qdict.h"
34 #include "block/block-copy.h"
35 #include "block/dirty-bitmap.h"
37 #include "block/copy-before-write.h"
38 #include "block/reqlist.h"
40 #include "qapi/qapi-visit-block-core.h"
57 * Reading from non-dirty areas leads to -EACCES.
63 * copy-before-write operations.
68 * @frozen_read_reqs: current read requests for fleecing user in bs->file
75 * @snapshot_error is normally zero. But on first copy-before-write failure
77 * value of this error (<0). After that all in-flight and further
78 * snapshot-API requests will fail with that error.
87 return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); in cbw_co_preadv()
98 * Do copy-before-write operation.
102 * On success, we also wait for all in-flight fleecing read requests in source
109 BDRVCopyBeforeWriteState *s = bs->opaque; in cbw_do_copy_before_write()
112 int64_t cluster_size = block_copy_cluster_size(s->bcs); in cbw_do_copy_before_write()
118 if (s->snapshot_error) { in cbw_do_copy_before_write()
126 * Increase in_flight, so that in case of timed-out block-copy, the in cbw_do_copy_before_write()
128 * cancelled by timeout) is presented in bs->in_flight. This way we are in cbw_do_copy_before_write()
129 * sure that on bs close() we'll previously wait for all timed-out but yet in cbw_do_copy_before_write()
133 ret = block_copy(s->bcs, off, end - off, true, s->cbw_timeout_ns, in cbw_do_copy_before_write()
135 if (ret < 0 && s->on_cbw_error == ON_CBW_ERROR_BREAK_GUEST_WRITE) { in cbw_do_copy_before_write()
139 WITH_QEMU_LOCK_GUARD(&s->lock) { in cbw_do_copy_before_write()
141 assert(s->on_cbw_error == ON_CBW_ERROR_BREAK_SNAPSHOT); in cbw_do_copy_before_write()
142 if (!s->snapshot_error) { in cbw_do_copy_before_write()
143 s->snapshot_error = ret; in cbw_do_copy_before_write()
146 bdrv_set_dirty_bitmap(s->done_bitmap, off, end - off); in cbw_do_copy_before_write()
148 reqlist_wait_all(&s->frozen_read_reqs, off, end - off, &s->lock); in cbw_do_copy_before_write()
162 return bdrv_co_pdiscard(bs->file, offset, bytes); in cbw_co_pdiscard()
174 return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); in cbw_co_pwrite_zeroes()
186 return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); in cbw_co_pwritev()
191 if (!bs->file) { in cbw_co_flush()
195 return bdrv_co_flush(bs->file->bs); in cbw_co_flush()
199 * If @offset not accessible - return NULL.
202 * to bs->file or to s->target). Return newly allocated BlockReq object that
212 BDRVCopyBeforeWriteState *s = bs->opaque; in cbw_snapshot_read_lock()
216 QEMU_LOCK_GUARD(&s->lock); in cbw_snapshot_read_lock()
218 if (s->snapshot_error) { in cbw_snapshot_read_lock()
223 if (bdrv_dirty_bitmap_next_zero(s->access_bitmap, offset, bytes) != -1) { in cbw_snapshot_read_lock()
228 done = bdrv_dirty_bitmap_status(s->done_bitmap, offset, bytes, pnum); in cbw_snapshot_read_lock()
233 * from s->target. in cbw_snapshot_read_lock()
235 *req = (BlockReq) {.offset = -1, .bytes = -1}; in cbw_snapshot_read_lock()
236 *file = s->target; in cbw_snapshot_read_lock()
238 reqlist_init_req(&s->frozen_read_reqs, req, offset, bytes); in cbw_snapshot_read_lock()
239 *file = bs->file; in cbw_snapshot_read_lock()
248 BDRVCopyBeforeWriteState *s = bs->opaque; in cbw_snapshot_read_unlock()
250 if (req->offset == -1 && req->bytes == -1) { in cbw_snapshot_read_unlock()
255 QEMU_LOCK_GUARD(&s->lock); in cbw_snapshot_read_unlock()
275 return -EACCES; in cbw_co_preadv_snapshot()
285 bytes -= cur_bytes; in cbw_co_preadv_snapshot()
299 BDRVCopyBeforeWriteState *s = bs->opaque; in cbw_co_snapshot_block_status()
307 return -EACCES; in cbw_co_snapshot_block_status()
310 ret = bdrv_co_block_status(child->bs, offset, cur_bytes, pnum, map, file); in cbw_co_snapshot_block_status()
311 if (child == s->target) { in cbw_co_snapshot_block_status()
313 * We refer to s->target only for areas that we've written to it. in cbw_co_snapshot_block_status()
314 * And we can not report unallocated blocks in s->target: this will in cbw_co_snapshot_block_status()
315 * break generic block-status-above logic, that will go to in cbw_co_snapshot_block_status()
316 * copy-before-write filtered child in this case. in cbw_co_snapshot_block_status()
329 BDRVCopyBeforeWriteState *s = bs->opaque; in cbw_co_pdiscard_snapshot()
330 uint32_t cluster_size = block_copy_cluster_size(s->bcs); in cbw_co_pdiscard_snapshot()
338 aligned_bytes = aligned_end - aligned_offset; in cbw_co_pdiscard_snapshot()
340 WITH_QEMU_LOCK_GUARD(&s->lock) { in cbw_co_pdiscard_snapshot()
341 bdrv_reset_dirty_bitmap(s->access_bitmap, aligned_offset, in cbw_co_pdiscard_snapshot()
345 block_copy_reset(s->bcs, aligned_offset, aligned_bytes); in cbw_co_pdiscard_snapshot()
347 return bdrv_co_pdiscard(s->target, aligned_offset, aligned_bytes); in cbw_co_pdiscard_snapshot()
352 pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), in cbw_refresh_filename()
353 bs->file->bs->filename); in cbw_refresh_filename()
362 BDRVCopyBeforeWriteState *s = bs->opaque; in cbw_child_perm()
370 * Can't resize during a backup block job because we check the size in cbw_child_perm()
380 if (!QLIST_EMPTY(&bs->parents)) { in cbw_child_perm()
383 * does create own blk parent on copy-before-write node, so this in cbw_child_perm()
388 if (s->discard_source) { in cbw_child_perm()
402 qdict_put_str(options, "driver", "copy-before-write"); in cbw_parse_options()
419 qdict_del(options, "on-cbw-error"); in cbw_parse_options()
420 qdict_del(options, "cbw-timeout"); in cbw_parse_options()
421 qdict_del(options, "min-cluster-size"); in cbw_parse_options()
434 BDRVCopyBeforeWriteState *s = bs->opaque; in cbw_open()
443 return -EINVAL; in cbw_open()
445 assert(full_opts->driver == BLOCKDEV_DRIVER_COPY_BEFORE_WRITE); in cbw_open()
446 opts = &full_opts->u.copy_before_write; in cbw_open()
453 s->target = bdrv_open_child(NULL, options, "target", bs, &child_of_bds, in cbw_open()
455 if (!s->target) { in cbw_open()
456 return -EINVAL; in cbw_open()
461 if (opts->bitmap) { in cbw_open()
462 bitmap = block_dirty_bitmap_lookup(opts->bitmap->node, in cbw_open()
463 opts->bitmap->name, NULL, errp); in cbw_open()
465 return -EINVAL; in cbw_open()
468 s->on_cbw_error = opts->has_on_cbw_error ? opts->on_cbw_error : in cbw_open()
470 s->cbw_timeout_ns = opts->has_cbw_timeout ? in cbw_open()
471 opts->cbw_timeout * NANOSECONDS_PER_SECOND : 0; in cbw_open()
473 bs->total_sectors = bs->file->bs->total_sectors; in cbw_open()
474 bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | in cbw_open()
475 (BDRV_REQ_FUA & bs->file->bs->supported_write_flags); in cbw_open()
476 bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | in cbw_open()
478 bs->file->bs->supported_zero_flags); in cbw_open()
480 s->discard_source = flags & BDRV_O_CBW_DISCARD_SOURCE; in cbw_open()
482 s->bcs = block_copy_state_new(bs->file, s->target, bs, bitmap, in cbw_open()
484 opts->min_cluster_size, errp); in cbw_open()
485 if (!s->bcs) { in cbw_open()
486 error_prepend(errp, "Cannot create block-copy-state: "); in cbw_open()
487 return -EINVAL; in cbw_open()
490 cluster_size = block_copy_cluster_size(s->bcs); in cbw_open()
492 s->done_bitmap = bdrv_create_dirty_bitmap(bs, cluster_size, NULL, errp); in cbw_open()
493 if (!s->done_bitmap) { in cbw_open()
494 return -EINVAL; in cbw_open()
496 bdrv_disable_dirty_bitmap(s->done_bitmap); in cbw_open()
498 /* s->access_bitmap starts equal to bcs bitmap */ in cbw_open()
499 s->access_bitmap = bdrv_create_dirty_bitmap(bs, cluster_size, NULL, errp); in cbw_open()
500 if (!s->access_bitmap) { in cbw_open()
501 return -EINVAL; in cbw_open()
503 bdrv_disable_dirty_bitmap(s->access_bitmap); in cbw_open()
504 bdrv_dirty_bitmap_merge_internal(s->access_bitmap, in cbw_open()
505 block_copy_dirty_bitmap(s->bcs), NULL, in cbw_open()
508 qemu_co_mutex_init(&s->lock); in cbw_open()
509 QLIST_INIT(&s->frozen_read_reqs); in cbw_open()
515 BDRVCopyBeforeWriteState *s = bs->opaque; in cbw_close()
517 bdrv_release_dirty_bitmap(s->access_bitmap); in cbw_close()
518 bdrv_release_dirty_bitmap(s->done_bitmap); in cbw_close()
520 block_copy_state_free(s->bcs); in cbw_close()
521 s->bcs = NULL; in cbw_close()
525 .format_name = "copy-before-write",
561 assert(source->total_sectors == target->total_sectors); in bdrv_cbw_append()
565 qdict_put_str(opts, "driver", "copy-before-write"); in bdrv_cbw_append()
567 qdict_put_str(opts, "node-name", filter_node_name); in bdrv_cbw_append()
573 error_setg(errp, "min-cluster-size too large: %" PRIu64 " > %" PRIi64, in bdrv_cbw_append()
578 qdict_put_int(opts, "min-cluster-size", (int64_t)min_cluster_size); in bdrv_cbw_append()
585 state = top->opaque; in bdrv_cbw_append()
586 *bcs = state->bcs; in bdrv_cbw_append()