Received: by 2002:a05:6a11:4021:0:0:0:0 with SMTP id ky33csp1047118pxb; Wed, 29 Sep 2021 15:49:10 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz+8S6oz1+qX1NhsZ7hJHS6IhqQtMcD3RxQErKHD3ZSGz/9DoS6dEhS7f43r00cetPHafTb X-Received: by 2002:a17:906:1d41:: with SMTP id o1mr2892563ejh.232.1632955749879; Wed, 29 Sep 2021 15:49:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1632955749; cv=none; d=google.com; s=arc-20160816; b=W325StiVBJ1Q+OFgMv0w7wlzXntuotV6759KTjKTBF8d1REuvbEGWwhEiv8y87mIK3 lQXLPRHyUspb13zaoDF1ZQ0gLKbtS+LEb6/NKpQPR3hNtxUBuUfgqaZrKAn+ucFhsCee zN9ZtmJaH2QyOPQHDrNAZm2hV65IyWArh6WX0j95xQ5XIYYx1RrsByBI/F1RmNdmzbJf Nldq5mS7FelZPVN0uO9cGwNQcQx1Vtw9u3jtvl+bV0VznHvyLZZzRTgvS1B+eJi9En8z 7wAzD8ffGaHoFOMQgl8JmtV5Uz+BCEFOlF9ohOKIfON3Fz4xIBqOnBOrJn15aF02RRIU PnGw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=WOwoHv88CcMlew28O/5Op0/z52m2pNxCN322nUNt0kQ=; b=Fnh5XJV3LXnmo4oz0VOzrJSyjbLbrFGrORwfcj3Coc5za5m4bWsH87stjUANwe1vMX PvJduE7gLsH0KWXIy1TwYs8cCk4aZpCfVVlzixaU4nsz5oj0w3ZMhnPU1G5Ae2mm1SFI 2Y9c6rUc+gTXRwqVphKroAj/vh/+C0Q6AnCx6DYMeQIP+G1u+V4VzAd1/ewfg8d3U6no +cuiKKcUqTHuNCh6mp5twTjt2DJOTSEZbj/XO96pmjnvNViuNo4Ba+B27mZRrfXTsV+J Zmj2kU1xuDqlutwPbCLSt9sVwfAMtbq03suwVNSsLMAd2ohprbvustX3LrCEmBtW4w4l LmoA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=YJhXZEah; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id f15si50914edx.534.2021.09.29.15.48.44; Wed, 29 Sep 2021 15:49:09 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=YJhXZEah; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1347192AbhI2WMN (ORCPT + 99 others); Wed, 29 Sep 2021 18:12:13 -0400 Received: from mail.kernel.org ([198.145.29.99]:60604 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347187AbhI2WMI (ORCPT ); Wed, 29 Sep 2021 18:12:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 56DF261452; Wed, 29 Sep 2021 22:10:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1632953426; bh=wsDMm7If47HCZO3ALGN+KOfL0mejbrd6DItavWuFyDU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YJhXZEah5eeO8PUoB1h3SEiEERvHRBAFnHu7C/grMMe50MXgDGBDvUMQsqHpLbCn6 4vKdUL0eg3aG2EFH5ZUVMXWuOlCgeO3SPodg1NeTmitvUfcts134iZJUq/86J0ALrc mlISkoUrDpbOI3p0n7pG5zO/0EqSJZp5XwQNcofSPSE7GbBlLtVdZB442rHpIFneI2 V57qexRzRL68GT/+zO/bqKTUMBl5MWaKG51dAOS/4CPm4r5nfgdzUU4SDkq1ve9oVx 312+rCwSSd5aExj8IeSmqnP1vM7TDuDCoz+/rXrrsfYNWiiTCbkrwq0rRU8wBFue5a Hlb0yKEvibMbA== From: Frederic Weisbecker To: "Paul E . McKenney" Cc: LKML , Frederic Weisbecker , Sebastian Andrzej Siewior , Peter Zijlstra , Uladzislau Rezki , Valentin Schneider , Thomas Gleixner , Boqun Feng , Neeraj Upadhyay , Josh Triplett , Joel Fernandes , rcu@vger.kernel.org Subject: [PATCH 03/11] rcu/nocb: Invoke rcu_core() at the start of deoffloading Date: Thu, 30 Sep 2021 00:10:04 +0200 Message-Id: <20210929221012.228270-4-frederic@kernel.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210929221012.228270-1-frederic@kernel.org> References: <20210929221012.228270-1-frederic@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On PREEMPT_RT, if rcu_core() is preempted by the de-offloading process, some work, such as callbacks acceleration and invocation, may be left unattended due to the volatile checks on the offloaded state. In the worst case this work is postponed until the next rcu_pending() check that can take a jiffy to reach, which can be a problem in case of callbacks flooding. Solve that with invoking rcu_core() early in the de-offloading process. This way any work dismissed by an ongoing rcu_core() call fooled by a preempting deoffloading process will be caught up by a nearby future recall to rcu_core(), this time fully aware of the de-offloading state. Signed-off-by: Frederic Weisbecker Cc: Valentin Schneider Cc: Peter Zijlstra Cc: Sebastian Andrzej Siewior Cc: Josh Triplett Cc: Joel Fernandes Cc: Boqun Feng Cc: Neeraj Upadhyay Cc: Uladzislau Rezki Cc: Thomas Gleixner --- include/linux/rcu_segcblist.h | 14 ++++++++++++++ kernel/rcu/rcu_segcblist.c | 6 ++---- kernel/rcu/tree.c | 17 +++++++++++++++++ kernel/rcu/tree_nocb.h | 9 +++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/include/linux/rcu_segcblist.h b/include/linux/rcu_segcblist.h index 812961b1d064..659d13a7ddaa 100644 --- a/include/linux/rcu_segcblist.h +++ b/include/linux/rcu_segcblist.h @@ -136,6 +136,20 @@ struct rcu_cblist { * |--------------------------------------------------------------------------| * | SEGCBLIST_RCU_CORE | | * | SEGCBLIST_LOCKING | | + * | SEGCBLIST_OFFLOADED | | + * | SEGCBLIST_KTHREAD_CB | | + * | SEGCBLIST_KTHREAD_GP | + * | | + * | CB/GP kthreads handle callbacks holding nocb_lock, local rcu_core() | + * | handles callbacks concurrently. Bypass enqueue is enabled. | + * | Invoke RCU core so we make sure not to preempt it in the middle with | + * | leaving some urgent work unattended within a jiffy. | + * ---------------------------------------------------------------------------- + * | + * v + * |--------------------------------------------------------------------------| + * | SEGCBLIST_RCU_CORE | | + * | SEGCBLIST_LOCKING | | * | SEGCBLIST_KTHREAD_CB | | * | SEGCBLIST_KTHREAD_GP | * | | diff --git a/kernel/rcu/rcu_segcblist.c b/kernel/rcu/rcu_segcblist.c index c07aab6e39ef..81145c3ece25 100644 --- a/kernel/rcu/rcu_segcblist.c +++ b/kernel/rcu/rcu_segcblist.c @@ -265,12 +265,10 @@ void rcu_segcblist_disable(struct rcu_segcblist *rsclp) */ void rcu_segcblist_offload(struct rcu_segcblist *rsclp, bool offload) { - if (offload) { + if (offload) rcu_segcblist_set_flags(rsclp, SEGCBLIST_LOCKING | SEGCBLIST_OFFLOADED); - } else { - rcu_segcblist_set_flags(rsclp, SEGCBLIST_RCU_CORE); + else rcu_segcblist_clear_flags(rsclp, SEGCBLIST_OFFLOADED); - } } /* diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index ef417769bab2..1512efc52816 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2717,6 +2717,23 @@ static __latent_entropy void rcu_core(void) unsigned long flags; struct rcu_data *rdp = raw_cpu_ptr(&rcu_data); struct rcu_node *rnp = rdp->mynode; + /* + * On RT rcu_core() can be preempted when IRQs aren't disabled. + * Therefore this function can race with concurrent NOCB (de-)offloading + * on this CPU and the below condition must be considered volatile. + * However if we race with: + * + * _ Offloading: In the worst case we accelerate or process callbacks + * concurrently with NOCB kthreads. We are guaranteed to + * call rcu_nocb_lock() if that happens. + * + * _ Deoffloading: In the worst case we miss callbacks acceleration or + * processing. This is fine because the early stage + * of deoffloading invokes rcu_core() after setting + * SEGCBLIST_RCU_CORE. So we guarantee that we'll process + * what could have been dismissed without the need to wait + * for the next rcu_pending() check in the next jiffy. + */ const bool do_batch = !rcu_segcblist_completely_offloaded(&rdp->cblist); if (cpu_is_offline(smp_processor_id())) diff --git a/kernel/rcu/tree_nocb.h b/kernel/rcu/tree_nocb.h index 71a28f50b40f..3b470113ae38 100644 --- a/kernel/rcu/tree_nocb.h +++ b/kernel/rcu/tree_nocb.h @@ -990,6 +990,15 @@ static long rcu_nocb_rdp_deoffload(void *arg) * will refuse to put anything into the bypass. */ WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, jiffies)); + /* + * Start with invoking rcu_core() early. This way if the current thread + * happens to preempt an ongoing call to rcu_core() in the middle, + * leaving some work dismissed because rcu_core() still thinks the rdp is + * completely offloaded, we are guaranteed a nearby future instance of + * rcu_core() to catch up. + */ + rcu_segcblist_set_flags(cblist, SEGCBLIST_RCU_CORE); + invoke_rcu_core(); ret = rdp_offload_toggle(rdp, false, flags); swait_event_exclusive(rdp->nocb_state_wq, !rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_CB | -- 2.25.1