From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=95.215.58.15 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1792848650; b=EusoYKiSCC0mgEVwrD7yCX+i66pS1Wicrzaj8AyA0d3Nw58wC4EUlf2kEAMV6jD6a8Qm 5Fyq2/BrCLLyKrCmzSsKHnqsUlZqmojDuNb6+sNYof7GCz/kmtdcOSnDYzdBctOS8DKXY dI+xxfSUy8ZSkYYV4TBUq97FUtlij6YSjAzE7bTFjGUjp0fwinPU6U2jEcsUWcfl9uNd5 W3zKk5iWCutdyvyeN4gkdL/+pi1tDPJywWVVcP518IMpUera3b+kBVrXciqLEPLoLplYp e3mEgavBydfd+yMgobnlmPtWoC3BltX29s1CwZHuVl4G7YZ79EJwAd5StV6LF2VeHTw== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1792848650; h=DMARC-Filter:X-Envelope-To:DKIM-Signature:X-Envelope-To:Received: X-Mizu-Trace-ID:X-Migadu-Flow:From:To:Cc:Subject:Date:Message-Id: X-Mailer:MIME-Version:Content-Transfer-Encoding; bh=JMRt7rJPXPcARxUK6s7H9SY/U6y3tk2GjmMDJbMd+CI=; b=RuXIKEfwExTqm000l3osiaqlxojjYBG8doUfH8B7CONrRgaM2Ich+hKmsyyv5t/RtExI BONtmCa/HIYLisRP78B9XCew4dUVFtaMK/dFsJOUu9oBV1jstJh56xH4JfAtXC8xPxwIP cG+q6Jc8MveGbV0tckF3NoMu7NmGq4NOl/+BK0DwtusmE7fEuUHqd/GyPEILrIVFotdT3 eSiQbrRNDCWjbC02dhqaLNHVPww7q9YuqB42xUP+LC89b9OyoOiLYWUyMGwD3GdT5HtpD RIIhYxPYVzHMhELStP3FEIuXspTqA4cn/wI8yVAdogQVTANI4rApP7B1UwEQa0Iz4Zg== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass header.d=linux.dev header.i=@linux.dev header.a=rsa-sha256 header.s=key1 header.b=vSeMs3n0; arc=none smtp.remote-ip=95.215.58.15 Received: from mta1.migadu.com (out-15.mta1.migadu.com [95.215.58.15]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4E983606A31E for ; Sat, 24 Oct 2026 13:30:47 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 4E983606A31E Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key, unprotected) header.d=linux.dev header.i=@linux.dev header.a=rsa-sha256 header.s=key1 header.b=vSeMs3n0 X-Envelope-To: linux-rt-devel@lists.linux.dev DKIM-Signature: a=rsa-sha256; bh=av5UBGTD5N0nshuFf6bT8k3hSLsVBbNFZHiiF298YkI=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1792848646; v=1; x=1793453446; b=vSeMs3n0drL+H0mvnfUgfAczEkXJYsN3/7BeBXGXQsKYS0YjcVwXeSV+giHnKiFMqvrqgd6w uTNnvjQalQd/IoM99dHAssyPyW3c0fBXLaxQgFB+KnXLEUg8QHCpUuE9gygdCBCHtbf+y9nhbNp XtxH16GP4eIh3oa1KxiIhGt4= X-Envelope-To: linux-rt-devel@lists.linux.dev Received: by mta11.migadu.com with ESMTPS id 01e9a5a2a190b8b0; Sat, 24 Oct 2026 13:30:45 +0000 X-Mizu-Trace-ID: 01e9a5a2a190b8b0 X-Migadu-Flow: FLOW_OUT From: wen.yang@linux.dev To: Sebastian Andrzej Siewior , Clark Williams , Steven Rostedt Cc: linux-rt-devel@lists.linux.dev Subject: [PATCH 6.1-rt v2 00/15] net: Backport backlog-NAPI threads to resolve PREEMPT_RT softirq warning in SMP flush Date: Sat, 24 Oct 2026 21:30:24 +0800 Message-Id: X-Mailer: git-send-email 2.25.1 X-Mailing-List: linux-rt-devel@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Wen Yang Backport the backlog-NAPI smpboot-thread mechanism and its prerequisite NAPI/RPS/defer_list work from upstream (v6.4 - v6.9) to v6.1-rt-next. Issues ------ On PREEMPT_RT, RPS steers packets to a remote CPU's backlog by sending an IPI. The IPI handler (rps_trigger_softirq) calls ____napi_schedule(), which raises NET_RX_SOFTIRQ. do_softirq_post_smp_call_flush() then sees a softirq pending that was not pending before the flush, and NET_RX_SOFTIRQ is not masked by SCHED_SOFTIRQ_MASK, so it fires: WARNING: CPU: 1 PID: 0 at kernel/softirq.c:315 do_softirq_post_smp_call_flush+0x3d/0x50 Call Trace: flush_smp_call_function_queue+0x50/0x70 do_idle+0x178/0x260 cpu_startup_entry+0x21/0x30 The same path then calls invoke_softirq() -> wakeup_softirqd() with IRQs disabled in interrupt context, which the RT maintainers consider a design violation ("raising a softirq from an SMP call function"). Commit 8d152d22d9f0 ("net: Avoid the IPI to free the") worked around this only for the skb defer_list by delegating the purge to a workqueue. That was incomplete: it did not touch RPS steering, and workqueue scheduling adds latency to deferred skb recycling. Solution -------- Upstream v6.9 dad6b9770263 ("net: Allow to use SMP threads for backlog NAPI") adds per-CPU smpboot threads ("backlog_napi/%u"). On PREEMPT_RT use_backlog_threads() is unconditionally true, so cross-CPU backlog and defer_list work bypasses IPIs and softirqs entirely: 1) Cross-CPU backlog enqueue sets NAPI_STATE_SCHED_THREADED and wakes the remote CPU's backlog_napi thread with wake_up_process(). 2) defer_list cleanup is folded into the same thread (80d2eefcb4c8). 3) The old defer_work workaround is reverted (patch 01). Backport notes -------------- All 15 patches apply cleanly in sequence against 6271c130c6e5. Two patches needed hand work. Every deviation from the upstream text is listed below, together with the base difference that forced it -- there is no edit made just for the sake of editing. 1. Patch 06 (____napi_schedule): upstream 8b43fd3d1d7d writes __raise_softirq_irqoff(); the backport keeps raise_softirq_irqoff(). Reason: 6.1-rt's ____napi_schedule() already uses raise_softirq_irqoff(), because stable 533824e6a0fb (upstream 77e45145e303, "net: Handle napi_schedule() calls from non-interrupt") deliberately added the ksoftirqd wakeup there to fix the NOHZ tick-stop "local softirq work is pending" stall. Applying the 2023 upstream text verbatim would silently revert that later fix. The 2023 commit predates it, so this is a forward-port artefact, not a behavioural choice. 2. Patch 13 (backlog-NAPI threads): five hunks were re-anchored. None changes behaviour; each is forced by a 6.1-vs-v6.9 base difference, verified against 6271c130c6e5: a) backlog_napi percpu definition upstream anchor : "unsigned int sysctl_skb_defer_max" 6.1 anchor : "int netdev_max_backlog" Both variables sit in the same block right after the "Receiver routines" comment, so the declaration lands in the identical place. Pure textual anchor. b) ____napi_schedule(): WRITE_ONCE(napi->list_owner, ...) dropped napi_struct has no list_owner member on 6.1 (grep over 6271c130c6e5's netdevice.h returns nothing), so keeping the line does not compile. list_owner only backs the napi_by_id()/list-ownership bookkeeping from a later upstream series; it is not consulted anywhere on the backlog path, so omitting it cannot change behaviour. c) napi_threaded_poll() split into napi_threaded_poll_loop() + wrapper Not a deviation: the same split, applied to 6.1's function body, which after patches 09-11 is textually the upstream pre-image. Verified: the extracted napi_threaded_poll_loop() is byte-identical between upstream dad6b9770263 and this backport. d) smpboot block anchor Upstream anchors the new backlog_threads block on the code following net_page_pool_create(); 6.1 has no net_page_pool_create() (0 occurrences in 6271c130c6e5). The block is anchored on the comment preceding net_dev_init() instead. The inserted code is identical. e) net_dev_init() Same cause: the "if (net_page_pool_create(i)) goto out;" context lines do not exist on 6.1 and were dropped. Both substantive additions are kept verbatim, and one of them is load-bearing, not cosmetic: INIT_LIST_HEAD(&sd->backlog.poll_list); 6.1 never initialises backlog.poll_list (no INIT_LIST_HEAD and no netif_napi_add for the backlog NAPI in 6271c130c6e5's dev.c). That was harmless while the backlog NAPI was only ever reached via list_add_tail(), which does not require a pre-initialised node. The threaded path calls __napi_poll() on the backlog NAPI with no list_add() at all, and __napi_poll() tests: if (unlikely(!list_empty(&n->poll_list))) { pr_warn_once("%s: Budget exhausted after napi rescheduled\n", n->dev ? n->dev->name : "backlog"); return work; /* leaves *repoll unset */ } (the "backlog" fallback in that message shows upstream expects this NAPI to reach it). On a zeroed node list_empty() returns false, so the backlog thread would take this branch on every budget exhaustion, print the spurious "backlog: Budget exhausted after napi rescheduled" warning and stop repolling. The INIT_LIST_HEAD is therefore required for correctness on 6.1, exactly as it is upstream. Verification ------------ Each of the five stages was replayed against the base snapshot and compiled for net/core/dev.o and net/core/skbuff.o. The baseline and final RT/RPS bzImages were built with byte-identical normalized configs using GCC 9.4.0, with no compiler warnings or errors. Tests use virtme-ng 1.38, x86_64 QEMU/KVM, four vCPUs and 2 GiB memory: vng --run --cpus 4 --memory 2G \ --qemu-opts='-machine accel=kvm' --exec 'bash