All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Ciprian Costea" <ciprianmarian.costea@oss.nxp.com>
Cc: Frank.Li@kernel.org, "Vincent Mailhol" <mailhol@kernel.org>,
	"Oleksij Rempel" <o.rempel@pengutronix.de>,
	"Oliver Hartkopp" <socketcan@hartkopp.net>,
	linux-can@vger.kernel.org,
	"Marc Kleine-Budde" <mkl@pengutronix.de>,
	imx@lists.linux.dev
Subject: Re: [PATCH v5 1/3] can: rx-offload: make skb_irq_queue per-CPU
Date: Mon, 07 Sep 2026 11:12:27 +0000	[thread overview]
Message-ID: <20260907111228.3869A1F00A3A@smtp.kernel.org> (raw)
In-Reply-To: <20260907104942.17089-2-ciprianmarian.costea@oss.nxp.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Scheduling while atomic BUG on PREEMPT_RT and high preemption latency due to wrapping hardware drain loop in get_cpu_ptr().
- [High] Lockless list corruption and smp_processor_id() BUG on PREEMPT_RT due to preemptible use of this_cpu_ptr() and splice in can_rx_offload_irq_finish().
--

commit c8905dbba299961e2728d05040d60499542251c0
Author: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>

can: rx-offload: make skb_irq_queue per-CPU

This commit makes skb_irq_queue per-CPU to prevent concurrent list
corruption when multiple IRQ lines are affined to different CPUs. It
uses get_cpu_ptr() during enqueue to disable preemption, and splices
the queues in the IRQ finish handlers.

