aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergio Lopez <slp@redhat.com>2019-09-11 12:03:16 +0200
committerMichael Roth <mdroth@linux.vnet.ibm.com>2019-10-01 16:58:28 -0500
commitb9405afb0956fe2c293a94bdc4440579e5c0efee (patch)
treecd68ed028e35bc9d901d984b4043703622a788ca
parent6cb3e9e4f17c182c43ded773a04b1072c881aa78 (diff)
blockjob: update nodes head while removing all bdrv
block_job_remove_all_bdrv() iterates through job->nodes, calling bdrv_root_unref_child() for each entry. The call to the latter may reach child_job_[can_]set_aio_ctx(), which will also attempt to traverse job->nodes, potentially finding entries that where freed on previous iterations. To avoid this situation, update job->nodes head on each iteration to ensure that already freed entries are no longer linked to the list. RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1746631 Signed-off-by: Sergio Lopez <slp@redhat.com> Cc: qemu-stable@nongnu.org Signed-off-by: Max Reitz <mreitz@redhat.com> Message-id: 20190911100316.32282-1-mreitz@redhat.com Reviewed-by: Sergio Lopez <slp@redhat.com> Signed-off-by: Max Reitz <mreitz@redhat.com> (cherry picked from commit d876bf676f5e7c6aa9ac64555e48cba8734ecb2f) Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
-rw-r--r--blockjob.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/blockjob.c b/blockjob.c
index 730101d282..d770144fd6 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -193,14 +193,23 @@ static const BdrvChildRole child_job = {
void block_job_remove_all_bdrv(BlockJob *job)
{
- GSList *l;
- for (l = job->nodes; l; l = l->next) {
+ /*
+ * bdrv_root_unref_child() may reach child_job_[can_]set_aio_ctx(),
+ * which will also traverse job->nodes, so consume the list one by
+ * one to make sure that such a concurrent access does not attempt
+ * to process an already freed BdrvChild.
+ */
+ while (job->nodes) {
+ GSList *l = job->nodes;
BdrvChild *c = l->data;
+
+ job->nodes = l->next;
+
bdrv_op_unblock_all(c->bs, job->blocker);
bdrv_root_unref_child(c);
+
+ g_slist_free_1(l);
}
- g_slist_free(job->nodes);
- job->nodes = NULL;
}
int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,