* [PATCH net v4 0/3] macsec: use rcu_work to fix crypto cleanup in softirq context
@ 2026-05-11 15:30 alexjlzheng
2026-05-11 15:30 ` [PATCH net v4 v4 1/3] macsec: introduce dedicated workqueue for SA crypto cleanup alexjlzheng
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: alexjlzheng @ 2026-05-11 15:30 UTC (permalink / raw)
To: sd, andrew+netdev, davem, edumazet, kuba, pabeni, horms, hannes,
albinwyang, shenyangyang4, kuniyu
Cc: netdev, linux-kernel, Jinliang Zheng
From: Jinliang Zheng <alexjlzheng@tencent.com>
crypto_free_aead() can internally call vunmap() (e.g. via dma_free_attrs()
in hardware crypto drivers like hisi_sec2), which must not be invoked from
softirq context. Both free_rxsa() and free_txsa() are RCU callbacks that
run in softirq, causing a kernel crash on affected hardware.
This series fixes the issue by deferring the actual cleanup to a workqueue
using rcu_work, which combines the RCU grace period and workqueue dispatch
into a single primitive.
Two design decisions worth noting:
1. rcu_work instead of schedule_work() + synchronize_rcu()
An alternative would be to call schedule_work() directly from
macsec_rxsa_put()/macsec_txsa_put(), then call synchronize_rcu() at
the start of the work handler to replace the grace period previously
provided by call_rcu(). However, synchronize_rcu() blocks the worker
thread for the duration of a full RCU grace period. Under high SA
churn (e.g. tearing down an interface with many SAs), each SA would
occupy a worker thread while waiting, and multiple concurrent calls
cannot share the same grace period — leading to unnecessary latency
and resource waste.
rcu_work uses call_rcu_hurry() internally, which is fully asynchronous:
the worker thread is only dispatched after the grace period has elapsed,
and multiple concurrent queue_rcu_work() calls naturally batch under the
same grace period via the RCU subsystem's existing coalescing mechanism.
2. Dedicated workqueue instead of system_wq
Using a dedicated workqueue (macsec_wq) allows macsec_exit() to drain
exactly the work items belonging to this module — by calling
destroy_workqueue() after rcu_barrier(). If system_wq were used,
flush_scheduled_work() would drain all pending work items across the
entire system, creating unnecessary coupling with unrelated subsystems
and potentially causing unexpected delays. The dedicated workqueue
provides a clean, contained teardown path.
Changes in v4:
- Switch from alloc_ordered_workqueue() to alloc_workqueue() with
WQ_UNBOUND since there is no ordering dependency between SA cleanups
(suggested by Sabrina Dubroca)
Changes in v3:
- Add rcu_barrier() before destroy_workqueue() in the error path of
macsec_init() as a precaution, mirroring macsec_exit() to stay safe
if work ever becomes queueable earlier (suggested by Jakub Kicinski)
- Rename error labels in macsec_init() from resource-named style
(rtnl:, notifier:, wq:) to err_xxx: style (suggested by Jakub Kicinski)
- Add kdoc for the new destroy_work field in struct macsec_rx_sa and
struct macsec_tx_sa (suggested by Jakub Kicinski)
Changes in v2:
- Use rcu_work instead of work_struct to avoid the manual RCU callback
wrapper (suggested by Kuniyuki Iwashima)
- Introduce a dedicated workqueue and drain it properly in macsec_exit()
to prevent potential crash on module unload (noted by Sabrina Dubroca)
- Extend the fix to TX SAs, which suffer from the same issue
(noted by Sabrina Dubroca)
- Add Fixes tag (noted by Sabrina Dubroca)
- Split into three patches
Thanks to Jakub Kicinski, Kuniyuki Iwashima, and Sabrina Dubroca for
the review.
Link: https://lore.kernel.org/netdev/20260506100107.388184-1-alexjlzheng@tencent.com/T/#u
Link: https://lore.kernel.org/netdev/20260509020054.1792674-1-alexjlzheng@tencent.com/T/#u
Link: https://lore.kernel.org/netdev/20260509033353.1814289-1-alexjlzheng@tencent.com/
Jinliang Zheng (3):
macsec: introduce dedicated workqueue for SA crypto cleanup
macsec: use rcu_work to defer RX SA crypto cleanup out of softirq
macsec: use rcu_work to defer TX SA crypto cleanup out of softirq
drivers/net/macsec.c | 39 ++++++++++++++++++++++++++++-----------
include/net/macsec.h | 7 +++++--
2 files changed, 33 insertions(+), 13 deletions(-)
--
2.39.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net v4 v4 1/3] macsec: introduce dedicated workqueue for SA crypto cleanup
2026-05-11 15:30 [PATCH net v4 0/3] macsec: use rcu_work to fix crypto cleanup in softirq context alexjlzheng
@ 2026-05-11 15:30 ` alexjlzheng
2026-05-12 8:16 ` Sabrina Dubroca
2026-05-11 15:30 ` [PATCH net v4 v4 2/3] macsec: use rcu_work to defer RX SA crypto cleanup out of softirq alexjlzheng
2026-05-11 15:31 ` [PATCH net v4 v4 3/3] macsec: use rcu_work to defer TX " alexjlzheng
2 siblings, 1 reply; 5+ messages in thread
From: alexjlzheng @ 2026-05-11 15:30 UTC (permalink / raw)
To: sd, andrew+netdev, davem, edumazet, kuba, pabeni, horms, hannes,
albinwyang, shenyangyang4, kuniyu
Cc: netdev, linux-kernel, Jinliang Zheng
From: Jinliang Zheng <alexjlzheng@tencent.com>
Introduce a dedicated ordered workqueue, macsec_wq, which will be used
by subsequent patches to defer SA crypto cleanup (crypto_free_aead and
related teardown) out of softirq context.
Using a dedicated workqueue instead of system_wq allows macsec_exit()
to drain exactly the work items belonging to this module via
destroy_workqueue(), without interfering with unrelated work items on
system_wq or causing unexpected delays elsewhere.
rcu_barrier() in macsec_exit() ensures all in-flight rcu_work callbacks
have enqueued their work items before destroy_workqueue() drains and
destroys the queue, making the two-step teardown correct and complete.
The same sequence is kept in the error path of macsec_init() as a
precaution, to mirror macsec_exit() and stay safe if work ever becomes
queueable before this point in the future.
While at it, rename the error labels in macsec_init() from the
resource-named style (rtnl:, notifier:, wq:) to the err_xxx: style
(err_rtnl:, err_notifier:, err_destroy_wq:) to align with the broader
kernel convention.
Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com>
---
drivers/net/macsec.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index f6cad0746a02..35284ff7a17e 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -26,6 +26,8 @@
#include <uapi/linux/if_macsec.h>
+static struct workqueue_struct *macsec_wq;
+
/* SecTAG length = macsec_eth_header without the optional SCI */
#define MACSEC_TAG_LEN 6
@@ -4450,25 +4452,35 @@ static int __init macsec_init(void)
{
int err;
+ macsec_wq = alloc_workqueue("macsec", WQ_UNBOUND, 0);
+ if (!macsec_wq)
+ return -ENOMEM;
+
pr_info("MACsec IEEE 802.1AE\n");
err = register_netdevice_notifier(&macsec_notifier);
if (err)
- return err;
+ goto err_destroy_wq;
err = rtnl_link_register(&macsec_link_ops);
if (err)
- goto notifier;
+ goto err_notifier;
err = genl_register_family(&macsec_fam);
if (err)
- goto rtnl;
+ goto err_rtnl;
return 0;
-rtnl:
+err_rtnl:
rtnl_link_unregister(&macsec_link_ops);
-notifier:
+err_notifier:
unregister_netdevice_notifier(&macsec_notifier);
+err_destroy_wq:
+ /* Precautionary, mirrors macsec_exit() to stay safe if work
+ * ever becomes queueable before this point in the future.
+ */
+ rcu_barrier();
+ destroy_workqueue(macsec_wq);
return err;
}
@@ -4478,6 +4490,7 @@ static void __exit macsec_exit(void)
rtnl_link_unregister(&macsec_link_ops);
unregister_netdevice_notifier(&macsec_notifier);
rcu_barrier();
+ destroy_workqueue(macsec_wq);
}
module_init(macsec_init);
--
2.39.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net v4 v4 2/3] macsec: use rcu_work to defer RX SA crypto cleanup out of softirq
2026-05-11 15:30 [PATCH net v4 0/3] macsec: use rcu_work to fix crypto cleanup in softirq context alexjlzheng
2026-05-11 15:30 ` [PATCH net v4 v4 1/3] macsec: introduce dedicated workqueue for SA crypto cleanup alexjlzheng
@ 2026-05-11 15:30 ` alexjlzheng
2026-05-11 15:31 ` [PATCH net v4 v4 3/3] macsec: use rcu_work to defer TX " alexjlzheng
2 siblings, 0 replies; 5+ messages in thread
From: alexjlzheng @ 2026-05-11 15:30 UTC (permalink / raw)
To: sd, andrew+netdev, davem, edumazet, kuba, pabeni, horms, hannes,
albinwyang, shenyangyang4, kuniyu
Cc: netdev, linux-kernel, Jinliang Zheng
From: Jinliang Zheng <alexjlzheng@tencent.com>
crypto_free_aead() can internally invoke vunmap() (e.g. via
dma_free_attrs() in hardware crypto drivers such as hisi_sec2).
vunmap() must not be called from softirq context, but free_rxsa()
is an RCU callback that runs in softirq, leading to a kernel crash:
vunmap+0x4c/0x70
__iommu_dma_free+0xd0/0x138
dma_free_attrs+0xf4/0x100
sec_aead_exit+0x64/0xb8 [hisi_sec2]
crypto_destroy_tfm+0x98/0x110
free_rxsa+0x28/0x50 [macsec]
rcu_do_batch+0x184/0x460
rcu_core+0xf4/0x1f8
handle_softirqs+0x118/0x330
Use rcu_work to defer the cleanup to a workqueue. rcu_work dispatches
the worker asynchronously after the RCU grace period, so no thread
blocks waiting, and concurrent releases of multiple SAs naturally
share the same grace period.
Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver")
Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
---
drivers/net/macsec.c | 8 +++++---
include/net/macsec.h | 4 +++-
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 35284ff7a17e..1b0ff7fa5ec6 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -176,9 +176,10 @@ static void macsec_rxsc_put(struct macsec_rx_sc *sc)
call_rcu(&sc->rcu_head, free_rx_sc_rcu);
}
-static void free_rxsa(struct rcu_head *head)
+static void free_rxsa_work(struct work_struct *work)
{
- struct macsec_rx_sa *sa = container_of(head, struct macsec_rx_sa, rcu);
+ struct macsec_rx_sa *sa =
+ container_of(to_rcu_work(work), struct macsec_rx_sa, destroy_work);
crypto_free_aead(sa->key.tfm);
free_percpu(sa->stats);
@@ -188,7 +189,7 @@ static void free_rxsa(struct rcu_head *head)
static void macsec_rxsa_put(struct macsec_rx_sa *sa)
{
if (refcount_dec_and_test(&sa->refcnt))
- call_rcu(&sa->rcu, free_rxsa);
+ queue_rcu_work(macsec_wq, &sa->destroy_work);
}
static struct macsec_tx_sa *macsec_txsa_get(struct macsec_tx_sa __rcu *ptr)
@@ -1409,6 +1410,7 @@ static int init_rx_sa(struct macsec_rx_sa *rx_sa, char *sak, int key_len,
rx_sa->next_pn = 1;
refcount_set(&rx_sa->refcnt, 1);
spin_lock_init(&rx_sa->lock);
+ INIT_RCU_WORK(&rx_sa->destroy_work, free_rxsa_work);
return 0;
}
diff --git a/include/net/macsec.h b/include/net/macsec.h
index bc7de5b53e54..0980ef36fbf0 100644
--- a/include/net/macsec.h
+++ b/include/net/macsec.h
@@ -9,6 +9,7 @@
#include <linux/u64_stats_sync.h>
#include <linux/if_vlan.h>
+#include <linux/workqueue.h>
#include <uapi/linux/if_link.h>
#include <uapi/linux/if_macsec.h>
@@ -123,6 +124,7 @@ struct macsec_dev_stats {
* @key: key structure
* @ssci: short secure channel identifier
* @stats: per-SA stats
+ * @destroy_work: deferred work to free the SA in process context after RCU grace period
*/
struct macsec_rx_sa {
struct macsec_key key;
@@ -136,7 +138,7 @@ struct macsec_rx_sa {
bool active;
struct macsec_rx_sa_stats __percpu *stats;
struct macsec_rx_sc *sc;
- struct rcu_head rcu;
+ struct rcu_work destroy_work;
};
struct pcpu_rx_sc_stats {
--
2.39.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net v4 v4 3/3] macsec: use rcu_work to defer TX SA crypto cleanup out of softirq
2026-05-11 15:30 [PATCH net v4 0/3] macsec: use rcu_work to fix crypto cleanup in softirq context alexjlzheng
2026-05-11 15:30 ` [PATCH net v4 v4 1/3] macsec: introduce dedicated workqueue for SA crypto cleanup alexjlzheng
2026-05-11 15:30 ` [PATCH net v4 v4 2/3] macsec: use rcu_work to defer RX SA crypto cleanup out of softirq alexjlzheng
@ 2026-05-11 15:31 ` alexjlzheng
2 siblings, 0 replies; 5+ messages in thread
From: alexjlzheng @ 2026-05-11 15:31 UTC (permalink / raw)
To: sd, andrew+netdev, davem, edumazet, kuba, pabeni, horms, hannes,
albinwyang, shenyangyang4, kuniyu
Cc: netdev, linux-kernel, Jinliang Zheng
From: Jinliang Zheng <alexjlzheng@tencent.com>
free_txsa() is an RCU callback running in softirq context, but calls
crypto_free_aead() which can invoke vunmap() internally on hardware
crypto drivers (e.g. hisi_sec2), triggering a kernel crash.
Use rcu_work to defer the cleanup to a workqueue, for the same reasons
as the analogous fix to free_rxsa() in the previous patch.
Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver")
Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
---
drivers/net/macsec.c | 8 +++++---
include/net/macsec.h | 3 ++-
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 1b0ff7fa5ec6..79df71ea9edb 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -205,9 +205,10 @@ static struct macsec_tx_sa *macsec_txsa_get(struct macsec_tx_sa __rcu *ptr)
return sa;
}
-static void free_txsa(struct rcu_head *head)
+static void free_txsa_work(struct work_struct *work)
{
- struct macsec_tx_sa *sa = container_of(head, struct macsec_tx_sa, rcu);
+ struct macsec_tx_sa *sa =
+ container_of(to_rcu_work(work), struct macsec_tx_sa, destroy_work);
crypto_free_aead(sa->key.tfm);
free_percpu(sa->stats);
@@ -217,7 +218,7 @@ static void free_txsa(struct rcu_head *head)
static void macsec_txsa_put(struct macsec_tx_sa *sa)
{
if (refcount_dec_and_test(&sa->refcnt))
- call_rcu(&sa->rcu, free_txsa);
+ queue_rcu_work(macsec_wq, &sa->destroy_work);
}
static struct macsec_cb *macsec_skb_cb(struct sk_buff *skb)
@@ -1510,6 +1511,7 @@ static int init_tx_sa(struct macsec_tx_sa *tx_sa, char *sak, int key_len,
tx_sa->active = false;
refcount_set(&tx_sa->refcnt, 1);
spin_lock_init(&tx_sa->lock);
+ INIT_RCU_WORK(&tx_sa->destroy_work, free_txsa_work);
return 0;
}
diff --git a/include/net/macsec.h b/include/net/macsec.h
index 0980ef36fbf0..d962093ee923 100644
--- a/include/net/macsec.h
+++ b/include/net/macsec.h
@@ -176,6 +176,7 @@ struct macsec_rx_sc {
* @key: key structure
* @ssci: short secure channel identifier
* @stats: per-SA stats
+ * @destroy_work: deferred work to free the SA in process context after RCU grace period
*/
struct macsec_tx_sa {
struct macsec_key key;
@@ -188,7 +189,7 @@ struct macsec_tx_sa {
refcount_t refcnt;
bool active;
struct macsec_tx_sa_stats __percpu *stats;
- struct rcu_head rcu;
+ struct rcu_work destroy_work;
};
/**
--
2.39.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net v4 v4 1/3] macsec: introduce dedicated workqueue for SA crypto cleanup
2026-05-11 15:30 ` [PATCH net v4 v4 1/3] macsec: introduce dedicated workqueue for SA crypto cleanup alexjlzheng
@ 2026-05-12 8:16 ` Sabrina Dubroca
0 siblings, 0 replies; 5+ messages in thread
From: Sabrina Dubroca @ 2026-05-12 8:16 UTC (permalink / raw)
To: alexjlzheng
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, horms, hannes,
albinwyang, shenyangyang4, kuniyu, netdev, linux-kernel,
Jinliang Zheng
2026-05-11, 23:30:58 +0800, alexjlzheng@gmail.com wrote:
> From: Jinliang Zheng <alexjlzheng@tencent.com>
>
> Introduce a dedicated ordered workqueue, macsec_wq, which will be used
> by subsequent patches to defer SA crypto cleanup (crypto_free_aead and
> related teardown) out of softirq context.
>
> Using a dedicated workqueue instead of system_wq allows macsec_exit()
> to drain exactly the work items belonging to this module via
> destroy_workqueue(), without interfering with unrelated work items on
> system_wq or causing unexpected delays elsewhere.
>
> rcu_barrier() in macsec_exit() ensures all in-flight rcu_work callbacks
> have enqueued their work items before destroy_workqueue() drains and
> destroys the queue, making the two-step teardown correct and complete.
> The same sequence is kept in the error path of macsec_init() as a
> precaution, to mirror macsec_exit() and stay safe if work ever becomes
> queueable before this point in the future.
>
> While at it, rename the error labels in macsec_init() from the
> resource-named style (rtnl:, notifier:, wq:) to the err_xxx: style
> (err_rtnl:, err_notifier:, err_destroy_wq:) to align with the broader
> kernel convention.
>
> Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com>
> ---
> drivers/net/macsec.c | 23 ++++++++++++++++++-----
> 1 file changed, 18 insertions(+), 5 deletions(-)
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Thanks for the fixes!
--
Sabrina
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-05-12 8:17 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-11 15:30 [PATCH net v4 0/3] macsec: use rcu_work to fix crypto cleanup in softirq context alexjlzheng
2026-05-11 15:30 ` [PATCH net v4 v4 1/3] macsec: introduce dedicated workqueue for SA crypto cleanup alexjlzheng
2026-05-12 8:16 ` Sabrina Dubroca
2026-05-11 15:30 ` [PATCH net v4 v4 2/3] macsec: use rcu_work to defer RX SA crypto cleanup out of softirq alexjlzheng
2026-05-11 15:31 ` [PATCH net v4 v4 3/3] macsec: use rcu_work to defer TX " alexjlzheng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox