From nobody Wed Nov 5 10:30:41 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1499359379064879.2955207546722; Thu, 6 Jul 2017 09:42:59 -0700 (PDT) Received: from localhost ([::1]:52399 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dT9rk-0008MD-PR for importer@patchew.org; Thu, 06 Jul 2017 12:42:56 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:33126) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dT9nh-0004qP-OT for qemu-devel@nongnu.org; Thu, 06 Jul 2017 12:38:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dT9ng-00062i-Jf for qemu-devel@nongnu.org; Thu, 06 Jul 2017 12:38:45 -0400 Received: from mx1.redhat.com ([209.132.183.28]:46164) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dT9nd-0005zn-Sb; Thu, 06 Jul 2017 12:38:42 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D87364DD49; Thu, 6 Jul 2017 16:38:40 +0000 (UTC) Received: from donizetti.redhat.com (ovpn-117-229.ams2.redhat.com [10.36.117.229]) by smtp.corp.redhat.com (Postfix) with ESMTP id B8FAC60A9D; Thu, 6 Jul 2017 16:38:39 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com D87364DD49 Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=pbonzini@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com D87364DD49 From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Thu, 6 Jul 2017 18:38:21 +0200 Message-Id: <20170706163828.24082-5-pbonzini@redhat.com> In-Reply-To: <20170706163828.24082-1-pbonzini@redhat.com> References: <20170706163828.24082-1-pbonzini@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Thu, 06 Jul 2017 16:38:41 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 04/11] block: make before-write notifiers thread-safe X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: famz@redhat.com, stefanha@redhat.com, qemu-block@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Reads access the list in RCU style, so be careful to avoid use-after-free scenarios in the backup block job. Apart from this, all that's needed is protecting updates with a mutex. Signed-off-by: Paolo Bonzini Reviewed-by: Stefan Hajnoczi --- block/backup.c | 17 +++++++++++++---- block/io.c | 12 ++++++++++++ block/write-threshold.c | 2 +- include/block/block_int.h | 16 ++++++++++++++++ 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/block/backup.c b/block/backup.c index 5387fbd84e..9214ffcc58 100644 --- a/block/backup.c +++ b/block/backup.c @@ -246,6 +246,13 @@ static void backup_abort(BlockJob *job) static void backup_clean(BlockJob *job) { BackupBlockJob *s =3D container_of(job, BackupBlockJob, common); + + /* Ensure that no I/O is using the notifier anymore before freeing + * the bitmap and the job. + */ + blk_drain(job->blk); + g_free(s->done_bitmap); + assert(s->target); blk_unref(s->target); s->target =3D NULL; @@ -526,12 +533,14 @@ static void coroutine_fn backup_run(void *opaque) } } =20 - notifier_with_return_remove(&job->before_write); - - /* wait until pending backup_do_cow() calls have completed */ + /* At this point, all future invocations of the write notifier will + * find a 1 in the done_bitmap, but we still have to wait for pending + * backup_do_cow() calls to complete. + */ qemu_co_rwlock_wrlock(&job->flush_rwlock); qemu_co_rwlock_unlock(&job->flush_rwlock); - g_free(job->done_bitmap); + + bdrv_remove_before_write_notifier(bs, &job->before_write); =20 data =3D g_malloc(sizeof(*data)); data->ret =3D ret; diff --git a/block/io.c b/block/io.c index 68f19bbe69..089866bb5e 100644 --- a/block/io.c +++ b/block/io.c @@ -2499,10 +2499,22 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEM= UIOVector *qiov) return true; } =20 +static QemuSpin notifiers_spin_lock; + void bdrv_add_before_write_notifier(BlockDriverState *bs, NotifierWithReturn *notifier) { + qemu_spin_lock(¬ifiers_spin_lock); notifier_with_return_list_add(&bs->before_write_notifiers, notifier); + qemu_spin_unlock(¬ifiers_spin_lock); +} + +void bdrv_remove_before_write_notifier(BlockDriverState *bs, + NotifierWithReturn *notifier) +{ + qemu_spin_lock(¬ifiers_spin_lock); + notifier_with_return_remove(notifier); + qemu_spin_unlock(¬ifiers_spin_lock); } =20 void bdrv_io_plug(BlockDriverState *bs) diff --git a/block/write-threshold.c b/block/write-threshold.c index 64ddd3d653..53c8caeda7 100644 --- a/block/write-threshold.c +++ b/block/write-threshold.c @@ -32,7 +32,7 @@ bool bdrv_write_threshold_is_set(const BlockDriverState *= bs) static void write_threshold_disable(BlockDriverState *bs) { if (bdrv_write_threshold_is_set(bs)) { - notifier_with_return_remove(&bs->write_threshold_notifier); + bdrv_remove_before_write_notifier(bs, &bs->write_threshold_notifie= r); bs->write_threshold_offset =3D 0; } } diff --git a/include/block/block_int.h b/include/block/block_int.h index 6d3fbbfc1e..173d9dcaf9 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -707,6 +707,8 @@ void bdrv_parse_filename_strip_prefix(const char *filen= ame, const char *prefix, =20 /** * bdrv_add_before_write_notifier: + * @bs: The #BlockDriverState for which to register the notifier + * @notifier: The notifier to add * * Register a callback that is invoked before write requests are processed= but * after any throttling or waiting for overlapping requests. @@ -715,6 +717,20 @@ void bdrv_add_before_write_notifier(BlockDriverState *= bs, NotifierWithReturn *notifier); =20 /** + * bdrv_remove_before_write_notifier: + * @bs: The #BlockDriverState for which to register the notifier + * @notifier: The notifier to add + * + * Unregister a callback that is invoked before write requests are process= ed but + * after any throttling or waiting for overlapping requests. + * + * Note that more I/O could be pending on @bs. You need to wait for + * it to finish, for example with bdrv_drain(), before freeing @notifier. + */ +void bdrv_remove_before_write_notifier(BlockDriverState *bs, + NotifierWithReturn *notifier); + +/** * bdrv_detach_aio_context: * * May be called from .bdrv_detach_aio_context() to detach children from t= he --=20 2.13.0