[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v13 14/15] block: introduce backup-top filter driver
From: |
Vladimir Sementsov-Ogievskiy |
Subject: |
[PATCH v13 14/15] block: introduce backup-top filter driver |
Date: |
Fri, 20 Sep 2019 17:20:55 +0300 |
Backup-top filter caches write operations and does copy-before-write
operations.
The driver will be used in backup instead of write-notifiers.
Signed-off-by: Vladimir Sementsov-Ogievskiy <address@hidden>
Reviewed-by: Max Reitz <address@hidden>
---
block/backup-top.h | 37 +++++++
block/backup-top.c | 244 ++++++++++++++++++++++++++++++++++++++++++++
block/Makefile.objs | 2 +
3 files changed, 283 insertions(+)
create mode 100644 block/backup-top.h
create mode 100644 block/backup-top.c
diff --git a/block/backup-top.h b/block/backup-top.h
new file mode 100644
index 0000000000..67de7a9133
--- /dev/null
+++ b/block/backup-top.h
@@ -0,0 +1,37 @@
+/*
+ * backup-top filter driver
+ *
+ * The driver performs Copy-Before-Write (CBW) operation: it is injected above
+ * some node, and before each write it copies _old_ data to the target node.
+ *
+ * Copyright (c) 2018-2019 Virtuozzo International GmbH.
+ *
+ * Author:
+ * Sementsov-Ogievskiy Vladimir <address@hidden>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef BACKUP_TOP_H
+#define BACKUP_TOP_H
+
+#include "block/block_int.h"
+
+BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
+ const char *filter_node_name,
+ Error **errp);
+void bdrv_backup_top_set_bcs(BlockDriverState *bs, BlockCopyState *copy_state);
+void bdrv_backup_top_drop(BlockDriverState *bs);
+
+#endif /* BACKUP_TOP_H */
diff --git a/block/backup-top.c b/block/backup-top.c
new file mode 100644
index 0000000000..0991b64759
--- /dev/null
+++ b/block/backup-top.c
@@ -0,0 +1,244 @@
+/*
+ * backup-top filter driver
+ *
+ * The driver performs Copy-Before-Write (CBW) operation: it is injected above
+ * some node, and before each write it copies _old_ data to the target node.
+ *
+ * Copyright (c) 2018-2019 Virtuozzo International GmbH.
+ *
+ * Author:
+ * Sementsov-Ogievskiy Vladimir <address@hidden>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+
+#include "sysemu/block-backend.h"
+#include "qemu/cutils.h"
+#include "qapi/error.h"
+#include "block/block_int.h"
+#include "block/qdict.h"
+#include "block/block-copy.h"
+
+#include "block/backup-top.h"
+
+typedef struct BDRVBackupTopState {
+ BlockCopyState *bcs;
+ bool active;
+} BDRVBackupTopState;
+
+static coroutine_fn int backup_top_co_preadv(
+ BlockDriverState *bs, uint64_t offset, uint64_t bytes,
+ QEMUIOVector *qiov, int flags)
+{
+ return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
+}
+
+static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
+ uint64_t bytes)
+{
+ /*
+ * Here we'd like to use block_copy(), but it needs some additional
+ * synchronization mechanism to prevent intersecting guest writes during
+ * copy operation. The will appear in further commit (it should be done
+ * together with moving backup to using of backup-top and to the same
+ * synchronization mechanism), and for now it is a TODO.
+ */
+
+ abort();
+}
+
+static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs,
+ int64_t offset, int bytes)
+{
+ int ret = backup_top_cbw(bs, offset, bytes);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return bdrv_co_pdiscard(bs->backing, offset, bytes);
+}
+
+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);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return bdrv_co_pwrite_zeroes(bs->backing, offset, bytes, flags);
+}
+
+static coroutine_fn int backup_top_co_pwritev(BlockDriverState *bs,
+ uint64_t offset,
+ 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;
+ }
+ }
+
+ return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags);
+}
+
+static int coroutine_fn backup_top_co_flush(BlockDriverState *bs)
+{
+ if (!bs->backing) {
+ return 0;
+ }
+
+ return bdrv_co_flush(bs->backing->bs);
+}
+
+static void backup_top_refresh_filename(BlockDriverState *bs)
+{
+ if (bs->backing == NULL) {
+ /*
+ * we can be here after failed bdrv_attach_child in
+ * bdrv_set_backing_hd
+ */
+ return;
+ }
+ pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
+ bs->backing->bs->filename);
+}
+
+static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
+ const BdrvChildRole *role,
+ BlockReopenQueue *reopen_queue,
+ uint64_t perm, uint64_t shared,
+ uint64_t *nperm, uint64_t *nshared)
+{
+ BDRVBackupTopState *s = bs->opaque;
+
+ if (!s->active) {
+ /*
+ * The filter node may be in process of bdrv_append(), which firstly do
+ * bdrv_set_backing_hd() and then bdrv_replace_node(). This means that
+ * we can't unshare BLK_PERM_WRITE during bdrv_append() operation. So,
+ * let's require nothing during bdrv_append() and refresh permissions
+ * after it (see bdrv_backup_top_append()).
+ */
+ *nperm = 0;
+ *nshared = BLK_PERM_ALL;
+ return;
+ }
+
+ bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
+ nperm, nshared);
+
+ *nshared &= ~BLK_PERM_WRITE;
+}
+
+BlockDriver bdrv_backup_top_filter = {
+ .format_name = "backup-top",
+ .instance_size = sizeof(BDRVBackupTopState),
+
+ .bdrv_co_preadv = backup_top_co_preadv,
+ .bdrv_co_pwritev = backup_top_co_pwritev,
+ .bdrv_co_pwrite_zeroes = backup_top_co_pwrite_zeroes,
+ .bdrv_co_pdiscard = backup_top_co_pdiscard,
+ .bdrv_co_flush = backup_top_co_flush,
+
+ .bdrv_co_block_status = bdrv_co_block_status_from_backing,
+
+ .bdrv_refresh_filename = backup_top_refresh_filename,
+
+ .bdrv_child_perm = backup_top_child_perm,
+
+ .is_filter = true,
+};
+
+BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
+ const char *filter_node_name,
+ Error **errp)
+{
+ Error *local_err = NULL;
+ BDRVBackupTopState *state;
+ BlockDriverState *top = bdrv_new_open_driver(&bdrv_backup_top_filter,
+ filter_node_name,
+ BDRV_O_RDWR, errp);
+
+ if (!top) {
+ return NULL;
+ }
+
+ top->total_sectors = source->total_sectors;
+ top->opaque = state = g_new0(BDRVBackupTopState, 1);
+
+ bdrv_drained_begin(source);
+
+ bdrv_ref(top);
+ bdrv_append(top, source, &local_err);
+ if (local_err) {
+ error_prepend(&local_err, "Cannot append backup-top filter: ");
+ } else {
+ /*
+ * bdrv_append() finished successfully, now we can require permissions
+ * we want.
+ */
+ state->active = true;
+ bdrv_child_refresh_perms(top, top->backing, &local_err);
+ if (local_err) {
+ state->active = false;
+ bdrv_backup_top_drop(top);
+ error_prepend(&local_err,
+ "Cannot set permissions for backup-top filter: ");
+ }
+ }
+
+ bdrv_drained_end(source);
+
+ if (local_err) {
+ bdrv_unref(top);
+ error_propagate(errp, local_err);
+ return NULL;
+ }
+
+ return top;
+}
+
+void bdrv_backup_top_set_bcs(BlockDriverState *bs, BlockCopyState *copy_state)
+{
+ BDRVBackupTopState *s = bs->opaque;
+
+ assert(blk_bs(copy_state->source) == bs->backing->bs);
+ s->bcs = copy_state;
+}
+
+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);
+
+ s->active = false;
+ bdrv_child_refresh_perms(bs, bs->backing, &error_abort);
+ bdrv_replace_node(bs, backing_bs(bs), &error_abort);
+ bdrv_set_backing_hd(bs, NULL, &error_abort);
+
+ bdrv_drained_end(bs);
+
+ bdrv_unref(bs);
+
+ aio_context_release(aio_context);
+}
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 0b5c635fb2..6f348c56c9 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -41,6 +41,8 @@ block-obj-y += block-copy.o
block-obj-y += crypto.o
+block-obj-y += backup-top.o
+
common-obj-y += stream.o
nfs.o-libs := $(LIBNFS_LIBS)
--
2.21.0
- [PATCH v13 00/15] backup-top filter driver for backup, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 01/15] block/backup: fix max_transfer handling for copy_range, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 03/15] block/backup: split shareable copying part from backup_do_cow, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 13/15] block: add lock/unlock range functions, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 06/15] block/backup: fix block-comment style, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 02/15] block/backup: fix backup_cow_with_offload for last cluster, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 08/15] block: teach bdrv_debug_breakpoint skip filters with backing, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 14/15] block: introduce backup-top filter driver,
Vladimir Sementsov-Ogievskiy <=
- [PATCH v13 04/15] block/backup: improve comment about image fleecing, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 05/15] block/backup: introduce BlockCopyState, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 07/15] block: move block_copy from block/backup.c to separate file, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 12/15] block/io: refactor wait_serialising_requests, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 11/15] iotests: 257: drop device_add, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 10/15] iotests: 257: drop unused Drive.device field, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 09/15] iotests: prepare 124 and 257 bitmap querying for backup-top filter, Vladimir Sementsov-Ogievskiy, 2019/09/20
- [PATCH v13 15/15] block/backup: use backup-top instead of write notifiers, Vladimir Sementsov-Ogievskiy, 2019/09/20
- Re: [PATCH v13 00/15] backup-top filter driver for backup, Max Reitz, 2019/09/20