From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932283AbbIUNG5 (ORCPT ); Mon, 21 Sep 2015 09:06:57 -0400 Received: from mx2.suse.de ([195.135.220.15]:52550 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756918AbbIUNFz (ORCPT ); Mon, 21 Sep 2015 09:05:55 -0400 From: Petr Mladek To: Andrew Morton , Oleg Nesterov , Tejun Heo , Ingo Molnar , Peter Zijlstra Cc: Steven Rostedt , "Paul E. McKenney" , Josh Triplett , Thomas Gleixner , Linus Torvalds , Jiri Kosina , Borislav Petkov , Michal Hocko , linux-mm@kvack.org, Vlastimil Babka , live-patching@vger.kernel.org, linux-api@vger.kernel.org, linux-kernel@vger.kernel.org, Petr Mladek Subject: [RFC v2 16/18] rcu: Check actual RCU_GP_FLAG_FQS when handling quiescent state Date: Mon, 21 Sep 2015 15:03:57 +0200 Message-Id: <1442840639-6963-17-git-send-email-pmladek@suse.com> X-Mailer: git-send-email 1.8.5.6 In-Reply-To: <1442840639-6963-1-git-send-email-pmladek@suse.com> References: <1442840639-6963-1-git-send-email-pmladek@suse.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This change will help a lot if we want to split RCU kthreads into few kthread works. The variable "qf" was added by the commit 88d6df612cc3c99f56 ("rcu: Prevent spurious-wakeup DoS attack on rcu_gp_kthread()"). IMHO, the primary fix is the "ret" handling. If I read the code correctly, RCU_GP_FLAG_FQS should not get lost at this stage. rsp->gp_flags are written in these functions: + rcu_gp_init() + rcu_gp_cleanup() + Both are safe. They are called from other part of the kthread that can't get accessed when "gf" is used. + rcu_gp_fqs() + Safe. It is the function that we call when the flag is set. + rcu_report_qs_rsp() + force_quiescent_state() + Both should be safe. They set RCU_GP_FLAG_FQS and therefore they could not cause loss of rcu_gp_fqs() call. + rcu_start_gp_advanced() + This should be safe. It is called only when the last grace period was completed and we are opening a new one. Therefore it should not happen when "gf" is set and tested because the grace period is closed by the kthread. Signed-off-by: Petr Mladek --- kernel/rcu/tree.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 286e300794f0..08d1d3e63b9b 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -1908,13 +1908,12 @@ static int rcu_gp_init(struct rcu_state *rsp) * Helper function for wait_event_interruptible_timeout() wakeup * at force-quiescent-state time. */ -static bool rcu_gp_fqs_check_wake(struct rcu_state *rsp, int *gfp) +static bool rcu_gp_fqs_check_wake(struct rcu_state *rsp) { struct rcu_node *rnp = rcu_get_root(rsp); /* Someone like call_rcu() requested a force-quiescent-state scan. */ - *gfp = READ_ONCE(rsp->gp_flags); - if (*gfp & RCU_GP_FLAG_FQS) + if (READ_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) return true; /* The current grace period has completed. */ @@ -2072,7 +2071,6 @@ static unsigned long normalize_jiffies_till_next_fqs(void) */ static int __noreturn rcu_gp_kthread(void *arg) { - int gf; unsigned long timeout, j; struct rcu_state *rsp = arg; struct rcu_node *rnp = rcu_get_root(rsp); @@ -2111,7 +2109,7 @@ static int __noreturn rcu_gp_kthread(void *arg) TPS("fqswait")); rsp->gp_state = RCU_GP_WAIT_FQS; wait_event_interruptible_timeout(rsp->gp_wq, - rcu_gp_fqs_check_wake(rsp, &gf), + rcu_gp_fqs_check_wake(rsp), timeout); rsp->gp_state = RCU_GP_DOING_FQS; try_again: @@ -2122,7 +2120,7 @@ try_again: break; /* If time for quiescent-state forcing, do it. */ if (ULONG_CMP_GE(jiffies, rsp->jiffies_force_qs) || - (gf & RCU_GP_FLAG_FQS)) { + (READ_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS)) { trace_rcu_grace_period(rsp->name, READ_ONCE(rsp->gpnum), TPS("fqsstart")); -- 1.8.5.6