From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
To: qemu-devel@nongnu.org, qemu-block@nongnu.org
Cc: fam@euphon.net, kwolf@redhat.com, vsementsov@virtuozzo.com,
mreitz@redhat.com, den@openvz.org, jsnow@redhat.com
Subject: [Qemu-devel] [PATCH v3 1/9] block: add .bdrv_need_rw_file_child_during_reopen_rw handler
Date: Thu, 25 Jul 2019 12:18:52 +0300 [thread overview]
Message-ID: <20190725091900.30542-2-vsementsov@virtuozzo.com> (raw)
In-Reply-To: <20190725091900.30542-1-vsementsov@virtuozzo.com>
On reopen to rw parent may need rw access to child in .prepare, for
example qcow2 needs to write IN_USE flags into stored bitmaps
(currently it is done in a hacky way after commit and don't work).
So, let's introduce such logic.
The drawback is that in worst case bdrv_reopen_set_read_only may finish
with error and in some intermediate state: some nodes reopened RW and
some are not. But this is a way to fix bug around reopening qcow2
bitmaps in the following commits.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
include/block/block_int.h | 2 +
block.c | 144 ++++++++++++++++++++++++++++++++++----
2 files changed, 133 insertions(+), 13 deletions(-)
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 3aa1e832a8..7bd6fd68dd 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -531,6 +531,8 @@ struct BlockDriver {
uint64_t parent_perm, uint64_t parent_shared,
uint64_t *nperm, uint64_t *nshared);
+ bool (*bdrv_need_rw_file_child_during_reopen_rw)(BlockDriverState *bs);
+
/**
* Bitmaps should be marked as 'IN_USE' in the image on reopening image
* as rw. This handler should realize it. It also should unset readonly
diff --git a/block.c b/block.c
index cbd8da5f3b..3c8e1c59b4 100644
--- a/block.c
+++ b/block.c
@@ -1715,10 +1715,12 @@ static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
uint64_t *shared_perm);
typedef struct BlockReopenQueueEntry {
- bool prepared;
- bool perms_checked;
- BDRVReopenState state;
- QSIMPLEQ_ENTRY(BlockReopenQueueEntry) entry;
+ bool reopened_file_child_rw;
+ bool changed_file_child_perm_rw;
+ bool prepared;
+ bool perms_checked;
+ BDRVReopenState state;
+ QSIMPLEQ_ENTRY(BlockReopenQueueEntry) entry;
} BlockReopenQueueEntry;
/*
@@ -3421,6 +3423,105 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
keep_old_opts);
}
+static int bdrv_reopen_set_read_only_drained(BlockDriverState *bs,
+ bool read_only,
+ Error **errp)
+{
+ BlockReopenQueue *queue;
+ QDict *opts = qdict_new();
+
+ qdict_put_bool(opts, BDRV_OPT_READ_ONLY, read_only);
+
+ queue = bdrv_reopen_queue(NULL, bs, opts, true);
+
+ return bdrv_reopen_multiple(queue, errp);
+}
+
+/*
+ * handle_recursive_reopens
+ *
+ * On fail it needs rollback_recursive_reopens to be called.
+ */
+static int handle_recursive_reopens(BlockReopenQueueEntry *current,
+ Error **errp)
+{
+ int ret;
+ BlockDriverState *bs = current->state.bs;
+
+ /*
+ * We use the fact that in reopen-queue children are always following
+ * parents.
+ * TODO: Switch BlockReopenQueue to be QTAILQ and use
+ * QTAILQ_FOREACH_REVERSE.
+ */
+ if (QSIMPLEQ_NEXT(current, entry)) {
+ ret = handle_recursive_reopens(QSIMPLEQ_NEXT(current, entry), errp);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ if ((current->state.flags & BDRV_O_RDWR) && bs->file && bs->drv &&
+ bs->drv->bdrv_need_rw_file_child_during_reopen_rw &&
+ bs->drv->bdrv_need_rw_file_child_during_reopen_rw(bs))
+ {
+ if (!bdrv_is_writable(bs->file->bs)) {
+ ret = bdrv_reopen_set_read_only_drained(bs->file->bs, false, errp);
+ if (ret < 0) {
+ return ret;
+ }
+ current->reopened_file_child_rw = true;
+ }
+
+ if (!(bs->file->perm & BLK_PERM_WRITE)) {
+ ret = bdrv_child_try_set_perm(bs->file,
+ bs->file->perm | BLK_PERM_WRITE,
+ bs->file->shared_perm, errp);
+ if (ret < 0) {
+ return ret;
+ }
+ current->changed_file_child_perm_rw = true;
+ }
+ }
+
+ return 0;
+}
+
+static int rollback_recursive_reopens(BlockReopenQueue *bs_queue,
+ Error **errp)
+{
+ int ret;
+ BlockReopenQueueEntry *bs_entry;
+
+ /*
+ * We use the fact that in reopen-queue children are always following
+ * parents.
+ */
+ QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
+ BlockDriverState *bs = bs_entry->state.bs;
+
+ if (bs_entry->changed_file_child_perm_rw) {
+ ret = bdrv_child_try_set_perm(bs->file,
+ bs->file->perm & ~BLK_PERM_WRITE,
+ bs->file->shared_perm, errp);
+
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ if (bs_entry->reopened_file_child_rw) {
+ ret = bdrv_reopen_set_read_only_drained(bs, true, errp);
+
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
/*
* Reopen multiple BlockDriverStates atomically & transactionally.
*
@@ -3440,11 +3541,18 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
*/
int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
{
- int ret = -1;
+ int ret;
BlockReopenQueueEntry *bs_entry, *next;
assert(bs_queue != NULL);
+ ret = handle_recursive_reopens(QSIMPLEQ_FIRST(bs_queue), errp);
+ if (ret < 0) {
+ goto rollback_recursion;
+ }
+
+ ret = -1;
+
QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
assert(bs_entry->state.bs->quiesce_counter > 0);
if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, errp)) {
@@ -3485,7 +3593,7 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
ret = 0;
cleanup_perm:
- QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
+ QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
BDRVReopenState *state = &bs_entry->state;
if (!bs_entry->perms_checked) {
@@ -3502,7 +3610,7 @@ cleanup_perm:
}
}
cleanup:
- QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
+ QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
if (ret) {
if (bs_entry->prepared) {
bdrv_reopen_abort(&bs_entry->state);
@@ -3513,8 +3621,23 @@ cleanup:
if (bs_entry->state.new_backing_bs) {
bdrv_unref(bs_entry->state.new_backing_bs);
}
+ }
+
+rollback_recursion:
+ if (ret) {
+ Error *local_err = NULL;
+ int ret2 = rollback_recursive_reopens(bs_queue, &local_err);
+
+ if (ret2 < 0) {
+ error_reportf_err(local_err, "Failed to rollback partially "
+ "succeeded reopen to RW: ");
+ }
+ }
+
+ QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
g_free(bs_entry);
}
+
g_free(bs_queue);
return ret;
@@ -3524,14 +3647,9 @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
Error **errp)
{
int ret;
- BlockReopenQueue *queue;
- QDict *opts = qdict_new();
-
- qdict_put_bool(opts, BDRV_OPT_READ_ONLY, read_only);
bdrv_subtree_drained_begin(bs);
- queue = bdrv_reopen_queue(NULL, bs, opts, true);
- ret = bdrv_reopen_multiple(queue, errp);
+ ret = bdrv_reopen_set_read_only_drained(bs, read_only, errp);
bdrv_subtree_drained_end(bs);
return ret;
--
2.18.0
next prev parent reply other threads:[~2019-07-25 9:21 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-07-25 9:18 [Qemu-devel] [PATCH v3 for-4.1? 0/9] qcow2-bitmaps: rewrite reopening logic Vladimir Sementsov-Ogievskiy
2019-07-25 9:18 ` Vladimir Sementsov-Ogievskiy [this message]
2019-07-31 12:09 ` [Qemu-devel] [PATCH v3 1/9] block: add .bdrv_need_rw_file_child_during_reopen_rw handler Max Reitz
2019-08-01 14:02 ` Vladimir Sementsov-Ogievskiy
2019-08-01 19:06 ` Max Reitz
2019-08-02 8:49 ` Vladimir Sementsov-Ogievskiy
2019-08-02 15:42 ` Kevin Wolf
2019-08-02 16:23 ` Vladimir Sementsov-Ogievskiy
2019-08-02 16:41 ` Vladimir Sementsov-Ogievskiy
2019-07-25 9:18 ` [Qemu-devel] [PATCH v3 2/9] iotests.py: add event_wait_log and events_wait_log helpers Vladimir Sementsov-Ogievskiy
2019-07-25 9:18 ` [Qemu-devel] [PATCH v3 3/9] iotests: add test 260 to check bitmap life after snapshot + commit Vladimir Sementsov-Ogievskiy
2019-07-25 9:18 ` [Qemu-devel] [PATCH v3 4/9] block/qcow2-bitmap: get rid of bdrv_has_changed_persistent_bitmaps Vladimir Sementsov-Ogievskiy
2019-07-25 9:18 ` [Qemu-devel] [PATCH v3 5/9] block/qcow2-bitmap: drop qcow2_reopen_bitmaps_rw_hint() Vladimir Sementsov-Ogievskiy
2019-07-25 9:18 ` [Qemu-devel] [PATCH v3 6/9] block/qcow2-bitmap: do not remove bitmaps on reopen-ro Vladimir Sementsov-Ogievskiy
2019-07-25 9:18 ` [Qemu-devel] [PATCH v3 7/9] block/qcow2-bitmap: fix and improve qcow2_reopen_bitmaps_rw Vladimir Sementsov-Ogievskiy
2019-07-25 9:18 ` [Qemu-devel] [PATCH v3 8/9] block/qcow2-bitmap: fix reopening bitmaps to RW Vladimir Sementsov-Ogievskiy
2019-07-25 9:19 ` [Qemu-devel] [PATCH v3 9/9] qcow2-bitmap: move bitmap reopen-rw code to qcow2_reopen_prepare Vladimir Sementsov-Ogievskiy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190725091900.30542-2-vsementsov@virtuozzo.com \
--to=vsementsov@virtuozzo.com \
--cc=den@openvz.org \
--cc=fam@euphon.net \
--cc=jsnow@redhat.com \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).