Received: by 2002:a05:6358:11c7:b0:104:8066:f915 with SMTP id i7csp6798413rwl; Wed, 22 Mar 2023 16:12:41 -0700 (PDT) X-Google-Smtp-Source: AK7set9CUNWTKWOgfDu6NyisMQWoTx4hc7vDco/a2iQzx0tUrBR689CSnZyM7aZYRWh27D/XhatJ X-Received: by 2002:a17:90b:4c8e:b0:23f:e653:4a5a with SMTP id my14-20020a17090b4c8e00b0023fe6534a5amr5762525pjb.39.1679526761468; Wed, 22 Mar 2023 16:12:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1679526761; cv=none; d=google.com; s=arc-20160816; b=aQsrLL773x+CkQThU8uwdW7+TgDNa4ejH+vPqms1Om68TyWUuBNfbi01dim5H0QtU2 wD3vO3TNxHfndE6RW1ZdhLSSqd9kSe2UHOETb+uCVi2NlpBCb1Q8m1GMKBbFd9NGSiG0 9kOcegx6Lttw7nOSGqfIMu9dfYNGfzd4mS9g1fHuqLi9uQRGYbps/YoW/mwBgCOX53oc 0xKN4QPHJ52EJM7udtUmH65jcqEDiroumF0+l4mi26lEG8sSjK8pcojg9ImaPzXoeK7q fLZNHrl+ai8Msmcs3sfLet1Svz24b+gi8ShdO1Dt6K8anE8Bv+lJGPXYPDZ8m/C4BTo8 0sIg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:in-reply-to:content-disposition:mime-version :references:reply-to:message-id:subject:cc:to:from:date :dkim-signature; bh=zo/WEJ5FBVjBDZFbIp9qFaHVTqQBT6RUL1IMmcXeRKg=; b=doiJS2JWFuVa+Qq9MU5XlO2JE9MLSbY/uGKO4NYtIQkJc38YlkMH9MwbrfmKLWO6af bs/w8Yxkmis6X7zn7q3s58QuE4JCnmGQpVCkcUc21qSgg+mgBnjsJS9PteSgeYw+ozMZ SjzcSHnMaCgQ1vwS70imhkB5VBPPrdI1yWfHaBLMva2zG2WrsSRFdHB+3ggY5fzQnTVT kTgzfcu/7j3Yxch6yMbunM0mgHZFDV42xcBcvBU0YTJah7MUGjFQWBGntG0fVdV1Ih/c FOSgMr55LFtDCm+D3EFvd6T1DYLbZUmc4TFGuy3PFhIl4cRNbR3340FCaGOhgB6QdWwS yQyQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=VTvSBxgE; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 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 out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id i71-20020a63874a000000b004fc4c511c57si18123174pge.307.2023.03.22.16.12.28; Wed, 22 Mar 2023 16:12:41 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=VTvSBxgE; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 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 S229555AbjCVXKb (ORCPT + 99 others); Wed, 22 Mar 2023 19:10:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36480 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229713AbjCVXK3 (ORCPT ); Wed, 22 Mar 2023 19:10:29 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5E3C9F974; Wed, 22 Mar 2023 16:10:27 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 13206B81E53; Wed, 22 Mar 2023 23:10:26 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id BAC32C433EF; Wed, 22 Mar 2023 23:10:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1679526624; bh=Wf4AgwlGiL40JvNImMnaz29SvkVmE/NH+GJD3zL+bfg=; h=Date:From:To:Cc:Subject:Reply-To:References:In-Reply-To:From; b=VTvSBxgE1Xo6IWI8zm3nzP49jNOkVCtsYRMmYKXsyTvrb2ewEXBvEAbOqrOXNnp6Q KMpxVko5TzWsW4eYK168vrEal9l+hhoS05Usf77dctryp6QeM7DInOfLFcKRFrVU6W W88DlNuCC9e+2XTjAyCr9ye7HADrUQMRva1YqFoln0do90U4xEU00GbkUwx39+CUBs lekkF0G7g8uKmgVZDVU+gbjiKBrqXHtsgBXENyniRXXuXSM35eaGXkbSYQhxND7Zml RA6mFsZc3gF0Ioj0R4vMrM+AyyKFuqcoPBQdrkq7ixZNGBXgYfG+7lNTG2NHPXqN58 Ty5PlC7oYz5Lg== Received: by paulmck-ThinkPad-P72.home (Postfix, from userid 1000) id 4F7021540397; Wed, 22 Mar 2023 16:10:24 -0700 (PDT) Date: Wed, 22 Mar 2023 16:10:24 -0700 From: "Paul E. McKenney" To: "Zhang, Qiang1" Cc: "frederic@kernel.org" , "joel@joelfernandes.org" , "rcu@vger.kernel.org" , "linux-kernel@vger.kernel.org" , "qiang.zhang1211@gmail.com" Subject: Re: [PATCH] srcu: Fix flush sup work warning in cleanup_srcu_struct() Message-ID: <4a9525f8-30a3-4ca9-87ec-355cde7f6ed6@paulmck-laptop> Reply-To: paulmck@kernel.org References: <20230321081346.192000-1-qiang1.zhang@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: X-Spam-Status: No, score=-2.5 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_MED,SPF_HELO_NONE, SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed, Mar 22, 2023 at 10:08:54PM +0000, Zhang, Qiang1 wrote: > > > > insmod rcutorture.ko > > > > rmmod rcutorture.ko > > > > > > > > [ 209.437327] WARNING: CPU: 0 PID: 508 at kernel/workqueue.c:3167 > > > > __flush_work+0x50a/0x540 [ 209.437346] Modules linked in: > > > > rcutorture(-) torture [last unloaded: rcutorture] [ 209.437382] > > > > CPU: 0 PID: 508 Comm: rmmod Tainted: G W 6.3.0-rc1-yocto-standard+ > > > > [ 209.437406] RIP: 0010:__flush_work+0x50a/0x540 ..... > > > > [ 209.437758] flush_delayed_work+0x36/0x90 [ 209.437776] > > > > cleanup_srcu_struct+0x68/0x2e0 [ 209.437817] > > > > srcu_module_notify+0x71/0x140 [ 209.437854] > > > > blocking_notifier_call_chain+0x9d/0xd0 > > > > [ 209.437880] __x64_sys_delete_module+0x223/0x2e0 > > > > [ 209.438046] do_syscall_64+0x43/0x90 [ 209.438062] > > > > entry_SYSCALL_64_after_hwframe+0x72/0xdc > > > > > > > > For srcu objects defined with DEFINE_SRCU() or DEFINE_STATIC_SRCU(), > > > > when compiling and loading as modules, the srcu_module_coming() is > > > > invoked, allocate memory for srcu structure's->sda and initialize > > > > sda structure, due to not fully initialize srcu structure's->sup, so > > > > at this time the sup structure's->delaywork.func is null, if not > > > > invoke init_srcu_struct_fields() before unloading modules, in > > > > srcu_module_going() the __flush_work() find > > > > work->func is empty, will raise the warning above. > > > > > > > > This commit add init_srcu_struct_fields() to initialize srcu > > > > structure's->sup, in srcu_module_coming(). > > > > > > > > Signed-off-by: Zqiang > > > > > > > >Good catch, and thank you for testing the in-module case! > > > > > > > >One question below... > > > > > > > > Thanx, Paul > > > > > > > > --- > > > > kernel/rcu/srcutree.c | 11 ++++++++--- > > > > 1 file changed, 8 insertions(+), 3 deletions(-) > > > > > > > > diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c index > > > > 1fb078abbdc9..42d8720e016c 100644 > > > > --- a/kernel/rcu/srcutree.c > > > > +++ b/kernel/rcu/srcutree.c > > > > @@ -1921,7 +1921,8 @@ static int srcu_module_coming(struct module *mod) > > > > ssp->sda = alloc_percpu(struct srcu_data); > > > > if (WARN_ON_ONCE(!ssp->sda)) > > > > return -ENOMEM; > > > > - init_srcu_struct_data(ssp); > > > > + if (WARN_ON_ONCE(init_srcu_struct_fields(ssp, true))) > > > > + return -ENOMEM; > > > > > > > >Wouldn't it be better to simply delete the init_srcu_struct_data()? > > > > > > > >Then the first call to check_init_srcu_struct() would take care of > > > >the initialization, just as for the non-module case. Or am I missing > > > >something subtle? > > > > > > Hi Paul > > > > > > Maybe the check_init_srcu_struct() is always not invoked, for example, > > > In rcutorture.c, here is such a definition DEFINE_STATIC_SRCU(srcu_ctl), > > > but we use torture_type=rcu to test, there will not be any interface > > > calling > > > check_init_srcu_struct() to initialize srcu_ctl and set > > > structure's->delaywork.func is process_srcu(). > > > when we unload the rcutorture module, invoke cleanup_srcu_struct() to > > > flush sup structure's->delaywork.func, due to the func pointer is not > > > initialize, it's null, will trigger warning. > > > > > > About kernel/workqueue.c:3167 > > > > > > __flush_work > > > if (WARN_ON(!work->func)) <---------trigger waning > > > return false; > > > > > > > > > and in init_srcu_struct_fields(ssp, true), wil set > > > srcu_sup->sda_is_static is true and set srcu_sup-> srcu_gp_seq_needed > > > is zero, after that when we call > > > check_init_srcu_struct() again, it not be initialized again. > > > > > > > > >Good point! In the non-module statically allocated case there is never a call to cleanup_srcu_struct(). > > > > > >So suppose the code in srcu_module_coming() only did the alloc_percpu(), and then the > > >code in srcu_module_going() only did the the matching > > >free_percpu() instead of the current cleanup_srcu_struct()? > > > > But in modules, for srcu objects defined with DEFINE_SRCU() or DEFINE_STATIC_SRCU(), > > when a module is unloaded, we usually don't call cleanup_srcu_struct() in the module > > unload function. > > If in srcu_module_going() only do free_percpu(), the srcu_sup->node memory maybe > > can not free and also lost the opportunity to refresh the running work. > > > > > >But in the module case, isn't the srcu_sup->node also statically > >allocated via the "static struct srcu_usage" declaration? > > static bool init_srcu_struct_nodes(struct srcu_struct *ssp, gfp_t gfp_flags) > { > sp->srcu_sup->node = kcalloc(rcu_num_nodes, sizeof(*ssp->srcu_sup->node), gfp_flags); > ... > } > > Regardless of whether the srcu object is declared in the module or not, sup->node is dynamically allocated. > right? You are absolutely right, thank you! There are a couple of ways to resolve this. One is to simply add a check_init_srcu_struct() before the call to cleanup_srcu_struct() from srcu_module_going(), as shown below. This seems a bit silly, potentially initializing fields for no good reason. Another way is to make cleanup_srcu_struct() do the same check that check_init_srcu_struct() does: rcu_seq_state(smp_load_acquire(&ssp->srcu_sup->srcu_gp_seq_needed)) If the value is non-zero, then cleanup_srcu_struct() should skip consistency checks that complain about things that cannot happen if there never was an RCU grace period. Maybe something as shown after the second line of dashes. Thoughts? Thanx, Paul ------------------------------------------------------------------------ /* Initialize any global-scope srcu_struct structures used by this module. */ static int srcu_module_coming(struct module *mod) { int i; struct srcu_struct **sspp = mod->srcu_struct_ptrs; struct srcu_struct *ssp; for (i = 0; i < mod->num_srcu_structs; i++) { ssp = *(sspp++); ssp->sda = alloc_percpu(struct srcu_data); if (WARN_ON_ONCE(!ssp->sda)) return -ENOMEM; init_srcu_struct_data(ssp); } return 0; } /* Clean up any global-scope srcu_struct structures used by this module. */ static void srcu_module_going(struct module *mod) { int i; struct srcu_struct *ssp; struct srcu_struct **sspp = mod->srcu_struct_ptrs; for (i = 0; i < mod->num_srcu_structs; i++) { ssp = *(sspp++); check_init_srcu_struct(ssp); cleanup_srcu_struct(ssp); } } ------------------------------------------------------------------------ void cleanup_srcu_struct(struct srcu_struct *ssp) { int cpu; struct srcu_usage *sup = ssp->srcu_sup; bool wasused = !rcu_seq_state(smp_load_acquire(&ssp->srcu_sup->srcu_gp_seq_needed)); if (WARN_ON(wasused && !srcu_get_delay(ssp))) return; /* Just leak it! */ if (WARN_ON(srcu_readers_active(ssp))) return; /* Just leak it! */ flush_delayed_work(&sup->work); if (wasused) { for_each_possible_cpu(cpu) { struct srcu_data *sdp = per_cpu_ptr(ssp->sda, cpu); del_timer_sync(&sdp->delay_work); flush_work(&sdp->work); if (WARN_ON(rcu_segcblist_n_cbs(&sdp->srcu_cblist))) return; /* Forgot srcu_barrier(), so just leak it! */ } } if (WARN_ON(wasused && rcu_seq_state(READ_ONCE(sup->srcu_gp_seq)) != SRCU_STATE_IDLE) || WARN_ON(wasused && rcu_seq_current(&sup->srcu_gp_seq) != sup->srcu_gp_seq_needed) || WARN_ON(srcu_readers_active(ssp))) { pr_info("%s: Active srcu_struct %p read state: %d gp state: %lu/%lu\n", __func__, ssp, rcu_seq_state(READ_ONCE(sup->srcu_gp_seq)), rcu_seq_current(&sup->srcu_gp_seq), sup->srcu_gp_seq_needed); return; /* Caller forgot to stop doing call_srcu()? */ } kfree(sup->node); sup->node = NULL; sup->srcu_size_state = SRCU_SIZE_SMALL; if (!sup->sda_is_static) { free_percpu(ssp->sda); ssp->sda = NULL; kfree(sup); ssp->srcu_sup = NULL; } }