From nobody Sat Feb 7 09:30:33 2026 Received: from mail-07.mail-europe.com (mail-0701.mail-europe.com [51.83.17.38]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9D5F34779B5 for ; Wed, 21 Jan 2026 13:20:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=51.83.17.38 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769001650; cv=none; b=UoG8B101XTnjb8tX2/2kBnCw8TVO/JGx2J0oK2pfUkIc/UA5vBddRPx1sUwCh1AYp24ETf9MHM3II22omuNI//MDmWoVN6VEXTte+YgcdYAiWlvtDLnMDGoojXsPZVrum4IY30QCGcfrDsNEoOWy2wLqXwsfb5OcMJYWdxobm4U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769001650; c=relaxed/simple; bh=yd2NOl8qR9vazUYyuNp5iURVq8i3q+QR3gXcTq1q5bM=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HHTueMw0q2/iEk+xSbvP0Qqci/p5ntbB0PwOn8H09ZmCKlwVnTfys5GWOFyj4j4XWT4GGhf2ZMSBfrfe9oZbu41GrMVyS+RAxKvrRFPJFIp7t1fvA9ishH/dPqm4Aksn0Fp4DYkbmHMcpXqxuXAhAQM+fRfex85dMhCWmXo8i1c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org; spf=fail smtp.mailfrom=1g4.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b=FinjMozh; arc=none smtp.client-ip=51.83.17.38 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=1g4.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b="FinjMozh" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1g4.org; s=protonmail2; t=1769001638; x=1769260838; bh=uR0vWLX68z8KOTADUQfKb6VvihqOcenbH5spIdlB5Z4=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=FinjMozh5Z5R9rPjNI107142E9H/ovUjDxoovDjwCOOJrkK2gsjBnZ38IzCwG6ymA C031a+Sl/TKWnCq2ifB3EhSLmXj7NfNRYzR7YzUCGgpGbptpSc4xs6CXcuEBePyedx jQf4FAl1hh/sKqD6sl5J6KAOmbyXOS/DB6csf47/jY91YHNmye0G5VJRBGBeUD9Tjh hJXkTkBRWxB5fZAdWFHl5fxrO6vqKDn1P6TMN9Devwg+0Iwi/mFs3o86ha3IOSw9Rp Z7jvyo7cVlea2PPQSXAJ9lKSzzMxxRH/HHexB3gywu8SgsDa5BI5JEo3SlaL1kXxsb /E5ONiWnWAgIA== Date: Wed, 21 Jan 2026 13:20:35 +0000 To: netdev@vger.kernel.org From: Paul Moses Cc: Jamal Hadi Salim , Cong Wang , Jiri Pirko , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , linux-kernel@vger.kernel.org, Paul Moses , stable@vger.kernel.org Subject: [PATCH net v3 1/7] net/sched: act_gate: zero-initialize netlink dump struct Message-ID: <20260121131954.2710459-2-p@1g4.org> In-Reply-To: <20260121131954.2710459-1-p@1g4.org> References: <20260121131954.2710459-1-p@1g4.org> Feedback-ID: 8253658:user:proton X-Pm-Message-ID: 2edab436c14d019c28ffa4bb4b211b0ade442e2d Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Zero-initialize the dump struct before selective assignment to avoid leaking stack padding in netlink replies. This matches other actions (e.g. act_connmark) that zero-init their dump structs. Fixes: a51c328df310 ("net: qos: introduce a gate control flow action") Cc: stable@vger.kernel.org Signed-off-by: Paul Moses --- net/sched/act_gate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/sched/act_gate.c b/net/sched/act_gate.c index c1f75f2727576..aacd57e5f4374 100644 --- a/net/sched/act_gate.c +++ b/net/sched/act_gate.c @@ -499,16 +499,16 @@ static int tcf_gate_dump(struct sk_buff *skb, struct = tc_action *a, { unsigned char *b =3D skb_tail_pointer(skb); struct tcf_gate *gact =3D to_gate(a); - struct tc_gate opt =3D { - .index =3D gact->tcf_index, - .refcnt =3D refcount_read(&gact->tcf_refcnt) - ref, - .bindcnt =3D atomic_read(&gact->tcf_bindcnt) - bind, - }; + struct tc_gate opt =3D { }; struct tcfg_gate_entry *entry; struct tcf_gate_params *p; struct nlattr *entry_list; struct tcf_t t; =20 + opt.index =3D gact->tcf_index; + opt.refcnt =3D refcount_read(&gact->tcf_refcnt) - ref; + opt.bindcnt =3D atomic_read(&gact->tcf_bindcnt) - bind; + spin_lock_bh(&gact->tcf_lock); opt.action =3D gact->tcf_action; =20 --=20 2.52.GIT From nobody Sat Feb 7 09:30:33 2026 Received: from mail-244102.protonmail.ch (mail-244102.protonmail.ch [109.224.244.102]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 566C32638BA for ; Wed, 21 Jan 2026 13:30:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=109.224.244.102 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769002226; cv=none; b=pKzl2t7G64vLdVgLZTN3AHumLOfdAv1Az8oWSTxsE8nd06gKjQ26bsiZyzgK/FuoxNWWw5/XpDfwPbWB3eX+HyVFXShIzbPC9j01UikEw2Nl1SRQ5TimLAlJhfmFhurpa2S2585jtsuyR/ra3aYj21co7uIfAunvw9bYRABczns= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769002226; c=relaxed/simple; bh=CByq8Rjc7VnWJfDcxQGqjCghF/JuTIVolRuNii0tPg4=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=riHn3hDGHgdHxsB2uirCjpozZqGX8r4Oy9kNKsvouLadaFVO14AT7XUDFeiWziJh/ppNCbG6ZWDmEjCzbOw60OJ5jS/rii1jFpZlkHf0OX4bl9i7WJwmek7H4/88CEueJgyWl4oLeAqvxAXWA5N1AVtdbmFh7+QgMOKk7UruwFk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org; spf=pass smtp.mailfrom=1g4.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b=VCfohR/n; arc=none smtp.client-ip=109.224.244.102 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=1g4.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b="VCfohR/n" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1g4.org; s=protonmail2; t=1769001643; x=1769260843; bh=U370DSssnpJ04+nHhdTe4tH1gCzAdqbKpil7xi9UpNU=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=VCfohR/nwz52wB3iLx37KLtEnpqLoKsBh2rvzOM8SOIA2+kAsV9ES5i/9osHfqS7c 2Tnet479Ed/fWeohSy2qA2a19D3sPx+HUQ29jv7pbxwkt6TEE2SDn5IpXvE8S74up4 /Oy8NcltDzfd3nNlrmjVNYHMF6jrPktM2rYEViTCWfcRA+HVEUHD2TFZghYR6z8Ofy tnCIJdHKT+Fn2AbABu2Bz0L+IzFjdJDnaSDTR2Vl8QmfXnfuvl+cvdRbyGNPSUcRdt KZ3BnmomXTIQuShiP5jOnfGOprQ6dPxUkQL4KsutmCsvER5e/eCQbs8x/kAw38yraL rE0NV6t/IN7Lg== Date: Wed, 21 Jan 2026 13:20:39 +0000 To: netdev@vger.kernel.org From: Paul Moses Cc: Jamal Hadi Salim , Cong Wang , Jiri Pirko , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , linux-kernel@vger.kernel.org, Paul Moses , stable@vger.kernel.org Subject: [PATCH net v3 2/7] net/sched: act_gate: add RCU support for parameter update Message-ID: <20260121131954.2710459-3-p@1g4.org> In-Reply-To: <20260121131954.2710459-1-p@1g4.org> References: <20260121131954.2710459-1-p@1g4.org> Feedback-ID: 8253658:user:proton X-Pm-Message-ID: 13488128ec5e4befd59ea54409ca5ada35b66313 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Make gact->param RCU-protected and reclaim old params via call_rcu(). This follows the pattern used by other actions: act_pedit swaps params with rcu_replace_pointer() and defers free via call_rcu() (commit 52cf89f78c01bf= ), act_connmark uses rcu_replace_pointer() under tcf_lock (commit 288864effe33= 88), and act_tunnel_key does the same under lockdep (commit 445d3749315f34). Dump readers in act_ct and act_pedit already use rcu_read_lock() + rcu_dereference() (commits 554e66bad84ce4 and 9d096746572616), so act_gate must keep old params alive past updates as well. Fixes: a51c328df310 ("net: qos: introduce a gate control flow action") Signed-off-by: Paul Moses Cc: stable@vger.kernel.org --- include/net/tc_act/tc_gate.h | 31 ++++++++++++++----- net/sched/act_gate.c | 59 +++++++++++++++++++++++++++--------- 2 files changed, 69 insertions(+), 21 deletions(-) diff --git a/include/net/tc_act/tc_gate.h b/include/net/tc_act/tc_gate.h index c1a67149c6b62..05968b3822392 100644 --- a/include/net/tc_act/tc_gate.h +++ b/include/net/tc_act/tc_gate.h @@ -32,6 +32,7 @@ struct tcf_gate_params { s32 tcfg_clockid; size_t num_entries; struct list_head entries; + struct rcu_head rcu; }; =20 #define GATE_ACT_GATE_OPEN BIT(0) @@ -39,7 +40,7 @@ struct tcf_gate_params { =20 struct tcf_gate { struct tc_action common; - struct tcf_gate_params param; + struct tcf_gate_params __rcu *param; u8 current_gate_status; ktime_t current_close_time; u32 current_entry_octets; @@ -54,8 +55,11 @@ struct tcf_gate { static inline s32 tcf_gate_prio(const struct tc_action *a) { s32 tcfg_prio; + struct tcf_gate_params *p; =20 - tcfg_prio =3D to_gate(a)->param.tcfg_priority; + p =3D rcu_dereference_protected(to_gate(a)->param, + lockdep_rtnl_is_held()); + tcfg_prio =3D p->tcfg_priority; =20 return tcfg_prio; } @@ -63,8 +67,11 @@ static inline s32 tcf_gate_prio(const struct tc_action *= a) static inline u64 tcf_gate_basetime(const struct tc_action *a) { u64 tcfg_basetime; + struct tcf_gate_params *p; =20 - tcfg_basetime =3D to_gate(a)->param.tcfg_basetime; + p =3D rcu_dereference_protected(to_gate(a)->param, + lockdep_rtnl_is_held()); + tcfg_basetime =3D p->tcfg_basetime; =20 return tcfg_basetime; } @@ -72,8 +79,11 @@ static inline u64 tcf_gate_basetime(const struct tc_acti= on *a) static inline u64 tcf_gate_cycletime(const struct tc_action *a) { u64 tcfg_cycletime; + struct tcf_gate_params *p; =20 - tcfg_cycletime =3D to_gate(a)->param.tcfg_cycletime; + p =3D rcu_dereference_protected(to_gate(a)->param, + lockdep_rtnl_is_held()); + tcfg_cycletime =3D p->tcfg_cycletime; =20 return tcfg_cycletime; } @@ -81,8 +91,11 @@ static inline u64 tcf_gate_cycletime(const struct tc_act= ion *a) static inline u64 tcf_gate_cycletimeext(const struct tc_action *a) { u64 tcfg_cycletimeext; + struct tcf_gate_params *p; =20 - tcfg_cycletimeext =3D to_gate(a)->param.tcfg_cycletime_ext; + p =3D rcu_dereference_protected(to_gate(a)->param, + lockdep_rtnl_is_held()); + tcfg_cycletimeext =3D p->tcfg_cycletime_ext; =20 return tcfg_cycletimeext; } @@ -90,8 +103,11 @@ static inline u64 tcf_gate_cycletimeext(const struct tc= _action *a) static inline u32 tcf_gate_num_entries(const struct tc_action *a) { u32 num_entries; + struct tcf_gate_params *p; =20 - num_entries =3D to_gate(a)->param.num_entries; + p =3D rcu_dereference_protected(to_gate(a)->param, + lockdep_rtnl_is_held()); + num_entries =3D p->num_entries; =20 return num_entries; } @@ -105,7 +121,8 @@ static inline struct action_gate_entry u32 num_entries; int i =3D 0; =20 - p =3D &to_gate(a)->param; + p =3D rcu_dereference_protected(to_gate(a)->param, + lockdep_rtnl_is_held()); num_entries =3D p->num_entries; =20 list_for_each_entry(entry, &p->entries, list) diff --git a/net/sched/act_gate.c b/net/sched/act_gate.c index aacd57e5f4374..faaf34bcaff5d 100644 --- a/net/sched/act_gate.c +++ b/net/sched/act_gate.c @@ -34,7 +34,8 @@ static ktime_t gate_get_time(struct tcf_gate *gact) =20 static void gate_get_start_time(struct tcf_gate *gact, ktime_t *start) { - struct tcf_gate_params *param =3D &gact->param; + struct tcf_gate_params *param =3D rcu_dereference_protected(gact->param, + lockdep_is_held(&gact->tcf_lock)); ktime_t now, base, cycle; u64 n; =20 @@ -69,12 +70,14 @@ static enum hrtimer_restart gate_timer_func(struct hrti= mer *timer) { struct tcf_gate *gact =3D container_of(timer, struct tcf_gate, hitimer); - struct tcf_gate_params *p =3D &gact->param; + struct tcf_gate_params *p; struct tcfg_gate_entry *next; ktime_t close_time, now; =20 spin_lock(&gact->tcf_lock); =20 + p =3D rcu_dereference_protected(gact->param, + lockdep_is_held(&gact->tcf_lock)); next =3D gact->next_entry; =20 /* cycle start, clear pending bit, clear total octets */ @@ -274,18 +277,26 @@ static void gate_setup_timer(struct tcf_gate *gact, u= 64 basetime, enum tk_offsets tko, s32 clockid, bool do_init) { + struct tcf_gate_params *p; + if (!do_init) { - if (basetime =3D=3D gact->param.tcfg_basetime && + p =3D rcu_dereference_protected(gact->param, + lockdep_is_held(&gact->tcf_lock)); + if (basetime =3D=3D p->tcfg_basetime && tko =3D=3D gact->tk_offset && - clockid =3D=3D gact->param.tcfg_clockid) + clockid =3D=3D p->tcfg_clockid) return; =20 spin_unlock_bh(&gact->tcf_lock); hrtimer_cancel(&gact->hitimer); spin_lock_bh(&gact->tcf_lock); } - gact->param.tcfg_basetime =3D basetime; - gact->param.tcfg_clockid =3D clockid; + p =3D rcu_dereference_protected(gact->param, + lockdep_is_held(&gact->tcf_lock)); + if (p) { + p->tcfg_basetime =3D basetime; + p->tcfg_clockid =3D clockid; + } gact->tk_offset =3D tko; hrtimer_setup(&gact->hitimer, gate_timer_func, clockid, HRTIMER_MODE_ABS_= SOFT); } @@ -376,15 +387,25 @@ static int tcf_gate_init(struct net *net, struct nlat= tr *nla, gflags =3D nla_get_u32(tb[TCA_GATE_FLAGS]); =20 gact =3D to_gate(*a); - if (ret =3D=3D ACT_P_CREATED) - INIT_LIST_HEAD(&gact->param.entries); =20 err =3D tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); if (err < 0) goto release_idr; =20 spin_lock_bh(&gact->tcf_lock); - p =3D &gact->param; + + if (ret =3D=3D ACT_P_CREATED) { + p =3D kzalloc(sizeof(*p), GFP_ATOMIC); + if (!p) { + err =3D -ENOMEM; + goto chain_put; + } + INIT_LIST_HEAD(&p->entries); + rcu_assign_pointer(gact->param, p); + } else { + p =3D rcu_dereference_protected(gact->param, + lockdep_is_held(&gact->tcf_lock)); + } =20 if (tb[TCA_GATE_CYCLE_TIME]) cycletime =3D nla_get_u64(tb[TCA_GATE_CYCLE_TIME]); @@ -446,21 +467,30 @@ static int tcf_gate_init(struct net *net, struct nlat= tr *nla, * without taking tcf_lock. */ if (ret =3D=3D ACT_P_CREATED) - gate_setup_timer(gact, gact->param.tcfg_basetime, - gact->tk_offset, gact->param.tcfg_clockid, + gate_setup_timer(gact, 0, + gact->tk_offset, 0, true); tcf_idr_release(*a, bind); return err; } =20 +static void tcf_gate_params_free_rcu(struct rcu_head *head) +{ + struct tcf_gate_params *p =3D container_of(head, struct tcf_gate_params, = rcu); + + release_entry_list(&p->entries); + kfree(p); +} + static void tcf_gate_cleanup(struct tc_action *a) { struct tcf_gate *gact =3D to_gate(a); struct tcf_gate_params *p; =20 - p =3D &gact->param; + p =3D rcu_replace_pointer(gact->param, NULL, lockdep_rtnl_is_held()); hrtimer_cancel(&gact->hitimer); - release_entry_list(&p->entries); + if (p) + call_rcu(&p->rcu, tcf_gate_params_free_rcu); } =20 static int dumping_entry(struct sk_buff *skb, @@ -512,7 +542,8 @@ static int tcf_gate_dump(struct sk_buff *skb, struct tc= _action *a, spin_lock_bh(&gact->tcf_lock); opt.action =3D gact->tcf_action; =20 - p =3D &gact->param; + p =3D rcu_dereference_protected(gact->param, + lockdep_is_held(&gact->tcf_lock)); =20 if (nla_put(skb, TCA_GATE_PARMS, sizeof(opt), &opt)) goto nla_put_failure; --=20 2.52.GIT From nobody Sat Feb 7 09:30:33 2026 Received: from mail-08.mail-europe.com (mail-08.mail-europe.com [57.129.93.249]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9167339341C; Wed, 21 Jan 2026 13:21:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=57.129.93.249 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769001669; cv=none; b=gUrIkSvFF7tndlsiGn4pSlX5fFza5UpAuuhPB1OdLTxcJtWbl7/bI3VIONzyh4OXhscbbLz0KcJtAZWzO3VqHlAOszy4glAa1CTTeuUQF+ppHlw+w8VMTUsapEoaGmZqL+eEFgHiltGF/e/7aRpRr1fbIoMP77xMzxJQW4EPz30= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769001669; c=relaxed/simple; bh=jCFQmfh2EdjZed4puszkJhORKGrQiKPW5zwgnkEzpF0=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=EKzVlJ7KKF3ZkkhLFTbFoKwwO7VsG/rym6O/LLmriBaTWx6KDlZxaqomN4U+dx87q8m5wQ1pGHPr/8Qg/k+DicrRRvjpaiw15cgt8QKbN9waBxnrUF545WrF1n+Uq1QHC9xO9zz01BDTSaXJUrbqT96RWfmwejA3XihNw21BKEU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org; spf=pass smtp.mailfrom=1g4.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b=R0JkSntQ; arc=none smtp.client-ip=57.129.93.249 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=1g4.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b="R0JkSntQ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1g4.org; s=protonmail2; t=1769001649; x=1769260849; bh=ByI5Y6LRa442jW3BYasuSZquiCEX29TTkkQTPTu1ss0=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=R0JkSntQYEYp+tgw1ssgQjsb/HLdcCsobbOCAQ/PuBn75W2VaRVBQ5v8Y/lFDxjSX Zu9QELgC+JhguZShs/55Im2BcHTqZ8ahDYmkd/vKjOzVHZN4p1am8jG+d4RFXx9NCa oUIrciqLrmp+d6VFYev+oO1G4cQF6g2iDjEFfzbDLMeHOq4tIcSHHI3SHXG67AH38f PnKza24GT+lkheUtU3zCO7AuwIS93cVtEntVkpfneOt79YsqiFuSdVJQvqalrDUJr8 tH+m9kLedKUT4qxqzokUHeh9x2+KJW6RQe+VbJ3NjmdS88N5EdODvT8QwVdd+1MdYQ LW8MmN9XDuoFg== Date: Wed, 21 Jan 2026 13:20:43 +0000 To: netdev@vger.kernel.org From: Paul Moses Cc: Jamal Hadi Salim , Cong Wang , Jiri Pirko , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , linux-kernel@vger.kernel.org, Paul Moses , stable@vger.kernel.org Subject: [PATCH net v3 3/7] net/sched: act_gate: build schedule and RCU-swap Message-ID: <20260121131954.2710459-4-p@1g4.org> In-Reply-To: <20260121131954.2710459-1-p@1g4.org> References: <20260121131954.2710459-1-p@1g4.org> Feedback-ID: 8253658:user:proton X-Pm-Message-ID: e04293c8aae82946e238d7ce6cced05fb0fcd6c0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Build a fresh params snapshot and swap it in with rcu_replace_pointer(), then free the old snapshot via call_rcu(). This is the same publish+defer pattern used in taprio sched swapping (sch_taprio.c, commit d5c4546062fd6f) and in act_pedit param updates (act_pedit.c, commit 52cf89f78c01bf). When REPLACE omits TCA_GATE_ENTRY_LIST, carry forward the old snapshot fiel= ds (basetime/clockid/flags/cycletime/priority) and only override provided attr= s, so partial updates don=E2=80=99t reset unrelated state. Parse entry lists with GFP_KERNEL and explicit error handling, matching tap= rio=E2=80=99s schedule parsing (sch_taprio.c, commit 5a781ccbd19e46). Fixes: a51c328df310 ("net: qos: introduce a gate control flow action") Signed-off-by: Paul Moses Cc: stable@vger.kernel.org --- net/sched/act_gate.c | 185 ++++++++++++++++++++++++++++++++----------- 1 file changed, 140 insertions(+), 45 deletions(-) diff --git a/net/sched/act_gate.c b/net/sched/act_gate.c index faaf34bcaff5d..016708c10a8e0 100644 --- a/net/sched/act_gate.c +++ b/net/sched/act_gate.c @@ -32,10 +32,12 @@ static ktime_t gate_get_time(struct tcf_gate *gact) return KTIME_MAX; } =20 -static void gate_get_start_time(struct tcf_gate *gact, ktime_t *start) +static void tcf_gate_params_free_rcu(struct rcu_head *head); + +static void gate_get_start_time(struct tcf_gate *gact, + const struct tcf_gate_params *param, + ktime_t *start) { - struct tcf_gate_params *param =3D rcu_dereference_protected(gact->param, - lockdep_is_held(&gact->tcf_lock)); ktime_t now, base, cycle; u64 n; =20 @@ -228,13 +230,44 @@ static void release_entry_list(struct list_head *entr= ies) } } =20 +static int tcf_gate_copy_entries(struct tcf_gate_params *dst, + const struct tcf_gate_params *src, + struct netlink_ext_ack *extack) +{ + struct tcfg_gate_entry *entry; + int i =3D 0; + + list_for_each_entry(entry, &src->entries, list) { + struct tcfg_gate_entry *new; + + new =3D kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) { + NL_SET_ERR_MSG(extack, "Not enough memory for entry"); + return -ENOMEM; + } + + new->index =3D entry->index; + new->gate_state =3D entry->gate_state; + new->interval =3D entry->interval; + new->ipv =3D entry->ipv; + new->maxoctets =3D entry->maxoctets; + INIT_LIST_HEAD(&new->list); + list_add_tail(&new->list, &dst->entries); + i++; + } + + dst->num_entries =3D i; + + return i; +} + static int parse_gate_list(struct nlattr *list_attr, struct tcf_gate_params *sched, struct netlink_ext_ack *extack) { struct tcfg_gate_entry *entry; struct nlattr *n; - int err, rem; + int err =3D -EINVAL, rem; int i =3D 0; =20 if (!list_attr) @@ -246,7 +279,7 @@ static int parse_gate_list(struct nlattr *list_attr, continue; } =20 - entry =3D kzalloc(sizeof(*entry), GFP_ATOMIC); + entry =3D kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { NL_SET_ERR_MSG(extack, "Not enough memory for entry"); err =3D -ENOMEM; @@ -269,6 +302,7 @@ static int parse_gate_list(struct nlattr *list_attr, =20 release_list: release_entry_list(&sched->entries); + sched->num_entries =3D 0; =20 return err; } @@ -291,12 +325,6 @@ static void gate_setup_timer(struct tcf_gate *gact, u6= 4 basetime, hrtimer_cancel(&gact->hitimer); spin_lock_bh(&gact->tcf_lock); } - p =3D rcu_dereference_protected(gact->param, - lockdep_is_held(&gact->tcf_lock)); - if (p) { - p->tcfg_basetime =3D basetime; - p->tcfg_clockid =3D clockid; - } gact->tk_offset =3D tko; hrtimer_setup(&gact->hitimer, gate_timer_func, clockid, HRTIMER_MODE_ABS_= SOFT); } @@ -307,20 +335,20 @@ static int tcf_gate_init(struct net *net, struct nlat= tr *nla, struct netlink_ext_ack *extack) { struct tc_action_net *tn =3D net_generic(net, act_gate_ops.net_id); - enum tk_offsets tk_offset =3D TK_OFFS_TAI; - bool bind =3D flags & TCA_ACT_FLAGS_BIND; - struct nlattr *tb[TCA_GATE_MAX + 1]; + struct tcf_gate_params *p, *old_p =3D NULL; struct tcf_chain *goto_ch =3D NULL; - u64 cycletime =3D 0, basetime =3D 0; - struct tcf_gate_params *p; - s32 clockid =3D CLOCK_TAI; struct tcf_gate *gact; struct tc_gate *parm; - int ret =3D 0, err; - u32 gflags =3D 0; - s32 prio =3D -1; + struct nlattr *tb[TCA_GATE_MAX + 1]; + enum tk_offsets tk_offset =3D TK_OFFS_TAI; + u64 cycletime =3D 0, basetime =3D 0, cycletime_ext =3D 0; ktime_t start; + s32 clockid =3D CLOCK_TAI; + s32 prio =3D -1; + u32 gflags =3D 0; u32 index; + int ret =3D 0, err; + bool bind =3D flags & TCA_ACT_FLAGS_BIND; =20 if (!nla) return -EINVAL; @@ -388,32 +416,92 @@ static int tcf_gate_init(struct net *net, struct nlat= tr *nla, =20 gact =3D to_gate(*a); =20 - err =3D tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); - if (err < 0) + p =3D kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) { + err =3D -ENOMEM; goto release_idr; + } + INIT_LIST_HEAD(&p->entries); =20 - spin_lock_bh(&gact->tcf_lock); + if (!tb[TCA_GATE_ENTRY_LIST] && ret !=3D ACT_P_CREATED) { + const struct tcf_gate_params *old_p_local; =20 - if (ret =3D=3D ACT_P_CREATED) { - p =3D kzalloc(sizeof(*p), GFP_ATOMIC); - if (!p) { - err =3D -ENOMEM; - goto chain_put; + old_p_local =3D rcu_dereference_protected(gact->param, + lockdep_rtnl_is_held()); + if (!old_p_local) { + NL_SET_ERR_MSG(extack, "Missing schedule entries"); + err =3D -EINVAL; + goto release_mem; } - INIT_LIST_HEAD(&p->entries); - rcu_assign_pointer(gact->param, p); - } else { - p =3D rcu_dereference_protected(gact->param, - lockdep_is_held(&gact->tcf_lock)); + + if (!tb[TCA_GATE_PRIORITY]) + prio =3D old_p_local->tcfg_priority; + + if (!tb[TCA_GATE_BASE_TIME]) + basetime =3D old_p_local->tcfg_basetime; + + if (!tb[TCA_GATE_FLAGS]) + gflags =3D old_p_local->tcfg_flags; + + if (!tb[TCA_GATE_CLOCKID]) { + clockid =3D old_p_local->tcfg_clockid; + switch (clockid) { + case CLOCK_REALTIME: + tk_offset =3D TK_OFFS_REAL; + break; + case CLOCK_MONOTONIC: + tk_offset =3D TK_OFFS_MAX; + break; + case CLOCK_BOOTTIME: + tk_offset =3D TK_OFFS_BOOT; + break; + case CLOCK_TAI: + tk_offset =3D TK_OFFS_TAI; + break; + default: + NL_SET_ERR_MSG(extack, "Invalid 'clockid'"); + err =3D -EINVAL; + goto release_mem; + } + } + + if (!tb[TCA_GATE_CYCLE_TIME]) + cycletime =3D old_p_local->tcfg_cycletime; + + if (!tb[TCA_GATE_CYCLE_TIME_EXT]) + cycletime_ext =3D old_p_local->tcfg_cycletime_ext; } =20 + p->tcfg_priority =3D prio; + p->tcfg_flags =3D gflags; + p->tcfg_basetime =3D basetime; + p->tcfg_clockid =3D clockid; + if (tb[TCA_GATE_CYCLE_TIME]) cycletime =3D nla_get_u64(tb[TCA_GATE_CYCLE_TIME]); =20 if (tb[TCA_GATE_ENTRY_LIST]) { err =3D parse_gate_list(tb[TCA_GATE_ENTRY_LIST], p, extack); if (err < 0) - goto chain_put; + goto release_mem; + } else if (ret =3D=3D ACT_P_CREATED) { + NL_SET_ERR_MSG(extack, "The entry list is empty"); + err =3D -EINVAL; + goto release_mem; + } else { + const struct tcf_gate_params *old_p_local; + + old_p_local =3D rcu_dereference_protected(gact->param, + lockdep_rtnl_is_held()); + if (!old_p_local) { + NL_SET_ERR_MSG(extack, "Missing schedule entries"); + err =3D -EINVAL; + goto release_mem; + } + + err =3D tcf_gate_copy_entries(p, old_p_local, extack); + if (err < 0) + goto release_mem; } =20 if (!cycletime) { @@ -425,20 +513,26 @@ static int tcf_gate_init(struct net *net, struct nlat= tr *nla, cycletime =3D cycle; if (!cycletime) { err =3D -EINVAL; - goto chain_put; + goto release_mem; } } p->tcfg_cycletime =3D cycletime; =20 if (tb[TCA_GATE_CYCLE_TIME_EXT]) - p->tcfg_cycletime_ext =3D - nla_get_u64(tb[TCA_GATE_CYCLE_TIME_EXT]); + cycletime_ext =3D nla_get_u64(tb[TCA_GATE_CYCLE_TIME_EXT]); + p->tcfg_cycletime_ext =3D cycletime_ext; =20 + err =3D tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); + if (err < 0) + goto release_mem; + + spin_lock_bh(&gact->tcf_lock); gate_setup_timer(gact, basetime, tk_offset, clockid, ret =3D=3D ACT_P_CREATED); - p->tcfg_priority =3D prio; - p->tcfg_flags =3D gflags; - gate_get_start_time(gact, &start); + gate_get_start_time(gact, p, &start); + + old_p =3D rcu_replace_pointer(gact->param, p, + lockdep_is_held(&gact->tcf_lock)); =20 gact->current_close_time =3D start; gact->current_gate_status =3D GATE_ACT_GATE_OPEN | GATE_ACT_PENDING; @@ -455,13 +549,14 @@ static int tcf_gate_init(struct net *net, struct nlat= tr *nla, if (goto_ch) tcf_chain_put_by_act(goto_ch); =20 - return ret; + if (old_p) + call_rcu(&old_p->rcu, tcf_gate_params_free_rcu); =20 -chain_put: - spin_unlock_bh(&gact->tcf_lock); + return ret; =20 - if (goto_ch) - tcf_chain_put_by_act(goto_ch); +release_mem: + release_entry_list(&p->entries); + kfree(p); release_idr: /* action is not inserted in any list: it's safe to init hitimer * without taking tcf_lock. --=20 2.52.GIT From nobody Sat Feb 7 09:30:33 2026 Received: from mail-06.mail-europe.com (mail-06.mail-europe.com [85.9.210.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0B3E533F364 for ; Wed, 21 Jan 2026 13:21:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=85.9.210.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769001663; cv=none; b=spX52SDuJF9whwZx5UpIorQOGxf+UC2cLV97wGkyOnoeBmCP9HDoPz5NMJyNzkawO/b4BbXfJEv7slCwyGuZ3uIo2CDzeDltHjJPoT7gyyTw2C+ZhTXOBK//oV3IfIBiwtw5fpVB9BptMQBt4eTm8pR5767KlRUIf74ngpnZQAg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769001663; c=relaxed/simple; bh=EDqnzZEN7orb7ZGQ+93aCuksK9MrkNnuG8+bzoNPJ5o=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=tKtwRTEFxw8VCclRKleRBbUNKxwXu+VaeQqtXzYw9SA2RYGJvabK29Oinh8tc+xeTPcCf10rfZfgZy+1Q7Dl2H1Bi/E4V1XpYT3etb89N9XGVxGN3IUBOHwbQy9g2rz+2RWzCc7bZvbjpcsLOTOZv9qCYItcjZzOcNPFP9IS/YY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org; spf=pass smtp.mailfrom=1g4.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b=geHUA2+m; arc=none smtp.client-ip=85.9.210.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=1g4.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b="geHUA2+m" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1g4.org; s=protonmail2; t=1769001652; x=1769260852; bh=VQqC9st29svSgAOcWUIUXHbbKJPCeUzGVN5vug9MHKc=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=geHUA2+mJ7+w2S9X2AljL2vbIdOsi103NQ3lUAu3CazCR1vnOh1IAuzaThHzK0Ayz pUh+QSYbcWUxEthLL7pjmCgOSf4uCiQX95bWU2m25k5EOIp4GIdMQY4Be7GZW9tFUj E/Id206d+iqm7wySHK1PyxmeMkDS76F9zXCwg2CH+vOMM9uekda4u8QFT+FBxeY7hY GDcOst/SPMEuKUO/OwOZsssTXGIS3byntLhV05c88IDLMPISxR8DJFtCmy8Ix5R07O uDeQmgp5pTaZE8uImP4RJIIx2LxN3XZ+lOS1OmHAiyLWDotGgijsKH39MiKTyT0sxe hEb5uo7fH5sgA== Date: Wed, 21 Jan 2026 13:20:50 +0000 To: netdev@vger.kernel.org From: Paul Moses Cc: Jamal Hadi Salim , Cong Wang , Jiri Pirko , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , linux-kernel@vger.kernel.org, Paul Moses , stable@vger.kernel.org Subject: [PATCH net v3 4/7] net/sched: act_gate: read schedule via RCU Message-ID: <20260121131954.2710459-5-p@1g4.org> In-Reply-To: <20260121131954.2710459-1-p@1g4.org> References: <20260121131954.2710459-1-p@1g4.org> Feedback-ID: 8253658:user:proton X-Pm-Message-ID: 35e9f1a5787104e5795d193ad305baffc241ac0c Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Switch dump/accessor reads to RCU read-side sections. This matches other actions that read params under rcu_read_lock(), e.g. act_tunnel_key dump (commit e97ae742972f6c), act_ctinfo dump (commit 799c94178cf9c9), and act_skbedit dump (commit 1f376373bd225c). Dump reads tcf_action via READ_ONCE, following the lockless action reads us= ed in act_sample (commit 5c5670fae43027) and act_gact. Timer logic stays under tcf_lock and uses rcu_dereference_protected(), keep= ing RCU readers cheap while preserving lock-serialized timer updates. Fixes: a51c328df310 ("net: qos: introduce a gate control flow action") Signed-off-by: Paul Moses Cc: stable@vger.kernel.org --- include/net/tc_act/tc_gate.h | 38 +++++++++++++++++++++++------------- net/sched/act_gate.c | 32 +++++++++++++++--------------- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/include/net/tc_act/tc_gate.h b/include/net/tc_act/tc_gate.h index 05968b3822392..9587d9e9fa38f 100644 --- a/include/net/tc_act/tc_gate.h +++ b/include/net/tc_act/tc_gate.h @@ -57,9 +57,10 @@ static inline s32 tcf_gate_prio(const struct tc_action *= a) s32 tcfg_prio; struct tcf_gate_params *p; =20 - p =3D rcu_dereference_protected(to_gate(a)->param, - lockdep_rtnl_is_held()); + rcu_read_lock(); + p =3D rcu_dereference(to_gate(a)->param); tcfg_prio =3D p->tcfg_priority; + rcu_read_unlock(); =20 return tcfg_prio; } @@ -69,9 +70,10 @@ static inline u64 tcf_gate_basetime(const struct tc_acti= on *a) u64 tcfg_basetime; struct tcf_gate_params *p; =20 - p =3D rcu_dereference_protected(to_gate(a)->param, - lockdep_rtnl_is_held()); + rcu_read_lock(); + p =3D rcu_dereference(to_gate(a)->param); tcfg_basetime =3D p->tcfg_basetime; + rcu_read_unlock(); =20 return tcfg_basetime; } @@ -81,9 +83,10 @@ static inline u64 tcf_gate_cycletime(const struct tc_act= ion *a) u64 tcfg_cycletime; struct tcf_gate_params *p; =20 - p =3D rcu_dereference_protected(to_gate(a)->param, - lockdep_rtnl_is_held()); + rcu_read_lock(); + p =3D rcu_dereference(to_gate(a)->param); tcfg_cycletime =3D p->tcfg_cycletime; + rcu_read_unlock(); =20 return tcfg_cycletime; } @@ -93,9 +96,10 @@ static inline u64 tcf_gate_cycletimeext(const struct tc_= action *a) u64 tcfg_cycletimeext; struct tcf_gate_params *p; =20 - p =3D rcu_dereference_protected(to_gate(a)->param, - lockdep_rtnl_is_held()); + rcu_read_lock(); + p =3D rcu_dereference(to_gate(a)->param); tcfg_cycletimeext =3D p->tcfg_cycletime_ext; + rcu_read_unlock(); =20 return tcfg_cycletimeext; } @@ -105,9 +109,10 @@ static inline u32 tcf_gate_num_entries(const struct tc= _action *a) u32 num_entries; struct tcf_gate_params *p; =20 - p =3D rcu_dereference_protected(to_gate(a)->param, - lockdep_rtnl_is_held()); + rcu_read_lock(); + p =3D rcu_dereference(to_gate(a)->param); num_entries =3D p->num_entries; + rcu_read_unlock(); =20 return num_entries; } @@ -121,19 +126,23 @@ static inline struct action_gate_entry u32 num_entries; int i =3D 0; =20 - p =3D rcu_dereference_protected(to_gate(a)->param, - lockdep_rtnl_is_held()); + rcu_read_lock(); + p =3D rcu_dereference(to_gate(a)->param); num_entries =3D p->num_entries; =20 list_for_each_entry(entry, &p->entries, list) i++; =20 - if (i !=3D num_entries) + if (i !=3D num_entries) { + rcu_read_unlock(); return NULL; + } =20 oe =3D kcalloc(num_entries, sizeof(*oe), GFP_ATOMIC); - if (!oe) + if (!oe) { + rcu_read_unlock(); return NULL; + } =20 i =3D 0; list_for_each_entry(entry, &p->entries, list) { @@ -143,6 +152,7 @@ static inline struct action_gate_entry oe[i].maxoctets =3D entry->maxoctets; i++; } + rcu_read_unlock(); =20 return oe; } diff --git a/net/sched/act_gate.c b/net/sched/act_gate.c index 016708c10a8e0..da4802bbaf4ca 100644 --- a/net/sched/act_gate.c +++ b/net/sched/act_gate.c @@ -624,66 +624,66 @@ static int tcf_gate_dump(struct sk_buff *skb, struct = tc_action *a, { unsigned char *b =3D skb_tail_pointer(skb); struct tcf_gate *gact =3D to_gate(a); - struct tc_gate opt =3D { }; struct tcfg_gate_entry *entry; struct tcf_gate_params *p; struct nlattr *entry_list; + struct tc_gate opt =3D { }; struct tcf_t t; =20 opt.index =3D gact->tcf_index; opt.refcnt =3D refcount_read(&gact->tcf_refcnt) - ref; opt.bindcnt =3D atomic_read(&gact->tcf_bindcnt) - bind; =20 - spin_lock_bh(&gact->tcf_lock); - opt.action =3D gact->tcf_action; - - p =3D rcu_dereference_protected(gact->param, - lockdep_is_held(&gact->tcf_lock)); + opt.action =3D READ_ONCE(gact->tcf_action); =20 if (nla_put(skb, TCA_GATE_PARMS, sizeof(opt), &opt)) goto nla_put_failure; =20 + rcu_read_lock(); + p =3D rcu_dereference(gact->param); + if (nla_put_u64_64bit(skb, TCA_GATE_BASE_TIME, p->tcfg_basetime, TCA_GATE_PAD)) - goto nla_put_failure; + goto nla_put_failure_rcu; =20 if (nla_put_u64_64bit(skb, TCA_GATE_CYCLE_TIME, p->tcfg_cycletime, TCA_GATE_PAD)) - goto nla_put_failure; + goto nla_put_failure_rcu; =20 if (nla_put_u64_64bit(skb, TCA_GATE_CYCLE_TIME_EXT, p->tcfg_cycletime_ext, TCA_GATE_PAD)) - goto nla_put_failure; + goto nla_put_failure_rcu; =20 if (nla_put_s32(skb, TCA_GATE_CLOCKID, p->tcfg_clockid)) - goto nla_put_failure; + goto nla_put_failure_rcu; =20 if (nla_put_u32(skb, TCA_GATE_FLAGS, p->tcfg_flags)) - goto nla_put_failure; + goto nla_put_failure_rcu; =20 if (nla_put_s32(skb, TCA_GATE_PRIORITY, p->tcfg_priority)) - goto nla_put_failure; + goto nla_put_failure_rcu; =20 entry_list =3D nla_nest_start_noflag(skb, TCA_GATE_ENTRY_LIST); if (!entry_list) - goto nla_put_failure; + goto nla_put_failure_rcu; =20 list_for_each_entry(entry, &p->entries, list) { if (dumping_entry(skb, entry) < 0) - goto nla_put_failure; + goto nla_put_failure_rcu; } =20 nla_nest_end(skb, entry_list); + rcu_read_unlock(); =20 tcf_tm_dump(&t, &gact->tcf_tm); if (nla_put_64bit(skb, TCA_GATE_TM, sizeof(t), &t, TCA_GATE_PAD)) goto nla_put_failure; - spin_unlock_bh(&gact->tcf_lock); =20 return skb->len; =20 +nla_put_failure_rcu: + rcu_read_unlock(); nla_put_failure: - spin_unlock_bh(&gact->tcf_lock); nlmsg_trim(skb, b); return -1; } --=20 2.52.GIT From nobody Sat Feb 7 09:30:33 2026 Received: from mail-06.mail-europe.com (mail-06.mail-europe.com [85.9.210.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 74AE248AE2A; Wed, 21 Jan 2026 13:21:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=85.9.210.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769001669; cv=none; b=FNSChJlhRKMtNzwX5GFcgE9f8o+8DCMdtZw/0VJSjgx2/qF4OL0lKO0h9wo9aBbCJxILN4a1lSMVfwqXnl4sbveLCvb03pD/H8l0lZX/QkAChmn3o5LUtf1Xu0XY56yS6VkqTHdFoaidGXPKaovTk6V/VQXXLNYkbm3NT3aDHP0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769001669; c=relaxed/simple; bh=I2r7cP/avxEfAooDdEHJNIdmgbvA2I/gO0PSjLhEXfo=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=p9UDS4IOkXt8ZbA3sMTmCRf/5Wta+5l8uN/Gm91PT4SSWH7Qj0KlwF6HoeHnceOQl6184ksOUlwrshmSndz3M4s44N4aYQW4VYWMuiCYFoR40sxNxb0oH16Fu0fwqh/zfagwyU7nAeUzMEnXIKVe1WPg7SKpNd61Yw4ZM7s9+kk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org; spf=pass smtp.mailfrom=1g4.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b=UbBXYkbb; arc=none smtp.client-ip=85.9.210.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=1g4.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b="UbBXYkbb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1g4.org; s=protonmail2; t=1769001657; x=1769260857; bh=97EnEXfdGOZnSlFj4TNmyaX9AtuuT1NFsPcfG7rTSxY=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=UbBXYkbboJzNarrfVp6R3LKDJwLmv8hvF8CWfD0eLP+QUGzEQ58Rve23UEOgSSOIZ FB5itLZOXvS7646dVxmH9rii4L8LBZCWnG+R1dCsJ07ZaMIknoFLE5nwQhrykXherK aIOrOVulBO4IOcsL9y5IY7hX7e7ZDf3M/u+vn3rTgf6hoc1vB65YyUaYQxcT5Pjnew LGWtCv4MsC/zS32RJDEPukUrbJxiol23cArWK0/vDs+exmX5ILWxj3KP0r77RFPF5e 2A1WqUYfJZqs2TJM6l3AvHjGffRWwOtHDlXsXNifYltc2pPtLeJmk1mrxITzD+HHUo KevGEMVc8k6YQ== Date: Wed, 21 Jan 2026 13:20:54 +0000 To: netdev@vger.kernel.org From: Paul Moses Cc: Jamal Hadi Salim , Cong Wang , Jiri Pirko , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , linux-kernel@vger.kernel.org, Paul Moses , stable@vger.kernel.org Subject: [PATCH net v3 5/7] net/sched: act_gate: cancel timer outside tcf_lock Message-ID: <20260121131954.2710459-6-p@1g4.org> In-Reply-To: <20260121131954.2710459-1-p@1g4.org> References: <20260121131954.2710459-1-p@1g4.org> Feedback-ID: 8253658:user:proton X-Pm-Message-ID: 17c3bed5517b3aeac02460dbb1810ac1584a97e5 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move hrtimer_cancel() out from under tcf_lock, cancel only on clockid chang= es, and always restart using the newly computed start time. For schedule replacement, bypass the prior expiry clamp so basetime moves forward without firing the new schedule early. Other schedulers explicitly cancel hrtimers on reconfig/teardown, e.g. sch_taprio advance_timer (commit 44d4775ca51805), sch_dualpi2 pi2_timer (commit 320d031ad6e4d6), and qdisc_watchdog_cancel() (commit 2fbd3da3877ad8= ). Fixes: a51c328df310 ("net: qos: introduce a gate control flow action") Signed-off-by: Paul Moses Cc: stable@vger.kernel.org --- net/sched/act_gate.c | 52 ++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/net/sched/act_gate.c b/net/sched/act_gate.c index da4802bbaf4ca..48ff378bb051a 100644 --- a/net/sched/act_gate.c +++ b/net/sched/act_gate.c @@ -55,15 +55,17 @@ static void gate_get_start_time(struct tcf_gate *gact, *start =3D ktime_add_ns(base, (n + 1) * cycle); } =20 -static void gate_start_timer(struct tcf_gate *gact, ktime_t start) +static void gate_start_timer(struct tcf_gate *gact, ktime_t start, bool re= place) { ktime_t expires; =20 - expires =3D hrtimer_get_expires(&gact->hitimer); - if (expires =3D=3D 0) - expires =3D KTIME_MAX; + if (!replace) { + expires =3D hrtimer_get_expires(&gact->hitimer); + if (expires =3D=3D 0) + expires =3D KTIME_MAX; =20 - start =3D min_t(ktime_t, start, expires); + start =3D min_t(ktime_t, start, expires); + } =20 hrtimer_start(&gact->hitimer, start, HRTIMER_MODE_ABS_SOFT); } @@ -307,24 +309,9 @@ static int parse_gate_list(struct nlattr *list_attr, return err; } =20 -static void gate_setup_timer(struct tcf_gate *gact, u64 basetime, - enum tk_offsets tko, s32 clockid, - bool do_init) +static void gate_setup_timer(struct tcf_gate *gact, + enum tk_offsets tko, s32 clockid) { - struct tcf_gate_params *p; - - if (!do_init) { - p =3D rcu_dereference_protected(gact->param, - lockdep_is_held(&gact->tcf_lock)); - if (basetime =3D=3D p->tcfg_basetime && - tko =3D=3D gact->tk_offset && - clockid =3D=3D p->tcfg_clockid) - return; - - spin_unlock_bh(&gact->tcf_lock); - hrtimer_cancel(&gact->hitimer); - spin_lock_bh(&gact->tcf_lock); - } gact->tk_offset =3D tko; hrtimer_setup(&gact->hitimer, gate_timer_func, clockid, HRTIMER_MODE_ABS_= SOFT); } @@ -527,8 +514,19 @@ static int tcf_gate_init(struct net *net, struct nlatt= r *nla, goto release_mem; =20 spin_lock_bh(&gact->tcf_lock); - gate_setup_timer(gact, basetime, tk_offset, clockid, - ret =3D=3D ACT_P_CREATED); + + if (ret =3D=3D ACT_P_CREATED) { + gate_setup_timer(gact, tk_offset, clockid); + } else { + old_p =3D rcu_dereference_protected(gact->param, + lockdep_is_held(&gact->tcf_lock)); + if (!old_p || clockid !=3D old_p->tcfg_clockid) { + spin_unlock_bh(&gact->tcf_lock); + hrtimer_cancel(&gact->hitimer); + spin_lock_bh(&gact->tcf_lock); + gate_setup_timer(gact, tk_offset, clockid); + } + } gate_get_start_time(gact, p, &start); =20 old_p =3D rcu_replace_pointer(gact->param, p, @@ -542,7 +540,7 @@ static int tcf_gate_init(struct net *net, struct nlattr= *nla, =20 goto_ch =3D tcf_action_set_ctrlact(*a, parm->action, goto_ch); =20 - gate_start_timer(gact, start); + gate_start_timer(gact, start, ret !=3D ACT_P_CREATED); =20 spin_unlock_bh(&gact->tcf_lock); =20 @@ -562,9 +560,7 @@ static int tcf_gate_init(struct net *net, struct nlattr= *nla, * without taking tcf_lock. */ if (ret =3D=3D ACT_P_CREATED) - gate_setup_timer(gact, 0, - gact->tk_offset, 0, - true); + gate_setup_timer(gact, gact->tk_offset, 0); tcf_idr_release(*a, bind); return err; } --=20 2.52.GIT From nobody Sat Feb 7 09:30:33 2026 Received: from mail-4398.protonmail.ch (mail-4398.protonmail.ch [185.70.43.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8490341C30E for ; Wed, 21 Jan 2026 13:21:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.70.43.98 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769001665; cv=none; b=J/0VV16w0oUf0xy0IsikNeseyQb6StLsFVpo6ITcPyAZwaEFA2juBpKHVnAQmbGy1Ikd+XyzQJjn3j9Ftqttg5qCc+9FpHN11BQbinBEof+sb9RUmNNtjvRhz9hGYuNvC8nhL9zIGuC+Dp94v8NQUQaFfXNf2OxDkf1Si5t5veA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769001665; c=relaxed/simple; bh=TPdEcIfJbqvoBHnoEwlBnlyJ+FPShZCQQ5uzsnJd7n0=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CzUFxZ0mc4DBApHJKK4HaRDpJ3oX0QszaI2eTS68EZmNMBUesXFWxPSCeHmRNDJBOrXr0rhFmzqWekb82h+8/yXj/fkF7mwO4vNKZbRKpb6+20/oSApsRM894+HcK2bM/eQBALVADwqGPxDH0vk45HR8sdjoInJ11sxTJ5dCBjw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org; spf=pass smtp.mailfrom=1g4.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b=g4k6poje; arc=none smtp.client-ip=185.70.43.98 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=1g4.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b="g4k6poje" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1g4.org; s=protonmail2; t=1769001661; x=1769260861; bh=TPdEcIfJbqvoBHnoEwlBnlyJ+FPShZCQQ5uzsnJd7n0=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=g4k6pojemtv1avJcQjJOb12NGsD6P71kYNK1XyAxg9oY0Tjg4ToGwCKXiev89NqdB jPqx2+zxqxTUWaWv9pMrJ7Btw+WlPtQlww7UMZfwynEV4JIPvpVa58UuUmcgjmD3dr pE6jdAAwrmT4XtelenZlaTXa0oFoE4cho7aLTZz3hjxXSyMCpp9hZi9kiNFQs/PT6j valIqdHgjCqt91gMRlP2ng2R3tjekZRpPU3wxLPyMi9RDG5Zl+IMzGfNLdcOuKGbMX K1T1CfrirRzuejchmKGHqltLwfQbN6uEGDyKy1RgOT7HMtI3OFDu+sbKmzI6OIhqBu 9K3k9fWTINlIQ== Date: Wed, 21 Jan 2026 13:20:59 +0000 To: netdev@vger.kernel.org From: Paul Moses Cc: Jamal Hadi Salim , Cong Wang , Jiri Pirko , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , linux-kernel@vger.kernel.org, Paul Moses , stable@vger.kernel.org Subject: [PATCH net v3 6/7] net/sched: act_gate: reject empty schedule list Message-ID: <20260121131954.2710459-7-p@1g4.org> In-Reply-To: <20260121131954.2710459-1-p@1g4.org> References: <20260121131954.2710459-1-p@1g4.org> Feedback-ID: 8253658:user:proton X-Pm-Message-ID: 7d60970e1245a4f9269fc3b9069c5a4c9c5c7552 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Reject empty schedules (num_entries =3D=3D 0) so next_entry is always valid= and RCU readers/timer logic never walk an empty list. taprio enforces the same constraint on schedules (sch_taprio.c, commit 09dbdf28f9f9fa). Fixes: a51c328df310 ("net: qos: introduce a gate control flow action") Signed-off-by: Paul Moses Cc: stable@vger.kernel.org --- net/sched/act_gate.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/sched/act_gate.c b/net/sched/act_gate.c index 48ff378bb051a..e4134b9a4a314 100644 --- a/net/sched/act_gate.c +++ b/net/sched/act_gate.c @@ -509,6 +509,12 @@ static int tcf_gate_init(struct net *net, struct nlatt= r *nla, cycletime_ext =3D nla_get_u64(tb[TCA_GATE_CYCLE_TIME_EXT]); p->tcfg_cycletime_ext =3D cycletime_ext; =20 + if (p->num_entries =3D=3D 0) { + NL_SET_ERR_MSG(extack, "The entry list is empty"); + err =3D -EINVAL; + goto release_mem; + } + err =3D tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); if (err < 0) goto release_mem; --=20 2.52.GIT From nobody Sat Feb 7 09:30:33 2026 Received: from mail-05.mail-europe.com (mail-05.mail-europe.com [85.9.206.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7C1DA47A0DF for ; Wed, 21 Jan 2026 13:21:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=85.9.206.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769001686; cv=none; b=OpTyUtJQgeDz4jbGSS0WJv9EZjdmsIZcOX6sxHfbaAVVhsmf4PbLNgxZhumHdUlJE9w1/ywOYFRHDYlSJZWgpNguJKMJmHOdwz1cbIAQy1kV7zoRn/shQqrOBkWEHKgCgUayP+xdl6owC76Wkt7Ac2B/jFTPY1RlAUTJh/p69LM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769001686; c=relaxed/simple; bh=/n6viW2cIV8LYeCmJQypGF6fqiDa/c1MK40py9z2tfU=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=IqvZySTu3gl/ddweX4v+nJUR1DMrx5ngfuGYpcPJPogI3FXhPCO+uA3sdVNHiKk2VhYWA130zk7lTzZ6YLuVUKeJjpQYOgUW88sAjUgIDyZmj2i05081q4h0xEwBP+HJ9X86TbZud5x+wLtUXXFeC/SgTU+65DjjIX+Izj7vEMM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org; spf=pass smtp.mailfrom=1g4.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b=mauM2t60; arc=none smtp.client-ip=85.9.206.169 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=1g4.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=1g4.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=1g4.org header.i=@1g4.org header.b="mauM2t60" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1g4.org; s=protonmail2; t=1769001667; x=1769260867; bh=HIKw1+wqe+XvmTdmySUfDBlg9ZDTRrTVJ1eruFyu27M=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=mauM2t60zXNLdv2Xg0TMv888hzxTB+ybh/oihFakJZBA7xe7Ztgeojbb5X3n7ZBo/ G+GsbXjYaHqiCxZWnFIN5XHejQBGviCzfQDKB+DE21B0JQRTS76Gc3IyDjOJt2zweL 8gLOGprs5o0+g7MLYlllSuUb2JSgfyxATaprwkvB3zYQ6dZ3SyN1/bovwmDtN34uAF OFDcKIjIYNFTd4/Vxng01iZmV/7T1C+AtdPldvHTm4zU6P+UmKjcZ/YKEEByFdsn0a WvPu9Dj98FJfHWs3gNmZPVRdBS9tzD4fBZME+W8zCcv+pm+xPh7qC0iwlaBOPYwEVM OrXAZFXAmEa6g== Date: Wed, 21 Jan 2026 13:21:03 +0000 To: netdev@vger.kernel.org From: Paul Moses Cc: Jamal Hadi Salim , Cong Wang , Jiri Pirko , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , linux-kernel@vger.kernel.org, Paul Moses , stable@vger.kernel.org Subject: [PATCH net v3 7/7] net/sched: act_gate: guard NULL params in accessors Message-ID: <20260121131954.2710459-8-p@1g4.org> In-Reply-To: <20260121131954.2710459-1-p@1g4.org> References: <20260121131954.2710459-1-p@1g4.org> Feedback-ID: 8253658:user:proton X-Pm-Message-ID: 6856574e11b1bd9d0c7295a64c4cb9c34798e67f Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Guard NULL params in accessors/dump/timer paths to avoid crashes during teardown or failed initialization. Other actions already guard params before RCU cleanup (act_pedit, commit 52cf89f78c01bf; act_vlan, commits 4c5b9d9642= c859 and 1edf8abe04090c), so act_gate should tolerate NULL in reader paths too. Fixes: a51c328df310 ("net: qos: introduce a gate control flow action") Signed-off-by: Paul Moses Cc: stable@vger.kernel.org --- include/net/tc_act/tc_gate.h | 30 ++++++++++++++++++++---------- net/sched/act_gate.c | 13 ++++++++++++- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/include/net/tc_act/tc_gate.h b/include/net/tc_act/tc_gate.h index 9587d9e9fa38f..8c3309b0dd779 100644 --- a/include/net/tc_act/tc_gate.h +++ b/include/net/tc_act/tc_gate.h @@ -54,12 +54,13 @@ struct tcf_gate { =20 static inline s32 tcf_gate_prio(const struct tc_action *a) { - s32 tcfg_prio; + s32 tcfg_prio =3D 0; struct tcf_gate_params *p; =20 rcu_read_lock(); p =3D rcu_dereference(to_gate(a)->param); - tcfg_prio =3D p->tcfg_priority; + if (p) + tcfg_prio =3D p->tcfg_priority; rcu_read_unlock(); =20 return tcfg_prio; @@ -67,12 +68,13 @@ static inline s32 tcf_gate_prio(const struct tc_action = *a) =20 static inline u64 tcf_gate_basetime(const struct tc_action *a) { - u64 tcfg_basetime; + u64 tcfg_basetime =3D 0; struct tcf_gate_params *p; =20 rcu_read_lock(); p =3D rcu_dereference(to_gate(a)->param); - tcfg_basetime =3D p->tcfg_basetime; + if (p) + tcfg_basetime =3D p->tcfg_basetime; rcu_read_unlock(); =20 return tcfg_basetime; @@ -80,12 +82,13 @@ static inline u64 tcf_gate_basetime(const struct tc_act= ion *a) =20 static inline u64 tcf_gate_cycletime(const struct tc_action *a) { - u64 tcfg_cycletime; + u64 tcfg_cycletime =3D 0; struct tcf_gate_params *p; =20 rcu_read_lock(); p =3D rcu_dereference(to_gate(a)->param); - tcfg_cycletime =3D p->tcfg_cycletime; + if (p) + tcfg_cycletime =3D p->tcfg_cycletime; rcu_read_unlock(); =20 return tcfg_cycletime; @@ -93,12 +96,13 @@ static inline u64 tcf_gate_cycletime(const struct tc_ac= tion *a) =20 static inline u64 tcf_gate_cycletimeext(const struct tc_action *a) { - u64 tcfg_cycletimeext; + u64 tcfg_cycletimeext =3D 0; struct tcf_gate_params *p; =20 rcu_read_lock(); p =3D rcu_dereference(to_gate(a)->param); - tcfg_cycletimeext =3D p->tcfg_cycletime_ext; + if (p) + tcfg_cycletimeext =3D p->tcfg_cycletime_ext; rcu_read_unlock(); =20 return tcfg_cycletimeext; @@ -106,12 +110,13 @@ static inline u64 tcf_gate_cycletimeext(const struct = tc_action *a) =20 static inline u32 tcf_gate_num_entries(const struct tc_action *a) { - u32 num_entries; + u32 num_entries =3D 0; struct tcf_gate_params *p; =20 rcu_read_lock(); p =3D rcu_dereference(to_gate(a)->param); - num_entries =3D p->num_entries; + if (p) + num_entries =3D p->num_entries; rcu_read_unlock(); =20 return num_entries; @@ -128,6 +133,11 @@ static inline struct action_gate_entry =20 rcu_read_lock(); p =3D rcu_dereference(to_gate(a)->param); + if (!p) { + rcu_read_unlock(); + return NULL; + } + num_entries =3D p->num_entries; =20 list_for_each_entry(entry, &p->entries, list) diff --git a/net/sched/act_gate.c b/net/sched/act_gate.c index e4134b9a4a314..65b53cbf37e67 100644 --- a/net/sched/act_gate.c +++ b/net/sched/act_gate.c @@ -82,7 +82,11 @@ static enum hrtimer_restart gate_timer_func(struct hrtim= er *timer) =20 p =3D rcu_dereference_protected(gact->param, lockdep_is_held(&gact->tcf_lock)); + if (!p) + goto out_unlock; next =3D gact->next_entry; + if (!next) + goto out_unlock; =20 /* cycle start, clear pending bit, clear total octets */ gact->current_gate_status =3D next->gate_state ? GATE_ACT_GATE_OPEN : 0; @@ -119,6 +123,11 @@ static enum hrtimer_restart gate_timer_func(struct hrt= imer *timer) spin_unlock(&gact->tcf_lock); =20 return HRTIMER_RESTART; + +out_unlock: + spin_unlock(&gact->tcf_lock); + + return HRTIMER_NORESTART; } =20 TC_INDIRECT_SCOPE int tcf_gate_act(struct sk_buff *skb, @@ -584,8 +593,8 @@ static void tcf_gate_cleanup(struct tc_action *a) struct tcf_gate *gact =3D to_gate(a); struct tcf_gate_params *p; =20 - p =3D rcu_replace_pointer(gact->param, NULL, lockdep_rtnl_is_held()); hrtimer_cancel(&gact->hitimer); + p =3D rcu_replace_pointer(gact->param, NULL, lockdep_rtnl_is_held()); if (p) call_rcu(&p->rcu, tcf_gate_params_free_rcu); } @@ -643,6 +652,8 @@ static int tcf_gate_dump(struct sk_buff *skb, struct tc= _action *a, =20 rcu_read_lock(); p =3D rcu_dereference(gact->param); + if (!p) + goto nla_put_failure_rcu; =20 if (nla_put_u64_64bit(skb, TCA_GATE_BASE_TIME, p->tcfg_basetime, TCA_GATE_PAD)) --=20 2.52.GIT