> diff --git a/drivers/net/can/dev/rx-offload.c b/drivers/net/can/dev/rx-offload.c
> index 46e7b6db4a1ef..7616a16d90497 100644
> --- a/drivers/net/can/dev/rx-offload.c
> +++ b/drivers/net/can/dev/rx-offload.c
[ ... ]
> @@ -175,9 +176,18 @@ can_rx_offload_offload_one(struct can_rx_offload *offload, unsigned int n)
>  int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
>  					 u64 pending)
>  {
> +	struct sk_buff_head *irq_queue;
>  	unsigned int i;
>  	int received = 0;
>  
> +	/*
> +	 * get_cpu_ptr() disables preemption so that the lockless
> +	 * __skb_queue_*() below operate on the current CPU's queue without
> +	 * racing a migration. This also keeps this_cpu_ptr() valid when a
> +	 * driver enqueues from a preemptible (threaded IRQ) context.
> +	 */
> +	irq_queue = get_cpu_ptr(offload->skb_irq_queue);
> +
>  	for (i = offload->mb_first;
>  	     can_rx_offload_le(offload, i, offload->mb_last);
>  	     can_rx_offload_inc(offload, &i)) {
> @@ -190,20 +200,25 @@ int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
>  		if (IS_ERR_OR_NULL(skb))
>  			continue;
>  

[Severity: High]
Does wrapping this entire hardware drain loop in get_cpu_ptr() cause a
"scheduling while atomic" BUG on PREEMPT_RT?

Inside the loop in drivers/net/can/dev/rx-offload.c,
can_rx_offload_offload_one() allocates memory. On PREEMPT_RT, GFP_ATOMIC
allocations acquire a local_lock, which maps to an rt_mutex and can sleep.
Acquiring a sleeping lock while preemption is explicitly disabled by
get_cpu_ptr() triggers the BUG splat, and can also cause significant preemption
latency spikes on non-RT systems.

Could get_cpu_ptr() be pushed down into the loop to strictly guard only the
lockless __skb_queue_add_sort() operation, similar to how it was correctly
done in can_rx_offload_queue_timestamp()?

> -		__skb_queue_add_sort(&offload->skb_irq_queue, skb,
> +		__skb_queue_add_sort(irq_queue, skb,
>  				     can_rx_offload_compare);
>  		received++;
>  	}
>  
> +	put_cpu_ptr(offload->skb_irq_queue);
> +
>  	return received;
>  }
>  EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_timestamp);
>  
>  int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload)
>  {
> +	struct sk_buff_head *irq_queue;
>  	struct sk_buff *skb;
>  	int received = 0;
>  
> +	irq_queue = get_cpu_ptr(offload->skb_irq_queue);
> +
>  	while (1) {
>  		skb = can_rx_offload_offload_one(offload, 0);

[Severity: High]
Does this unbounded read loop have the same "scheduling while atomic" issue
on PREEMPT_RT as in can_rx_offload_irq_offload_timestamp()?

By calling get_cpu_ptr() outside the while loop, preemption is disabled across
all memory allocations in can_rx_offload_offload_one() here as well.

[ ... ]
> @@ -307,14 +330,15 @@ EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb_queue_tail);
>  
>  void can_rx_offload_irq_finish(struct can_rx_offload *offload)
>  {
> +	struct sk_buff_head *irq_queue = this_cpu_ptr(offload->skb_irq_queue);

[Severity: High]
Does calling this_cpu_ptr() here in a preemptible context trigger a
"using smp_processor_id() in preemptible" BUG on PREEMPT_RT?

On PREEMPT_RT, standard hardware IRQ handlers like flexcan_irq execute as
preemptible IRQ threads. Because preemption is not disabled here, calling
this_cpu_ptr() is unsafe.

>  	unsigned long flags;
>  	int queue_len;
>  
> -	if (skb_queue_empty_lockless(&offload->skb_irq_queue))
> +	if (skb_queue_empty_lockless(irq_queue))
>  		return;
>  
>  	spin_lock_irqsave(&offload->skb_queue.lock, flags);
> -	skb_queue_splice_tail_init(&offload->skb_irq_queue, &offload->skb_queue);
> +	skb_queue_splice_tail_init(irq_queue, &offload->skb_queue);

[Severity: High]
Can another IRQ thread preempt this list splice and corrupt the list?

Since preemption is not disabled in this function (and spin_lock_irqsave
only disables migration on RT, not preemption), a higher-priority IRQ
thread on a multi-IRQ controller (like FlexCAN on S32G2) could preempt
the lower-priority one during this skb_queue_splice_tail_init() splice.

If the preempting thread then calls can_rx_offload_irq_offload_timestamp(),
it will explicitly disable preemption and push to the exact same CPU's
irq_queue, concurrently modifying the lockless list.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260907104942.17089-1-ciprianmarian.costea@oss.nxp.com?part=1

  reply	other threads:[~2026-09-07 11:12 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-07 10:49 [PATCH v5 0/3] can_rx_offload keeps a lockless irq_queue that the IRQ handlers fill and that is later spliced under skb_queue.lock into the NAPI-facing skb_queue. This works as long as a single context fills the irq_queue. flexcan with FLEXCAN_QUIRK_SECONDARY_MB_IRQ and mcf5441x use two mailbox IRQ lines. When those are affined to different CPUs the two handlers can enqueue into the same list at the same time and corrupt it Ciprian Costea
2026-09-07 10:49 ` [PATCH v5 1/3] can: rx-offload: make skb_irq_queue per-CPU Ciprian Costea
2026-09-07 11:12   ` sashiko-bot [this message]
2026-09-07 13:32     ` Ciprian Marian Costea
2026-09-07 10:49 ` [PATCH v5 2/3] can: at91_can: fix rx-offload cleanup on unbind and probe errors Ciprian Costea
2026-09-07 10:49 ` [PATCH v5 3/3] can: gs_usb: check can_rx_offload_add_manual() return value Ciprian Costea
2026-09-07 13:49 ` [PATCH v5 0/3] can_rx_offload keeps a lockless irq_queue that the IRQ handlers fill and that is later spliced under skb_queue.lock into the NAPI-facing skb_queue. This works as long as a single context fills the irq_queue. flexcan with FLEXCAN_QUIRK_SECONDARY_MB_IRQ and mcf5441x use two mailbox IRQ lines. When those are affined to different CPUs the two handlers can enqueue into the same list at the same time and corrupt it Marc Kleine-Budde
2026-09-07 15:07   ` Ciprian Marian Costea
2026-09-08  8:58     ` Marc Kleine-Budde

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260907111228.3869A1F00A3A@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=ciprianmarian.costea@oss.nxp.com \
    --cc=imx@lists.linux.dev \
    --cc=linux-can@vger.kernel.org \
    --cc=mailhol@kernel.org \
    --cc=mkl@pengutronix.de \
    --cc=o.rempel@pengutronix.de \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=socketcan@hartkopp.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.