[PATCH net v4 0/3] macsec: use rcu_work to fix crypto cleanup in softirq context

From: alexjlzheng

Date: Mon May 11 2026 - 11:36:21 EST


From: Jinliang Zheng <alexjlzheng@xxxxxxxxxxx>

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@xxxxxxxxxxx/T/#u
Link: https://lore.kernel.org/netdev/20260509020054.1792674-1-alexjlzheng@xxxxxxxxxxx/T/#u
Link: https://lore.kernel.org/netdev/20260509033353.1814289-1-alexjlzheng@xxxxxxxxxxx/

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