58 lines
2.1 KiB
Diff
58 lines
2.1 KiB
Diff
From 95166cdeaeaa9d00330483988b818abfcc473efe Mon Sep 17 00:00:00 2001
|
|
From: Kevin Wolf <kwolf@redhat.com>
|
|
Date: Mon, 29 May 2017 14:08:32 +0200
|
|
Subject: [PATCH 10/15] mirror: Drop permissions on s->target on completion
|
|
|
|
This fixes an assertion failure that was triggered by qemu-iotests 129
|
|
on some CI host, while the same test case didn't seem to fail on other
|
|
hosts.
|
|
|
|
Essentially the problem is that the blk_unref(s->target) in
|
|
mirror_exit() doesn't necessarily mean that the BlockBackend goes away
|
|
immediately. It is possible that the job completion was triggered nested
|
|
in mirror_drain(), which looks like this:
|
|
|
|
BlockBackend *target = s->target;
|
|
blk_ref(target);
|
|
blk_drain(target);
|
|
blk_unref(target);
|
|
|
|
In this case, the write permissions for s->target are retained until
|
|
after blk_drain(), which makes removing mirror_top_bs fail for the
|
|
active commit case (can't have a writable backing file in the chain
|
|
without the filter driver).
|
|
|
|
Explicitly dropping the permissions first means that the additional
|
|
reference doesn't hurt and the job can complete successfully even if
|
|
called from the nested blk_drain().
|
|
|
|
Cc: qemu-stable@nongnu.org
|
|
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
|
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
|
---
|
|
block/mirror.c | 7 ++++++-
|
|
1 file changed, 6 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/block/mirror.c b/block/mirror.c
|
|
index 164438f422..779b753b8a 100644
|
|
--- a/block/mirror.c
|
|
+++ b/block/mirror.c
|
|
@@ -514,7 +514,12 @@ static void mirror_exit(BlockJob *job, void *opaque)
|
|
|
|
/* Remove target parent that still uses BLK_PERM_WRITE/RESIZE before
|
|
* inserting target_bs at s->to_replace, where we might not be able to get
|
|
- * these permissions. */
|
|
+ * these permissions.
|
|
+ *
|
|
+ * Note that blk_unref() alone doesn't necessarily drop permissions because
|
|
+ * we might be running nested inside mirror_drain(), which takes an extra
|
|
+ * reference, so use an explicit blk_set_perm() first. */
|
|
+ blk_set_perm(s->target, 0, BLK_PERM_ALL, &error_abort);
|
|
blk_unref(s->target);
|
|
s->target = NULL;
|
|
|
|
--
|
|
2.11.0
|
|
|