Netdev List
 help / color / mirror / Atom feed
* [net PATCH v4] octeontx2-af: Validate NIX maximum LFs correctly
From: Subbaraya Sundeep @ 2026-06-21 23:00 UTC (permalink / raw)
  To: andrew+netdev, davem, edumazet, kuba, pabeni, sgoutham, gakula,
	bbhushan2, rkannoth
  Cc: netdev, linux-kernel, Subbaraya Sundeep

NIX maximum number of LFs can be set via devlink command
but that can be done before assigning any LFs to a PF/VF.
The condition used to check whether any LFs are assigned is
incorrect. This patch fixes that condition.

Fixes: dd7842878633 ("octeontx2-af: Add new devlink param to configure maximum usable NIX block LFs")
Signed-off-by: Subbaraya Sundeep <sbhatta@marvell.com>
---
v4 changes:
	Rebased to latest net
v3 changes:
        None, updated changelog
v2 changes:
        Fixed AI review by updating error message
        Updated comment to mention modifying NIXLFs has to be done prior
        to attaching NIXLFs to any PFs/VFs.

 .../marvell/octeontx2/af/rvu_devlink.c        | 27 +++++++++++++------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
index aa3ecab5ebd8..d63c3d33775a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
@@ -1511,7 +1511,9 @@ static int rvu_af_dl_nix_maxlf_validate(struct devlink *devlink, u32 id,
 	struct rvu_devlink *rvu_dl = devlink_priv(devlink);
 	struct rvu *rvu = rvu_dl->rvu;
 	u16 max_nix0_lf, max_nix1_lf;
-	struct npc_mcam *mcam;
+	struct rvu_block *block;
+	int blkaddr = 0;
+	int free_lfs;
 	u64 cfg;
 
 	cfg = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_CONST2);
@@ -1519,14 +1521,23 @@ static int rvu_af_dl_nix_maxlf_validate(struct devlink *devlink, u32 id,
 	cfg = rvu_read64(rvu, BLKADDR_NIX1, NIX_AF_CONST2);
 	max_nix1_lf = cfg & 0xFFF;
 
-	/* Do not allow user to modify maximum NIX LFs while mcam entries
-	 * have already been assigned.
+	/* Do not allow user to modify maximum NIX LFs while NIX LFs
+	 * have already been assigned. Note that modifying NIX LFs count
+	 * can be done only before any LF attach requests from PFs and VFs
+	 * and not later or concurrently.
 	 */
-	mcam = &rvu->hw->mcam;
-	if (mcam->bmap_fcnt < mcam->bmap_entries) {
-		NL_SET_ERR_MSG_MOD(extack,
-				   "mcam entries have already been assigned, can't resize");
-		return -EPERM;
+	blkaddr = rvu_get_next_nix_blkaddr(rvu, blkaddr);
+	while (blkaddr) {
+		block = &rvu->hw->block[blkaddr];
+
+		free_lfs = rvu_rsrc_free_count(&block->lf);
+		if (free_lfs != block->lf.max) {
+			NL_SET_ERR_MSG_MOD(extack,
+					   "NIX LFs already assigned, can't resize");
+			return -EPERM;
+		}
+
+		blkaddr = rvu_get_next_nix_blkaddr(rvu, blkaddr);
 	}
 
 	if (max_nix0_lf && val->vu16 > max_nix0_lf) {
-- 
2.48.1


^ permalink raw reply related

* Re: [PATCH bpf] bpf: zero-initialize the fib lookup flow struct
From: patchwork-bot+netdevbpf @ 2026-06-22  1:10 UTC (permalink / raw)
  To: Avinash Duduskar
  Cc: ast, daniel, andrii, bpf, davem, dsahern, eddyz87, edumazet, emil,
	horms, john.fastabend, jolsa, kuba, linux-kernel, martin.lau,
	memxor, netdev, pabeni, sdf, song, toke, yonghong.song
In-Reply-To: <20260617224719.1428599-1-avinash.duduskar@gmail.com>

Hello:

This patch was applied to bpf/bpf.git (master)
by Alexei Starovoitov <ast@kernel.org>:

On Thu, 18 Jun 2026 04:17:19 +0530 you wrote:
> bpf_ipv4_fib_lookup() and bpf_ipv6_fib_lookup() build the flow key on
> the stack with a bare "struct flowi4 fl4;" / "struct flowi6 fl6;" and
> fill it field by field, but never set flowi4_l3mdev / flowi6_l3mdev.
> 
> On the non-DIRECT path the lookup goes through the fib rules whenever the
> netns has custom rules, which a VRF installs:
> 
> [...]

Here is the summary with links:
  - [bpf] bpf: zero-initialize the fib lookup flow struct
    https://git.kernel.org/bpf/bpf/c/0dfcb68a6a5a

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* Re: [PATCH net] net, bpf: check master for NULL in xdp_master_redirect()
From: Jiayuan Chen @ 2026-06-22  1:21 UTC (permalink / raw)
  To: Xiang Mei, Daniel Borkmann, Martin KaFai Lau,
	Jesper Dangaard Brouer, netdev, bpf
  Cc: John Fastabend, Stanislav Fomichev, Alexei Starovoitov,
	Jussi Maki, Paolo Abeni, Weiming Shi
In-Reply-To: <20260620201531.180123-1-xmei5@asu.edu>


On 6/21/26 4:15 AM, Xiang Mei wrote:
> xdp_master_redirect() dereferences the result of
> netdev_master_upper_dev_get_rcu() without a NULL check, but that helper
> returns NULL when the receiving device has no upper-master adjacency.
>
> The reach guard only checks netif_is_bond_slave(). On bond slave release
> bond_upper_dev_unlink() drops the upper-master adjacency before clearing
> IFF_SLAVE, so an XDP_TX reaching xdp_master_redirect() in that window
> still passes netif_is_bond_slave() while master is already NULL, and
> faults on master->flags at offset 0xb0:
>
>    BUG: kernel NULL pointer dereference, address: 00000000000000b0
>    RIP: 0010:xdp_master_redirect (net/core/filter.c:4432)
>    Call Trace:
>     xdp_master_redirect (net/core/filter.c:4432)
>     bpf_prog_run_generic_xdp (include/net/xdp.h:700)
>     do_xdp_generic (net/core/dev.c:5608)
>     __netif_receive_skb_one_core (net/core/dev.c:6204)
>     process_backlog (net/core/dev.c:6319)
>     __napi_poll (net/core/dev.c:7729)
>     net_rx_action (net/core/dev.c:7792)
>     handle_softirqs (kernel/softirq.c:622)
>     __dev_queue_xmit (include/linux/bottom_half.h:33)
>     packet_sendmsg (net/packet/af_packet.c:3082)
>     __sys_sendto (net/socket.c:2252)
>    Kernel panic - not syncing: Fatal exception in interrupt
>
> The missing check dates back to the original code; commit 1921f91298d1
> ("net, bpf: fix null-ptr-deref in xdp_master_redirect() for down master")
> later added the master->flags read where the fault now lands but kept the
> unconditional deref. Check master for NULL before use; a NULL master is
> treated the same as one that is not up.
>
> Fixes: 879af96ffd72 ("net, core: Add support for XDP redirection to slave device")
> Reported-by: Weiming Shi <bestswngs@gmail.com>
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Xiang Mei <xmei5@asu.edu>
> ---
>   net/core/filter.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/core/filter.c b/net/core/filter.c
> index 40037413dd4e..6037860d5283 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -4430,7 +4430,7 @@ u32 xdp_master_redirect(struct xdp_buff *xdp)
>   	struct net_device *master, *slave;
>   
>   	master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev);
> -	if (unlikely(!(master->flags & IFF_UP)))
> +	if (unlikely(!master || !(master->flags & IFF_UP)))
>   		return XDP_ABORTED;


I recall that when I previously modified this code, I removed the 
!master check

because this is on the fastpath. However, since this is a triggerable bug,
I think adding it here is fine.

Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>


^ permalink raw reply

* Re: [PATCH net] net, bpf: check master for NULL in xdp_master_redirect()
From: Xiang Mei @ 2026-06-22  1:28 UTC (permalink / raw)
  To: Jiayuan Chen
  Cc: Daniel Borkmann, Martin KaFai Lau, Jesper Dangaard Brouer, netdev,
	bpf, John Fastabend, Stanislav Fomichev, Alexei Starovoitov,
	Jussi Maki, Paolo Abeni, Weiming Shi
In-Reply-To: <7791b9cc-86f4-424b-aa1a-d1a869814130@linux.dev>

On Sun, Jun 21, 2026 at 6:21 PM Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
>
>
> On 6/21/26 4:15 AM, Xiang Mei wrote:
> > xdp_master_redirect() dereferences the result of
> > netdev_master_upper_dev_get_rcu() without a NULL check, but that helper
> > returns NULL when the receiving device has no upper-master adjacency.
> >
> > The reach guard only checks netif_is_bond_slave(). On bond slave release
> > bond_upper_dev_unlink() drops the upper-master adjacency before clearing
> > IFF_SLAVE, so an XDP_TX reaching xdp_master_redirect() in that window
> > still passes netif_is_bond_slave() while master is already NULL, and
> > faults on master->flags at offset 0xb0:
> >
> >    BUG: kernel NULL pointer dereference, address: 00000000000000b0
> >    RIP: 0010:xdp_master_redirect (net/core/filter.c:4432)
> >    Call Trace:
> >     xdp_master_redirect (net/core/filter.c:4432)
> >     bpf_prog_run_generic_xdp (include/net/xdp.h:700)
> >     do_xdp_generic (net/core/dev.c:5608)
> >     __netif_receive_skb_one_core (net/core/dev.c:6204)
> >     process_backlog (net/core/dev.c:6319)
> >     __napi_poll (net/core/dev.c:7729)
> >     net_rx_action (net/core/dev.c:7792)
> >     handle_softirqs (kernel/softirq.c:622)
> >     __dev_queue_xmit (include/linux/bottom_half.h:33)
> >     packet_sendmsg (net/packet/af_packet.c:3082)
> >     __sys_sendto (net/socket.c:2252)
> >    Kernel panic - not syncing: Fatal exception in interrupt
> >
> > The missing check dates back to the original code; commit 1921f91298d1
> > ("net, bpf: fix null-ptr-deref in xdp_master_redirect() for down master")
> > later added the master->flags read where the fault now lands but kept the
> > unconditional deref. Check master for NULL before use; a NULL master is
> > treated the same as one that is not up.
> >
> > Fixes: 879af96ffd72 ("net, core: Add support for XDP redirection to slave device")
> > Reported-by: Weiming Shi <bestswngs@gmail.com>
> > Assisted-by: Claude:claude-opus-4-8
> > Signed-off-by: Xiang Mei <xmei5@asu.edu>
> > ---
> >   net/core/filter.c | 2 +-
> >   1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/net/core/filter.c b/net/core/filter.c
> > index 40037413dd4e..6037860d5283 100644
> > --- a/net/core/filter.c
> > +++ b/net/core/filter.c
> > @@ -4430,7 +4430,7 @@ u32 xdp_master_redirect(struct xdp_buff *xdp)
> >       struct net_device *master, *slave;
> >
> >       master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev);
> > -     if (unlikely(!(master->flags & IFF_UP)))
> > +     if (unlikely(!master || !(master->flags & IFF_UP)))
> >               return XDP_ABORTED;
>
>
> I recall that when I previously modified this code, I removed the
> !master check
>
> because this is on the fastpath. However, since this is a triggerable bug,
> I think adding it here is fine.
>
Thanks for the review. It's difficult to hit under normal statue, but
the bug is real.
We have triggered this bug with a PoC plus GDB to pause one thread (no
other `cheating').

(Theoretically) Race condition exploitation techniques such as expRace
[1] or CardShark [2] may help trigger it.

Xiang

[1]: https://www.usenix.org/conference/usenixsecurity21/presentation/lee-yoochan
[2]: https://www.usenix.org/conference/usenixsecurity24/presentation/han-tianshuo

> Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
>

^ permalink raw reply

* Re: [Intel-wired-lan] [PATCH 1/2] igc: Wait for MAC passthrough after reset
From: Chia-Lin Kao (AceLan) @ 2026-06-22  1:57 UTC (permalink / raw)
  To: Ruinskiy, Dima
  Cc: Loktionov, Aleksandr, Nguyen, Anthony L, Kitszel, Przemyslaw,
	Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, intel-wired-lan@lists.osuosl.org,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <c3030882-55c8-486f-8ff3-571d001b99a1@intel.com>

On Thu, Jun 18, 2026 at 11:51:35AM +0300, Ruinskiy, Dima wrote:
> On 18/06/2026 10:55, Loktionov, Aleksandr wrote:
> >
> >
> > > -----Original Message-----
> > > From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> > > Of Chia-Lin Kao (AceLan) via Intel-wired-lan
> > > Sent: Thursday, June 18, 2026 9:33 AM
> > > To: Nguyen, Anthony L <anthony.l.nguyen@intel.com>; Kitszel,
> > > Przemyslaw <przemyslaw.kitszel@intel.com>
> > > Cc: Andrew Lunn <andrew+netdev@lunn.ch>; David S. Miller
> > > <davem@davemloft.net>; Eric Dumazet <edumazet@google.com>; Jakub
> > > Kicinski <kuba@kernel.org>; Paolo Abeni <pabeni@redhat.com>; intel-
> > > wired-lan@lists.osuosl.org; netdev@vger.kernel.org; linux-
> > > kernel@vger.kernel.org
> > > Subject: [Intel-wired-lan] [PATCH 1/2] igc: Wait for MAC passthrough
> > > after reset
> > >
> > > Some systems support MAC passthrough for dock Ethernet controllers by
> > > having firmware rewrite the receive address registers after the
> > > controller reset completes.
> > >
> > > igc resets the controller before reading RAL0/RAH0, so that reset can
> > > restore the controller native MAC address temporarily. If the driver
> > > reads the registers immediately, it can race the firmware rewrite and
> > > keep the native dock MAC instead of the host passthrough MAC.
> > >
> > > For LMVP devices, poll RAL0/RAH0 after reset and before reading the
> > > MAC address. Stop once the address registers change to another valid
> > > Ethernet address, allowing firmware a bounded window to complete the
> > > passthrough update.
> > >
Hi Aleksandr and Dima,

Let me answer your questions below.

> > Good day, Chia-Lin
> >
> > It'd be great if you could share more details on how to reproduce the issue.
> >
> > What exact hardware setup is affected (dock model, NIC, system)?
We've observed this issue for a long time, and encountered the issue on
Lenovo's P15 Gen 2 (type 20YQ, 20YR) Laptops (ThinkPad) the first
time at 2021 and added 600ms delay.
Recently, we encountered the same issue on Dell, too, and then
increased the delay to 1000ms.
And now, the issue occurs again.

https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1942999
https://lore.kernel.org/lkml/20210702045120.22855-2-aaron.ma@canonical.com/
https://bugs.launchpad.net/ubuntu/+source/linux-oem-6.17/+bug/2143197

> > Which firmware/BIOS version?
It doesn't happen on a single firmware or BIOS, and not a single
hardware or a single brand.

> > How often does the race trigger?
It may happen when re-plug the dock cable.
With the mainline kernel, it's easy to reproduce the issue by
re-plugging the dock cable.

> > Do you have a way to reliably reproduce it?
Yes, I can find some machines to reproduce the issue reliably.

> >
> > Also, what is the observed behavior vs. expected behavior? For example,
> > which MAC address is seen and which one should be used?
Here is the debugging logs, fc:4c:ea:ae:a1:e3 is the MAC
address of the machine, and c4:d6:d3:83:75:d1 is the MAC of the dock.

It gets the correct passthrough MAC address after bootup and the
first re-plug at 40s, and fails to update the MAC address in time
after couple of re-plugs.

[    0.689873] igc 0000:70:00.0: MAC debug before reset_hw: RAL0=0xaeea4cfc RAH0=0x8000e3a1 RAR0=fc:4c:ea:ae:a1:e3 valid=1
[    0.755187] igc 0000:70:00.0: MAC debug after reset_hw: RAL0=0x83d3d6c4 RAH0=0x8000d175 RAR0=c4:d6:d3:83:75:d1 valid=1
[    0.755576] igc 0000:70:00.0: MAC debug: eth_platform_get_mac_address ret=-19, reading RAR0/NVM fallback
[    0.755582] igc 0000:70:00.0: MAC debug: read_mac_addr ret=0 addr=fc:4c:ea:ae:a1:e3 perm_addr=fc:4c:ea:ae:a1:e3
[    4.687730] igc 0000:70:00.0: MAC debug firmware: fwnode=<none> props(mac=0 local=0 address=0) fwnode_ret=-19 fwnode_mac=00:00:00:00:00:00 device_ret=-2 device_mac=00:00:00:00:00:00 is_tbt=0 external=0 hotplug_bridge=0
[    4.687739] igc 0000:70:00.0: MAC debug before reset_hw: RAL0=0xaeea4cfc RAH0=0x8000e3a1 RAR0=fc:4c:ea:ae:a1:e3 valid=1
[    4.748545] igc 0000:70:00.0: MAC debug after reset_hw: RAL0=0x83d3d6c4 RAH0=0x8000d175 RAR0=c4:d6:d3:83:75:d1 valid=1
[    4.748937] igc 0000:70:00.0: MAC debug: eth_platform_get_mac_address ret=-19, reading RAR0/NVM fallback
[    4.748944] igc 0000:70:00.0: MAC debug: read_mac_addr ret=0 addr=fc:4c:ea:ae:a1:e3 perm_addr=fc:4c:ea:ae:a1:e3
[   40.892715] igc 0000:70:00.0: MAC debug firmware: fwnode=<none> props(mac=0 local=0 address=0) fwnode_ret=-19 fwnode_mac=00:00:00:00:00:00 device_ret=-2 device_mac=00:00:00:00:00:00 is_tbt=0 external=0 hotplug_bridge=0
[   40.892724] igc 0000:70:00.0: MAC debug before reset_hw: RAL0=0x83d3d6c4 RAH0=0x8000d175 RAR0=c4:d6:d3:83:75:d1 valid=1
[   40.953524] igc 0000:70:00.0: MAC debug after reset_hw: RAL0=0x83d3d6c4 RAH0=0x8000d175 RAR0=c4:d6:d3:83:75:d1 valid=1
[   40.953933] igc 0000:70:00.0: MAC debug: eth_platform_get_mac_address ret=-19, reading RAR0/NVM fallback
[   40.953941] igc 0000:70:00.0: MAC debug: read_mac_addr ret=0 addr=c4:d6:d3:83:75:d1 perm_addr=c4:d6:d3:83:75:d1
...
[  307.387282] igc 0000:70:00.0: MAC poll change at 700ms: RAL0=0xaeea4cfc RAH0=0x8000e3a1 RAR0=fc:4c:ea:ae:a1:e3 valid=1 prev=c4:d6:d3:83:75:d1
[  328.826084] igc 0000:38:00.0: MAC poll change at 1000ms: RAL0=0xaeea4cfc RAH0=0x8000e3a1 RAR0=fc:4c:ea:ae:a1:e3 valid=1 prev=c4:d6:d3:83:75:d1
[  429.070519] igc 0000:38:00.0: MAC poll change at 1100ms: RAL0=0xaeea4cfc RAH0=0x8000e3a1 RAR0=fc:4c:ea:ae:a1:e3 valid=1 prev=c4:d6:d3:83:75:d1
[  466.509571] igc 0000:70:00.0: MAC poll change at 1000ms: RAL0=0xaeea4cfc RAH0=0x8000e3a1 RAR0=fc:4c:ea:ae:a1:e3 valid=1 prev=c4:d6:d3:83:75:d1

> >
> In addition to that - I would ask - when the race triggers - how much wait
> time do you need to reliably resolve it (i.e., for the FW to have completed
> the MAC update)?
We have tried to unconditionally wait for 1 second while probing, but
it still not enough sometimes. In rare case, it might exceed 2
seconds.

https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/noble/tree/drivers/net/ethernet/intel/igc/igc_main.c?h=hwe-7.0-next#n7205
	if (pci_is_thunderbolt_attached(pdev))
		msleep(1000);

>
> Because 100 iterations of 100msec each - this translates to up-to 10
> seconds, no?
Yes, just in case it takes longer.
I think 5 seconds should be enough if you feel this is feasible.

> The weak spot here is what if you are on an LMvP system where MAC
> passthrough has not been enabled. You will always wait for the full 10
> seconds after every reset until you give up and just continue with the
> default MAC. Hardly desirable behavior.
Right, that is the case. But we won't re-plug the dock frequently, so
it is not so bad to wait for a while for the Ethernet to get connected.

>
> We've implemented something like this in another driver at one point, and
> the default polling timeout there is 1 second (which does not affect the UX
> too much).
>
> A better way may be using a FW interrupt to notify the driver when the MAC
> address has been updated. The usability of this approach depends on whether
> it is possible to update the MAC address up the stack after the device has
> already been initialized. Does the framework support this?
I wish we can detect if the MAC passthrough is enabled, so that we
know if we need to poll for the MAC address.
For the FW interrupt mechanism also needs BIOS support, and we don't
have the power to push this.

>
> Thanks,
> Dima.
>
> >
> > > Signed-off-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com>
> > > ---
> > >   drivers/net/ethernet/intel/igc/igc_main.c | 48
> > > +++++++++++++++++++++++
> > >   1 file changed, 48 insertions(+)
> > >
> > > diff --git a/drivers/net/ethernet/intel/igc/igc_main.c
> > > b/drivers/net/ethernet/intel/igc/igc_main.c
> > > index 2c9e2dfd8499..fa9752ed8bc5 100644
> > > --- a/drivers/net/ethernet/intel/igc/igc_main.c
> > > +++ b/drivers/net/ethernet/intel/igc/igc_main.c
> > > @@ -11,6 +11,7 @@
> > >   #include <net/pkt_sched.h>
> > >   #include <linux/bpf_trace.h>
> > >   #include <net/xdp_sock_drv.h>
> > > +#include <linux/etherdevice.h>
> > >   #include <linux/pci.h>
> > >   #include <linux/mdio.h>
> > >
> > > @@ -69,6 +70,52 @@ static const struct pci_device_id igc_pci_tbl[] = {
> > >
> > >   MODULE_DEVICE_TABLE(pci, igc_pci_tbl);
> > >
> > > +static void igc_read_rar0(struct igc_hw *hw, u8 *addr, u32 *ral, u32
> > > +*rah) {
> > > +	*ral = rd32(IGC_RAL(0));
> > > +	*rah = rd32(IGC_RAH(0));
> > > +
> > > +	addr[0] = *ral & 0xff;
> > > +	addr[1] = (*ral >> 8) & 0xff;
> > > +	addr[2] = (*ral >> 16) & 0xff;
> > > +	addr[3] = (*ral >> 24) & 0xff;
> > > +	addr[4] = *rah & 0xff;
> > > +	addr[5] = (*rah >> 8) & 0xff;
> > > +}
> > > +
> > > +static bool igc_is_lmvp_device(struct pci_dev *pdev) {
> > > +	switch (pdev->device) {
> > > +	case IGC_DEV_ID_I225_LMVP:
> > > +	case IGC_DEV_ID_I226_LMVP:
> > > +		return true;
> > > +	default:
> > > +		return false;
> > > +	}
> > > +}
> > > +
> > > +static void igc_wait_for_lmvp_mac_passthrough(struct pci_dev *pdev,
> > > +					      struct igc_hw *hw)
> > > +{
> > > +	u8 addr[ETH_ALEN] __aligned(2);
> > > +	u32 orig_ral, orig_rah;
> > > +	u32 ral, rah;
> > > +	int i;
> > > +
> > > +	if (!igc_is_lmvp_device(pdev))
> > > +		return;
> > > +
> > > +	igc_read_rar0(hw, addr, &orig_ral, &orig_rah);
> > > +
> > > +	for (i = 0; i < 100; i++) {
> > > +		msleep(100);
> > > +		igc_read_rar0(hw, addr, &ral, &rah);
> > > +		if ((ral != orig_ral || rah != orig_rah) &&
> > > +		    is_valid_ether_addr(addr))
> > > +			return;
> > > +	}
> > > +}
> > > +
> > >   enum latency_range {
> > >   	lowest_latency = 0,
> > >   	low_latency = 1,
> > > @@ -7259,6 +7306,7 @@ static int igc_probe(struct pci_dev *pdev,
> > >   	 * known good starting state
> > >   	 */
> > >   	hw->mac.ops.reset_hw(hw);
> > > +	igc_wait_for_lmvp_mac_passthrough(pdev, hw);
> > >
> > >   	if (igc_get_flash_presence_i225(hw)) {
> > >   		if (hw->nvm.ops.validate(hw) < 0) {
> > > --
> > > 2.53.0
> >
>

^ permalink raw reply

* Re: [PATCH net] net: rnpgbe: fix mailbox endianness handling
From: Yibo Dong @ 2026-06-22  2:10 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Andrew Lunn, andrew+netdev, davem, edumazet, pabeni,
	vadim.fedorenko, netdev, linux-kernel, yaojun
In-Reply-To: <20260617134505.57fea1be@kernel.org>

On Wed, Jun 17, 2026 at 01:45:05PM -0700, Jakub Kicinski wrote:
> On Wed, 17 Jun 2026 22:05:30 +0800 Yibo Dong wrote:
> > On Wed, Jun 17, 2026 at 02:09:00PM +0200, Andrew Lunn wrote:
> > > > My understanding is as follows:
> > > > The firmware structures are defined with__le16 / __le32 for wire format,
> > > > but the original code cast these struct pointers to u32 * before passing
> > > > them to the mailbox read/write routines:
> > > > - Send path: (u32 *)&req -> msg buffer -> writel()
> > > > - Receive path: readl() -> msg buffer -> (u32 *)&reply
> > > > Sparse only sees pure u32 = u32 assignments here, so no type mismatch is
> > > > reported.  
> > > 
> > > Can the code be changed so that it does not need the cast? Casts are
> > > bad, as you have just shown. This is something i try to push back on,
> > > it makes you think about types and avoid issues like this.
> > > 
> > > 	Andrew
> > >   
> > Thinking... Yes. A few possibilities:
> > 
> > 1. Make all fields __le32, then extract via shifts:
> >    struct mbx_fw_cmd_req {
> >        __le32 word0;  // [15:0]=flags  [31:16]=opcode
> >        __le32 word1;  // [15:0]=datalen [31:16]=ret_value
> >        ...
> >    };
> >    But that's painful — le32_to_cpu(req.word0) >> 16 vs req.opcode.
> > 
> > 2. Use a union to keep named fields while also exposing __le32[] access:
> >    union mbx_fw_cmd_req_u {
> >        struct mbx_fw_cmd_req req;
> >        __le32 dwords[sizeof(struct mbx_fw_cmd_req) / sizeof(__le32)];
> >    };
> >    union mbx_fw_cmd_reply_u {
> >        struct mbx_fw_cmd_reply reply;
> >        __le32 dwords[sizeof(struct mbx_fw_cmd_reply) / sizeof(__le32)];
> >    };
> > 
> >    The transport interface becomes:
> >    int mucse_write_mbx_pf(struct mucse_hw *hw, const __le32 *msg, u16 size);
> >    int mucse_read_mbx_pf(struct mucse_hw *hw, __le32 *msg, u16 size);
> > 
> >    Callers would use:
> >    union mbx_fw_cmd_req_u cmd = {};
> >    cmd.req.opcode = cpu_to_le16(...);
> >    cmd.req.flags  = cpu_to_le16(...);
> >    mucse_write_mbx_pf(hw, cmd.dwords, sizeof(cmd.req));
> > 
> >    If the transport layer forgets le32_to_cpu(), sparse would catch it
> >    because msg is __le32 * and mbx_data_rd32() returns u32.
> > 
> >    The downside is an extra union wrapper and an extra level in field
> >    access (cmd.req.opcode vs req.opcode) — a minor inconvenience.
> > 
> > Do you have a preference between these, or another approach?
> > 
> > Thanks for the feedback.
> 
> 3. Maybe use memcpy_toio() to transfer the data without any byteswaps?
> 
That's an elegant approach and would work perfectly if the mailbox was
backed by shared RAM. However, the rnpgbe mailbox is implemented with
32-bit registers, not byte-addressable memory.
Unfortunately, memcpy_toio() cannot guarantee 32-bit access width. On
some architectures it decomposes into the widest aligned access
available — e.g., alpha uses __raw_writeq() for 8-byte aligned blocks,
which would corrupt data on a 32-bit register.
For register-based mailboxes, readl()/writel() remain the correct choice
because they guarantee 32-bit access width. The byte-order conversion
then needs to happen at the CPU side via cpu_to_le32()/le32_to_cpu(),
which is what the current fix does.

Should I change to '2 (the union version)' for next version?

Sorry for delay replay.

Thanks for your feedback.

^ permalink raw reply

* Re: [PATCH net] appletalk: fix use-after-free in atalk_find_primary()
From: Yizhou Zhao @ 2026-06-22  2:14 UTC (permalink / raw)
  To: horms
  Cc: davem, edumazet, fengxw06, kees, kuba, linux-kernel, netdev,
	pabeni, qli01, stable, veritas501, wangao, xuke, yangyx22,
	zhaoyz24
In-Reply-To: <20260616163403.GA827683@horms.kernel.org>

Hi Simon,

Thanks for the review.

I noticed that AppleTalk has since been moved out of tree by commit
8a398a0c189e ("appletalk: move the protocol out of tree"), so this patch no
longer applies to the current tree. I will not respin a v2 for mainline.

If you think this should still be addressed for stable trees or the
out-of-tree AppleTalk code, I can respin the fix there following your
comments.

Best,
Yizhou


^ permalink raw reply

* [PATCH net] gianfar: fix memory leak in gfar_parse_group error paths
From: Rosen Penev @ 2026-06-22  2:19 UTC (permalink / raw)
  To: netdev
  Cc: Claudiu Manoil, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Sandeep Gopalpet, open list

In gfar_parse_group, if any allocation in the irqinfo[] loop fails,
or if of_iomap fails, or if the IRQ parsing fails, the already-
allocated irqinfo[] entries and mapped regs are not freed.  The
caller's free_gfar_dev cannot clean them up because priv->num_grps
is only incremented after a successful return.

Fix by adding an err_out label that frees all successfully allocated
irqinfo entries and unmaps regs if mapped.  Track the number of
allocated entries with 'allocated' and propagate the correct error
code.

Fixes: 46ceb60ca80fa ("gianfar: Add Multiple group Support")
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 drivers/net/ethernet/freescale/gianfar.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 3271de5844f84..12ebb207be0be 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -502,17 +502,19 @@ static int gfar_parse_group(struct device_node *np,
 			    struct gfar_private *priv, const char *model)
 {
 	struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps];
-	int i;
+	int err = -ENOMEM;
+	int i, allocated = 0;
 
 	for (i = 0; i < GFAR_NUM_IRQS; i++) {
 		grp->irqinfo[i] = kzalloc_obj(struct gfar_irqinfo);
 		if (!grp->irqinfo[i])
-			return -ENOMEM;
+			goto err_out;
+		allocated++;
 	}
 
 	grp->regs = of_iomap(np, 0);
 	if (!grp->regs)
-		return -ENOMEM;
+		goto err_out;
 
 	gfar_irq(grp, TX)->irq = irq_of_parse_and_map(np, 0);
 
@@ -522,8 +524,10 @@ static int gfar_parse_group(struct device_node *np,
 		gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2);
 		if (!gfar_irq(grp, TX)->irq ||
 		    !gfar_irq(grp, RX)->irq ||
-		    !gfar_irq(grp, ER)->irq)
-			return -EINVAL;
+		    !gfar_irq(grp, ER)->irq) {
+			err = -EINVAL;
+			goto err_out;
+		}
 	}
 
 	grp->priv = priv;
@@ -567,6 +571,13 @@ static int gfar_parse_group(struct device_node *np,
 	priv->num_grps++;
 
 	return 0;
+
+err_out:
+	for (i = 0; i < allocated; i++)
+		kfree(grp->irqinfo[i]);
+	if (grp->regs)
+		iounmap(grp->regs);
+	return err;
 }
 
 /* Reads the controller's registers to determine what interface
-- 
2.54.0


^ permalink raw reply related

* Re: Re: [PATCH net-next v8 3/6] net: stmmac: eic7700: make RGMII delay properties optional
From: 李志 @ 2026-06-22  2:19 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Maxime Chevallier, devicetree, andrew+netdev, davem, edumazet,
	kuba, robh, krzk+dt, conor+dt, netdev, pabeni, mcoquelin.stm32,
	alexandre.torgue, rmk+kernel, pjw, palmer, aou, alex, linux-riscv,
	linux-stm32, linux-arm-kernel, linux-kernel, ningyu, linmin,
	pinkesh.vaghela, pritesh.patel, weishangjuan, horms, lee
In-Reply-To: <30229cfe-b395-4d0f-81ef-eb780ac26599@lunn.ch>




> -----Original Messages-----
> From: "Andrew Lunn" <andrew@lunn.ch>
> Send time:Saturday, 13/06/2026 15:48:46
> To: "Maxime Chevallier" <maxime.chevallier@bootlin.com>
> Cc: lizhi2@eswincomputing.com, devicetree@vger.kernel.org, andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, netdev@vger.kernel.org, pabeni@redhat.com, mcoquelin.stm32@gmail.com, alexandre.torgue@foss.st.com, rmk+kernel@armlinux.org.uk, pjw@kernel.org, palmer@dabbelt.com, aou@eecs.berkeley.edu, alex@ghiti.fr, linux-riscv@lists.infradead.org, linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, ningyu@eswincomputing.com, linmin@eswincomputing.com, pinkesh.vaghela@einfochips.com, pritesh.patel@einfochips.com, weishangjuan@eswincomputing.com, horms@kernel.org, lee@kernel.org
> Subject: Re: [PATCH net-next v8 3/6] net: stmmac: eic7700: make RGMII delay properties optional
> 
> On Wed, Jun 10, 2026 at 10:26:50AM +0200, Maxime Chevallier wrote:
> > Hi,
> > 
> > On 6/10/26 03:29, lizhi2@eswincomputing.com wrote:
> > > From: Zhi Li <lizhi2@eswincomputing.com>
> > > 
> > > Make rx-internal-delay-ps and tx-internal-delay-ps optional in the
> > > EIC7700 DWMAC driver.
> > > 
> > > The driver previously required both properties to be present and would
> > > fail probe when they were missing. This restricts valid hardware
> > > configurations where RGMII timing is instead provided by the PHY or
> > > board design.
> > > 
> > > Update the driver to treat missing delay properties as zero delay,
> > > allowing systems without explicit MAC-side delay tuning to operate
> > > correctly.
> > > 
> > > This aligns the driver behavior with the updated device tree binding
> > > and provides a safe default configuration when MAC-side delay
> > > programming is not required.
> > > 
> > > Signed-off-by: Zhi Li <lizhi2@eswincomputing.com>
> > > ---
> > >  drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c | 6 ------
> > >  1 file changed, 6 deletions(-)
> > > 
> > > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
> > > index 4ac979d874d6..ec99b597aeaf 100644
> > > --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
> > > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
> > > @@ -165,9 +165,6 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
> > >  		dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_RX_ADJ_DELAY;
> > >  		dwc_priv->eth_clk_dly_param |=
> > >  				 FIELD_PREP(EIC7700_ETH_RX_ADJ_DELAY, val);
> > > -	} else {
> > > -		return dev_err_probe(&pdev->dev, -EINVAL,
> > > -			"missing required property rx-internal-delay-ps\n");
> > >  	}
> > >  
> > >  	/* Read tx-internal-delay-ps and update tx_clk delay */
> > > @@ -187,9 +184,6 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
> > >  		dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_TX_ADJ_DELAY;
> > >  		dwc_priv->eth_clk_dly_param |=
> > >  				 FIELD_PREP(EIC7700_ETH_TX_ADJ_DELAY, val);
> > > -	} else {
> > > -		return dev_err_probe(&pdev->dev, -EINVAL,
> > > -			"missing required property tx-internal-delay-ps\n");
> > >  	}
> > 
> > I think then you need to handle RGMII, RGMII_ID, RGMII_RXID and RGMII_TXID,
> > by using default delays for these (usually around 2ns), as here all delays
> > will be set to 0, regardless of the RGMII mode in use.
> 
> No. By default, the MAC adds 0ns delay, and passes the phy-mode to the
> PHY. It will then add the 2ns delay. It is possible to use the
> tx-internal-delay-ps and rx-internal-delay-ps in the MAC to add small
> tuning delays, but not the full 2ns.
> 
> https://elixir.bootlin.com/linux/v6.15/source/Documentation/devicetree/bindings/net/ethernet-controller.yaml#L287
> 

Thanks for the earlier discussion and for helping clarify the eth0
design.

I'm preparing a v9 of the series. The next revision will address the
issues reported by Sashiko review, mainly DT binding schema and DTS
warnings.

Before I post v9, I'd like to check whether you have any concerns or
suggestions regarding the driver changes.

Thanks,
Zhi

^ permalink raw reply

* Re: [PATCH net-next v3] virtio-net: xsk: support tx wake up
From: Xuan Zhuo @ 2026-06-22  2:40 UTC (permalink / raw)
  To: Menglong Dong
  Cc: mst, jasowang, andrew+netdev, davem, edumazet, kuba, pabeni,
	netdev, virtualization, linux-kernel, eperezma
In-Reply-To: <20260616115912.513183-1-dongml2@chinatelecom.cn>

On Tue, 16 Jun 2026 19:59:12 +0800, Menglong Dong <menglong8.dong@gmail.com> wrote:
> For now, XDP_RING_NEED_WAKEUP is not supported properly by the virtio-net
> in the tx path for example: we set xsk_set_tx_need_wakeup() in
> virtnet_xsk_xmit(), but we didn't call xsk_clear_tx_need_wakeup()
> anywhere, which means the user will call send() for every packet.
>
> We call xsk_set_tx_need_wakeup() after virtnet_xsk_xmit_batch() if sq->vq
> is empty, as we can't be wakeup by the skb_xmit_done() in this case.
> Otherwise, we will clear the wakeup flag.
>
> Race condition is considered for tx path.
>
> Fixes: 89f86675cb03 ("virtio_net: xsk: tx: support xmit xsk buffer")

This is not a bug, so we do not need this.
And you post this to net-next.


> Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
> ---
> v3:
> - remove the confusing comment
>
> v2:
> - add the Fixes tag
> ---
>  drivers/net/virtio_net.c | 23 +++++++++++++++++++----
>  1 file changed, 19 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index f4adcfee7a80..6e099edef6e9 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -1440,8 +1440,9 @@ static bool virtnet_xsk_xmit(struct send_queue *sq, struct xsk_buff_pool *pool,
>  	struct virtnet_info *vi = sq->vq->vdev->priv;
>  	struct virtnet_sq_free_stats stats = {};
>  	struct net_device *dev = vi->dev;
> +	int sent, vring_size;
> +	bool need_wakeup;
>  	u64 kicks = 0;
> -	int sent;
>
>  	/* Avoid to wakeup napi meanless, so call __free_old_xmit instead of
>  	 * free_old_xmit().
> @@ -1451,8 +1452,25 @@ static bool virtnet_xsk_xmit(struct send_queue *sq, struct xsk_buff_pool *pool,
>  	if (stats.xsk)
>  		xsk_tx_completed(sq->xsk_pool, stats.xsk);
>
> +	vring_size = virtqueue_get_vring_size(sq->vq);
> +	need_wakeup = xsk_uses_need_wakeup(pool);
> +
> +	if (need_wakeup && vring_size == sq->vq->num_free)
> +		xsk_set_tx_need_wakeup(pool);

You need to comment this.


> +
>  	sent = virtnet_xsk_xmit_batch(sq, pool, budget, &kicks);
>
> +	if (need_wakeup) {
> +		if (vring_size == sq->vq->num_free)
> +			/* we can't wake up by ourself, and it should be done
> +			 * by the user.
> +			 */
> +			xsk_set_tx_need_wakeup(pool);
> +		else
> +			/* we can wake up from skb_xmit_done() */
> +			xsk_clear_tx_need_wakeup(pool);
> +	}
> +
>  	if (!is_xdp_raw_buffer_queue(vi, sq - vi->sq))
>  		check_sq_full_and_disable(vi, vi->dev, sq);


After fixed above comments, you can add:

Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>

Thanks.


>
> @@ -1470,9 +1488,6 @@ static bool virtnet_xsk_xmit(struct send_queue *sq, struct xsk_buff_pool *pool,
>  	u64_stats_add(&sq->stats.xdp_tx,  sent);
>  	u64_stats_update_end(&sq->stats.syncp);
>
> -	if (xsk_uses_need_wakeup(pool))
> -		xsk_set_tx_need_wakeup(pool);
> -
>  	return sent;
>  }
>
> --
> 2.54.0
>

^ permalink raw reply

* [PATCH net] net: dst: block BH in ipip6_tunnel_xmit
From: yuan.gao @ 2026-06-22  3:31 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Yue Haibing, Kuniyuki Iwashima, Thorsten Blum,
	Kyle Zeng, yuan.gao, Kees Cook, netdev, linux-kernel

Similar to commit 1378817486d6 ("tipc: block BH before using dst_cache"),
the dst cache helper functions must be invoked with local BH disabled.

This ensures proper synchronization and fixes a potential race condition
on SMP systems.

Signed-off-by: yuan.gao <yuan.gao@ucloud.cn>
---
 net/ipv6/sit.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 201347b4e1274..2a63b346634e7 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -934,14 +934,20 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
 			   IPPROTO_IPV6, 0, dst, tiph->saddr, 0, 0,
 			   sock_net_uid(tunnel->net, NULL));
 
+	local_bh_disable();
 	rt = dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr);
+	local_bh_enable();
+
 	if (!rt) {
 		rt = ip_route_output_flow(tunnel->net, &fl4, NULL);
 		if (IS_ERR(rt)) {
 			DEV_STATS_INC(dev, tx_carrier_errors);
 			goto tx_error_icmp;
 		}
+
+		local_bh_disable();
 		dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst, fl4.saddr);
+		local_bh_enable();
 	}
 
 	if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) {
-- 
2.32.0


^ permalink raw reply related

* [PATCH net v2] octeontx2-af: fix CGX debugfs RVU AF PCI reference leaks
From: Ratheesh Kannoth @ 2026-06-22  3:42 UTC (permalink / raw)
  To: davem, hkelam, lcherian, linux-kernel, netdev, pabeni, sgoutham
  Cc: andrew+netdev, edumazet, kuba, Ratheesh Kannoth, Yuho Choi,
	Simon Horman

CGX per-lmac debugfs seq readers obtained struct rvu via
pci_get_drvdata(pci_get_device(..., PCI_DEVID_OCTEONTX2_RVU_AF, ...)),
which leaks a PCI device reference on every read. Store rvu and the CGX
handle in debugfs inode private data when creating stats, mac_filter,
and fwdata files (one context per CGX), and use debugfs aux numbers for
fwdata so lmac_id matches the other CGX debugfs entries.

Fixes: f967488d095e ("octeontx2-af: Add per CGX port level NIX Rx/Tx counters")
Fixes: dbc52debf95f ("octeontx2-af: Debugfs support for DMAC filters")
Fixes: 49f02e6877d1 ("Octeontx2-af: Debugfs support for firmware data")
Cc: Linu Cherian <lcherian@marvell.com>
Reported-by: Yuho Choi <dbgh9129@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>

--
v1 -> v2: Addressed Simon/Jakub comments
	https://lore.kernel.org/netdev/20260621144405.0abfc627@kernel.org/
---
 .../marvell/octeontx2/af/rvu_debugfs.c        | 76 ++++++++++---------
 1 file changed, 41 insertions(+), 35 deletions(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
index ca2704b188a5..5f4679604a53 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
@@ -2810,6 +2810,14 @@ static void rvu_dbg_npa_init(struct rvu *rvu)
 			    &rvu_dbg_npa_ndc_hits_miss_fops);
 }
 
+/* Per-lmac CGX debugfs files need both RVU and CGX handle; inode->i_private
+ * points here so seq_file ops avoid pci_get_device(PCI_DEVID_OCTEONTX2_RVU_AF).
+ */
+struct rvu_cgx_lmac_dbgfs_ctx {
+	struct rvu	*rvu;
+	void		*cgxd;
+};
+
 #define PRINT_CGX_CUML_NIXRX_STATUS(idx, name)				\
 	({								\
 		u64 cnt;						\
@@ -2832,18 +2840,14 @@ static void rvu_dbg_npa_init(struct rvu *rvu)
 
 static int cgx_print_stats(struct seq_file *s, int lmac_id)
 {
+	struct rvu_cgx_lmac_dbgfs_ctx *dctx = s->private;
 	struct cgx_link_user_info linfo;
+	struct rvu *rvu = dctx->rvu;
 	struct mac_ops *mac_ops;
-	void *cgxd = s->private;
+	void *cgxd = dctx->cgxd;
 	u64 ucast, mcast, bcast;
 	int stat = 0, err = 0;
 	u64 tx_stat, rx_stat;
-	struct rvu *rvu;
-
-	rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM,
-					     PCI_DEVID_OCTEONTX2_RVU_AF, NULL));
-	if (!rvu)
-		return -ENODEV;
 
 	mac_ops = get_mac_ops(cgxd);
 	/* There can be no CGX devices at all */
@@ -2950,20 +2954,16 @@ RVU_DEBUG_SEQ_FOPS(cgx_stat, cgx_stat_display, NULL);
 
 static int cgx_print_dmac_flt(struct seq_file *s, int lmac_id)
 {
+	struct rvu_cgx_lmac_dbgfs_ctx *dctx = s->private;
+	struct rvu *rvu = dctx->rvu;
 	struct pci_dev *pdev = NULL;
-	void *cgxd = s->private;
+	void *cgxd = dctx->cgxd;
 	char *bcast, *mcast;
 	u16 index, domain;
 	u8 dmac[ETH_ALEN];
-	struct rvu *rvu;
 	u64 cfg, mac;
 	int pf;
 
-	rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM,
-					     PCI_DEVID_OCTEONTX2_RVU_AF, NULL));
-	if (!rvu)
-		return -ENODEV;
-
 	pf = cgxlmac_to_pf(rvu, cgx_get_cgxid(cgxd), lmac_id);
 	domain = 2;
 
@@ -3010,17 +3010,13 @@ RVU_DEBUG_SEQ_FOPS(cgx_dmac_flt, cgx_dmac_flt_display, NULL);
 
 static int cgx_print_fwdata(struct seq_file *s, int lmac_id)
 {
+	struct rvu_cgx_lmac_dbgfs_ctx *dctx = s->private;
 	struct cgx_lmac_fwdata_s *fwdata;
-	void *cgxd = s->private;
+	struct rvu *rvu = dctx->rvu;
+	void *cgxd = dctx->cgxd;
 	struct phy_s *phy;
-	struct rvu *rvu;
 	int cgx_id, i;
 
-	rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM,
-					     PCI_DEVID_OCTEONTX2_RVU_AF, NULL));
-	if (!rvu)
-		return -ENODEV;
-
 	if (!rvu->fwdata)
 		return -EAGAIN;
 
@@ -3101,6 +3097,7 @@ RVU_DEBUG_SEQ_FOPS(cgx_fwdata, cgx_fwdata_display, NULL);
 
 static void rvu_dbg_cgx_init(struct rvu *rvu)
 {
+	struct rvu_cgx_lmac_dbgfs_ctx *ctx;
 	struct mac_ops *mac_ops;
 	unsigned long lmac_bmap;
 	int i, lmac_id;
@@ -3127,20 +3124,29 @@ static void rvu_dbg_cgx_init(struct rvu *rvu)
 		rvu->rvu_dbg.cgx = debugfs_create_dir(dname,
 						      rvu->rvu_dbg.cgx_root);
 
-		for_each_set_bit(lmac_id, &lmac_bmap, rvu->hw->lmac_per_cgx) {
-			/* lmac debugfs dir */
-			sprintf(dname, "lmac%d", lmac_id);
-			rvu->rvu_dbg.lmac =
-				debugfs_create_dir(dname, rvu->rvu_dbg.cgx);
-
-			debugfs_create_file_aux_num("stats", 0600, rvu->rvu_dbg.lmac,
-					    cgx, lmac_id, &rvu_dbg_cgx_stat_fops);
-			debugfs_create_file_aux_num("mac_filter", 0600,
-					    rvu->rvu_dbg.lmac, cgx, lmac_id,
-					    &rvu_dbg_cgx_dmac_flt_fops);
-			debugfs_create_file("fwdata", 0600,
-					    rvu->rvu_dbg.lmac, cgx,
-					    &rvu_dbg_cgx_fwdata_fops);
+		{
+			ctx = devm_kzalloc(rvu->dev, sizeof(*ctx), GFP_KERNEL);
+			if (!ctx)
+				continue;
+
+			ctx->rvu = rvu;
+			ctx->cgxd = cgx;
+
+			for_each_set_bit(lmac_id, &lmac_bmap, rvu->hw->lmac_per_cgx) {
+				/* lmac debugfs dir */
+				sprintf(dname, "lmac%d", lmac_id);
+				rvu->rvu_dbg.lmac =
+					debugfs_create_dir(dname, rvu->rvu_dbg.cgx);
+
+				debugfs_create_file_aux_num("stats", 0600, rvu->rvu_dbg.lmac,
+							    ctx, lmac_id, &rvu_dbg_cgx_stat_fops);
+				debugfs_create_file_aux_num("mac_filter", 0600,
+							    rvu->rvu_dbg.lmac, ctx, lmac_id,
+							    &rvu_dbg_cgx_dmac_flt_fops);
+				debugfs_create_file_aux_num("fwdata", 0600,
+							    rvu->rvu_dbg.lmac, ctx,
+							    lmac_id, &rvu_dbg_cgx_fwdata_fops);
+			}
 		}
 	}
 }
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state
From: Kaitao Cheng @ 2026-06-22  4:05 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König
  Cc: David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, linux-kernel, cgroups,
	linux-ntfs-dev, linux-fsdevel, io-uring, audit, bpf, netdev,
	dri-devel, linux-perf-users, linux-trace-kernel, kexec,
	live-patching, linux-modules, linux-crypto, linux-pm, rcu,
	sched-ext, linux-mm, virtualization, damon, llvm, chengkaitao

From: chengkaitao <chengkaitao@kylinos.cn>

The list_for_each*_safe() helpers are used when the loop body may remove
the current entry.  Their current interface, however, forces every caller
to define a temporary cursor outside the macro and pass it in, even when
the caller never uses that cursor directly.  For most call sites this
extra cursor is just boilerplate required by the macro implementation.

This is awkward because the saved next pointer is an internal detail of
the iteration.  Callers that only remove or move the current entry do not
need to spell it out.

The _safe() suffix has also caused confusion.  Christian Koenig pointed
out that the name is easy to read as a thread-safe variant, especially
for beginners, even though it only means that the iterator keeps enough
state to tolerate removal of the current entry.  He suggested _mutable()
as a clearer description of what the loop permits.

Add *_mutable() iterator variants for list, hlist and llist.  The new
helpers are variadic and support both forms.  In the common case, the
caller omits the temporary cursor and the macro creates a unique internal
cursor with typeof(pos) and __UNIQUE_ID().  If a loop really needs an
explicit temporary cursor, the caller can still pass it and the helper
keeps the existing *_safe() behaviour.

For example, a call site may use the shorter form:

  list_for_each_entry_mutable(pos, head, member)

or keep the explicit temporary cursor form:

  list_for_each_entry_mutable(pos, tmp, head, member)

The existing *_safe() helpers remain available for compatibility.  This
series only converts users in mm, block, kernel, init and io_uring.  If
this approach looks acceptable, the remaining users can be converted in
follow-up series.

Changes in v3 (Christian König, Andy Shevchenko):
- Convert safe list walks to mutable iterators

Changes in v2 (Muchun Song, Andy Shevchenko):
- Drop the list_for_each_entry_mutable*() helpers from v1 and make the
  cursor change directly in the existing list_for_each_entry*() helpers.
- Open-code special list walks that rely on updating the loop cursor in
  the body, preserving their existing traversal semantics.

Link to v2:
https://lore.kernel.org/all/20260609061347.93688-1-kaitao.cheng@linux.dev/

Link to v1:
https://lore.kernel.org/all/20260529082149.76764-1-kaitao.cheng@linux.dev/

Kaitao Cheng (7):
  list: Add mutable iterator variants
  llist: Add mutable iterator variants
  mm: Use mutable list iterators
  block: Use mutable list iterators
  kernel: Use mutable list iterators
  initramfs: Use mutable list iterator
  io_uring: Use mutable list iterators

 block/bfq-iosched.c                 |  17 +-
 block/blk-cgroup.c                  |  12 +-
 block/blk-flush.c                   |   4 +-
 block/blk-iocost.c                  |  18 +-
 block/blk-mq.c                      |   8 +-
 block/blk-throttle.c                |   4 +-
 block/kyber-iosched.c               |   4 +-
 block/partitions/ldm.c              |   8 +-
 block/sed-opal.c                    |   4 +-
 include/linux/list.h                | 269 ++++++++++++++++++++++++----
 include/linux/llist.h               |  81 +++++++--
 init/initramfs.c                    |   5 +-
 io_uring/cancel.c                   |   6 +-
 io_uring/poll.c                     |   3 +-
 io_uring/rw.c                       |   4 +-
 io_uring/timeout.c                  |   8 +-
 io_uring/uring_cmd.c                |   3 +-
 kernel/audit_tree.c                 |   4 +-
 kernel/audit_watch.c                |  16 +-
 kernel/auditfilter.c                |   4 +-
 kernel/auditsc.c                    |   4 +-
 kernel/bpf/arena.c                  |  10 +-
 kernel/bpf/arraymap.c               |   8 +-
 kernel/bpf/bpf_local_storage.c      |   3 +-
 kernel/bpf/bpf_lru_list.c           |  25 ++-
 kernel/bpf/btf.c                    |  18 +-
 kernel/bpf/cgroup.c                 |   7 +-
 kernel/bpf/cpumap.c                 |   4 +-
 kernel/bpf/devmap.c                 |  10 +-
 kernel/bpf/helpers.c                |   8 +-
 kernel/bpf/local_storage.c          |   4 +-
 kernel/bpf/memalloc.c               |  16 +-
 kernel/bpf/offload.c                |   8 +-
 kernel/bpf/states.c                 |   4 +-
 kernel/bpf/stream.c                 |   4 +-
 kernel/bpf/verifier.c               |   6 +-
 kernel/cgroup/cgroup-v1.c           |   4 +-
 kernel/cgroup/cgroup.c              |  54 +++---
 kernel/cgroup/dmem.c                |  12 +-
 kernel/cgroup/rdma.c                |   8 +-
 kernel/events/core.c                |  44 +++--
 kernel/events/uprobes.c             |  12 +-
 kernel/exit.c                       |   8 +-
 kernel/fail_function.c              |   4 +-
 kernel/gcov/clang.c                 |   4 +-
 kernel/irq_work.c                   |   4 +-
 kernel/kexec_core.c                 |   4 +-
 kernel/kprobes.c                    |  16 +-
 kernel/livepatch/core.c             |   4 +-
 kernel/livepatch/core.h             |   4 +-
 kernel/liveupdate/kho_block.c       |   4 +-
 kernel/liveupdate/luo_flb.c         |   4 +-
 kernel/locking/rwsem.c              |   2 +-
 kernel/locking/test-ww_mutex.c      |   2 +-
 kernel/module/main.c                |  11 +-
 kernel/padata.c                     |   4 +-
 kernel/power/snapshot.c             |   8 +-
 kernel/power/wakelock.c             |   4 +-
 kernel/printk/printk.c              |  11 +-
 kernel/ptrace.c                     |   4 +-
 kernel/rcu/rcutorture.c             |   3 +-
 kernel/rcu/tasks.h                  |   9 +-
 kernel/rcu/tree.c                   |   6 +-
 kernel/resource.c                   |   4 +-
 kernel/sched/core.c                 |   4 +-
 kernel/sched/ext.c                  |  22 +--
 kernel/sched/fair.c                 |  28 +--
 kernel/sched/topology.c             |   4 +-
 kernel/sched/wait.c                 |   4 +-
 kernel/seccomp.c                    |   4 +-
 kernel/signal.c                     |  11 +-
 kernel/smp.c                        |   4 +-
 kernel/taskstats.c                  |   8 +-
 kernel/time/clockevents.c           |   6 +-
 kernel/time/clocksource.c           |   4 +-
 kernel/time/posix-cpu-timers.c      |   4 +-
 kernel/time/posix-timers.c          |   3 +-
 kernel/torture.c                    |   3 +-
 kernel/trace/bpf_trace.c            |   4 +-
 kernel/trace/ftrace.c               |  49 +++--
 kernel/trace/ring_buffer.c          |  25 ++-
 kernel/trace/trace.c                |  12 +-
 kernel/trace/trace_dynevent.c       |   6 +-
 kernel/trace/trace_dynevent.h       |   5 +-
 kernel/trace/trace_events.c         |  35 ++--
 kernel/trace/trace_events_filter.c  |   4 +-
 kernel/trace/trace_events_hist.c    |   8 +-
 kernel/trace/trace_events_trigger.c |  17 +-
 kernel/trace/trace_events_user.c    |  16 +-
 kernel/trace/trace_stat.c           |   4 +-
 kernel/user-return-notifier.c       |   3 +-
 kernel/workqueue.c                  |  16 +-
 mm/backing-dev.c                    |   8 +-
 mm/balloon.c                        |   8 +-
 mm/cma.c                            |   4 +-
 mm/compaction.c                     |   4 +-
 mm/damon/core.c                     |   4 +-
 mm/damon/sysfs-schemes.c            |   4 +-
 mm/dmapool.c                        |   4 +-
 mm/huge_memory.c                    |   8 +-
 mm/hugetlb.c                        |  56 +++---
 mm/hugetlb_vmemmap.c                |  16 +-
 mm/khugepaged.c                     |  14 +-
 mm/kmemleak.c                       |   7 +-
 mm/ksm.c                            |  25 +--
 mm/list_lru.c                       |   4 +-
 mm/memcontrol-v1.c                  |   8 +-
 mm/memory-failure.c                 |  12 +-
 mm/memory-tiers.c                   |   4 +-
 mm/migrate.c                        |  23 ++-
 mm/mmu_notifier.c                   |   9 +-
 mm/page_alloc.c                     |   8 +-
 mm/page_reporting.c                 |   2 +-
 mm/percpu.c                         |  11 +-
 mm/pgtable-generic.c                |   4 +-
 mm/rmap.c                           |  10 +-
 mm/shmem.c                          |   9 +-
 mm/slab_common.c                    |  14 +-
 mm/slub.c                           |  33 ++--
 mm/swapfile.c                       |   4 +-
 mm/userfaultfd.c                    |  12 +-
 mm/vmalloc.c                        |  24 +--
 mm/vmscan.c                         |   7 +-
 mm/zsmalloc.c                       |   4 +-
 124 files changed, 875 insertions(+), 681 deletions(-)

-- 
2.43.0


^ permalink raw reply

* [PATCH v3 1/7] list: Add mutable iterator variants
From: Kaitao Cheng @ 2026-06-22  4:05 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König
  Cc: David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, linux-kernel, cgroups,
	linux-ntfs-dev, linux-fsdevel, io-uring, audit, bpf, netdev,
	dri-devel, linux-perf-users, linux-trace-kernel, kexec,
	live-patching, linux-modules, linux-crypto, linux-pm, rcu,
	sched-ext, linux-mm, virtualization, damon, llvm, Kaitao Cheng
In-Reply-To: <20260622040533.29824-1-kaitao.cheng@linux.dev>

From: Kaitao Cheng <chengkaitao@kylinos.cn>

The list_for_each*_safe() helpers are used when the loop body may
remove the current entry.  Their API exposes the temporary cursor at
every call site, even though most users only need it for the iterator
implementation and never reference it in the loop body.

Add *_mutable() variants for list and hlist iteration.  The new helpers
support both forms: callers may keep passing an explicit temporary cursor
when they need to inspect or reset it, or omit it and let the helper use
a unique internal cursor.

This makes call sites that only mutate the list through the current entry
less noisy, while keeping the existing *_safe() helpers available for
compatibility.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 include/linux/list.h | 269 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 231 insertions(+), 38 deletions(-)

diff --git a/include/linux/list.h b/include/linux/list.h
index 09d979976b3b..1081def7cea9 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -7,6 +7,7 @@
 #include <linux/stddef.h>
 #include <linux/poison.h>
 #include <linux/const.h>
+#include <linux/args.h>
 
 #include <asm/barrier.h>
 
@@ -763,28 +764,72 @@ static inline void list_splice_tail_init(struct list_head *list,
 #define list_for_each_prev(pos, head) \
 	for (pos = (head)->prev; !list_is_head(pos, (head)); pos = pos->prev)
 
-/**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @pos:	the &struct list_head to use as a loop cursor.
- * @n:		another &struct list_head to use as temporary storage
- * @head:	the head for your list.
+/*
+ * list_for_each_safe is an old interface, use list_for_each_mutable instead.
  */
 #define list_for_each_safe(pos, n, head) \
 	for (pos = (head)->next, n = pos->next; \
 	     !list_is_head(pos, (head)); \
 	     pos = n, n = pos->next)
 
+#define __list_for_each_mutable_internal(pos, tmp, head)		\
+	for (typeof(pos) tmp = (pos = (head)->next)->next;		\
+	     !list_is_head(pos, (head));				\
+	     pos = tmp, tmp = pos->next)
+
+#define __list_for_each_mutable1(pos, head)				\
+	__list_for_each_mutable_internal(pos, __UNIQUE_ID(next), head)
+
+#define __list_for_each_mutable2(pos, next, head)			\
+	list_for_each_safe(pos, next, head)
+
 /**
- * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * list_for_each_mutable - iterate over a list safe against entry removal
  * @pos:	the &struct list_head to use as a loop cursor.
- * @n:		another &struct list_head to use as temporary storage
- * @head:	the head for your list.
+ * @...:	either (head) or (next, head)
+ *
+ * next:	another &struct list_head to use as optional temporary storage.
+ *		The temporary cursor is internal unless explicitly supplied by
+ *		the caller.
+ * head:	the head for your list.
+ */
+#define list_for_each_mutable(pos, ...)					\
+	CONCATENATE(__list_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
+		(pos, __VA_ARGS__)
+
+/*
+ * list_for_each_prev_safe is an old interface, use list_for_each_prev_mutable instead.
  */
 #define list_for_each_prev_safe(pos, n, head) \
 	for (pos = (head)->prev, n = pos->prev; \
 	     !list_is_head(pos, (head)); \
 	     pos = n, n = pos->prev)
 
+#define __list_for_each_prev_mutable_internal(pos, tmp, head)		\
+	for (typeof(pos) tmp = (pos = (head)->prev)->prev;		\
+	     !list_is_head(pos, (head));				\
+	     pos = tmp, tmp = pos->prev)
+
+#define __list_for_each_prev_mutable1(pos, head)			\
+	__list_for_each_prev_mutable_internal(pos, __UNIQUE_ID(prev), head)
+
+#define __list_for_each_prev_mutable2(pos, prev, head)			\
+	list_for_each_prev_safe(pos, prev, head)
+
+/**
+ * list_for_each_prev_mutable - iterate over a list backwards safe against entry removal
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @...:	either (head) or (prev, head)
+ *
+ * prev:	another &struct list_head to use as optional temporary storage.
+ *		The temporary cursor is internal unless explicitly supplied by
+ *		the caller.
+ * head:	the head for your list.
+ */
+#define list_for_each_prev_mutable(pos, ...)				\
+	CONCATENATE(__list_for_each_prev_mutable, COUNT_ARGS(__VA_ARGS__)) \
+		(pos, __VA_ARGS__)
+
 /**
  * list_count_nodes - count nodes in the list
  * @head:	the head for your list.
@@ -895,12 +940,8 @@ static inline size_t list_count_nodes(struct list_head *head)
 	for (; !list_entry_is_head(pos, head, member);			\
 	     pos = list_prev_entry(pos, member))
 
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_head within the struct.
+/*
+ * list_for_each_entry_safe is an old interface, use list_for_each_entry_mutable instead.
  */
 #define list_for_each_entry_safe(pos, n, head, member)			\
 	for (pos = list_first_entry(head, typeof(*pos), member),	\
@@ -908,15 +949,36 @@ static inline size_t list_count_nodes(struct list_head *head)
 	     !list_entry_is_head(pos, head, member); 			\
 	     pos = n, n = list_next_entry(n, member))
 
+#define __list_for_each_entry_mutable_internal(pos, tmp, head, member)	\
+	for (typeof(pos) tmp = list_next_entry(pos =			\
+		list_first_entry(head, typeof(*pos), member), member);	\
+	     !list_entry_is_head(pos, head, member);			\
+	     pos = tmp, tmp = list_next_entry(tmp, member))
+
+#define __list_for_each_entry_mutable2(pos, head, member)		\
+	__list_for_each_entry_mutable_internal(pos, __UNIQUE_ID(next), head, member)
+
+#define __list_for_each_entry_mutable3(pos, next, head, member)		\
+	list_for_each_entry_safe(pos, next, head, member)
+
 /**
- * list_for_each_entry_safe_continue - continue list iteration safe against removal
+ * list_for_each_entry_mutable - iterate over a list safe against entry removal
  * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_head within the struct.
+ * @...:	either (head, member) or (next, head, member)
  *
- * Iterate over list of given type, continuing after current point,
- * safe against removal of list entry.
+ * next:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your list.
+ * member:	the name of the list_head within the struct.
+ */
+#define list_for_each_entry_mutable(pos, ...)				\
+	CONCATENATE(__list_for_each_entry_mutable, COUNT_ARGS(__VA_ARGS__)) \
+		(pos, __VA_ARGS__)
+
+/*
+ * list_for_each_entry_safe_continue is an old interface,
+ * use list_for_each_entry_mutable_continue instead.
  */
 #define list_for_each_entry_safe_continue(pos, n, head, member) 		\
 	for (pos = list_next_entry(pos, member), 				\
@@ -924,30 +986,79 @@ static inline size_t list_count_nodes(struct list_head *head)
 	     !list_entry_is_head(pos, head, member);				\
 	     pos = n, n = list_next_entry(n, member))
 
+#define __list_for_each_entry_mutable_continue_internal(pos, tmp, head, member) \
+	for (typeof(pos) tmp = list_next_entry(pos =			\
+		list_next_entry(pos, member), member);			\
+	     !list_entry_is_head(pos, head, member);			\
+	     pos = tmp, tmp = list_next_entry(tmp, member))
+
+#define __list_for_each_entry_mutable_continue2(pos, head, member)	\
+	__list_for_each_entry_mutable_continue_internal(pos,		\
+		__UNIQUE_ID(next), head, member)
+
+#define __list_for_each_entry_mutable_continue3(pos, next, head, member) \
+	list_for_each_entry_safe_continue(pos, next, head, member)
+
 /**
- * list_for_each_entry_safe_from - iterate over list from current point safe against removal
+ * list_for_each_entry_mutable_continue - continue list iteration safe against removal
  * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_head within the struct.
+ * @...:	either (head, member) or (next, head, member)
  *
- * Iterate over list of given type from current point, safe against
- * removal of list entry.
+ * next:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your list.
+ * member:	the name of the list_head within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_mutable_continue(pos, ...)			\
+	CONCATENATE(__list_for_each_entry_mutable_continue,		\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
+
+/*
+ * list_for_each_entry_safe_from is an old interface,
+ * use list_for_each_entry_mutable_from instead.
  */
 #define list_for_each_entry_safe_from(pos, n, head, member) 			\
 	for (n = list_next_entry(pos, member);					\
 	     !list_entry_is_head(pos, head, member);				\
 	     pos = n, n = list_next_entry(n, member))
 
+#define __list_for_each_entry_mutable_from_internal(pos, tmp, head, member) \
+	for (typeof(pos) tmp = list_next_entry(pos, member);		\
+	     !list_entry_is_head(pos, head, member);			\
+	     pos = tmp, tmp = list_next_entry(tmp, member))
+
+#define __list_for_each_entry_mutable_from2(pos, head, member)		\
+	__list_for_each_entry_mutable_from_internal(pos,		\
+		__UNIQUE_ID(next), head, member)
+
+#define __list_for_each_entry_mutable_from3(pos, next, head, member)	\
+	list_for_each_entry_safe_from(pos, next, head, member)
+
 /**
- * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
+ * list_for_each_entry_mutable_from - iterate over list from current point safe against removal
  * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_head within the struct.
+ * @...:	either (head, member) or (next, head, member)
  *
- * Iterate backwards over list of given type, safe against removal
- * of list entry.
+ * next:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your list.
+ * member:	the name of the list_head within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_mutable_from(pos, ...)			\
+	CONCATENATE(__list_for_each_entry_mutable_from,			\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
+
+/*
+ * list_for_each_entry_safe_reverse is an old interface,
+ * use list_for_each_entry_mutable_reverse instead.
  */
 #define list_for_each_entry_safe_reverse(pos, n, head, member)		\
 	for (pos = list_last_entry(head, typeof(*pos), member),		\
@@ -955,6 +1066,37 @@ static inline size_t list_count_nodes(struct list_head *head)
 	     !list_entry_is_head(pos, head, member); 			\
 	     pos = n, n = list_prev_entry(n, member))
 
+#define __list_for_each_entry_mutable_reverse_internal(pos, tmp, head, member) \
+	for (typeof(pos) tmp = list_prev_entry(pos =			\
+		list_last_entry(head, typeof(*pos), member), member);	\
+	     !list_entry_is_head(pos, head, member);			\
+	     pos = tmp, tmp = list_prev_entry(tmp, member))
+
+#define __list_for_each_entry_mutable_reverse2(pos, head, member)	\
+	__list_for_each_entry_mutable_reverse_internal(pos,		\
+		__UNIQUE_ID(prev), head, member)
+
+#define __list_for_each_entry_mutable_reverse3(pos, prev, head, member)	\
+	list_for_each_entry_safe_reverse(pos, prev, head, member)
+
+/**
+ * list_for_each_entry_mutable_reverse - iterate backwards over list safe against removal
+ * @pos:	the type * to use as a loop cursor.
+ * @...:	either (head, member) or (prev, head, member)
+ *
+ * prev:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your list.
+ * member:	the name of the list_head within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_mutable_reverse(pos, ...)			\
+	CONCATENATE(__list_for_each_entry_mutable_reverse,		\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
+
 /**
  * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
  * @pos:	the loop cursor used in the list_for_each_entry_safe loop
@@ -1189,6 +1331,31 @@ static inline void hlist_splice_init(struct hlist_head *from,
 	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
 	     pos = n)
 
+#define __hlist_for_each_mutable_internal(pos, tmp, head)		\
+	for (typeof(pos) tmp = (pos = (head)->first) ? pos->next : NULL; \
+	     pos;							\
+	     pos = tmp, tmp = pos ? pos->next : NULL)
+
+#define __hlist_for_each_mutable1(pos, head)				\
+	__hlist_for_each_mutable_internal(pos, __UNIQUE_ID(next), head)
+
+#define __hlist_for_each_mutable2(pos, next, head)			\
+	hlist_for_each_safe(pos, next, head)
+
+/**
+ * hlist_for_each_mutable - iterate over a hlist safe against entry removal
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @...:	either (head) or (next, head)
+ *
+ * next:	another &struct hlist_node to use as optional temporary storage.
+ *		The temporary cursor is internal unless explicitly supplied by
+ *		the caller.
+ * head:	the head for your hlist.
+ */
+#define hlist_for_each_mutable(pos, ...)				\
+	CONCATENATE(__hlist_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
+		(pos, __VA_ARGS__)
+
 #define hlist_entry_safe(ptr, type, member) \
 	({ typeof(ptr) ____ptr = (ptr); \
 	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
@@ -1224,18 +1391,44 @@ static inline void hlist_splice_init(struct hlist_head *from,
 	for (; pos;							\
 	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
 
-/**
- * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos:	the type * to use as a loop cursor.
- * @n:		a &struct hlist_node to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the hlist_node within the struct.
+/*
+ * hlist_for_each_entry_safe is an old interface, use hlist_for_each_entry_mutable instead.
  */
 #define hlist_for_each_entry_safe(pos, n, head, member) 		\
 	for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
 	     pos && ({ n = pos->member.next; 1; });			\
 	     pos = hlist_entry_safe(n, typeof(*pos), member))
 
+#define __hlist_for_each_entry_mutable_internal(pos, tmp, head, member)	\
+	for (struct hlist_node *tmp = (pos =				\
+		hlist_entry_safe((head)->first, typeof(*pos), member)) ? \
+		pos->member.next : NULL;				\
+	     pos;							\
+	     pos = hlist_entry_safe((tmp), typeof(*pos), member),	\
+		tmp = pos ? pos->member.next : NULL)
+
+#define __hlist_for_each_entry_mutable2(pos, head, member)		\
+	__hlist_for_each_entry_mutable_internal(pos,			\
+		__UNIQUE_ID(next), head, member)
+
+#define __hlist_for_each_entry_mutable3(pos, next, head, member)	\
+	hlist_for_each_entry_safe(pos, next, head, member)
+
+/**
+ * hlist_for_each_entry_mutable - iterate over hlist safe against entry removal
+ * @pos:	the type * to use as a loop cursor.
+ * @...:	either (head, member) or (next, head, member)
+ *
+ * next:	a &struct hlist_node to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your hlist.
+ * member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_mutable(pos, ...)				\
+	CONCATENATE(__hlist_for_each_entry_mutable,			\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
+
 /**
  * hlist_count_nodes - count nodes in the hlist
  * @head:	the head for your hlist.
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 2/7] llist: Add mutable iterator variants
From: Kaitao Cheng @ 2026-06-22  4:05 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König
  Cc: David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, linux-kernel, cgroups,
	linux-ntfs-dev, linux-fsdevel, io-uring, audit, bpf, netdev,
	dri-devel, linux-perf-users, linux-trace-kernel, kexec,
	live-patching, linux-modules, linux-crypto, linux-pm, rcu,
	sched-ext, linux-mm, virtualization, damon, llvm, Kaitao Cheng
In-Reply-To: <20260622040533.29824-1-kaitao.cheng@linux.dev>

From: Kaitao Cheng <chengkaitao@kylinos.cn>

llist_for_each_safe() and llist_for_each_entry_safe() require callers to
provide a temporary cursor even when the cursor is only needed by the
iterator itself.  This makes call sites noisier than necessary for the
common case where the loop body may remove the current entry but does
not otherwise inspect the saved next pointer.

Add llist_for_each_mutable() and llist_for_each_entry_mutable() variants
that support both forms.  Callers may omit the temporary cursor and let
the helper create an internal unique cursor, or keep passing an explicit
cursor when the loop needs to inspect or reset it.

Keep the existing safe helpers as compatibility wrappers so current users
continue to build unchanged while new code can use the shorter mutable
form.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 include/linux/llist.h | 81 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 65 insertions(+), 16 deletions(-)

diff --git a/include/linux/llist.h b/include/linux/llist.h
index 8846b7709669..1c6f12411d5e 100644
--- a/include/linux/llist.h
+++ b/include/linux/llist.h
@@ -49,6 +49,7 @@
  */
 
 #include <linux/atomic.h>
+#include <linux/args.h>
 #include <linux/container_of.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
@@ -143,12 +144,33 @@ static inline bool llist_on_list(const struct llist_node *node)
 #define llist_for_each(pos, node)			\
 	for ((pos) = (node); pos; (pos) = (pos)->next)
 
+/*
+ * llist_for_each_safe is an old interface, use llist_for_each_mutable instead.
+ */
+#define llist_for_each_safe(pos, n, node)			\
+	for ((pos) = (node); (pos) && ((n) = (pos)->next, true); (pos) = (n))
+
+#define __llist_for_each_mutable_internal(pos, tmp, node)		\
+	for (typeof(pos) tmp = ((pos) = (node)) ? (pos)->next : NULL;	\
+	     (pos);							\
+	     (pos) = tmp, tmp = (pos) ? (pos)->next : NULL)
+
+#define __llist_for_each_mutable1(pos, node)				\
+	__llist_for_each_mutable_internal(pos, __UNIQUE_ID(next), node)
+
+#define __llist_for_each_mutable2(pos, next, node)			\
+	llist_for_each_safe(pos, next, node)
+
 /**
- * llist_for_each_safe - iterate over some deleted entries of a lock-less list
- *			 safe against removal of list entry
+ * llist_for_each_mutable - iterate over some deleted entries of a lock-less list
+ *			    safe against removal of list entry
  * @pos:	the &struct llist_node to use as a loop cursor
- * @n:		another &struct llist_node to use as temporary storage
- * @node:	the first entry of deleted list entries
+ * @...:	either (node) or (next, node)
+ *
+ * next:	another &struct llist_node to use as optional temporary storage.
+ *		The temporary cursor is internal unless explicitly supplied by
+ *		the caller.
+ * node:	the first entry of deleted list entries
  *
  * In general, some entries of the lock-less list can be traversed
  * safely only after being deleted from list, so start with an entry
@@ -159,8 +181,9 @@ static inline bool llist_on_list(const struct llist_node *node)
  * you want to traverse from the oldest to the newest, you must
  * reverse the order by yourself before traversing.
  */
-#define llist_for_each_safe(pos, n, node)			\
-	for ((pos) = (node); (pos) && ((n) = (pos)->next, true); (pos) = (n))
+#define llist_for_each_mutable(pos, ...)				\
+	CONCATENATE(__llist_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
+		(pos, __VA_ARGS__)
 
 /**
  * llist_for_each_entry - iterate over some deleted entries of lock-less list of given type
@@ -182,13 +205,41 @@ static inline bool llist_on_list(const struct llist_node *node)
 	     member_address_is_nonnull(pos, member);			\
 	     (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))
 
+/*
+ * llist_for_each_entry_safe is an old interface, use llist_for_each_entry_mutable instead.
+ */
+#define llist_for_each_entry_safe(pos, n, node, member)			       \
+	for (pos = llist_entry((node), typeof(*pos), member);		       \
+	     member_address_is_nonnull(pos, member) &&			       \
+	        (n = llist_entry(pos->member.next, typeof(*n), member), true); \
+	     pos = n)
+
+#define __llist_for_each_entry_mutable_internal(pos, tmp, node, member)	\
+	for (typeof(pos) tmp = ((pos) = llist_entry((node), typeof(*pos), member), \
+		member_address_is_nonnull(pos, member) ?			\
+		llist_entry((pos)->member.next, typeof(*pos), member) : NULL);	\
+	     member_address_is_nonnull(pos, member);				\
+	     (pos) = tmp, tmp = member_address_is_nonnull(pos, member) ?	\
+		llist_entry((pos)->member.next, typeof(*pos), member) : NULL)
+
+#define __llist_for_each_entry_mutable2(pos, node, member)			\
+	__llist_for_each_entry_mutable_internal(pos, __UNIQUE_ID(next), node, member)
+
+#define __llist_for_each_entry_mutable3(pos, next, node, member)		\
+	llist_for_each_entry_safe(pos, next, node, member)
+
 /**
- * llist_for_each_entry_safe - iterate over some deleted entries of lock-less list of given type
- *			       safe against removal of list entry
+ * llist_for_each_entry_mutable - iterate over some deleted entries of
+ *				  lock-less list of given type safe against
+ *				  removal of list entry
  * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @node:	the first entry of deleted list entries.
- * @member:	the name of the llist_node with the struct.
+ * @...:	either (node, member) or (next, node, member)
+ *
+ * next:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * node:	the first entry of deleted list entries.
+ * member:	the name of the llist_node with the struct.
  *
  * In general, some entries of the lock-less list can be traversed
  * safely only after being removed from list, so start with an entry
@@ -199,11 +250,9 @@ static inline bool llist_on_list(const struct llist_node *node)
  * you want to traverse from the oldest to the newest, you must
  * reverse the order by yourself before traversing.
  */
-#define llist_for_each_entry_safe(pos, n, node, member)			       \
-	for (pos = llist_entry((node), typeof(*pos), member);		       \
-	     member_address_is_nonnull(pos, member) &&			       \
-	        (n = llist_entry(pos->member.next, typeof(*n), member), true); \
-	     pos = n)
+#define llist_for_each_entry_mutable(pos, ...)				\
+	CONCATENATE(__llist_for_each_entry_mutable,			\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
 
 /**
  * llist_empty - tests whether a lock-less list is empty
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH net] gianfar: fix memory leak in gfar_parse_group error paths
From: Pavan Chebbi @ 2026-06-22  4:08 UTC (permalink / raw)
  To: Rosen Penev
  Cc: netdev, Claudiu Manoil, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Sandeep Gopalpet,
	open list
In-Reply-To: <20260622021934.1415455-1-rosenp@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 3204 bytes --]

On Mon, Jun 22, 2026 at 7:49 AM Rosen Penev <rosenp@gmail.com> wrote:
>
> In gfar_parse_group, if any allocation in the irqinfo[] loop fails,
> or if of_iomap fails, or if the IRQ parsing fails, the already-
> allocated irqinfo[] entries and mapped regs are not freed.  The
> caller's free_gfar_dev cannot clean them up because priv->num_grps
> is only incremented after a successful return.
>
> Fix by adding an err_out label that frees all successfully allocated
> irqinfo entries and unmaps regs if mapped.  Track the number of
> allocated entries with 'allocated' and propagate the correct error
> code.
>
> Fixes: 46ceb60ca80fa ("gianfar: Add Multiple group Support")
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
>  drivers/net/ethernet/freescale/gianfar.c | 21 ++++++++++++++++-----
>  1 file changed, 16 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
> index 3271de5844f84..12ebb207be0be 100644
> --- a/drivers/net/ethernet/freescale/gianfar.c
> +++ b/drivers/net/ethernet/freescale/gianfar.c
> @@ -502,17 +502,19 @@ static int gfar_parse_group(struct device_node *np,
>                             struct gfar_private *priv, const char *model)
>  {
>         struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps];
> -       int i;
> +       int err = -ENOMEM;
> +       int i, allocated = 0;

Declarations should follow reverse xmas-tree fashion.
BTW, why num_grps cannot be incremented quicker? Not sure it can cause
any issues, since all this is happening probe(), it should be safe to
do that?
That way you could avoid cleaning up at two different places...

>
>         for (i = 0; i < GFAR_NUM_IRQS; i++) {
>                 grp->irqinfo[i] = kzalloc_obj(struct gfar_irqinfo);
>                 if (!grp->irqinfo[i])
> -                       return -ENOMEM;
> +                       goto err_out;
> +               allocated++;
>         }
>
>         grp->regs = of_iomap(np, 0);
>         if (!grp->regs)
> -               return -ENOMEM;
> +               goto err_out;
>
>         gfar_irq(grp, TX)->irq = irq_of_parse_and_map(np, 0);
>
> @@ -522,8 +524,10 @@ static int gfar_parse_group(struct device_node *np,
>                 gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2);
>                 if (!gfar_irq(grp, TX)->irq ||
>                     !gfar_irq(grp, RX)->irq ||
> -                   !gfar_irq(grp, ER)->irq)
> -                       return -EINVAL;
> +                   !gfar_irq(grp, ER)->irq) {
> +                       err = -EINVAL;
> +                       goto err_out;
> +               }
>         }
>
>         grp->priv = priv;
> @@ -567,6 +571,13 @@ static int gfar_parse_group(struct device_node *np,
>         priv->num_grps++;
>
>         return 0;
> +
> +err_out:
> +       for (i = 0; i < allocated; i++)
> +               kfree(grp->irqinfo[i]);
> +       if (grp->regs)
> +               iounmap(grp->regs);
> +       return err;
>  }
>
>  /* Reads the controller's registers to determine what interface
> --
> 2.54.0
>
>

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5469 bytes --]

^ permalink raw reply

* [Intel-wired-lan] [PATCH net] igc: Fix RX HW timestamp reporting when NET_RX_BUSY_POLL is disabled
From: Ding Meng @ 2026-06-22  4:13 UTC (permalink / raw)
  To: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem,
	edumazet, kuba, pabeni, jan.kiszka, florian.bezdeka
  Cc: intel-wired-lan, linux-kernel, netdev, meng.ding, wq.wang

When CONFIG_NET_RX_BUSY_POLL is deactivated, fetching RX HW timestamps
from the NIC no longer works as expected.

This occurs because disabling CONFIG_NET_RX_BUSY_POLL disables the
SKB NAPI mapping in __skb_mark_napi_id(). Consequently, get_timestamp()
fails to perform its driver lookup, and the igc driver's struct
net_device_ops::ndo_get_tstamp is never invoked.

Instead, get_timestamp() falls back to use shhwtstamps(skb)->hwtstamp,
a field that the driver has not populated.

Fix this by populating the hwtstamp field with the correct timestamp
in the default timer when CONFIG_NET_RX_BUSY_POLL is disabled.

Fixes: 069b142f5819 ("igc: Add support for PTP .getcyclesx64()")
Co-developed-by: Florian Bezdeka <florian.bezdeka@siemens.com>
Signed-off-by: Florian Bezdeka <florian.bezdeka@siemens.com>
Signed-off-by: Ding Meng <meng.ding@siemens.com>
---
 drivers/net/ethernet/intel/igc/igc_main.c | 38 ++++++++++++++++-------
 1 file changed, 26 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 8ac16808023..1da8d7aa76d 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -1992,7 +1992,26 @@ static struct sk_buff *igc_build_skb(struct igc_ring *rx_ring,
 	return skb;
 }
 
-static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring,
+static void igc_construct_skb_timestamps(struct igc_adapter *adapter,
+					 struct sk_buff *skb,
+					 struct igc_xdp_buff *ctx)
+{
+	if (!ctx->rx_ts)
+		return;
+#ifdef CONFIG_NET_RX_BUSY_POLL
+	skb_shinfo(skb)->tx_flags |= SKBTX_HW_TSTAMP_NETDEV;
+	skb_hwtstamps(skb)->netdev_data = ctx->rx_ts;
+#else
+	struct igc_inline_rx_tstamps *tstamps;
+
+	tstamps = ctx->rx_ts;
+	skb_hwtstamps(skb)->hwtstamp = igc_ptp_rx_pktstamp(adapter,
+							   tstamps->timer0);
+#endif
+}
+
+static struct sk_buff *igc_construct_skb(struct igc_adapter *adapter,
+					 struct igc_ring *rx_ring,
 					 struct igc_rx_buffer *rx_buffer,
 					 struct igc_xdp_buff *ctx)
 {
@@ -2013,10 +2032,7 @@ static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring,
 	if (unlikely(!skb))
 		return NULL;
 
-	if (ctx->rx_ts) {
-		skb_shinfo(skb)->tx_flags |= SKBTX_HW_TSTAMP_NETDEV;
-		skb_hwtstamps(skb)->netdev_data = ctx->rx_ts;
-	}
+	igc_construct_skb_timestamps(adapter, skb, ctx);
 
 	/* Determine available headroom for copy */
 	headlen = size;
@@ -2686,7 +2702,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
 		else if (ring_uses_build_skb(rx_ring))
 			skb = igc_build_skb(rx_ring, rx_buffer, &ctx.xdp);
 		else
-			skb = igc_construct_skb(rx_ring, rx_buffer, &ctx);
+			skb = igc_construct_skb(adapter, rx_ring, rx_buffer, &ctx);
 
 		/* exit if we failed to retrieve a buffer */
 		if (!xdp_res && !skb) {
@@ -2738,7 +2754,8 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
 	return total_packets;
 }
 
-static struct sk_buff *igc_construct_skb_zc(struct igc_ring *ring,
+static struct sk_buff *igc_construct_skb_zc(struct igc_adapter *adapter,
+					    struct igc_ring *ring,
 					    struct igc_xdp_buff *ctx)
 {
 	struct xdp_buff *xdp = &ctx->xdp;
@@ -2760,10 +2777,7 @@ static struct sk_buff *igc_construct_skb_zc(struct igc_ring *ring,
 		__skb_pull(skb, metasize);
 	}
 
-	if (ctx->rx_ts) {
-		skb_shinfo(skb)->tx_flags |= SKBTX_HW_TSTAMP_NETDEV;
-		skb_hwtstamps(skb)->netdev_data = ctx->rx_ts;
-	}
+	igc_construct_skb_timestamps(adapter, skb, ctx);
 
 	return skb;
 }
@@ -2775,7 +2789,7 @@ static void igc_dispatch_skb_zc(struct igc_q_vector *q_vector,
 	struct igc_ring *ring = q_vector->rx.ring;
 	struct sk_buff *skb;
 
-	skb = igc_construct_skb_zc(ring, ctx);
+	skb = igc_construct_skb_zc(q_vector->adapter, ring, ctx);
 	if (!skb) {
 		ring->rx_stats.alloc_failed++;
 		set_bit(IGC_RING_FLAG_RX_ALLOC_FAILED, &ring->flags);

base-commit: 4549871118cf616eecdd2d939f78e3b9e1dddc48
-- 
2.47.3


^ permalink raw reply related

* [PATCH v3 5/7] kernel: Use mutable list iterators
From: Kaitao Cheng @ 2026-06-22  4:28 UTC (permalink / raw)
  To: Paul Moore, Eric Paris, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	David S. Miller, Jakub Kicinski, Jesper Dangaard Brouer,
	John Fastabend, Tejun Heo, Johannes Weiner, Michal Koutný,
	Maarten Lankhorst, Maxime Ripard, Natalie Vock, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Masami Hiramatsu, Oleg Nesterov, Peter Oberparleiter,
	Andrew Morton, Baoquan He, Mike Rapoport, Pasha Tatashin,
	Pratyush Yadav, Naveen N Rao, Josh Poimboeuf, Jiri Kosina,
	Miroslav Benes, Petr Mladek, Will Deacon, Boqun Feng,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Steffen Klassert, Daniel Jordan, Rafael J. Wysocki,
	Davidlohr Bueso, Paul E. McKenney, Josh Triplett,
	Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
	Uladzislau Rezki, Juri Lelli, Vincent Guittot, Kees Cook,
	Balbir Singh, Anna-Maria Behnsen, Thomas Gleixner, John Stultz,
	KP Singh, Matt Bobrowski, Nathan Chancellor, Martin KaFai Lau,
	Song Liu, Mark Rutland, Mathieu Desnoyers, Dietmar Eggemann,
	David Vernet, Steven Rostedt
  Cc: audit, linux-kernel, bpf, netdev, cgroups, dri-devel,
	linux-perf-users, linux-trace-kernel, kexec, live-patching,
	linux-modules, linux-crypto, linux-pm, rcu, sched-ext, llvm,
	Kaitao Cheng
In-Reply-To: <20260622040533.29824-1-kaitao.cheng@linux.dev>

From: Kaitao Cheng <chengkaitao@kylinos.cn>

The safe list iteration helpers require callers to provide a temporary
cursor even when the cursor is only used internally by the loop. This
leaves many functions with otherwise unused variables whose only purpose
is to satisfy the old iterator interface.

Use the mutable list iteration helpers for those cases. The mutable
helpers keep the same removal-safe traversal semantics, while allowing
the temporary cursor to be internal to the macro when the caller does
not need to observe it.

Convert list, hlist and llist users under kernel/ where the temporary
cursor is not used outside the iteration. Keep the explicit cursor form
where the next entry is still needed by the surrounding code.

No functional change intended.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 kernel/audit_tree.c                 |  4 +--
 kernel/audit_watch.c                | 16 ++++-----
 kernel/auditfilter.c                |  4 +--
 kernel/auditsc.c                    |  4 +--
 kernel/bpf/arena.c                  | 10 +++---
 kernel/bpf/arraymap.c               |  8 ++---
 kernel/bpf/bpf_local_storage.c      |  3 +-
 kernel/bpf/bpf_lru_list.c           | 25 ++++++-------
 kernel/bpf/btf.c                    | 18 +++++-----
 kernel/bpf/cgroup.c                 |  7 ++--
 kernel/bpf/cpumap.c                 |  4 +--
 kernel/bpf/devmap.c                 | 10 +++---
 kernel/bpf/helpers.c                |  8 ++---
 kernel/bpf/local_storage.c          |  4 +--
 kernel/bpf/memalloc.c               | 16 ++++-----
 kernel/bpf/offload.c                |  8 ++---
 kernel/bpf/states.c                 |  4 +--
 kernel/bpf/stream.c                 |  4 +--
 kernel/bpf/verifier.c               |  6 ++--
 kernel/cgroup/cgroup-v1.c           |  4 +--
 kernel/cgroup/cgroup.c              | 54 ++++++++++++++---------------
 kernel/cgroup/dmem.c                | 12 +++----
 kernel/cgroup/rdma.c                |  8 ++---
 kernel/events/core.c                | 44 +++++++++++------------
 kernel/events/uprobes.c             | 12 +++----
 kernel/exit.c                       |  8 ++---
 kernel/fail_function.c              |  4 +--
 kernel/gcov/clang.c                 |  4 +--
 kernel/irq_work.c                   |  4 +--
 kernel/kexec_core.c                 |  4 +--
 kernel/kprobes.c                    | 16 ++++-----
 kernel/livepatch/core.c             |  4 +--
 kernel/livepatch/core.h             |  4 +--
 kernel/liveupdate/kho_block.c       |  4 +--
 kernel/liveupdate/luo_flb.c         |  4 +--
 kernel/locking/rwsem.c              |  2 +-
 kernel/locking/test-ww_mutex.c      |  2 +-
 kernel/module/main.c                | 11 +++---
 kernel/padata.c                     |  4 +--
 kernel/power/snapshot.c             |  8 ++---
 kernel/power/wakelock.c             |  4 +--
 kernel/printk/printk.c              | 11 +++---
 kernel/ptrace.c                     |  4 +--
 kernel/rcu/rcutorture.c             |  3 +-
 kernel/rcu/tasks.h                  |  9 +++--
 kernel/rcu/tree.c                   |  6 ++--
 kernel/resource.c                   |  4 +--
 kernel/sched/core.c                 |  4 +--
 kernel/sched/ext.c                  | 22 ++++++------
 kernel/sched/fair.c                 | 28 +++++++--------
 kernel/sched/topology.c             |  4 +--
 kernel/sched/wait.c                 |  4 +--
 kernel/seccomp.c                    |  4 +--
 kernel/signal.c                     | 11 +++---
 kernel/smp.c                        |  4 +--
 kernel/taskstats.c                  |  8 ++---
 kernel/time/clockevents.c           |  6 ++--
 kernel/time/clocksource.c           |  4 +--
 kernel/time/posix-cpu-timers.c      |  4 +--
 kernel/time/posix-timers.c          |  3 +-
 kernel/torture.c                    |  3 +-
 kernel/trace/bpf_trace.c            |  4 +--
 kernel/trace/ftrace.c               | 49 +++++++++++---------------
 kernel/trace/ring_buffer.c          | 25 +++++++------
 kernel/trace/trace.c                | 12 +++----
 kernel/trace/trace_dynevent.c       |  6 ++--
 kernel/trace/trace_dynevent.h       |  5 ++-
 kernel/trace/trace_events.c         | 35 +++++++++----------
 kernel/trace/trace_events_filter.c  |  4 +--
 kernel/trace/trace_events_hist.c    |  8 ++---
 kernel/trace/trace_events_trigger.c | 17 ++++-----
 kernel/trace/trace_events_user.c    | 16 ++++-----
 kernel/trace/trace_stat.c           |  4 +--
 kernel/user-return-notifier.c       |  3 +-
 kernel/workqueue.c                  | 16 ++++-----
 75 files changed, 353 insertions(+), 381 deletions(-)

diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 1ed19b775912..9652b0595ad4 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -543,10 +543,10 @@ static void audit_tree_log_remove_rule(struct audit_context *context,
 
 static void kill_rules(struct audit_context *context, struct audit_tree *tree)
 {
-	struct audit_krule *rule, *next;
+	struct audit_krule *rule;
 	struct audit_entry *entry;
 
-	list_for_each_entry_safe(rule, next, &tree->rules, rlist) {
+	list_for_each_entry_mutable(rule, &tree->rules, rlist) {
 		entry = container_of(rule, struct audit_entry, rule);
 
 		list_del_init(&rule->rlist);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 06dd0ebe73e2..f56812c8186f 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -247,14 +247,14 @@ static void audit_update_watch(struct audit_parent *parent,
 			       u64 ino, unsigned int invalidating,
 			       struct audit_watch_ctx *ctx)
 {
-	struct audit_watch *owatch, *nwatch, *nextw;
-	struct audit_krule *r, *nextr;
+	struct audit_watch *owatch, *nwatch;
+	struct audit_krule *r;
 	struct audit_entry *oentry, *nentry;
 
 	mutex_lock(&audit_filter_mutex);
 	/* Run all of the watches on this parent looking for the one that
 	 * matches the given dname */
-	list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
+	list_for_each_entry_mutable(owatch, &parent->watches, wlist) {
 		if (audit_compare_dname_path(dname, owatch->path,
 					     AUDIT_NAME_FULL))
 			continue;
@@ -275,7 +275,7 @@ static void audit_update_watch(struct audit_parent *parent,
 		nwatch->dev = dev;
 		nwatch->ino = ino;
 
-		list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {
+		list_for_each_entry_mutable(r, &owatch->rules, rlist) {
 
 			oentry = container_of(r, struct audit_entry, rule);
 			list_del(&oentry->rule.rlist);
@@ -322,13 +322,13 @@ static void audit_update_watch(struct audit_parent *parent,
 /* Remove all watches & rules associated with a parent that is going away. */
 static void audit_remove_parent_watches(struct audit_parent *parent)
 {
-	struct audit_watch *w, *nextw;
-	struct audit_krule *r, *nextr;
+	struct audit_watch *w;
+	struct audit_krule *r;
 	struct audit_entry *e;
 
 	mutex_lock(&audit_filter_mutex);
-	list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
-		list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
+	list_for_each_entry_mutable(w, &parent->watches, wlist) {
+		list_for_each_entry_mutable(r, &w->rules, rlist) {
 			e = container_of(r, struct audit_entry, rule);
 			audit_watch_log_rule_change(r, w, "remove_rule");
 			if (e->rule.exe)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 4401119b5275..6a4936870903 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1445,14 +1445,14 @@ static int update_lsm_rule(struct audit_krule *r)
  * updated rule. */
 int audit_update_lsm_rules(void)
 {
-	struct audit_krule *r, *n;
+	struct audit_krule *r;
 	int i, err = 0;
 
 	/* audit_filter_mutex synchronizes the writers */
 	mutex_lock(&audit_filter_mutex);
 
 	for (i = 0; i < AUDIT_NR_FILTERS; i++) {
-		list_for_each_entry_safe(r, n, &audit_rules_list[i], list) {
+		list_for_each_entry_mutable(r, &audit_rules_list[i], list) {
 			int res = update_lsm_rule(r);
 			if (!err)
 				err = res;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 6610e667c728..df9c6c9e9e49 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -929,9 +929,9 @@ static inline void audit_free_module(struct audit_context *context)
 }
 static inline void audit_free_names(struct audit_context *context)
 {
-	struct audit_names *n, *next;
+	struct audit_names *n;
 
-	list_for_each_entry_safe(n, next, &context->names_list, list) {
+	list_for_each_entry_mutable(n, &context->names_list, list) {
 		list_del(&n->list);
 		if (n->name)
 			putname(n->name);
diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
index 80b7b8a69446..597c3cd428eb 100644
--- a/kernel/bpf/arena.c
+++ b/kernel/bpf/arena.c
@@ -842,7 +842,7 @@ static void arena_free_pages(struct bpf_arena *arena, long uaddr, long page_cnt,
 	long kaddr, pgoff;
 	struct page *page;
 	struct llist_head free_pages;
-	struct llist_node *pos, *t;
+	struct llist_node *pos;
 	struct arena_free_span *s;
 	struct clear_range_data cdata;
 	unsigned long flags;
@@ -889,7 +889,7 @@ static void arena_free_pages(struct bpf_arena *arena, long uaddr, long page_cnt,
 		/* bulk zap if multiple pages being freed */
 		zap_pages(arena, full_uaddr, page_cnt);
 
-	llist_for_each_safe(pos, t, __llist_del_all(&free_pages)) {
+	llist_for_each_mutable(pos, __llist_del_all(&free_pages)) {
 		page = llist_entry(pos, struct page, pcp_llist);
 		if (page_cnt == 1 && page_ref_count(page) > 1) /* maybe mapped by user space */
 			/* Optimization for the common case of page_cnt==1:
@@ -963,7 +963,7 @@ static void arena_free_worker(struct work_struct *work)
 {
 	struct bpf_arena *arena = container_of(work, struct bpf_arena, free_work);
 	struct mem_cgroup *new_memcg, *old_memcg;
-	struct llist_node *list, *pos, *t;
+	struct llist_node *list, *pos;
 	struct arena_free_span *s;
 	u64 arena_vm_start, user_vm_start;
 	struct llist_head free_pages;
@@ -1002,7 +1002,7 @@ static void arena_free_worker(struct work_struct *work)
 	raw_res_spin_unlock_irqrestore(&arena->spinlock, flags);
 
 	/* Iterate the list again without holding spinlock to do the tlb flush and zap_pages */
-	llist_for_each_safe(pos, t, list) {
+	llist_for_each_mutable(pos, list) {
 		s = llist_entry(pos, struct arena_free_span, node);
 		page_cnt = s->page_cnt;
 		full_uaddr = clear_lo32(user_vm_start) + s->uaddr;
@@ -1018,7 +1018,7 @@ static void arena_free_worker(struct work_struct *work)
 	}
 
 	/* free all pages collected by apply_to_existing_page_range() in the first loop */
-	llist_for_each_safe(pos, t, __llist_del_all(&free_pages)) {
+	llist_for_each_mutable(pos, __llist_del_all(&free_pages)) {
 		page = llist_entry(pos, struct page, pcp_llist);
 		__free_page(page);
 	}
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 248b4818178c..1150179a90f7 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -1083,12 +1083,12 @@ static int prog_array_map_poke_track(struct bpf_map *map,
 static void prog_array_map_poke_untrack(struct bpf_map *map,
 					struct bpf_prog_aux *prog_aux)
 {
-	struct prog_poke_elem *elem, *tmp;
+	struct prog_poke_elem *elem;
 	struct bpf_array_aux *aux;
 
 	aux = container_of(map, struct bpf_array, map)->aux;
 	mutex_lock(&aux->poke_mutex);
-	list_for_each_entry_safe(elem, tmp, &aux->poke_progs, list) {
+	list_for_each_entry_mutable(elem, &aux->poke_progs, list) {
 		if (elem->aux == prog_aux) {
 			list_del_init(&elem->list);
 			kfree(elem);
@@ -1196,11 +1196,11 @@ static struct bpf_map *prog_array_map_alloc(union bpf_attr *attr)
 
 static void prog_array_map_free(struct bpf_map *map)
 {
-	struct prog_poke_elem *elem, *tmp;
+	struct prog_poke_elem *elem;
 	struct bpf_array_aux *aux;
 
 	aux = container_of(map, struct bpf_array, map)->aux;
-	list_for_each_entry_safe(elem, tmp, &aux->poke_progs, list) {
+	list_for_each_entry_mutable(elem, &aux->poke_progs, list) {
 		list_del_init(&elem->list);
 		kfree(elem);
 	}
diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c
index 6fc6a4b672b5..5f01ba032b12 100644
--- a/kernel/bpf/bpf_local_storage.c
+++ b/kernel/bpf/bpf_local_storage.c
@@ -161,14 +161,13 @@ void bpf_selem_free(struct bpf_local_storage_elem *selem,
 static void bpf_selem_free_list(struct hlist_head *list, bool reuse_now)
 {
 	struct bpf_local_storage_elem *selem;
-	struct hlist_node *n;
 
 	/* The "_safe" iteration is needed.
 	 * The loop is not removing the selem from the list
 	 * but bpf_selem_free will use the selem->rcu_head
 	 * which is union-ized with the selem->free_node.
 	 */
-	hlist_for_each_entry_safe(selem, n, list, free_node)
+	hlist_for_each_entry_mutable(selem, list, free_node)
 		bpf_selem_free(selem, reuse_now);
 }
 
diff --git a/kernel/bpf/bpf_lru_list.c b/kernel/bpf/bpf_lru_list.c
index 5ed7cb4b98c0..4b7306ade684 100644
--- a/kernel/bpf/bpf_lru_list.c
+++ b/kernel/bpf/bpf_lru_list.c
@@ -126,11 +126,11 @@ static void __bpf_lru_list_rotate_active(struct bpf_lru *lru,
 					 struct bpf_lru_list *l)
 {
 	struct list_head *active = &l->lists[BPF_LRU_LIST_T_ACTIVE];
-	struct bpf_lru_node *node, *tmp_node, *first_node;
+	struct bpf_lru_node *node, *first_node;
 	unsigned int i = 0;
 
 	first_node = list_first_entry(active, struct bpf_lru_node, list);
-	list_for_each_entry_safe_reverse(node, tmp_node, active, list) {
+	list_for_each_entry_mutable_reverse(node, active, list) {
 		if (bpf_lru_node_is_ref(node))
 			__bpf_lru_node_move(l, node, BPF_LRU_LIST_T_ACTIVE);
 		else
@@ -196,11 +196,11 @@ __bpf_lru_list_shrink_inactive(struct bpf_lru *lru,
 			       enum bpf_lru_list_type tgt_free_type)
 {
 	struct list_head *inactive = &l->lists[BPF_LRU_LIST_T_INACTIVE];
-	struct bpf_lru_node *node, *tmp_node;
+	struct bpf_lru_node *node;
 	unsigned int nshrinked = 0;
 	unsigned int i = 0;
 
-	list_for_each_entry_safe_reverse(node, tmp_node, inactive, list) {
+	list_for_each_entry_mutable_reverse(node, inactive, list) {
 		if (bpf_lru_node_is_ref(node) &&
 		    !READ_ONCE(node->pending_free)) {
 			__bpf_lru_node_move(l, node, BPF_LRU_LIST_T_ACTIVE);
@@ -247,7 +247,7 @@ static unsigned int __bpf_lru_list_shrink(struct bpf_lru *lru,
 					  enum bpf_lru_list_type tgt_free_type)
 
 {
-	struct bpf_lru_node *node, *tmp_node;
+	struct bpf_lru_node *node;
 	struct list_head *force_shrink_list;
 	unsigned int nshrinked;
 
@@ -262,8 +262,7 @@ static unsigned int __bpf_lru_list_shrink(struct bpf_lru *lru,
 	else
 		force_shrink_list = &l->lists[BPF_LRU_LIST_T_ACTIVE];
 
-	list_for_each_entry_safe_reverse(node, tmp_node, force_shrink_list,
-					 list) {
+	list_for_each_entry_mutable_reverse(node, force_shrink_list, list) {
 		if (READ_ONCE(node->pending_free) ||
 		    lru->del_from_htab(lru->del_arg, node)) {
 			__bpf_lru_node_move_to_free(l, node, free_list,
@@ -279,10 +278,9 @@ static unsigned int __bpf_lru_list_shrink(struct bpf_lru *lru,
 static void __local_list_flush(struct bpf_lru_list *l,
 			       struct bpf_lru_locallist *loc_l)
 {
-	struct bpf_lru_node *node, *tmp_node;
+	struct bpf_lru_node *node;
 
-	list_for_each_entry_safe_reverse(node, tmp_node,
-					 &loc_l->pending_list, list) {
+	list_for_each_entry_mutable_reverse(node, &loc_l->pending_list, list) {
 		if (READ_ONCE(node->pending_free))
 			__bpf_lru_node_move_in(l, node, BPF_LRU_LIST_T_FREE);
 		else if (bpf_lru_node_is_ref(node))
@@ -313,7 +311,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru,
 					   struct bpf_lru_locallist *loc_l)
 {
 	struct bpf_lru_list *l = &lru->common_lru.lru_list;
-	struct bpf_lru_node *node, *tmp_node;
+	struct bpf_lru_node *node;
 	unsigned int nfree = 0;
 	LIST_HEAD(tmp_free);
 
@@ -324,8 +322,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru,
 
 	__bpf_lru_list_rotate(lru, l);
 
-	list_for_each_entry_safe(node, tmp_node, &l->lists[BPF_LRU_LIST_T_FREE],
-				 list) {
+	list_for_each_entry_mutable(node, &l->lists[BPF_LRU_LIST_T_FREE], list) {
 		__bpf_lru_node_move_to_free(l, node, &tmp_free,
 					    BPF_LRU_LOCAL_LIST_T_FREE);
 		if (++nfree == lru->target_free)
@@ -343,7 +340,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru,
 	 * Transfer the harvested nodes from the temporary list_head into
 	 * the lockless per-CPU free llist.
 	 */
-	list_for_each_entry_safe(node, tmp_node, &tmp_free, list) {
+	list_for_each_entry_mutable(node, &tmp_free, list) {
 		list_del(&node->list);
 		llist_add(&node->llist, &loc_l->free_llist);
 	}
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 15ae7c43f594..983928bd774b 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -8439,7 +8439,7 @@ static void purge_cand_cache(struct btf *btf);
 static int btf_module_notify(struct notifier_block *nb, unsigned long op,
 			     void *module)
 {
-	struct btf_module *btf_mod, *tmp;
+	struct btf_module *btf_mod;
 	struct module *mod = module;
 	struct btf *btf;
 	int err = 0;
@@ -8512,7 +8512,7 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op,
 		break;
 	case MODULE_STATE_LIVE:
 		mutex_lock(&btf_module_mutex);
-		list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+		list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 			if (btf_mod->module != module)
 				continue;
 
@@ -8523,7 +8523,7 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op,
 		break;
 	case MODULE_STATE_GOING:
 		mutex_lock(&btf_module_mutex);
-		list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+		list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 			if (btf_mod->module != module)
 				continue;
 
@@ -8567,10 +8567,10 @@ struct module *btf_try_get_module(const struct btf *btf)
 {
 	struct module *res = NULL;
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
-	struct btf_module *btf_mod, *tmp;
+	struct btf_module *btf_mod;
 
 	mutex_lock(&btf_module_mutex);
-	list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+	list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 		if (btf_mod->btf != btf)
 			continue;
 
@@ -8596,7 +8596,7 @@ struct module *btf_try_get_module(const struct btf *btf)
 static struct btf *btf_get_module_btf(const struct module *module)
 {
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
-	struct btf_module *btf_mod, *tmp;
+	struct btf_module *btf_mod;
 #endif
 	struct btf *btf = NULL;
 
@@ -8609,7 +8609,7 @@ static struct btf *btf_get_module_btf(const struct module *module)
 
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
 	mutex_lock(&btf_module_mutex);
-	list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+	list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 		if (btf_mod->module != module)
 			continue;
 
@@ -8773,7 +8773,7 @@ static int btf_check_iter_kfuncs(struct btf *btf, const char *func_name,
 static int btf_check_kfunc_name(struct btf *btf, const char *func_name, u32 kind)
 {
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
-	struct btf_module *btf_mod, *tmp;
+	struct btf_module *btf_mod;
 #endif
 	s32 id;
 
@@ -8789,7 +8789,7 @@ static int btf_check_kfunc_name(struct btf *btf, const char *func_name, u32 kind
 
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
 	guard(mutex)(&btf_module_mutex);
-	list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+	list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 		if (btf_mod->btf == btf)
 			continue;
 		id = btf_find_by_name_kind(btf_mod->btf, func_name, kind);
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 83ce66296ac1..a3bd18ab9246 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -328,7 +328,7 @@ static void cgroup_bpf_release(struct work_struct *work)
 					       bpf.release_work);
 	struct bpf_prog_array *old_array;
 	struct list_head *storages = &cgrp->bpf.storages;
-	struct bpf_cgroup_storage *storage, *stmp;
+	struct bpf_cgroup_storage *storage;
 
 	unsigned int atype;
 
@@ -337,9 +337,8 @@ static void cgroup_bpf_release(struct work_struct *work)
 	for (atype = 0; atype < ARRAY_SIZE(cgrp->bpf.progs); atype++) {
 		struct hlist_head *progs = &cgrp->bpf.progs[atype];
 		struct bpf_prog_list *pl;
-		struct hlist_node *pltmp;
 
-		hlist_for_each_entry_safe(pl, pltmp, progs, node) {
+		hlist_for_each_entry_mutable(pl, progs, node) {
 			hlist_del(&pl->node);
 			if (pl->prog) {
 				if (pl->prog->expected_attach_type == BPF_LSM_CGROUP)
@@ -360,7 +359,7 @@ static void cgroup_bpf_release(struct work_struct *work)
 		bpf_prog_array_free(old_array);
 	}
 
-	list_for_each_entry_safe(storage, stmp, storages, list_cg) {
+	list_for_each_entry_mutable(storage, storages, list_cg) {
 		bpf_cgroup_storage_unlink(storage);
 		bpf_cgroup_storage_free(storage);
 	}
diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c
index 5e59ab896f05..fa3a1b3559e2 100644
--- a/kernel/bpf/cpumap.c
+++ b/kernel/bpf/cpumap.c
@@ -821,9 +821,9 @@ int cpu_map_generic_redirect(struct bpf_cpu_map_entry *rcpu,
 
 void __cpu_map_flush(struct list_head *flush_list)
 {
-	struct xdp_bulk_queue *bq, *tmp;
+	struct xdp_bulk_queue *bq;
 
-	list_for_each_entry_safe(bq, tmp, flush_list, flush_node) {
+	list_for_each_entry_mutable(bq, flush_list, flush_node) {
 		local_lock_nested_bh(&bq->obj->bulkq->bq_lock);
 		bq_flush_to_queue(bq);
 		local_unlock_nested_bh(&bq->obj->bulkq->bq_lock);
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index dc7b859e8bbf..d85e4f955061 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -219,11 +219,10 @@ static void dev_map_free(struct bpf_map *map)
 		for (i = 0; i < dtab->n_buckets; i++) {
 			struct bpf_dtab_netdev *dev;
 			struct hlist_head *head;
-			struct hlist_node *next;
 
 			head = dev_map_index_hash(dtab, i);
 
-			hlist_for_each_entry_safe(dev, next, head, index_hlist) {
+			hlist_for_each_entry_mutable(dev, head, index_hlist) {
 				hlist_del_rcu(&dev->index_hlist);
 				if (dev->xdp_prog)
 					bpf_prog_put(dev->xdp_prog);
@@ -426,9 +425,9 @@ static void bq_xmit_all(struct xdp_dev_bulk_queue *bq, u32 flags)
  */
 void __dev_flush(struct list_head *flush_list)
 {
-	struct xdp_dev_bulk_queue *bq, *tmp;
+	struct xdp_dev_bulk_queue *bq;
 
-	list_for_each_entry_safe(bq, tmp, flush_list, flush_node) {
+	list_for_each_entry_mutable(bq, flush_list, flush_node) {
 		local_lock_nested_bh(&bq->dev->xdp_bulkq->bq_lock);
 		bq_xmit_all(bq, XDP_XMIT_FLUSH);
 		bq->dev_rx = NULL;
@@ -1124,11 +1123,10 @@ static void dev_map_hash_remove_netdev(struct bpf_dtab *dtab,
 	for (i = 0; i < dtab->n_buckets; i++) {
 		struct bpf_dtab_netdev *dev;
 		struct hlist_head *head;
-		struct hlist_node *next;
 
 		head = dev_map_index_hash(dtab, i);
 
-		hlist_for_each_entry_safe(dev, next, head, index_hlist) {
+		hlist_for_each_entry_mutable(dev, head, index_hlist) {
 			if (netdev != dev->dev)
 				continue;
 
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index c18f1e16edee..cfaf97dd970a 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -1662,7 +1662,7 @@ static void bpf_async_process_op(struct bpf_async_cb *cb, u32 op,
 static void bpf_async_irq_worker(struct irq_work *work)
 {
 	struct bpf_async_cb *cb = container_of(work, struct bpf_async_cb, worker);
-	struct llist_node *pos, *n, *list;
+	struct llist_node *pos, *list;
 
 	list = llist_del_all(&cb->async_cmds);
 	if (!list)
@@ -1670,7 +1670,7 @@ static void bpf_async_irq_worker(struct irq_work *work)
 
 	list = llist_reverse_order(list);
 	this_cpu_write(async_cb_running, cb);
-	llist_for_each_safe(pos, n, list) {
+	llist_for_each_mutable(pos, list) {
 		struct bpf_async_cmd *cmd;
 
 		cmd = container_of(pos, struct bpf_async_cmd, node);
@@ -2247,7 +2247,7 @@ EXPORT_SYMBOL_GPL(bpf_base_func_proto);
 void bpf_list_head_free(const struct btf_field *field, void *list_head,
 			struct bpf_spin_lock *spin_lock)
 {
-	struct list_head *head = list_head, drain, *pos, *n;
+	struct list_head *head = list_head, drain, *pos;
 
 	BUILD_BUG_ON(sizeof(struct list_head) > sizeof(struct bpf_list_head));
 	BUILD_BUG_ON(__alignof__(struct list_head) > __alignof__(struct bpf_list_head));
@@ -2262,7 +2262,7 @@ void bpf_list_head_free(const struct btf_field *field, void *list_head,
 	__bpf_spin_lock_irqsave(spin_lock);
 	if (!head->next || list_empty(head))
 		goto unlock;
-	list_for_each_safe(pos, n, head) {
+	list_for_each_mutable(pos, head) {
 		struct bpf_list_node_kern *node;
 
 		node = container_of(pos, struct bpf_list_node_kern, list_head);
diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c
index 23267213a17f..2595c5a4d171 100644
--- a/kernel/bpf/local_storage.c
+++ b/kernel/bpf/local_storage.c
@@ -342,11 +342,11 @@ static void cgroup_storage_map_free(struct bpf_map *_map)
 {
 	struct bpf_cgroup_storage_map *map = map_to_storage(_map);
 	struct list_head *storages = &map->list;
-	struct bpf_cgroup_storage *storage, *stmp;
+	struct bpf_cgroup_storage *storage;
 
 	cgroup_lock();
 
-	list_for_each_entry_safe(storage, stmp, storages, list_map) {
+	list_for_each_entry_mutable(storage, storages, list_map) {
 		bpf_cgroup_storage_unlink(storage);
 		bpf_cgroup_storage_free(storage);
 	}
diff --git a/kernel/bpf/memalloc.c b/kernel/bpf/memalloc.c
index e9662db7198f..09adb1d0e101 100644
--- a/kernel/bpf/memalloc.c
+++ b/kernel/bpf/memalloc.c
@@ -264,10 +264,10 @@ static void free_one(void *obj, bool percpu)
 
 static int free_all(struct bpf_mem_cache *c, struct llist_node *llnode, bool percpu)
 {
-	struct llist_node *pos, *t;
+	struct llist_node *pos;
 	int cnt = 0;
 
-	llist_for_each_safe(pos, t, llnode) {
+	llist_for_each_mutable(pos, llnode) {
 		if (c->dtor)
 			c->dtor((void *)pos + LLIST_NODE_SZ, c->dtor_ctx);
 		free_one(pos, percpu);
@@ -296,7 +296,7 @@ static void enque_to_free(struct bpf_mem_cache *c, void *obj)
 
 static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
 {
-	struct llist_node *llnode, *t;
+	struct llist_node *llnode;
 
 	if (atomic_xchg(&c->call_rcu_ttrace_in_progress, 1)) {
 		if (unlikely(READ_ONCE(c->draining))) {
@@ -307,7 +307,7 @@ static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
 	}
 
 	WARN_ON_ONCE(!llist_empty(&c->waiting_for_gp_ttrace));
-	llist_for_each_safe(llnode, t, llist_del_all(&c->free_by_rcu_ttrace))
+	llist_for_each_mutable(llnode, llist_del_all(&c->free_by_rcu_ttrace))
 		llist_add(llnode, &c->waiting_for_gp_ttrace);
 
 	if (unlikely(READ_ONCE(c->draining))) {
@@ -326,7 +326,7 @@ static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
 static void free_bulk(struct bpf_mem_cache *c)
 {
 	struct bpf_mem_cache *tgt = c->tgt;
-	struct llist_node *llnode, *t;
+	struct llist_node *llnode;
 	unsigned long flags;
 	int cnt;
 
@@ -346,7 +346,7 @@ static void free_bulk(struct bpf_mem_cache *c)
 	} while (cnt > (c->high_watermark + c->low_watermark) / 2);
 
 	/* and drain free_llist_extra */
-	llist_for_each_safe(llnode, t, llist_del_all(&c->free_llist_extra))
+	llist_for_each_mutable(llnode, llist_del_all(&c->free_llist_extra))
 		enque_to_free(tgt, llnode);
 	do_call_rcu_ttrace(tgt);
 }
@@ -374,13 +374,13 @@ static void __free_by_rcu(struct rcu_head *head)
 
 static void check_free_by_rcu(struct bpf_mem_cache *c)
 {
-	struct llist_node *llnode, *t;
+	struct llist_node *llnode;
 	unsigned long flags;
 
 	/* drain free_llist_extra_rcu */
 	if (unlikely(!llist_empty(&c->free_llist_extra_rcu))) {
 		inc_active(c, &flags);
-		llist_for_each_safe(llnode, t, llist_del_all(&c->free_llist_extra_rcu))
+		llist_for_each_mutable(llnode, llist_del_all(&c->free_llist_extra_rcu))
 			if (__llist_add(llnode, &c->free_by_rcu))
 				c->free_by_rcu_tail = llnode;
 		dec_active(c, &flags);
diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c
index 0d6f5569588c..32a21613fe79 100644
--- a/kernel/bpf/offload.c
+++ b/kernel/bpf/offload.c
@@ -137,8 +137,8 @@ static void __bpf_offload_dev_netdev_unregister(struct bpf_offload_dev *offdev,
 						struct net_device *netdev)
 {
 	struct bpf_offload_netdev *ondev, *altdev = NULL;
-	struct bpf_offloaded_map *offmap, *mtmp;
-	struct bpf_prog_offload *offload, *ptmp;
+	struct bpf_offloaded_map *offmap;
+	struct bpf_prog_offload *offload;
 
 	ASSERT_RTNL();
 
@@ -165,9 +165,9 @@ static void __bpf_offload_dev_netdev_unregister(struct bpf_offload_dev *offdev,
 			offmap->netdev = altdev->netdev;
 		list_splice_init(&ondev->maps, &altdev->maps);
 	} else {
-		list_for_each_entry_safe(offload, ptmp, &ondev->progs, offloads)
+		list_for_each_entry_mutable(offload, &ondev->progs, offloads)
 			__bpf_prog_offload_destroy(offload->prog);
-		list_for_each_entry_safe(offmap, mtmp, &ondev->maps, offloads)
+		list_for_each_entry_mutable(offmap, &ondev->maps, offloads)
 			__bpf_map_offload_destroy(offmap);
 	}
 
diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c
index 32f346ce3ffc..ec7942049c06 100644
--- a/kernel/bpf/states.c
+++ b/kernel/bpf/states.c
@@ -1241,7 +1241,7 @@ int bpf_is_state_visited(struct bpf_verifier_env *env, int insn_idx)
 	struct bpf_verifier_state *cur = env->cur_state, *new;
 	bool force_new_state, add_new_state, loop;
 	int n, err, states_cnt = 0;
-	struct list_head *pos, *tmp, *head;
+	struct list_head *pos, *head;
 
 	force_new_state = env->test_state_freq || bpf_is_force_checkpoint(env, insn_idx) ||
 			  /* Avoid accumulating infinitely long jmp history */
@@ -1267,7 +1267,7 @@ int bpf_is_state_visited(struct bpf_verifier_env *env, int insn_idx)
 
 	loop = false;
 	head = bpf_explored_state(env, insn_idx);
-	list_for_each_safe(pos, tmp, head) {
+	list_for_each_mutable(pos, head) {
 		sl = container_of(pos, struct bpf_verifier_state_list, node);
 		states_cnt++;
 		if (sl->state.insn_idx != insn_idx)
diff --git a/kernel/bpf/stream.c b/kernel/bpf/stream.c
index be9ce98e9469..3d722cfd1d07 100644
--- a/kernel/bpf/stream.c
+++ b/kernel/bpf/stream.c
@@ -96,9 +96,9 @@ static void bpf_stream_free_elem(struct bpf_stream_elem *elem)
 
 static void bpf_stream_free_list(struct llist_node *list)
 {
-	struct bpf_stream_elem *elem, *tmp;
+	struct bpf_stream_elem *elem;
 
-	llist_for_each_entry_safe(elem, tmp, list, node)
+	llist_for_each_entry_mutable(elem, list, node)
 		bpf_stream_free_elem(elem);
 }
 
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2abc79dbf281..7cd5d10b390a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -18285,7 +18285,7 @@ static void sanitize_dead_code(struct bpf_verifier_env *env)
 static void free_states(struct bpf_verifier_env *env)
 {
 	struct bpf_verifier_state_list *sl;
-	struct list_head *head, *pos, *tmp;
+	struct list_head *head, *pos;
 	struct bpf_scc_info *info;
 	int i, j;
 
@@ -18293,7 +18293,7 @@ static void free_states(struct bpf_verifier_env *env)
 	env->cur_state = NULL;
 	while (!pop_stack(env, NULL, NULL, false));
 
-	list_for_each_safe(pos, tmp, &env->free_list) {
+	list_for_each_mutable(pos, &env->free_list) {
 		sl = container_of(pos, struct bpf_verifier_state_list, node);
 		bpf_free_verifier_state(&sl->state, false);
 		kfree(sl);
@@ -18316,7 +18316,7 @@ static void free_states(struct bpf_verifier_env *env)
 	for (i = 0; i < state_htab_size(env); i++) {
 		head = &env->explored_states[i];
 
-		list_for_each_safe(pos, tmp, head) {
+		list_for_each_mutable(pos, head) {
 			sl = container_of(pos, struct bpf_verifier_state_list, node);
 			bpf_free_verifier_state(&sl->state, false);
 			kfree(sl);
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index a4337c9b5287..1c777b28861f 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -205,10 +205,10 @@ struct cgroup_pidlist {
  */
 void cgroup1_pidlist_destroy_all(struct cgroup *cgrp)
 {
-	struct cgroup_pidlist *l, *tmp_l;
+	struct cgroup_pidlist *l;
 
 	mutex_lock(&cgrp->pidlist_mutex);
-	list_for_each_entry_safe(l, tmp_l, &cgrp->pidlists, links)
+	list_for_each_entry_mutable(l, &cgrp->pidlists, links)
 		mod_delayed_work(cgroup_pidlist_destroy_wq, &l->destroy_dwork, 0);
 	mutex_unlock(&cgrp->pidlist_mutex);
 
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 38f8d9df8fbc..2b619c1553ee 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -872,9 +872,9 @@ static void css_set_update_populated(struct css_set *cset, bool populated)
 static void css_set_skip_task_iters(struct css_set *cset,
 				    struct task_struct *task)
 {
-	struct css_task_iter *it, *pos;
+	struct css_task_iter *it;
 
-	list_for_each_entry_safe(it, pos, &cset->task_iters, iters_node)
+	list_for_each_entry_mutable(it, &cset->task_iters, iters_node)
 		css_task_iter_skip(it, task);
 }
 
@@ -951,7 +951,7 @@ static unsigned long css_set_hash(struct cgroup_subsys_state **css)
 
 void put_css_set_locked(struct css_set *cset)
 {
-	struct cgrp_cset_link *link, *tmp_link;
+	struct cgrp_cset_link *link;
 	struct cgroup_subsys *ss;
 	int ssid;
 
@@ -970,7 +970,7 @@ void put_css_set_locked(struct css_set *cset)
 	hash_del(&cset->hlist);
 	css_set_count--;
 
-	list_for_each_entry_safe(link, tmp_link, &cset->cgrp_links, cgrp_link) {
+	list_for_each_entry_mutable(link, &cset->cgrp_links, cgrp_link) {
 		list_del(&link->cset_link);
 		list_del(&link->cgrp_link);
 		if (cgroup_parent(link->cgrp))
@@ -1129,9 +1129,9 @@ static struct css_set *find_existing_css_set(struct css_set *old_cset,
 
 static void free_cgrp_cset_links(struct list_head *links_to_free)
 {
-	struct cgrp_cset_link *link, *tmp_link;
+	struct cgrp_cset_link *link;
 
-	list_for_each_entry_safe(link, tmp_link, links_to_free, cset_link) {
+	list_for_each_entry_mutable(link, links_to_free, cset_link) {
 		list_del(&link->cset_link);
 		kfree(link);
 	}
@@ -1372,7 +1372,7 @@ void cgroup_free_root(struct cgroup_root *root)
 static void cgroup_destroy_root(struct cgroup_root *root)
 {
 	struct cgroup *cgrp = &root->cgrp;
-	struct cgrp_cset_link *link, *tmp_link;
+	struct cgrp_cset_link *link;
 	int ret;
 
 	trace_cgroup_destroy_root(root);
@@ -1395,7 +1395,7 @@ static void cgroup_destroy_root(struct cgroup_root *root)
 	 */
 	spin_lock_irq(&css_set_lock);
 
-	list_for_each_entry_safe(link, tmp_link, &cgrp->cset_links, cset_link) {
+	list_for_each_entry_mutable(link, &cgrp->cset_links, cset_link) {
 		list_del(&link->cset_link);
 		list_del(&link->cgrp_link);
 		kfree(link);
@@ -1887,7 +1887,7 @@ int rebind_subsystems(struct cgroup_root *dst_root, u32 ss_mask)
 		struct cgroup_root *src_root = ss->root;
 		struct cgroup *scgrp = &src_root->cgrp;
 		struct cgroup_subsys_state *css = cgroup_css(scgrp, ss);
-		struct css_set *cset, *cset_pos;
+		struct css_set *cset;
 		struct css_task_iter *it;
 
 		WARN_ON(!css || cgroup_css(dcgrp, ss));
@@ -1912,8 +1912,8 @@ int rebind_subsystems(struct cgroup_root *dst_root, u32 ss_mask)
 		spin_lock_irq(&css_set_lock);
 		css->cgroup = dcgrp;
 		WARN_ON(!list_empty(&dcgrp->e_csets[ss->id]));
-		list_for_each_entry_safe(cset, cset_pos, &scgrp->e_csets[ss->id],
-					 e_cset_node[ss->id]) {
+		list_for_each_entry_mutable(cset, &scgrp->e_csets[ss->id],
+					    e_cset_node[ss->id]) {
 			list_move_tail(&cset->e_cset_node[ss->id],
 				       &dcgrp->e_csets[ss->id]);
 			/*
@@ -2689,8 +2689,8 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
 {
 	struct cgroup_taskset *tset = &mgctx->tset;
 	struct cgroup_subsys *ss;
-	struct task_struct *task, *tmp_task;
-	struct css_set *cset, *tmp_cset;
+	struct task_struct *task;
+	struct css_set *cset;
 	int ssid, failed_ssid, ret;
 
 	/* check that we can legitimately attach to the cgroup */
@@ -2714,7 +2714,7 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
 	 */
 	spin_lock_irq(&css_set_lock);
 	list_for_each_entry(cset, &tset->src_csets, mg_node) {
-		list_for_each_entry_safe(task, tmp_task, &cset->mg_tasks, cg_list) {
+		list_for_each_entry_mutable(task, &cset->mg_tasks, cg_list) {
 			struct css_set *from_cset = task_css_set(task);
 			struct css_set *to_cset = cset->mg_dst_cset;
 
@@ -2767,7 +2767,7 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
 out_release_tset:
 	spin_lock_irq(&css_set_lock);
 	list_splice_init(&tset->dst_csets, &tset->src_csets);
-	list_for_each_entry_safe(cset, tmp_cset, &tset->src_csets, mg_node) {
+	list_for_each_entry_mutable(cset, &tset->src_csets, mg_node) {
 		list_splice_tail_init(&cset->mg_tasks, &cset->tasks);
 		list_del_init(&cset->mg_node);
 	}
@@ -2825,14 +2825,14 @@ int cgroup_migrate_vet_dst(struct cgroup *dst_cgrp)
  */
 void cgroup_migrate_finish(struct cgroup_mgctx *mgctx)
 {
-	struct css_set *cset, *tmp_cset;
+	struct css_set *cset;
 
 	lockdep_assert_held(&cgroup_mutex);
 
 	spin_lock_irq(&css_set_lock);
 
-	list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_src_csets,
-				 mg_src_preload_node) {
+	list_for_each_entry_mutable(cset, &mgctx->preloaded_src_csets,
+				    mg_src_preload_node) {
 		cset->mg_src_cgrp = NULL;
 		cset->mg_dst_cgrp = NULL;
 		cset->mg_dst_cset = NULL;
@@ -2840,8 +2840,8 @@ void cgroup_migrate_finish(struct cgroup_mgctx *mgctx)
 		put_css_set_locked(cset);
 	}
 
-	list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_dst_csets,
-				 mg_dst_preload_node) {
+	list_for_each_entry_mutable(cset, &mgctx->preloaded_dst_csets,
+				    mg_dst_preload_node) {
 		cset->mg_src_cgrp = NULL;
 		cset->mg_dst_cgrp = NULL;
 		cset->mg_dst_cset = NULL;
@@ -2917,13 +2917,13 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
  */
 int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
 {
-	struct css_set *src_cset, *tmp_cset;
+	struct css_set *src_cset;
 
 	lockdep_assert_held(&cgroup_mutex);
 
 	/* look up the dst cset for each src cset and link it to src */
-	list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets,
-				 mg_src_preload_node) {
+	list_for_each_entry_mutable(src_cset, &mgctx->preloaded_src_csets,
+				    mg_src_preload_node) {
 		struct css_set *dst_cset;
 		struct cgroup_subsys *ss;
 		int ssid;
@@ -3225,10 +3225,10 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
 	spin_lock_irq(&css_set_lock);
 	list_for_each_entry(src_cset, &mgctx.preloaded_src_csets,
 			    mg_src_preload_node) {
-		struct task_struct *task, *ntask;
+		struct task_struct *task;
 
 		/* all tasks in src_csets need to be migrated */
-		list_for_each_entry_safe(task, ntask, &src_cset->tasks, cg_list)
+		list_for_each_entry_mutable(task, &src_cset->tasks, cg_list)
 			cgroup_migrate_add_task(task, &mgctx);
 	}
 	spin_unlock_irq(&css_set_lock);
@@ -7106,10 +7106,10 @@ static DEFINE_PER_CPU(struct irq_work, cgrp_dead_tasks_iwork);
 static void cgrp_dead_tasks_iwork_fn(struct irq_work *iwork)
 {
 	struct llist_node *lnode;
-	struct task_struct *task, *next;
+	struct task_struct *task;
 
 	lnode = llist_del_all(this_cpu_ptr(&cgrp_dead_tasks));
-	llist_for_each_entry_safe(task, next, lnode, cg_dead_lnode) {
+	llist_for_each_entry_mutable(task, lnode, cg_dead_lnode) {
 		do_cgroup_task_dead(task);
 		put_task_struct(task);
 	}
diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c
index 4753a67d0f0f..1daa8fb49fbe 100644
--- a/kernel/cgroup/dmem.c
+++ b/kernel/cgroup/dmem.c
@@ -203,10 +203,10 @@ static void dmemcs_offline(struct cgroup_subsys_state *css)
 static void dmemcs_free(struct cgroup_subsys_state *css)
 {
 	struct dmemcg_state *dmemcs = css_to_dmemcs(css);
-	struct dmem_cgroup_pool_state *pool, *next;
+	struct dmem_cgroup_pool_state *pool;
 
 	spin_lock(&dmemcg_lock);
-	list_for_each_entry_safe(pool, next, &dmemcs->pools, css_node) {
+	list_for_each_entry_mutable(pool, &dmemcs->pools, css_node) {
 		/*
 		 *The pool is dead and all references are 0,
 		 * no need for RCU protection with list_del_rcu or freeing.
@@ -444,9 +444,9 @@ get_cg_pool_locked(struct dmemcg_state *dmemcs, struct dmem_cgroup_region *regio
 static void dmemcg_free_rcu(struct rcu_head *rcu)
 {
 	struct dmem_cgroup_region *region = container_of(rcu, typeof(*region), rcu);
-	struct dmem_cgroup_pool_state *pool, *next;
+	struct dmem_cgroup_pool_state *pool;
 
-	list_for_each_entry_safe(pool, next, &region->pools, region_node)
+	list_for_each_entry_mutable(pool, &region->pools, region_node)
 		free_cg_pool(pool);
 	kfree(region->name);
 	kfree(region);
@@ -467,7 +467,7 @@ static void dmemcg_free_region(struct kref *ref)
  */
 void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region)
 {
-	struct dmem_cgroup_pool_state *pool, *next;
+	struct dmem_cgroup_pool_state *pool;
 
 	if (!region)
 		return;
@@ -477,7 +477,7 @@ void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region)
 	/* Remove from global region list */
 	list_del_rcu(&region->region_node);
 
-	list_for_each_entry_safe(pool, next, &region->pools, region_node) {
+	list_for_each_entry_mutable(pool, &region->pools, region_node) {
 		list_del_rcu(&pool->css_node);
 		list_del(&pool->region_node);
 		dmemcg_pool_put(pool);
diff --git a/kernel/cgroup/rdma.c b/kernel/cgroup/rdma.c
index 5e82a03b3270..5527375c16e1 100644
--- a/kernel/cgroup/rdma.c
+++ b/kernel/cgroup/rdma.c
@@ -444,7 +444,7 @@ EXPORT_SYMBOL(rdmacg_register_device);
  */
 void rdmacg_unregister_device(struct rdmacg_device *device)
 {
-	struct rdmacg_resource_pool *rpool, *tmp;
+	struct rdmacg_resource_pool *rpool;
 
 	/*
 	 * Synchronize with any active resource settings,
@@ -457,7 +457,7 @@ void rdmacg_unregister_device(struct rdmacg_device *device)
 	 * Now that this device is off the cgroup list, its safe to free
 	 * all the rpool resources.
 	 */
-	list_for_each_entry_safe(rpool, tmp, &device->rpools, dev_node)
+	list_for_each_entry_mutable(rpool, &device->rpools, dev_node)
 		free_cg_rpool_locked(rpool);
 
 	mutex_unlock(&rdmacg_mutex);
@@ -747,11 +747,11 @@ rdmacg_css_alloc(struct cgroup_subsys_state *parent)
 static void rdmacg_css_free(struct cgroup_subsys_state *css)
 {
 	struct rdma_cgroup *cg = css_rdmacg(css);
-	struct rdmacg_resource_pool *rpool, *tmp;
+	struct rdmacg_resource_pool *rpool;
 
 	/* Clean up rpools kept alive by non-zero peak values */
 	mutex_lock(&rdmacg_mutex);
-	list_for_each_entry_safe(rpool, tmp, &cg->rpools, cg_node)
+	list_for_each_entry_mutable(rpool, &cg->rpools, cg_node)
 		free_cg_rpool_locked(rpool);
 	mutex_unlock(&rdmacg_mutex);
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 00e6dcb931d9..dd93436f8f2d 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2346,7 +2346,7 @@ static inline struct list_head *get_event_list(struct perf_event *event)
 static void perf_group_detach(struct perf_event *event)
 {
 	struct perf_event *leader = event->group_leader;
-	struct perf_event *sibling, *tmp;
+	struct perf_event *sibling;
 	struct perf_event_context *ctx = event->ctx;
 
 	lockdep_assert_held(&ctx->lock);
@@ -2376,7 +2376,7 @@ static void perf_group_detach(struct perf_event *event)
 	 * upgrade the siblings to singleton events by adding them
 	 * to whatever list we are on.
 	 */
-	list_for_each_entry_safe(sibling, tmp, &event->sibling_list, sibling_list) {
+	list_for_each_entry_mutable(sibling, &event->sibling_list, sibling_list) {
 
 		/*
 		 * Events that have PERF_EV_CAP_SIBLING require being part of
@@ -2405,8 +2405,8 @@ static void perf_group_detach(struct perf_event *event)
 	}
 
 out:
-	for_each_sibling_event(tmp, leader)
-		perf_event__header_size(tmp);
+	for_each_sibling_event(sibling, leader)
+		perf_event__header_size(sibling);
 
 	perf_event__header_size(leader);
 }
@@ -3528,7 +3528,7 @@ static void __pmu_ctx_sched_out(struct perf_event_pmu_context *pmu_ctx,
 				enum event_type_t event_type)
 {
 	struct perf_event_context *ctx = pmu_ctx->ctx;
-	struct perf_event *event, *tmp;
+	struct perf_event *event;
 	struct pmu *pmu = pmu_ctx->pmu;
 
 	if (ctx->task && !(ctx->is_active & EVENT_ALL)) {
@@ -3543,16 +3543,14 @@ static void __pmu_ctx_sched_out(struct perf_event_pmu_context *pmu_ctx,
 
 	perf_pmu_disable(pmu);
 	if (event_type & EVENT_PINNED) {
-		list_for_each_entry_safe(event, tmp,
-					 &pmu_ctx->pinned_active,
-					 active_list)
+		list_for_each_entry_mutable(event, &pmu_ctx->pinned_active,
+					    active_list)
 			group_sched_out(event, ctx);
 	}
 
 	if (event_type & EVENT_FLEXIBLE) {
-		list_for_each_entry_safe(event, tmp,
-					 &pmu_ctx->flexible_active,
-					 active_list)
+		list_for_each_entry_mutable(event, &pmu_ctx->flexible_active,
+					    active_list)
 			group_sched_out(event, ctx);
 		/*
 		 * Since we cleared EVENT_FLEXIBLE, also clear
@@ -4738,7 +4736,7 @@ static void perf_event_exit_event(struct perf_event *event,
 static void perf_event_remove_on_exec(struct perf_event_context *ctx)
 {
 	struct perf_event_context *clone_ctx = NULL;
-	struct perf_event *event, *next;
+	struct perf_event *event;
 	unsigned long flags;
 	bool modified = false;
 
@@ -4747,7 +4745,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx)
 	if (WARN_ON_ONCE(ctx->task != current))
 		goto unlock;
 
-	list_for_each_entry_safe(event, next, &ctx->event_list, event_entry) {
+	list_for_each_entry_mutable(event, &ctx->event_list, event_entry) {
 		if (!event->attr.remove_on_exec)
 			continue;
 
@@ -11833,9 +11831,9 @@ perf_addr_filter_new(struct perf_event *event, struct list_head *filters)
 
 static void free_filters_list(struct list_head *filters)
 {
-	struct perf_addr_filter *filter, *iter;
+	struct perf_addr_filter *filter;
 
-	list_for_each_entry_safe(filter, iter, filters, entry) {
+	list_for_each_entry_mutable(filter, filters, entry) {
 		path_put(&filter->path);
 		list_del(&filter->entry);
 		kfree(filter);
@@ -14436,7 +14434,7 @@ static void __perf_pmu_install_event(struct pmu *pmu,
 static void __perf_pmu_install(struct perf_event_context *ctx,
 			       int cpu, struct pmu *pmu, struct list_head *events)
 {
-	struct perf_event *event, *tmp;
+	struct perf_event *event;
 
 	/*
 	 * Re-instate events in 2 passes.
@@ -14446,7 +14444,7 @@ static void __perf_pmu_install(struct perf_event_context *ctx,
 	 * leader will enable its siblings, even if those are still on the old
 	 * context.
 	 */
-	list_for_each_entry_safe(event, tmp, events, migrate_entry) {
+	list_for_each_entry_mutable(event, events, migrate_entry) {
 		if (event->group_leader == event)
 			continue;
 
@@ -14458,7 +14456,7 @@ static void __perf_pmu_install(struct perf_event_context *ctx,
 	 * Once all the siblings are setup properly, install the group leaders
 	 * to make it go.
 	 */
-	list_for_each_entry_safe(event, tmp, events, migrate_entry) {
+	list_for_each_entry_mutable(event, events, migrate_entry) {
 		list_del(&event->migrate_entry);
 		__perf_pmu_install_event(pmu, ctx, cpu, event);
 	}
@@ -14592,7 +14590,7 @@ perf_event_exit_event(struct perf_event *event,
 static void perf_event_exit_task_context(struct task_struct *task, bool exit)
 {
 	struct perf_event_context *ctx, *clone_ctx = NULL;
-	struct perf_event *child_event, *next;
+	struct perf_event *child_event;
 
 	ctx = perf_pin_task_context(task);
 	if (!ctx)
@@ -14642,7 +14640,7 @@ static void perf_event_exit_task_context(struct task_struct *task, bool exit)
 	if (exit)
 		perf_event_task(task, ctx, 0);
 
-	list_for_each_entry_safe(child_event, next, &ctx->event_list, event_entry)
+	list_for_each_entry_mutable(child_event, &ctx->event_list, event_entry)
 		perf_event_exit_event(child_event, ctx, exit ? task : NULL, false);
 
 	mutex_unlock(&ctx->mutex);
@@ -14675,13 +14673,13 @@ static void perf_event_exit_task_context(struct task_struct *task, bool exit)
  */
 void perf_event_exit_task(struct task_struct *task)
 {
-	struct perf_event *event, *tmp;
+	struct perf_event *event;
 
 	WARN_ON_ONCE(task != current);
 
 	mutex_lock(&task->perf_event_mutex);
-	list_for_each_entry_safe(event, tmp, &task->perf_event_list,
-				 owner_entry) {
+	list_for_each_entry_mutable(event, &task->perf_event_list,
+				    owner_entry) {
 		list_del_init(&event->owner_entry);
 
 		/*
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 4084e926e284..61aa48e3b5a6 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -258,13 +258,13 @@ static void delayed_uprobe_delete(struct delayed_uprobe *du)
 
 static void delayed_uprobe_remove(struct uprobe *uprobe, struct mm_struct *mm)
 {
-	struct list_head *pos, *q;
+	struct list_head *pos;
 	struct delayed_uprobe *du;
 
 	if (!uprobe && !mm)
 		return;
 
-	list_for_each_safe(pos, q, &delayed_uprobe_list) {
+	list_for_each_mutable(pos, &delayed_uprobe_list) {
 		du = list_entry(pos, struct delayed_uprobe, list);
 
 		if (uprobe && du->uprobe != uprobe)
@@ -1562,13 +1562,13 @@ static void build_probe_list(struct inode *inode,
 /* @vma contains reference counter, not the probed instruction. */
 static int delayed_ref_ctr_inc(struct vm_area_struct *vma)
 {
-	struct list_head *pos, *q;
+	struct list_head *pos;
 	struct delayed_uprobe *du;
 	unsigned long vaddr;
 	int ret = 0, err = 0;
 
 	mutex_lock(&delayed_uprobe_lock);
-	list_for_each_safe(pos, q, &delayed_uprobe_list) {
+	list_for_each_mutable(pos, &delayed_uprobe_list) {
 		du = list_entry(pos, struct delayed_uprobe, list);
 
 		if (du->mm != vma->vm_mm ||
@@ -1597,7 +1597,7 @@ static int delayed_ref_ctr_inc(struct vm_area_struct *vma)
 int uprobe_mmap(struct vm_area_struct *vma)
 {
 	struct list_head tmp_list;
-	struct uprobe *uprobe, *u;
+	struct uprobe *uprobe;
 	struct inode *inode;
 
 	if (no_uprobe_events())
@@ -1622,7 +1622,7 @@ int uprobe_mmap(struct vm_area_struct *vma)
 	 * removed. But in this case filter_chain() must return false, all
 	 * consumers have gone away.
 	 */
-	list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
+	list_for_each_entry_mutable(uprobe, &tmp_list, pending_list) {
 		if (!fatal_signal_pending(current) &&
 		    filter_chain(uprobe, vma->vm_mm)) {
 			unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset);
diff --git a/kernel/exit.c b/kernel/exit.c
index 1056422bc101..62ef6553253a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -630,7 +630,7 @@ static struct task_struct *find_child_reaper(struct task_struct *father,
 {
 	struct pid_namespace *pid_ns = task_active_pid_ns(father);
 	struct task_struct *reaper = pid_ns->child_reaper;
-	struct task_struct *p, *n;
+	struct task_struct *p;
 
 	if (likely(reaper != father))
 		return reaper;
@@ -644,7 +644,7 @@ static struct task_struct *find_child_reaper(struct task_struct *father,
 
 	write_unlock_irq(&tasklist_lock);
 
-	list_for_each_entry_safe(p, n, dead, ptrace_entry) {
+	list_for_each_entry_mutable(p, dead, ptrace_entry) {
 		list_del_init(&p->ptrace_entry);
 		release_task(p);
 	}
@@ -766,7 +766,7 @@ static void forget_original_parent(struct task_struct *father,
 static void exit_notify(struct task_struct *tsk, int group_dead)
 {
 	bool autoreap;
-	struct task_struct *p, *n;
+	struct task_struct *p;
 	LIST_HEAD(dead);
 
 	write_lock_irq(&tasklist_lock);
@@ -800,7 +800,7 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
 		wake_up_process(tsk->signal->group_exec_task);
 	write_unlock_irq(&tasklist_lock);
 
-	list_for_each_entry_safe(p, n, &dead, ptrace_entry) {
+	list_for_each_entry_mutable(p, &dead, ptrace_entry) {
 		list_del_init(&p->ptrace_entry);
 		release_task(p);
 	}
diff --git a/kernel/fail_function.c b/kernel/fail_function.c
index 2eaf55005f49..357c810c4908 100644
--- a/kernel/fail_function.c
+++ b/kernel/fail_function.c
@@ -226,9 +226,9 @@ static void fei_attr_remove(struct fei_attr *attr)
 
 static void fei_attr_remove_all(void)
 {
-	struct fei_attr *attr, *n;
+	struct fei_attr *attr;
 
-	list_for_each_entry_safe(attr, n, &fei_attr_list, list) {
+	list_for_each_entry_mutable(attr, &fei_attr_list, list) {
 		fei_attr_remove(attr);
 	}
 }
diff --git a/kernel/gcov/clang.c b/kernel/gcov/clang.c
index fd98ced0e51d..e9a86a04d793 100644
--- a/kernel/gcov/clang.c
+++ b/kernel/gcov/clang.c
@@ -347,9 +347,9 @@ struct gcov_info *gcov_info_dup(struct gcov_info *info)
  */
 void gcov_info_free(struct gcov_info *info)
 {
-	struct gcov_fn_info *fn, *tmp;
+	struct gcov_fn_info *fn;
 
-	list_for_each_entry_safe(fn, tmp, &info->functions, head) {
+	list_for_each_entry_mutable(fn, &info->functions, head) {
 		kvfree(fn->counters);
 		list_del(&fn->head);
 		kfree(fn);
diff --git a/kernel/irq_work.c b/kernel/irq_work.c
index f7e2dc2c30c6..ce454e12cd86 100644
--- a/kernel/irq_work.c
+++ b/kernel/irq_work.c
@@ -234,7 +234,7 @@ void irq_work_single(void *arg)
 
 static void irq_work_run_list(struct llist_head *list)
 {
-	struct irq_work *work, *tmp;
+	struct irq_work *work;
 	struct llist_node *llnode;
 
 	/*
@@ -248,7 +248,7 @@ static void irq_work_run_list(struct llist_head *list)
 		return;
 
 	llnode = llist_del_all(list);
-	llist_for_each_entry_safe(work, tmp, llnode, node.llist)
+	llist_for_each_entry_mutable(work, llnode, node.llist)
 		irq_work_single(work);
 }
 
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index dc770b9a6d05..d50d15d4709f 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -318,9 +318,9 @@ static void kimage_free_pages(struct page *page)
 
 void kimage_free_page_list(struct list_head *list)
 {
-	struct page *page, *next;
+	struct page *page;
 
-	list_for_each_entry_safe(page, next, list, lru) {
+	list_for_each_entry_mutable(page, list, lru) {
 		list_del(&page->lru);
 		kimage_free_pages(page);
 	}
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index bfc89083daa9..8e8fd6833d1c 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -228,12 +228,12 @@ static bool collect_one_slot(struct kprobe_insn_page *kip, int idx)
 
 static int collect_garbage_slots(struct kprobe_insn_cache *c)
 {
-	struct kprobe_insn_page *kip, *next;
+	struct kprobe_insn_page *kip;
 
 	/* Ensure no-one is interrupted on the garbages */
 	synchronize_rcu();
 
-	list_for_each_entry_safe(kip, next, &c->pages, list) {
+	list_for_each_entry_mutable(kip, &c->pages, list) {
 		int i;
 
 		if (kip->ngarbage == 0)
@@ -563,7 +563,7 @@ static void do_optimize_kprobes(void)
  */
 static void do_unoptimize_kprobes(void)
 {
-	struct optimized_kprobe *op, *tmp;
+	struct optimized_kprobe *op;
 
 	lockdep_assert_held(&text_mutex);
 	/* See comment in do_optimize_kprobes() */
@@ -573,7 +573,7 @@ static void do_unoptimize_kprobes(void)
 		arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list);
 
 	/* Loop on 'freeing_list' for disarming and removing from kprobe hash list */
-	list_for_each_entry_safe(op, tmp, &freeing_list, list) {
+	list_for_each_entry_mutable(op, &freeing_list, list) {
 		/* Switching from detour code to origin */
 		op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;
 		/* Disarm probes if marked disabled and not gone */
@@ -594,9 +594,9 @@ static void do_unoptimize_kprobes(void)
 /* Reclaim all kprobes on the 'freeing_list' */
 static void do_free_cleaned_kprobes(void)
 {
-	struct optimized_kprobe *op, *tmp;
+	struct optimized_kprobe *op;
 
-	list_for_each_entry_safe(op, tmp, &freeing_list, list) {
+	list_for_each_entry_mutable(op, &freeing_list, list) {
 		list_del_init(&op->list);
 		if (WARN_ON_ONCE(!kprobe_unused(&op->kp))) {
 			/*
@@ -2598,9 +2598,9 @@ static int __init populate_kprobe_blacklist(unsigned long *start,
 /* Remove all symbols in given area from kprobe blacklist */
 static void kprobe_remove_area_blacklist(unsigned long start, unsigned long end)
 {
-	struct kprobe_blacklist_entry *ent, *n;
+	struct kprobe_blacklist_entry *ent;
 
-	list_for_each_entry_safe(ent, n, &kprobe_blacklist, list) {
+	list_for_each_entry_mutable(ent, &kprobe_blacklist, list) {
 		if (ent->start_addr < start || ent->start_addr >= end)
 			continue;
 		list_del(&ent->list);
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 28d15ba58a26..6e433519bfff 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -788,9 +788,9 @@ void klp_free_patch_async(struct klp_patch *patch)
 
 void klp_free_replaced_patches_async(struct klp_patch *new_patch)
 {
-	struct klp_patch *old_patch, *tmp_patch;
+	struct klp_patch *old_patch;
 
-	klp_for_each_patch_safe(old_patch, tmp_patch) {
+	klp_for_each_patch_safe(old_patch) {
 		if (old_patch == new_patch)
 			return;
 		klp_free_patch_async(old_patch);
diff --git a/kernel/livepatch/core.h b/kernel/livepatch/core.h
index 38209c7361b6..274c8108062f 100644
--- a/kernel/livepatch/core.h
+++ b/kernel/livepatch/core.h
@@ -7,8 +7,8 @@
 extern struct mutex klp_mutex;
 extern struct list_head klp_patches;
 
-#define klp_for_each_patch_safe(patch, tmp_patch)		\
-	list_for_each_entry_safe(patch, tmp_patch, &klp_patches, list)
+#define klp_for_each_patch_safe(patch)		\
+	list_for_each_entry_mutable(patch, &klp_patches, list)
 
 #define klp_for_each_patch(patch)	\
 	list_for_each_entry(patch, &klp_patches, list)
diff --git a/kernel/liveupdate/kho_block.c b/kernel/liveupdate/kho_block.c
index 0d2a342ef422..40e42a47751c 100644
--- a/kernel/liveupdate/kho_block.c
+++ b/kernel/liveupdate/kho_block.c
@@ -298,9 +298,9 @@ int kho_block_set_restore(struct kho_block_set *bs, u64 head_pa)
  */
 void kho_block_set_destroy(struct kho_block_set *bs)
 {
-	struct kho_block *block, *tmp;
+	struct kho_block *block;
 
-	list_for_each_entry_safe(block, tmp, &bs->blocks, list) {
+	list_for_each_entry_mutable(block, &bs->blocks, list) {
 		list_del(&block->list);
 		kho_block_free_ser(bs, block->ser);
 		kfree(block);
diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
index 5c27134ce7ba..cf5d577e25e4 100644
--- a/kernel/liveupdate/luo_flb.c
+++ b/kernel/liveupdate/luo_flb.c
@@ -359,13 +359,13 @@ static void luo_flb_unregister_one(struct liveupdate_file_handler *fh,
 void luo_flb_unregister_all(struct liveupdate_file_handler *fh)
 {
 	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
-	struct luo_flb_link *iter, *tmp;
+	struct luo_flb_link *iter;
 
 	if (!liveupdate_enabled())
 		return;
 
 	lockdep_assert_held_write(&luo_register_rwlock);
-	list_for_each_entry_safe(iter, tmp, flb_list, list)
+	list_for_each_entry_mutable(iter, flb_list, list)
 		luo_flb_unregister_one(fh, iter->flb);
 }
 
diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c
index b9c180ac1eee..8db6caf31e41 100644
--- a/kernel/locking/rwsem.c
+++ b/kernel/locking/rwsem.c
@@ -567,7 +567,7 @@ static void rwsem_mark_wake(struct rw_semaphore *sem,
 		atomic_long_add(adjustment, &sem->count);
 
 	/* 2nd pass */
-	list_for_each_entry_safe(waiter, next, &wlist, list) {
+	list_for_each_entry_mutable(waiter, &wlist, list) {
 		struct task_struct *tsk;
 
 		tsk = waiter->task;
diff --git a/kernel/locking/test-ww_mutex.c b/kernel/locking/test-ww_mutex.c
index 838d631544ed..f290061a8b48 100644
--- a/kernel/locking/test-ww_mutex.c
+++ b/kernel/locking/test-ww_mutex.c
@@ -546,7 +546,7 @@ static void stress_reorder_work(struct work_struct *work)
 	} while (!time_after(jiffies, stress->timeout));
 
 out:
-	list_for_each_entry_safe(ll, ln, &locks, link)
+	list_for_each_entry_mutable(ll, &locks, link)
 		kfree(ll);
 	kfree(order);
 }
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 46dd8d25a605..471448804053 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -725,10 +725,10 @@ static int ref_module(struct module *a, struct module *b)
 /* Clear the unload stuff of the module. */
 static void module_unload_free(struct module *mod)
 {
-	struct module_use *use, *tmp;
+	struct module_use *use;
 
 	mutex_lock(&module_mutex);
-	list_for_each_entry_safe(use, tmp, &mod->target_list, target_list) {
+	list_for_each_entry_mutable(use, &mod->target_list, target_list) {
 		struct module *i = use->target;
 		pr_debug("%s unusing %s\n", mod->name, i->name);
 		module_put(i);
@@ -3041,14 +3041,14 @@ struct mod_initfree {
 
 static void do_free_init(struct work_struct *w)
 {
-	struct llist_node *pos, *n, *list;
+	struct llist_node *pos, *list;
 	struct mod_initfree *initfree;
 
 	list = llist_del_all(&init_free_list);
 
 	synchronize_rcu();
 
-	llist_for_each_safe(pos, n, list) {
+	llist_for_each_mutable(pos, list) {
 		initfree = container_of(pos, struct mod_initfree, node);
 		execmem_free(initfree->init_text);
 		execmem_free(initfree->init_data);
@@ -3701,11 +3701,10 @@ static int idempotent_complete(struct idempotent *u, int ret)
 	const void *cookie = u->cookie;
 	int hash = hash_ptr(cookie, IDEM_HASH_BITS);
 	struct hlist_head *head = idem_hash + hash;
-	struct hlist_node *next;
 	struct idempotent *pos;
 
 	spin_lock(&idem_lock);
-	hlist_for_each_entry_safe(pos, next, head, entry) {
+	hlist_for_each_entry_mutable(pos, head, entry) {
 		if (pos->cookie != cookie)
 			continue;
 		hlist_del_init(&pos->entry);
diff --git a/kernel/padata.c b/kernel/padata.c
index 0d3ea1b68b1f..270f7b0eca0a 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -134,13 +134,13 @@ static void padata_work_free(struct padata_work *pw)
 
 static void __init padata_works_free(struct list_head *works)
 {
-	struct padata_work *cur, *next;
+	struct padata_work *cur;
 
 	if (list_empty(works))
 		return;
 
 	spin_lock_bh(&padata_works_lock);
-	list_for_each_entry_safe(cur, next, works, pw_list) {
+	list_for_each_entry_mutable(cur, works, pw_list) {
 		list_del(&cur->pw_list);
 		padata_work_free(cur);
 	}
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index d933b5b2c05d..c4802f2a2e35 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -610,9 +610,9 @@ struct mem_extent {
  */
 static void free_mem_extents(struct list_head *list)
 {
-	struct mem_extent *ext, *aux;
+	struct mem_extent *ext;
 
-	list_for_each_entry_safe(ext, aux, list, hook) {
+	list_for_each_entry_mutable(ext, list, hook) {
 		list_del(&ext->hook);
 		kfree(ext);
 	}
@@ -633,7 +633,7 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
 
 	for_each_populated_zone(zone) {
 		unsigned long zone_start, zone_end;
-		struct mem_extent *ext, *cur, *aux;
+		struct mem_extent *ext, *cur;
 
 		zone_start = zone->zone_start_pfn;
 		zone_end = zone_end_pfn(zone);
@@ -665,7 +665,7 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
 
 		/* More merging may be possible */
 		cur = ext;
-		list_for_each_entry_safe_continue(cur, aux, list, hook) {
+		list_for_each_entry_mutable_continue(cur, list, hook) {
 			if (zone_end < cur->start)
 				break;
 			if (zone_end < cur->end)
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index fd763da06a87..c8718aacfa5a 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -102,13 +102,13 @@ static inline void wakelocks_lru_most_recent(struct wakelock *wl)
 
 static void __wakelocks_gc(struct work_struct *work)
 {
-	struct wakelock *wl, *aux;
+	struct wakelock *wl;
 	ktime_t now;
 
 	mutex_lock(&wakelocks_lock);
 
 	now = ktime_get();
-	list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
+	list_for_each_entry_mutable_reverse(wl, &wakelocks_lru_list, lru) {
 		u64 idle_time_ns;
 		bool active;
 
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 2fe9a963c823..3f524c6bdf6e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3787,7 +3787,6 @@ static struct syscore printk_syscore = {
  */
 static void printk_kthreads_check_locked(void)
 {
-	struct hlist_node *tmp;
 	struct console *con;
 
 	lockdep_assert_console_list_lock_held();
@@ -3805,7 +3804,7 @@ static void printk_kthreads_check_locked(void)
 			 * are any nbcon consoles, they will set up their own
 			 * kthread.
 			 */
-			hlist_for_each_entry_safe(con, tmp, &console_list, node) {
+			hlist_for_each_entry_mutable(con, &console_list, node) {
 				if (con->flags & CON_NBCON)
 					continue;
 
@@ -3833,7 +3832,7 @@ static void printk_kthreads_check_locked(void)
 	if (printk_kthreads_running)
 		return;
 
-	hlist_for_each_entry_safe(con, tmp, &console_list, node) {
+	hlist_for_each_entry_mutable(con, &console_list, node) {
 		if (!(con->flags & CON_NBCON))
 			continue;
 
@@ -4209,9 +4208,8 @@ void register_console(struct console *newcon)
 	if (bootcon_registered &&
 	    ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) &&
 	    !keep_bootcon) {
-		struct hlist_node *tmp;
 
-		hlist_for_each_entry_safe(con, tmp, &console_list, node) {
+		hlist_for_each_entry_mutable(con, &console_list, node) {
 			if (con->flags & CON_BOOT)
 				unregister_console_locked(con);
 		}
@@ -4426,12 +4424,11 @@ void __init console_init(void)
  */
 static int __init printk_late_init(void)
 {
-	struct hlist_node *tmp;
 	struct console *con;
 	int ret;
 
 	console_list_lock();
-	hlist_for_each_entry_safe(con, tmp, &console_list, node) {
+	hlist_for_each_entry_mutable(con, &console_list, node) {
 		if (!(con->flags & CON_BOOT))
 			continue;
 
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index d041645d9d17..8032b653af83 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -619,9 +619,9 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
  */
 void exit_ptrace(struct task_struct *tracer, struct list_head *dead)
 {
-	struct task_struct *p, *n;
+	struct task_struct *p;
 
-	list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
+	list_for_each_entry_mutable(p, &tracer->ptraced, ptrace_entry) {
 		if (unlikely(p->ptrace & PT_EXITKILL))
 			send_sig_info(SIGKILL, SEND_SIG_PRIV, p);
 
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 882a158ada7b..9eb0007411a9 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -537,11 +537,10 @@ static void
 rcu_torture_pipe_update(struct rcu_torture *old_rp)
 {
 	struct rcu_torture *rp;
-	struct rcu_torture *rp1;
 
 	if (old_rp)
 		list_add(&old_rp->rtort_free, &rcu_torture_removed);
-	list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) {
+	list_for_each_entry_mutable(rp, &rcu_torture_removed, rtort_free) {
 		if (rcu_torture_pipe_update_one(rp)) {
 			list_del(&rp->rtort_free);
 			rcu_torture_free(rp);
diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
index f4da5fad70f5..e79380d93c85 100644
--- a/kernel/rcu/tasks.h
+++ b/kernel/rcu/tasks.h
@@ -1052,12 +1052,11 @@ static void rcu_tasks_postscan(struct list_head *hop)
 	for_each_possible_cpu(cpu) {
 		unsigned long j = jiffies + 1;
 		struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rcu_tasks.rtpcpu, cpu);
-		struct task_struct *t;
-		struct task_struct *t1;
+		struct task_struct *t, *t1;
 		struct list_head tmp;
 
 		raw_spin_lock_irq_rcu_node(rtpcp);
-		list_for_each_entry_safe(t, t1, &rtpcp->rtp_exit_list, rcu_tasks_exit_list) {
+		list_for_each_entry_mutable(t, t1, &rtpcp->rtp_exit_list, rcu_tasks_exit_list) {
 			if (list_empty(&t->rcu_tasks_holdout_list))
 				rcu_tasks_pertask(t, hop);
 
@@ -1120,9 +1119,9 @@ static void check_holdout_task(struct task_struct *t,
 static void check_all_holdout_tasks(struct list_head *hop,
 				    bool needreport, bool *firstreport)
 {
-	struct task_struct *t, *t1;
+	struct task_struct *t;
 
-	list_for_each_entry_safe(t, t1, hop, rcu_tasks_holdout_list) {
+	list_for_each_entry_mutable(t, hop, rcu_tasks_holdout_list) {
 		check_holdout_task(t, needreport, firstreport);
 		cond_resched();
 	}
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 03a43d3d2616..7c7792d62ac5 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -1664,7 +1664,7 @@ static void rcu_sr_normal_complete(struct llist_node *node)
 
 static void rcu_sr_normal_gp_cleanup_work(struct work_struct *work)
 {
-	struct llist_node *done, *rcu, *next, *head;
+	struct llist_node *done, *rcu, *head;
 
 	/*
 	 * This work execution can potentially execute
@@ -1694,7 +1694,7 @@ static void rcu_sr_normal_gp_cleanup_work(struct work_struct *work)
 	 * nodes is removed, in next round of cleanup
 	 * work execution.
 	 */
-	llist_for_each_safe(rcu, next, head) {
+	llist_for_each_mutable(rcu, head) {
 		if (!rcu_sr_is_wait_head(rcu)) {
 			rcu_sr_normal_complete(rcu);
 			continue;
@@ -1726,7 +1726,7 @@ static void rcu_sr_normal_gp_cleanup(void)
 	/*
 	 * Process (a) and (d) cases. See an illustration.
 	 */
-	llist_for_each_safe(rcu, next, wait_tail->next) {
+	llist_for_each_mutable(rcu, next, wait_tail->next) {
 		if (rcu_sr_is_wait_head(rcu))
 			break;
 
diff --git a/kernel/resource.c b/kernel/resource.c
index e60539a55541..19b89b09e291 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -1951,9 +1951,9 @@ EXPORT_SYMBOL(resource_list_create_entry);
 
 void resource_list_free(struct list_head *head)
 {
-	struct resource_entry *entry, *tmp;
+	struct resource_entry *entry;
 
-	list_for_each_entry_safe(entry, tmp, head, node)
+	list_for_each_entry_mutable(entry, head, node)
 		resource_list_destroy_entry(entry);
 }
 EXPORT_SYMBOL(resource_list_free);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index e97e98c33be5..873e26f2a032 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3892,7 +3892,7 @@ void sched_ttwu_pending(void *arg)
 {
 	struct llist_node *llist = arg;
 	struct rq *rq = this_rq();
-	struct task_struct *p, *t;
+	struct task_struct *p;
 	struct rq_flags rf;
 
 	if (!llist)
@@ -3901,7 +3901,7 @@ void sched_ttwu_pending(void *arg)
 	rq_lock_irqsave(rq, &rf);
 	update_rq_clock(rq);
 
-	llist_for_each_entry_safe(p, t, llist, wake_entry.llist) {
+	llist_for_each_entry_mutable(p, llist, wake_entry.llist) {
 		if (WARN_ON_ONCE(p->on_cpu))
 			smp_cond_load_acquire(&p->on_cpu, !VAL);
 
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 0db6fa2daea3..2119f2629fd1 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -4121,7 +4121,7 @@ static void process_ddsp_deferred_locals(struct rq *rq)
 	 * Now that @rq can be unlocked, execute the deferred enqueueing of
 	 * tasks directly dispatched to the local DSQs of other CPUs. See
 	 * direct_dispatch(). Keep popping from the head instead of using
-	 * list_for_each_entry_safe() as dispatch_local_dsq() may unlock @rq
+	 * list_for_each_entry_mutable() as dispatch_local_dsq() may unlock @rq
 	 * temporarily.
 	 */
 	while ((p = list_first_entry_or_null(&rq->scx.ddsp_deferred_locals,
@@ -4186,7 +4186,7 @@ static u32 reenq_local(struct scx_sched *sch, struct rq *rq, u64 reenq_flags)
 {
 	LIST_HEAD(tasks);
 	u32 nr_enqueued = 0;
-	struct task_struct *p, *n;
+	struct task_struct *p;
 
 	lockdep_assert_rq_held(rq);
 
@@ -4200,8 +4200,8 @@ static u32 reenq_local(struct scx_sched *sch, struct rq *rq, u64 reenq_flags)
 	 * @rq->scx.local_dsq. Move all candidate tasks off to a private list
 	 * first to avoid processing the same tasks repeatedly.
 	 */
-	list_for_each_entry_safe(p, n, &rq->scx.local_dsq.list,
-				 scx.dsq_list.node) {
+	list_for_each_entry_mutable(p, &rq->scx.local_dsq.list,
+				    scx.dsq_list.node) {
 		struct scx_sched *task_sch = scx_task_sched(p);
 		u32 reason;
 
@@ -4234,7 +4234,7 @@ static u32 reenq_local(struct scx_sched *sch, struct rq *rq, u64 reenq_flags)
 		list_add_tail(&p->scx.dsq_list.node, &tasks);
 	}
 
-	list_for_each_entry_safe(p, n, &tasks, scx.dsq_list.node) {
+	list_for_each_entry_mutable(p, &tasks, scx.dsq_list.node) {
 		list_del_init(&p->scx.dsq_list.node);
 
 		do_enqueue_task(rq, p, SCX_ENQ_REENQ, -1);
@@ -4786,9 +4786,9 @@ static void free_dsq_rcufn(struct rcu_head *rcu)
 static void free_dsq_irq_workfn(struct irq_work *irq_work)
 {
 	struct llist_node *to_free = llist_del_all(&dsqs_to_free);
-	struct scx_dispatch_q *dsq, *tmp_dsq;
+	struct scx_dispatch_q *dsq;
 
-	llist_for_each_entry_safe(dsq, tmp_dsq, to_free, free_node)
+	llist_for_each_entry_mutable(dsq, to_free, free_node)
 		call_rcu(&dsq->rcu, free_dsq_rcufn);
 }
 
@@ -5684,7 +5684,7 @@ static void scx_bypass(struct scx_sched *sch, bool bypass)
 	 */
 	for_each_possible_cpu(cpu) {
 		struct rq *rq = cpu_rq(cpu);
-		struct task_struct *p, *n;
+		struct task_struct *p;
 
 		raw_spin_rq_lock(rq);
 		raw_spin_lock(&scx_sched_lock);
@@ -5711,14 +5711,14 @@ static void scx_bypass(struct scx_sched *sch, bool bypass)
 		}
 
 		/*
-		 * The use of list_for_each_entry_safe_reverse() is required
+		 * The use of list_for_each_entry_mutable_reverse() is required
 		 * because each task is going to be removed from and added back
 		 * to the runnable_list during iteration. Because they're added
 		 * to the tail of the list, safe reverse iteration can still
 		 * visit all nodes.
 		 */
-		list_for_each_entry_safe_reverse(p, n, &rq->scx.runnable_list,
-						 scx.runnable_node) {
+		list_for_each_entry_mutable_reverse(p, &rq->scx.runnable_list,
+						    scx.runnable_node) {
 			if (!scx_is_descendant(scx_task_sched(p), sch))
 				continue;
 
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d78467ec6ee1..0f21a168fd9a 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -408,9 +408,9 @@ static inline void assert_list_leaf_cfs_rq(struct rq *rq)
 }
 
 /* Iterate through all leaf cfs_rq's on a runqueue */
-#define for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos)			\
-	list_for_each_entry_safe(cfs_rq, pos, &rq->leaf_cfs_rq_list,	\
-				 leaf_cfs_rq_list)
+#define for_each_leaf_cfs_rq_safe(rq, cfs_rq)			\
+	list_for_each_entry_mutable(cfs_rq, &(rq)->leaf_cfs_rq_list,	\
+				    leaf_cfs_rq_list)
 
 /* Do the two (enqueued) entities belong to the same group ? */
 static inline struct cfs_rq *
@@ -494,8 +494,8 @@ static inline void assert_list_leaf_cfs_rq(struct rq *rq)
 {
 }
 
-#define for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos)	\
-		for (cfs_rq = &rq->cfs, pos = NULL; cfs_rq; cfs_rq = pos)
+#define for_each_leaf_cfs_rq_safe(rq, cfs_rq)	\
+		for (cfs_rq = &(rq)->cfs; cfs_rq; cfs_rq = NULL)
 
 static inline struct sched_entity *parent_entity(struct sched_entity *se)
 {
@@ -6724,7 +6724,7 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
 {
 	struct rq *rq = data;
 	struct cfs_rq *cfs_rq = tg_cfs_rq(tg, cpu_of(rq));
-	struct task_struct *p, *tmp;
+	struct task_struct *p;
 	LIST_HEAD(throttled_tasks);
 
 	/*
@@ -6765,7 +6765,7 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
 	list_splice_init(&cfs_rq->throttled_limbo_list, &throttled_tasks);
 
 	/* Re-enqueue the tasks that have been throttled at this level. */
-	list_for_each_entry_safe(p, tmp, &throttled_tasks, throttle_node) {
+	list_for_each_entry_mutable(p, &throttled_tasks, throttle_node) {
 		/*
 		 * Back to being throttled! Break out and put the remaining
 		 * tasks back onto the limbo_list to prevent running them
@@ -6966,7 +6966,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
 
 static void __cfsb_csd_unthrottle(void *arg)
 {
-	struct cfs_rq *cursor, *tmp;
+	struct cfs_rq *cursor;
 	struct rq *rq = arg;
 
 	guard(rq_lock)(rq);
@@ -6988,8 +6988,8 @@ static void __cfsb_csd_unthrottle(void *arg)
 	 */
 	guard(rcu)();
 
-	list_for_each_entry_safe(cursor, tmp, &rq->cfsb_csd_list,
-				 throttled_csd_list) {
+	list_for_each_entry_mutable(cursor, &rq->cfsb_csd_list,
+				    throttled_csd_list) {
 		list_del_init(&cursor->throttled_csd_list);
 
 		if (cfs_rq_throttled(cursor))
@@ -11118,14 +11118,14 @@ static bool __update_blocked_others(struct rq *rq, bool *done)
 
 static bool __update_blocked_fair(struct rq *rq, bool *done)
 {
-	struct cfs_rq *cfs_rq, *pos;
+	struct cfs_rq *cfs_rq;
 	bool decayed = false;
 
 	/*
 	 * Iterates the task_group tree in a bottom up fashion, see
 	 * list_add_leaf_cfs_rq() for details.
 	 */
-	for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos) {
+	for_each_leaf_cfs_rq_safe(rq, cfs_rq) {
 		struct sched_entity *se;
 
 		if (update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq)) {
@@ -15401,10 +15401,10 @@ DEFINE_SCHED_CLASS(fair) = {
 
 void print_cfs_stats(struct seq_file *m, int cpu)
 {
-	struct cfs_rq *cfs_rq, *pos;
+	struct cfs_rq *cfs_rq;
 
 	rcu_read_lock();
-	for_each_leaf_cfs_rq_safe(cpu_rq(cpu), cfs_rq, pos)
+	for_each_leaf_cfs_rq_safe(cpu_rq(cpu), cfs_rq)
 		print_cfs_rq(m, cpu, cfs_rq);
 	rcu_read_unlock();
 }
diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c
index 622e2e01974c..062887738bff 100644
--- a/kernel/sched/topology.c
+++ b/kernel/sched/topology.c
@@ -1753,7 +1753,7 @@ static inline void asym_cpu_capacity_update_data(int cpu)
  */
 static void asym_cpu_capacity_scan(void)
 {
-	struct asym_cap_data *entry, *next;
+	struct asym_cap_data *entry;
 	int cpu;
 
 	list_for_each_entry(entry, &asym_cap_list, link)
@@ -1762,7 +1762,7 @@ static void asym_cpu_capacity_scan(void)
 	for_each_cpu_and(cpu, cpu_possible_mask, housekeeping_cpumask(HK_TYPE_DOMAIN))
 		asym_cpu_capacity_update_data(cpu);
 
-	list_for_each_entry_safe(entry, next, &asym_cap_list, link) {
+	list_for_each_entry_mutable(entry, &asym_cap_list, link) {
 		if (cpumask_empty(cpu_capacity_span(entry))) {
 			list_del_rcu(&entry->link);
 			call_rcu(&entry->rcu, free_asym_cap_entry);
diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c
index 20f27e2cf7ae..3411f9ac2073 100644
--- a/kernel/sched/wait.c
+++ b/kernel/sched/wait.c
@@ -92,7 +92,7 @@ EXPORT_SYMBOL(remove_wait_queue);
 static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode,
 			int nr_exclusive, int wake_flags, void *key)
 {
-	wait_queue_entry_t *curr, *next;
+	wait_queue_entry_t *curr;
 
 	lockdep_assert_held(&wq_head->lock);
 
@@ -101,7 +101,7 @@ static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode,
 	if (&curr->entry == &wq_head->head)
 		return nr_exclusive;
 
-	list_for_each_entry_safe_from(curr, next, &wq_head->head, entry) {
+	list_for_each_entry_mutable_from(curr, &wq_head->head, entry) {
 		unsigned flags = curr->flags;
 		int ret;
 
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 066909393c38..7212e47703f9 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -1168,7 +1168,7 @@ static int seccomp_do_user_notification(int this_syscall,
 	u32 flags = 0;
 	long ret = 0;
 	struct seccomp_knotif n = {};
-	struct seccomp_kaddfd *addfd, *tmp;
+	struct seccomp_kaddfd *addfd;
 
 	mutex_lock(&match->notify_lock);
 	err = -ENOSYS;
@@ -1225,7 +1225,7 @@ static int seccomp_do_user_notification(int this_syscall,
 
 interrupted:
 	/* If there were any pending addfd calls, clear them out */
-	list_for_each_entry_safe(addfd, tmp, &n.addfd, list) {
+	list_for_each_entry_mutable(addfd, &n.addfd, list) {
 		/* The process went away before we got a chance to handle it */
 		addfd->ret = -ESRCH;
 		list_del_init(&addfd->list);
diff --git a/kernel/signal.c b/kernel/signal.c
index 9c2b32c4d755..072231bebf52 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -748,7 +748,7 @@ static void sigqueue_free_ignored(struct task_struct *tsk, struct sigqueue *q)
 /* Remove signals in mask from the pending set and queue. */
 static void flush_sigqueue_mask(struct task_struct *p, sigset_t *mask, struct sigpending *s)
 {
-	struct sigqueue *q, *n;
+	struct sigqueue *q;
 	sigset_t m;
 
 	lockdep_assert_held(&p->sighand->siglock);
@@ -758,7 +758,7 @@ static void flush_sigqueue_mask(struct task_struct *p, sigset_t *mask, struct si
 		return;
 
 	sigandnsets(&s->signal, &s->signal, mask);
-	list_for_each_entry_safe(q, n, &s->list, list) {
+	list_for_each_entry_mutable(q, &s->list, list) {
 		if (sigismember(mask, q->info.si_signo)) {
 			list_del_init(&q->list);
 			sigqueue_free_ignored(p, q);
@@ -1899,12 +1899,12 @@ EXPORT_SYMBOL(kill_pid);
 static void __flush_itimer_signals(struct sigpending *pending)
 {
 	sigset_t signal, retain;
-	struct sigqueue *q, *n;
+	struct sigqueue *q;
 
 	signal = pending->signal;
 	sigemptyset(&retain);
 
-	list_for_each_entry_safe(q, n, &pending->list, list) {
+	list_for_each_entry_mutable(q, &pending->list, list) {
 		int sig = q->info.si_signo;
 
 		if (likely(q->info.si_code != SI_TIMER)) {
@@ -2101,7 +2101,6 @@ static inline void posixtimer_sig_ignore(struct task_struct *tsk, struct sigqueu
 static void posixtimer_sig_unignore(struct task_struct *tsk, int sig)
 {
 	struct hlist_head *head = &tsk->signal->ignored_posix_timers;
-	struct hlist_node *tmp;
 	struct k_itimer *tmr;
 
 	if (likely(hlist_empty(head)))
@@ -2114,7 +2113,7 @@ static void posixtimer_sig_unignore(struct task_struct *tsk, int sig)
 	 * rearmed or not. This cannot be decided here w/o dropping sighand
 	 * lock and creating a loop retry horror show.
 	 */
-	hlist_for_each_entry_safe(tmr, tmp , head, ignored_list) {
+	hlist_for_each_entry_mutable(tmr, head, ignored_list) {
 		struct task_struct *target;
 
 		/*
diff --git a/kernel/smp.c b/kernel/smp.c
index a0bb56bd8dda..305187e50b58 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -544,7 +544,7 @@ static void __flush_smp_call_function_queue(bool warn_cpu_offline)
 	 * First; run all SYNC callbacks, people are waiting for us.
 	 */
 	prev = NULL;
-	llist_for_each_entry_safe(csd, csd_next, entry, node.llist) {
+	llist_for_each_entry_mutable(csd, csd_next, entry, node.llist) {
 		/* Do we wait until *after* callback? */
 		if (CSD_TYPE(csd) == CSD_TYPE_SYNC) {
 			smp_call_func_t func = csd->func;
@@ -572,7 +572,7 @@ static void __flush_smp_call_function_queue(bool warn_cpu_offline)
 	 * Second; run all !SYNC callbacks.
 	 */
 	prev = NULL;
-	llist_for_each_entry_safe(csd, csd_next, entry, node.llist) {
+	llist_for_each_entry_mutable(csd, csd_next, entry, node.llist) {
 		int type = CSD_TYPE(csd);
 
 		if (type != CSD_TYPE_TTWU) {
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 2cd0172d0516..08932d4776d1 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -111,7 +111,7 @@ static void send_cpu_listeners(struct sk_buff *skb,
 					struct listener_list *listeners)
 {
 	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
-	struct listener *s, *tmp;
+	struct listener *s;
 	struct sk_buff *skb_next, *skb_cur = skb;
 	void *reply = genlmsg_data(genlhdr);
 	int delcount = 0;
@@ -145,7 +145,7 @@ static void send_cpu_listeners(struct sk_buff *skb,
 
 	/* Delete invalidated entries */
 	down_write(&listeners->sem);
-	list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+	list_for_each_entry_mutable(s, &listeners->list, list) {
 		if (!s->valid) {
 			list_del(&s->list);
 			kfree(s);
@@ -299,7 +299,7 @@ static void fill_tgid_exit(struct task_struct *tsk)
 static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
 {
 	struct listener_list *listeners;
-	struct listener *s, *tmp, *s2;
+	struct listener *s, *s2;
 	unsigned int cpu;
 	int ret = 0;
 
@@ -343,7 +343,7 @@ static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
 	for_each_cpu(cpu, mask) {
 		listeners = &per_cpu(listener_array, cpu);
 		down_write(&listeners->sem);
-		list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+		list_for_each_entry_mutable(s, &listeners->list, list) {
 			if (s->pid == pid) {
 				list_del(&s->list);
 				kfree(s);
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 0014d163f989..a13eeab8d83f 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -678,7 +678,7 @@ void clockevents_resume(void)
  */
 void tick_offline_cpu(unsigned int cpu)
 {
-	struct clock_event_device *dev, *tmp;
+	struct clock_event_device *dev;
 
 	raw_spin_lock(&clockevents_lock);
 
@@ -689,13 +689,13 @@ void tick_offline_cpu(unsigned int cpu)
 	 * Unregister the clock event devices which were
 	 * released above.
 	 */
-	list_for_each_entry_safe(dev, tmp, &clockevents_released, list)
+	list_for_each_entry_mutable(dev, &clockevents_released, list)
 		list_del(&dev->list);
 
 	/*
 	 * Now check whether the CPU has left unused per cpu devices
 	 */
-	list_for_each_entry_safe(dev, tmp, &clockevent_devices, list) {
+	list_for_each_entry_mutable(dev, &clockevent_devices, list) {
 		if (cpumask_test_cpu(cpu, dev->cpumask) &&
 		    cpumask_weight(dev->cpumask) == 1 &&
 		    !tick_is_broadcast_device(dev)) {
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index e48c4d379a7c..ac857d7ce4bb 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -776,12 +776,12 @@ static void clocksource_dequeue_watchdog(struct clocksource *cs)
 
 static int __clocksource_watchdog_kthread(void)
 {
-	struct clocksource *cs, *tmp;
+	struct clocksource *cs;
 	unsigned long flags;
 	int select = 0;
 
 	spin_lock_irqsave(&watchdog_lock, flags);
-	list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) {
+	list_for_each_entry_mutable(cs, &watchdog_list, wd_list) {
 		if (cs->flags & CLOCK_SOURCE_UNSTABLE) {
 			list_del_init(&cs->wd_list);
 			clocksource_change_rating(cs, 0);
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index 5e633d8750d1..1f2c5533d598 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -1296,7 +1296,7 @@ static inline bool posix_cpu_timers_enable_work(struct task_struct *tsk,
 
 static void handle_posix_cpu_timers(struct task_struct *tsk)
 {
-	struct k_itimer *timer, *next;
+	struct k_itimer *timer;
 	unsigned long flags, start;
 	LIST_HEAD(firing);
 
@@ -1369,7 +1369,7 @@ static void handle_posix_cpu_timers(struct task_struct *tsk)
 	 * each timer's lock before clearing its firing flag, so no
 	 * timer call will interfere.
 	 */
-	list_for_each_entry_safe(timer, next, &firing, it.cpu.elist) {
+	list_for_each_entry_mutable(timer, &firing, it.cpu.elist) {
 		bool cpu_firing;
 
 		/*
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 436ba794cc0b..d89307c4adb0 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -1085,7 +1085,6 @@ SYSCALL_DEFINE1(timer_delete, timer_t, timer_id)
 void exit_itimers(struct task_struct *tsk)
 {
 	struct hlist_head timers;
-	struct hlist_node *next;
 	struct k_itimer *timer;
 
 	/* Clear restore mode for exec() */
@@ -1099,7 +1098,7 @@ void exit_itimers(struct task_struct *tsk)
 		hlist_move_list(&tsk->signal->posix_timers, &timers);
 
 	/* The timers are not longer accessible via tsk::signal */
-	hlist_for_each_entry_safe(timer, next, &timers, list) {
+	hlist_for_each_entry_mutable(timer, &timers, list) {
 		scoped_guard (spinlock_irq, &timer->it_lock)
 			posix_timer_delete(timer);
 		posix_timer_unhash_and_free(timer);
diff --git a/kernel/torture.c b/kernel/torture.c
index 77cb3589b19f..047dcde729dd 100644
--- a/kernel/torture.c
+++ b/kernel/torture.c
@@ -510,10 +510,9 @@ EXPORT_SYMBOL_GPL(torture_shuffle_task_register);
 static void torture_shuffle_task_unregister_all(void)
 {
 	struct shuffle_task *stp;
-	struct shuffle_task *p;
 
 	mutex_lock(&shuffle_task_mutex);
-	list_for_each_entry_safe(stp, p, &shuffle_task_list, st_l) {
+	list_for_each_entry_mutable(stp, &shuffle_task_list, st_l) {
 		list_del(&stp->st_l);
 		kfree(stp);
 	}
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 82f8feea6931..7f6d8b287adb 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2276,7 +2276,7 @@ subsys_initcall(send_signal_irq_work_init);
 static int bpf_event_notify(struct notifier_block *nb, unsigned long op,
 			    void *module)
 {
-	struct bpf_trace_module *btm, *tmp;
+	struct bpf_trace_module *btm;
 	struct module *mod = module;
 	int ret = 0;
 
@@ -2297,7 +2297,7 @@ static int bpf_event_notify(struct notifier_block *nb, unsigned long op,
 		}
 		break;
 	case MODULE_STATE_GOING:
-		list_for_each_entry_safe(btm, tmp, &bpf_trace_modules, list) {
+		list_for_each_entry_mutable(btm, &bpf_trace_modules, list) {
 			if (btm->module == module) {
 				list_del(&btm->list);
 				kfree(btm);
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index f93e34dd2328..422665c687ff 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1252,7 +1252,6 @@ void ftrace_hash_remove(struct ftrace_hash *hash)
 {
 	struct ftrace_func_entry *entry;
 	struct hlist_head *hhd;
-	struct hlist_node *tn;
 	int size;
 	int i;
 
@@ -1261,7 +1260,7 @@ void ftrace_hash_remove(struct ftrace_hash *hash)
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
 		hhd = &hash->buckets[i];
-		hlist_for_each_entry_safe(entry, tn, hhd, hlist)
+		hlist_for_each_entry_mutable(entry, hhd, hlist)
 			remove_hash_entry(hash, entry);
 	}
 	FTRACE_WARN_ON(hash->count);
@@ -1270,7 +1269,6 @@ void ftrace_hash_remove(struct ftrace_hash *hash)
 static void ftrace_hash_clear(struct ftrace_hash *hash)
 {
 	struct hlist_head *hhd;
-	struct hlist_node *tn;
 	struct ftrace_func_entry *entry;
 	int size = 1 << hash->size_bits;
 	int i;
@@ -1280,7 +1278,7 @@ static void ftrace_hash_clear(struct ftrace_hash *hash)
 
 	for (i = 0; i < size; i++) {
 		hhd = &hash->buckets[i];
-		hlist_for_each_entry_safe(entry, tn, hhd, hlist)
+		hlist_for_each_entry_mutable(entry, hhd, hlist)
 			free_hash_entry(hash, entry);
 	}
 	FTRACE_WARN_ON(hash->count);
@@ -1296,14 +1294,14 @@ static void free_ftrace_mod(struct ftrace_mod_load *ftrace_mod)
 
 static void clear_ftrace_mod_list(struct list_head *head)
 {
-	struct ftrace_mod_load *p, *n;
+	struct ftrace_mod_load *p;
 
 	/* stack tracer isn't supported yet */
 	if (!head)
 		return;
 
 	mutex_lock(&ftrace_lock);
-	list_for_each_entry_safe(p, n, head, list)
+	list_for_each_entry_mutable(p, head, list)
 		free_ftrace_mod(p);
 	mutex_unlock(&ftrace_lock);
 }
@@ -1451,7 +1449,6 @@ static struct ftrace_hash *__move_hash(struct ftrace_hash *src, int size)
 	struct ftrace_func_entry *entry;
 	struct ftrace_hash *new_hash;
 	struct hlist_head *hhd;
-	struct hlist_node *tn;
 	int bits = 0;
 	int i;
 
@@ -1474,7 +1471,7 @@ static struct ftrace_hash *__move_hash(struct ftrace_hash *src, int size)
 	size = 1 << src->size_bits;
 	for (i = 0; i < size; i++) {
 		hhd = &src->buckets[i];
-		hlist_for_each_entry_safe(entry, tn, hhd, hlist) {
+		hlist_for_each_entry_mutable(entry, hhd, hlist) {
 			remove_hash_entry(src, entry);
 			add_ftrace_hash_entry(new_hash, entry);
 		}
@@ -3327,7 +3324,6 @@ static int append_hash(struct ftrace_hash **hash, struct ftrace_hash *new_hash,
 static void remove_hash(struct ftrace_hash *hash, struct ftrace_hash *notrace_hash)
 {
 	struct ftrace_func_entry *entry;
-	struct hlist_node *tmp;
 	int size;
 	int i;
 
@@ -3337,7 +3333,7 @@ static void remove_hash(struct ftrace_hash *hash, struct ftrace_hash *notrace_ha
 
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
-		hlist_for_each_entry_safe(entry, tmp, &hash->buckets[i], hlist) {
+		hlist_for_each_entry_mutable(entry, &hash->buckets[i], hlist) {
 			if (!__ftrace_lookup_ip(notrace_hash, entry->ip))
 				continue;
 			remove_hash_entry(hash, entry);
@@ -5084,7 +5080,7 @@ static int ftrace_hash_move_and_update_ops(struct ftrace_ops *ops,
 static int cache_mod(struct trace_array *tr,
 		     const char *func, char *module, int enable)
 {
-	struct ftrace_mod_load *ftrace_mod, *n;
+	struct ftrace_mod_load *ftrace_mod;
 	struct list_head *head = enable ? &tr->mod_trace : &tr->mod_notrace;
 
 	guard(mutex)(&ftrace_lock);
@@ -5096,7 +5092,7 @@ static int cache_mod(struct trace_array *tr,
 		func++;
 
 		/* Look to remove this hash */
-		list_for_each_entry_safe(ftrace_mod, n, head, list) {
+		list_for_each_entry_mutable(ftrace_mod, head, list) {
 			if (strcmp(ftrace_mod->module, module) != 0)
 				continue;
 
@@ -5124,7 +5120,7 @@ static int cache_mod(struct trace_array *tr,
 static void process_mod_list(struct list_head *head, struct ftrace_ops *ops,
 			     char *mod, bool enable)
 {
-	struct ftrace_mod_load *ftrace_mod, *n;
+	struct ftrace_mod_load *ftrace_mod;
 	struct ftrace_hash **orig_hash, *new_hash;
 	LIST_HEAD(process_mods);
 	char *func;
@@ -5143,7 +5139,7 @@ static void process_mod_list(struct list_head *head, struct ftrace_ops *ops,
 
 	mutex_lock(&ftrace_lock);
 
-	list_for_each_entry_safe(ftrace_mod, n, head, list) {
+	list_for_each_entry_mutable(ftrace_mod, head, list) {
 
 		if (strcmp(ftrace_mod->module, mod) != 0)
 			continue;
@@ -5165,7 +5161,7 @@ static void process_mod_list(struct list_head *head, struct ftrace_ops *ops,
 
 	mutex_unlock(&ftrace_lock);
 
-	list_for_each_entry_safe(ftrace_mod, n, &process_mods, list) {
+	list_for_each_entry_mutable(ftrace_mod, &process_mods, list) {
 
 		func = ftrace_mod->func;
 
@@ -5616,7 +5612,6 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
 	struct ftrace_hash **orig_hash;
 	struct ftrace_hash *old_hash;
 	struct ftrace_hash *hash = NULL;
-	struct hlist_node *tmp;
 	struct hlist_head hhd;
 	char str[KSYM_SYMBOL_LEN];
 	int count = 0;
@@ -5677,7 +5672,7 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
 
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
-		hlist_for_each_entry_safe(entry, tmp, &hash->buckets[i], hlist) {
+		hlist_for_each_entry_mutable(entry, &hash->buckets[i], hlist) {
 
 			if (func_g.search) {
 				kallsyms_lookup(entry->ip, NULL, NULL,
@@ -5715,7 +5710,7 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
 				       &old_hash_ops);
 	synchronize_rcu();
 
-	hlist_for_each_entry_safe(entry, tmp, &hhd, hlist) {
+	hlist_for_each_entry_mutable(entry, &hhd, hlist) {
 		hlist_del(&entry->hlist);
 		if (probe_ops->free)
 			probe_ops->free(probe_ops, tr, entry->ip, probe->data);
@@ -5738,9 +5733,9 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
 
 void clear_ftrace_function_probes(struct trace_array *tr)
 {
-	struct ftrace_func_probe *probe, *n;
+	struct ftrace_func_probe *probe;
 
-	list_for_each_entry_safe(probe, n, &tr->func_probes, list)
+	list_for_each_entry_mutable(probe, &tr->func_probes, list)
 		unregister_ftrace_function_probe_func(NULL, tr, probe->probe_ops);
 }
 
@@ -5771,11 +5766,11 @@ __init int register_ftrace_command(struct ftrace_func_command *cmd)
  */
 __init int unregister_ftrace_command(struct ftrace_func_command *cmd)
 {
-	struct ftrace_func_command *p, *n;
+	struct ftrace_func_command *p;
 
 	guard(mutex)(&ftrace_cmd_mutex);
 
-	list_for_each_entry_safe(p, n, &ftrace_commands, list) {
+	list_for_each_entry_mutable(p, &ftrace_commands, list) {
 		if (strcmp(cmd->name, p->name) == 0) {
 			list_del_init(&p->list);
 			return 0;
@@ -7876,10 +7871,9 @@ static void ftrace_free_mod_map(struct rcu_head *rcu)
 {
 	struct ftrace_mod_map *mod_map = container_of(rcu, struct ftrace_mod_map, rcu);
 	struct ftrace_mod_func *mod_func;
-	struct ftrace_mod_func *n;
 
 	/* All the contents of mod_map are now not visible to readers */
-	list_for_each_entry_safe(mod_func, n, &mod_map->funcs, list) {
+	list_for_each_entry_mutable(mod_func, &mod_map->funcs, list) {
 		kfree(mod_func->name);
 		list_del(&mod_func->list);
 		kfree(mod_func);
@@ -7891,7 +7885,6 @@ static void ftrace_free_mod_map(struct rcu_head *rcu)
 void ftrace_release_mod(struct module *mod)
 {
 	struct ftrace_mod_map *mod_map;
-	struct ftrace_mod_map *n;
 	struct dyn_ftrace *rec;
 	struct ftrace_page **last_pg;
 	struct ftrace_page *tmp_page = NULL;
@@ -7903,7 +7896,7 @@ void ftrace_release_mod(struct module *mod)
 	 * To avoid the UAF problem after the module is unloaded, the
 	 * 'mod_map' resource needs to be released unconditionally.
 	 */
-	list_for_each_entry_safe(mod_map, n, &ftrace_mod_maps, list) {
+	list_for_each_entry_mutable(mod_map, &ftrace_mod_maps, list) {
 		if (mod_map->mod == mod) {
 			list_del_rcu(&mod_map->list);
 			call_rcu(&mod_map->rcu, ftrace_free_mod_map);
@@ -8290,7 +8283,7 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
 	struct dyn_ftrace *rec;
 	struct dyn_ftrace key;
 	struct ftrace_mod_map *mod_map = NULL;
-	struct ftrace_init_func *func, *func_next;
+	struct ftrace_init_func *func;
 	LIST_HEAD(clear_hash);
 
 	key.ip = start;
@@ -8341,7 +8334,7 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
 	}
 	mutex_unlock(&ftrace_lock);
 
-	list_for_each_entry_safe(func, func_next, &clear_hash, list) {
+	list_for_each_entry_mutable(func, &clear_hash, list) {
 		clear_func_from_hashes(func);
 		kfree(func);
 	}
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 56a328e94395..24b2deb1f7a6 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -2362,7 +2362,7 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
 {
 	struct trace_buffer *buffer = cpu_buffer->buffer;
 	struct ring_buffer_cpu_meta *meta = NULL;
-	struct buffer_page *bpage, *tmp;
+	struct buffer_page *bpage;
 	bool user_thread = current->mm != NULL;
 	struct ring_buffer_desc *desc = NULL;
 	long i;
@@ -2450,7 +2450,7 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
 	return 0;
 
 free_pages:
-	list_for_each_entry_safe(bpage, tmp, pages, list) {
+	list_for_each_entry_mutable(bpage, pages, list) {
 		list_del_init(&bpage->list);
 		free_buffer_page(bpage);
 	}
@@ -2609,7 +2609,7 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
 static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
 {
 	struct list_head *head = cpu_buffer->pages;
-	struct buffer_page *bpage, *tmp;
+	struct buffer_page *bpage;
 
 	irq_work_sync(&cpu_buffer->irq_work.work);
 
@@ -2621,7 +2621,7 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
 	if (head) {
 		rb_head_page_deactivate(cpu_buffer);
 
-		list_for_each_entry_safe(bpage, tmp, head, list) {
+		list_for_each_entry_mutable(bpage, head, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 		}
@@ -3163,9 +3163,9 @@ rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer)
 
 	/* free pages if they weren't inserted */
 	if (!success) {
-		struct buffer_page *bpage, *tmp;
-		list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages,
-					 list) {
+		struct buffer_page *bpage;
+
+		list_for_each_entry_mutable(bpage, &cpu_buffer->new_pages, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 		}
@@ -3395,7 +3395,7 @@ int ring_buffer_resize(struct trace_buffer *buffer, unsigned long size,
 
  out_err:
 	for_each_buffer_cpu(buffer, cpu) {
-		struct buffer_page *bpage, *tmp;
+		struct buffer_page *bpage;
 
 		cpu_buffer = buffer->buffers[cpu];
 		cpu_buffer->nr_pages_to_update = 0;
@@ -3403,8 +3403,7 @@ int ring_buffer_resize(struct trace_buffer *buffer, unsigned long size,
 		if (list_empty(&cpu_buffer->new_pages))
 			continue;
 
-		list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages,
-					list) {
+		list_for_each_entry_mutable(bpage, &cpu_buffer->new_pages, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 
@@ -7316,7 +7315,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_subbuf_order_get);
 int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
-	struct buffer_page *bpage, *tmp;
+	struct buffer_page *bpage;
 	int old_order, old_size;
 	int nr_pages;
 	int psize;
@@ -7436,7 +7435,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
 		raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 
 		/* Free old sub buffers */
-		list_for_each_entry_safe(bpage, tmp, &old_pages, list) {
+		list_for_each_entry_mutable(bpage, &old_pages, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 		}
@@ -7461,7 +7460,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
 		if (!cpu_buffer->nr_pages_to_update)
 			continue;
 
-		list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages, list) {
+		list_for_each_entry_mutable(bpage, &cpu_buffer->new_pages, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 		}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 1146b83b711a..f1049850e986 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1380,7 +1380,7 @@ static int do_run_tracer_selftest(struct tracer *type)
 
 static __init int init_trace_selftests(void)
 {
-	struct trace_selftests *p, *n;
+	struct trace_selftests *p;
 	struct tracer *t, **last;
 	int ret;
 
@@ -1394,7 +1394,7 @@ static __init int init_trace_selftests(void)
 	pr_info("Running postponed tracer tests:\n");
 
 	tracing_selftest_running = true;
-	list_for_each_entry_safe(p, n, &postponed_selftests, list) {
+	list_for_each_entry_mutable(p, &postponed_selftests, list) {
 		/* This loop can take minutes when sanitizers are enabled, so
 		 * lets make sure we allow RCU processing.
 		 */
@@ -1434,11 +1434,11 @@ static void __init apply_trace_boot_options(void);
 
 static void free_tracers(struct trace_array *tr)
 {
-	struct tracers *t, *n;
+	struct tracers *t;
 
 	lockdep_assert_held(&trace_types_lock);
 
-	list_for_each_entry_safe(t, n, &tr->tracers, list) {
+	list_for_each_entry_mutable(t, &tr->tracers, list) {
 		list_del(&t->list);
 		kfree(t->flags);
 		kfree(t);
@@ -6906,11 +6906,11 @@ void tracing_log_err(struct trace_array *tr,
 
 static void clear_tracing_err_log(struct trace_array *tr)
 {
-	struct tracing_log_err *err, *next;
+	struct tracing_log_err *err;
 
 	guard(mutex)(&tracing_err_log_lock);
 
-	list_for_each_entry_safe(err, next, &tr->err_log, list) {
+	list_for_each_entry_mutable(err, &tr->err_log, list) {
 		list_del(&err->list);
 		free_tracing_log_err(err);
 	}
diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
index c4dfbc293bae..9e076106bee7 100644
--- a/kernel/trace/trace_dynevent.c
+++ b/kernel/trace/trace_dynevent.c
@@ -100,7 +100,7 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type
 		return -EINVAL;
 
 	mutex_lock(&event_mutex);
-	for_each_dyn_event_safe(pos, n) {
+	for_each_dyn_event_safe(pos) {
 		if (type && type != pos->ops)
 			continue;
 		if (!pos->ops->match(system, event,
@@ -207,7 +207,7 @@ static const struct seq_operations dyn_event_seq_op = {
  */
 int dyn_events_release_all(struct dyn_event_operations *type)
 {
-	struct dyn_event *ev, *tmp;
+	struct dyn_event *ev;
 	int ret = 0;
 
 	mutex_lock(&event_mutex);
@@ -219,7 +219,7 @@ int dyn_events_release_all(struct dyn_event_operations *type)
 			goto out;
 		}
 	}
-	for_each_dyn_event_safe(ev, tmp) {
+	for_each_dyn_event_safe(ev) {
 		if (type && ev->ops != type)
 			continue;
 		ret = ev->ops->free(ev);
diff --git a/kernel/trace/trace_dynevent.h b/kernel/trace/trace_dynevent.h
index beee3f8d7544..a4dc0812284f 100644
--- a/kernel/trace/trace_dynevent.h
+++ b/kernel/trace/trace_dynevent.h
@@ -115,10 +115,9 @@ int dyn_event_create(const char *raw_command, struct dyn_event_operations *type)
 /*
  * for_each_dyn_event	-	iterate over the dyn_event list safely
  * @pos:	the struct dyn_event * to use as a loop cursor
- * @n:		the struct dyn_event * to use as temporary storage
  */
-#define for_each_dyn_event_safe(pos, n)	\
-	list_for_each_entry_safe(pos, n, &dyn_event_list, list)
+#define for_each_dyn_event_safe(pos)	\
+	list_for_each_entry_mutable(pos, &dyn_event_list, list)
 
 extern void dynevent_cmd_init(struct dynevent_cmd *cmd, char *buf, int maxlen,
 			      enum dynevent_type type,
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index c46e623e7e0d..a34fb3e688d5 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -75,8 +75,7 @@ static int system_refcount_dec(struct event_subsystem *system)
 
 #define do_for_each_event_file_safe(tr, file)			\
 	list_for_each_entry(tr, &ftrace_trace_arrays, list) {	\
-		struct trace_event_file *___n;				\
-		list_for_each_entry_safe(file, ___n, &tr->events, list)
+		list_for_each_entry_mutable(file, &tr->events, list)
 
 #define while_for_each_event_file()		\
 	}
@@ -219,11 +218,11 @@ static int trace_define_common_fields(void)
 
 static void trace_destroy_fields(struct trace_event_call *call)
 {
-	struct ftrace_event_field *field, *next;
+	struct ftrace_event_field *field;
 	struct list_head *head;
 
 	head = trace_get_fields(call);
-	list_for_each_entry_safe(field, next, head, link) {
+	list_for_each_entry_mutable(field, head, link) {
 		list_del(&field->link);
 		kmem_cache_free(field_cachep, field);
 	}
@@ -928,9 +927,9 @@ static void free_event_mod(struct event_mod_load *event_mod)
 
 static void clear_mod_events(struct trace_array *tr)
 {
-	struct event_mod_load *event_mod, *n;
+	struct event_mod_load *event_mod;
 
-	list_for_each_entry_safe(event_mod, n, &tr->mod_events, list) {
+	list_for_each_entry_mutable(event_mod, &tr->mod_events, list) {
 		free_event_mod(event_mod);
 	}
 }
@@ -938,10 +937,10 @@ static void clear_mod_events(struct trace_array *tr)
 static int remove_cache_mod(struct trace_array *tr, const char *mod,
 			    const char *match, const char *system, const char *event)
 {
-	struct event_mod_load *event_mod, *n;
+	struct event_mod_load *event_mod;
 	int ret = -EINVAL;
 
-	list_for_each_entry_safe(event_mod, n, &tr->mod_events, list) {
+	list_for_each_entry_mutable(event_mod, &tr->mod_events, list) {
 		if (strcmp(event_mod->module, mod) != 0)
 			continue;
 
@@ -3557,7 +3556,7 @@ static void update_event_fields(struct trace_event_call *call,
 /* Update all events for replacing eval and sanitizing */
 void trace_event_update_all(struct trace_eval_map **map, int len)
 {
-	struct trace_event_call *call, *p;
+	struct trace_event_call *call;
 	const char *last_system = NULL;
 	bool first = false;
 	bool updated;
@@ -3565,7 +3564,7 @@ void trace_event_update_all(struct trace_eval_map **map, int len)
 	int i;
 
 	down_write(&trace_event_sem);
-	list_for_each_entry_safe(call, p, &ftrace_events, list) {
+	list_for_each_entry_mutable(call, &ftrace_events, list) {
 		/* events are usually grouped together with systems */
 		if (!last_system || call->class->system != last_system) {
 			first = true;
@@ -3892,9 +3891,9 @@ EXPORT_SYMBOL_GPL(trace_remove_event_call);
 #ifdef CONFIG_MODULES
 static void update_mod_cache(struct trace_array *tr, struct module *mod)
 {
-	struct event_mod_load *event_mod, *n;
+	struct event_mod_load *event_mod;
 
-	list_for_each_entry_safe(event_mod, n, &tr->mod_events, list) {
+	list_for_each_entry_mutable(event_mod, &tr->mod_events, list) {
 		if (strcmp(event_mod->module, mod->name) != 0)
 			continue;
 
@@ -3940,18 +3939,18 @@ static void trace_module_add_events(struct module *mod)
 
 static void trace_module_remove_events(struct module *mod)
 {
-	struct trace_event_call *call, *p;
-	struct module_string *modstr, *m;
+	struct trace_event_call *call;
+	struct module_string *modstr;
 
 	down_write(&trace_event_sem);
-	list_for_each_entry_safe(call, p, &ftrace_events, list) {
+	list_for_each_entry_mutable(call, &ftrace_events, list) {
 		if ((call->flags & TRACE_EVENT_FL_DYNAMIC) || !call->module)
 			continue;
 		if (call->module == mod)
 			__trace_remove_event_call(call);
 	}
 	/* Check for any strings allocated for this module */
-	list_for_each_entry_safe(modstr, m, &module_strings, next) {
+	list_for_each_entry_mutable(modstr, &module_strings, next) {
 		if (modstr->module != mod)
 			continue;
 		list_del(&modstr->next);
@@ -4483,9 +4482,9 @@ void __trace_early_add_events(struct trace_array *tr)
 static void
 __trace_remove_event_dirs(struct trace_array *tr)
 {
-	struct trace_event_file *file, *next;
+	struct trace_event_file *file;
 
-	list_for_each_entry_safe(file, next, &tr->events, list)
+	list_for_each_entry_mutable(file, &tr->events, list)
 		remove_event_file_dir(file);
 }
 
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 609325f57942..d82128084a87 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -1352,9 +1352,9 @@ struct filter_head {
 
 static void free_filter_list(struct filter_head *filter_list)
 {
-	struct filter_list *filter_item, *tmp;
+	struct filter_list *filter_item;
 
-	list_for_each_entry_safe(filter_item, tmp, &filter_list->list, list) {
+	list_for_each_entry_mutable(filter_item, &filter_list->list, list) {
 		__free_filter(filter_item->filter);
 		list_del(&filter_item->list);
 		kfree(filter_item);
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 82ce492ab268..ff6016acab20 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -6765,7 +6765,7 @@ static bool hist_file_check_refs(struct trace_event_file *file)
 
 static void hist_unreg_all(struct trace_event_file *file)
 {
-	struct event_trigger_data *test, *n;
+	struct event_trigger_data *test;
 	struct hist_trigger_data *hist_data;
 	struct synth_event *se;
 	const char *se_name;
@@ -6775,7 +6775,7 @@ static void hist_unreg_all(struct trace_event_file *file)
 	if (hist_file_check_refs(file))
 		return;
 
-	list_for_each_entry_safe(test, n, &file->triggers, list) {
+	list_for_each_entry_mutable(test, &file->triggers, list) {
 		if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
 			hist_data = test->private_data;
 			list_del_rcu(&test->list);
@@ -7002,9 +7002,9 @@ hist_enable_trigger(struct event_trigger_data *data,
 
 static void hist_enable_unreg_all(struct trace_event_file *file)
 {
-	struct event_trigger_data *test, *n;
+	struct event_trigger_data *test;
 
-	list_for_each_entry_safe(test, n, &file->triggers, list) {
+	list_for_each_entry_mutable(test, &file->triggers, list) {
 		if (test->cmd_ops->trigger_type == ETT_HIST_ENABLE) {
 			list_del_rcu(&test->list);
 			update_cond_flag(file);
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c
index 655db2e82513..8654cd83f64d 100644
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
@@ -40,7 +40,7 @@ static void trigger_create_kthread_locked(void)
 
 static void trigger_data_free_queued_locked(void)
 {
-	struct event_trigger_data *data, *tmp;
+	struct event_trigger_data *data;
 	struct llist_node *llnodes;
 
 	lockdep_assert_held(&trigger_data_kthread_mutex);
@@ -51,14 +51,14 @@ static void trigger_data_free_queued_locked(void)
 
 	tracepoint_synchronize_unregister();
 
-	llist_for_each_entry_safe(data, tmp, llnodes, llist)
+	llist_for_each_entry_mutable(data, llnodes, llist)
 		kfree(data);
 }
 
 /* Bulk garbage collection of event_trigger_data elements */
 static int trigger_kthread_fn(void *ignore)
 {
-	struct event_trigger_data *data, *tmp;
+	struct event_trigger_data *data;
 	struct llist_node *llnodes;
 
 	/* Once this task starts, it lives forever */
@@ -74,7 +74,7 @@ static int trigger_kthread_fn(void *ignore)
 		/* make sure current triggers exit before free */
 		tracepoint_synchronize_unregister();
 
-		llist_for_each_entry_safe(data, tmp, llnodes, llist)
+		llist_for_each_entry_mutable(data, llnodes, llist)
 			kfree(data);
 	}
 
@@ -477,11 +477,11 @@ __init int register_event_command(struct event_command *cmd)
  */
 __init int unregister_event_command(struct event_command *cmd)
 {
-	struct event_command *p, *n;
+	struct event_command *p;
 
 	guard(mutex)(&trigger_cmd_mutex);
 
-	list_for_each_entry_safe(p, n, &trigger_commands, list) {
+	list_for_each_entry_mutable(p, &trigger_commands, list) {
 		if (strcmp(cmd->name, p->name) == 0) {
 			list_del_init(&p->list);
 			return 0;
@@ -632,8 +632,9 @@ clear_event_triggers(struct trace_array *tr)
 	struct trace_event_file *file;
 
 	list_for_each_entry(file, &tr->events, list) {
-		struct event_trigger_data *data, *n;
-		list_for_each_entry_safe(data, n, &file->triggers, list) {
+		struct event_trigger_data *data;
+
+		list_for_each_entry_mutable(data, &file->triggers, list) {
 			trace_event_trigger_enable_disable(file, 0);
 			list_del_rcu(&data->list);
 			if (data->cmd_ops->free)
diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index c4ba484f7b38..090d645eebf0 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -761,9 +761,9 @@ static struct user_event_mm *current_user_event_mm(void)
 
 static void user_event_mm_destroy(struct user_event_mm *mm)
 {
-	struct user_event_enabler *enabler, *next;
+	struct user_event_enabler *enabler;
 
-	list_for_each_entry_safe(enabler, next, &mm->enablers, mm_enablers_link)
+	list_for_each_entry_mutable(enabler, &mm->enablers, mm_enablers_link)
 		user_event_enabler_destroy(enabler, false);
 
 	mmdrop(mm->mm);
@@ -1085,10 +1085,10 @@ static int user_field_size(const char *type)
 
 static void user_event_destroy_validators(struct user_event *user)
 {
-	struct user_event_validator *validator, *next;
+	struct user_event_validator *validator;
 	struct list_head *head = &user->validators;
 
-	list_for_each_entry_safe(validator, next, head, user_event_link) {
+	list_for_each_entry_mutable(validator, head, user_event_link) {
 		list_del(&validator->user_event_link);
 		kfree(validator);
 	}
@@ -1096,10 +1096,10 @@ static void user_event_destroy_validators(struct user_event *user)
 
 static void user_event_destroy_fields(struct user_event *user)
 {
-	struct ftrace_event_field *field, *next;
+	struct ftrace_event_field *field;
 	struct list_head *head = &user->fields;
 
-	list_for_each_entry_safe(field, next, head, link) {
+	list_for_each_entry_mutable(field, head, link) {
 		list_del(&field->link);
 		kfree(field);
 	}
@@ -2611,7 +2611,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
 {
 	struct user_unreg __user *ureg = (struct user_unreg __user *)uarg;
 	struct user_event_mm *mm = current->user_event_mm;
-	struct user_event_enabler *enabler, *next;
+	struct user_event_enabler *enabler;
 	struct user_unreg reg;
 	unsigned long flags;
 	long ret;
@@ -2636,7 +2636,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
 	 */
 	mutex_lock(&event_mutex);
 
-	list_for_each_entry_safe(enabler, next, &mm->enablers, mm_enablers_link) {
+	list_for_each_entry_mutable(enabler, &mm->enablers, mm_enablers_link) {
 		if (enabler->addr == reg.disable_addr &&
 		    ENABLE_BIT(enabler) == reg.disable_bit) {
 			set_bit(ENABLE_VAL_FREEING_BIT, ENABLE_BITOPS(enabler));
diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c
index 856ece13b7dc..3240b1ff7418 100644
--- a/kernel/trace/trace_stat.c
+++ b/kernel/trace/trace_stat.c
@@ -344,10 +344,10 @@ int register_stat_tracer(struct tracer_stat *trace)
 
 void unregister_stat_tracer(struct tracer_stat *trace)
 {
-	struct stat_session *node, *tmp;
+	struct stat_session *node;
 
 	mutex_lock(&all_stat_sessions_mutex);
-	list_for_each_entry_safe(node, tmp, &all_stat_sessions, session_list) {
+	list_for_each_entry_mutable(node, &all_stat_sessions, session_list) {
 		if (node->ts == trace) {
 			list_del(&node->session_list);
 			destroy_session(node);
diff --git a/kernel/user-return-notifier.c b/kernel/user-return-notifier.c
index 870ecd7c63ed..9f1dcd72b756 100644
--- a/kernel/user-return-notifier.c
+++ b/kernel/user-return-notifier.c
@@ -35,11 +35,10 @@ EXPORT_SYMBOL_GPL(user_return_notifier_unregister);
 void fire_user_return_notifiers(void)
 {
 	struct user_return_notifier *urn;
-	struct hlist_node *tmp2;
 	struct hlist_head *head;
 
 	head = &get_cpu_var(return_notifier_list);
-	hlist_for_each_entry_safe(urn, tmp2, head, link)
+	hlist_for_each_entry_mutable(urn, head, link)
 		urn->on_user_return(urn);
 	put_cpu_var(return_notifier_list);
 }
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 78f25afb4a9d..8fbdf1664c38 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1167,7 +1167,7 @@ static void move_linked_works(struct work_struct *work, struct list_head *head,
 	 * Linked worklist will always end before the end of the list,
 	 * use NULL for list head.
 	 */
-	list_for_each_entry_safe_from(work, n, NULL, entry) {
+	list_for_each_entry_mutable_from(work, n, NULL, entry) {
 		list_move_tail(&work->entry, head);
 		if (!(*work_data_bits(work) & WORK_STRUCT_LINKED))
 			break;
@@ -1193,7 +1193,7 @@ static void move_linked_works(struct work_struct *work, struct list_head *head,
  *
  * If @nextp is not NULL, it's updated to point to the next work of the last
  * scheduled work. This allows assign_work() to be nested inside
- * list_for_each_entry_safe().
+ * list_for_each_entry_mutable().
  *
  * Returns %true if @work was successfully assigned to @worker. %false if @work
  * was punted to another worker already executing it.
@@ -2912,9 +2912,9 @@ static void detach_dying_workers(struct list_head *cull_list)
 
 static void reap_dying_workers(struct list_head *cull_list)
 {
-	struct worker *worker, *tmp;
+	struct worker *worker;
 
-	list_for_each_entry_safe(worker, tmp, cull_list, entry) {
+	list_for_each_entry_mutable(worker, cull_list, entry) {
 		list_del_init(&worker->entry);
 		kthread_stop_put(worker->task);
 		kfree(worker);
@@ -3550,7 +3550,7 @@ static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescu
 		work = list_next_entry(cursor, entry);
 
 	/* find the next work item to rescue */
-	list_for_each_entry_safe_from(work, n, &pool->worklist, entry) {
+	list_for_each_entry_mutable_from(work, n, &pool->worklist, entry) {
 		if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) {
 			pwq->stats[PWQ_STAT_RESCUED]++;
 			/* put the cursor for next search */
@@ -4157,7 +4157,7 @@ void __flush_workqueue(struct workqueue_struct *wq)
 		struct wq_flusher *next, *tmp;
 
 		/* complete all the flushers sharing the current flush color */
-		list_for_each_entry_safe(next, tmp, &wq->flusher_queue, list) {
+		list_for_each_entry_mutable(next, &wq->flusher_queue, list) {
 			if (next->flush_color != wq->flush_color)
 				break;
 			list_del_init(&next->list);
@@ -7080,7 +7080,7 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
 	LIST_HEAD(ctxs);
 	int ret = 0;
 	struct workqueue_struct *wq;
-	struct apply_wqattrs_ctx *ctx, *n;
+	struct apply_wqattrs_ctx *ctx;
 
 	lockdep_assert_held(&wq_pool_mutex);
 
@@ -7097,7 +7097,7 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
 		list_add_tail(&ctx->list, &ctxs);
 	}
 
-	list_for_each_entry_safe(ctx, n, &ctxs, list) {
+	list_for_each_entry_mutable(ctx, &ctxs, list) {
 		if (!ret)
 			apply_wqattrs_commit(ctx);
 		apply_wqattrs_cleanup(ctx);
-- 
2.43.0


^ permalink raw reply related

* [PATCH] net: ixp4xx_hss: fix duplicate HDLC netdev allocation
From: Haoxiang Li @ 2026-06-22  4:30 UTC (permalink / raw)
  To: linusw, kaloz, andrew+netdev, davem, edumazet, kuba, pabeni,
	huangguangbin2, lipeng321
  Cc: linux-arm-kernel, netdev, linux-kernel, Haoxiang Li, stable

ixp4xx_hss_probe() allocates two HDLC netdevs. The first one is stored
in ndev, initialized, and registered with register_hdlc_device(). The
second one is stored in port->netdev and later used by the remove path
for unregister_hdlc_device() and free_netdev().

This means that the registered netdev is not the same object that is
unregistered and freed on remove. It also leaks the first allocation if
the second alloc_hdlcdev() call fails, and the first allocation is not
checked before ndev is used.

Older code allocated the HDLC netdev only once and stored the same object
in both the local variable and port->netdev. The buggy conversion split
this into two alloc_hdlcdev() calls. A later rename changed the local
variable name to ndev, but the underlying mismatch remained.

Fix this by allocating the HDLC netdev only once and assigning the same
object to port->netdev.

Fixes: 99ebe65eb9c0 ("net: ixp4xx_hss: move out assignment in if condition")
Cc: stable@vger.kernel.org
Signed-off-by: Haoxiang Li <haoxiang_li2024@163.com>
---
 drivers/net/wan/ixp4xx_hss.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c
index 720c5dc889ea..7f4645ff90aa 100644
--- a/drivers/net/wan/ixp4xx_hss.c
+++ b/drivers/net/wan/ixp4xx_hss.c
@@ -1487,11 +1487,11 @@ static int ixp4xx_hss_probe(struct platform_device *pdev)
 				     "unable to get CLK internal GPIO\n");
 
 	ndev = alloc_hdlcdev(port);
-	port->netdev = alloc_hdlcdev(port);
-	if (!port->netdev) {
+	if (!ndev) {
 		err = -ENOMEM;
 		goto err_plat;
 	}
+	port->netdev = ndev;
 
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 	hdlc = dev_to_hdlc(ndev);
-- 
2.25.1


^ permalink raw reply related

* [PATCH 1/2] Protect skb pointer used by two different kernel instances
From: Selvamani Rajagopal via B4 Relay @ 2026-06-22  4:32 UTC (permalink / raw)
  To: Parthiban Veerasooran, Andrew Lunn, Piergiorgio Beruto,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: netdev, linux-kernel, Andrew Lunn, Parthiban Veerasooran,
	Selvamani Rajagopal
In-Reply-To: <20260621-fix-race-condition-and-crash-v1-0-87e290d9357f@onsemi.com>

From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>

Threaded IRQ uses waiting_tx_skb. Transmit path also uses
this pointer without any mutual exclusion protection. As a
result, it might leak skb buffer, particularly threaded IRQ
runs in the middle of tranmsmit path, near skb_linearize.

Fixes: b542d13fab0f ("net: ethernet: oa_tc6: Interrupt is active low, level triggered.")
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
 drivers/net/ethernet/oa_tc6.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
index 0727d53345a3..3fd4851ee66d 100644
--- a/drivers/net/ethernet/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6.c
@@ -672,10 +672,16 @@ static void oa_tc6_cleanup_ongoing_tx_skb(struct oa_tc6 *tc6)
 
 static void oa_tc6_cleanup_waiting_tx_skb(struct oa_tc6 *tc6)
 {
-	if (tc6->waiting_tx_skb) {
+	struct sk_buff *skb;
+
+	spin_lock_bh(&tc6->tx_skb_lock);
+	skb = tc6->waiting_tx_skb;
+	tc6->waiting_tx_skb = NULL;
+	spin_unlock_bh(&tc6->tx_skb_lock);
+
+	if (skb) {
 		tc6->netdev->stats.tx_dropped++;
-		kfree_skb(tc6->waiting_tx_skb);
-		tc6->waiting_tx_skb = NULL;
+		kfree_skb(skb);
 	}
 }
 
@@ -1250,11 +1256,6 @@ EXPORT_SYMBOL_GPL(oa_tc6_zero_align_receive_frame_enable);
  */
 netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb)
 {
-	if (tc6->disable_traffic || tc6->waiting_tx_skb) {
-		netif_stop_queue(tc6->netdev);
-		return NETDEV_TX_BUSY;
-	}
-
 	if (skb_linearize(skb)) {
 		dev_kfree_skb_any(skb);
 		tc6->netdev->stats.tx_dropped++;
@@ -1262,6 +1263,11 @@ netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb)
 	}
 
 	spin_lock_bh(&tc6->tx_skb_lock);
+	if (tc6->disable_traffic || tc6->waiting_tx_skb) {
+		netif_stop_queue(tc6->netdev);
+		spin_unlock_bh(&tc6->tx_skb_lock);
+		return NETDEV_TX_BUSY;
+	}
 	tc6->waiting_tx_skb = skb;
 	spin_unlock_bh(&tc6->tx_skb_lock);
 

-- 
2.43.0



^ permalink raw reply related

* [PATCH 0/2] Fix to possible skb leak due to race condtion in tx path
From: Selvamani Rajagopal via B4 Relay @ 2026-06-22  4:32 UTC (permalink / raw)
  To: Parthiban Veerasooran, Andrew Lunn, Piergiorgio Beruto,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: netdev, linux-kernel, Andrew Lunn, Parthiban Veerasooran,
	Selvamani Rajagopal

Now the traffic is handled in threaded IRQ, and the
disable_traffic flag is checked before handling the
data, new race condition is exposed, in which
buffer may leak, if threaded IRQ interrupts the
trasmit path midway.

With this change, disable_traffic and waiting_tx_skb
pointer are protected by spin lock/unlock pair.

This is highlighted in Sashiko review
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260611-level-trigger-v5-0-4533a9e85ce2%40onsemi.com

Also on buffer overrun condition, probably due to loss of
SPI data chunks, receive path doesn't see the expected
data chunk with end_valid bit set. As a result, driver
keeps adding data chunks to the skb before running out
of space and kernel panic is seen.

With this change, before adding data to the skb, if there
is no space, skb is freed and driver starts looking for
new frame by looking for a data chunk with start_valid
bit set.

[  705.405490] skbuff: skb_over_panic: text:ffffffd2eb72a264 len:1600 put:64 head:ffffff804e5cdc40 data:ffffff804e5cdc80 tail:0x680 end:0x640 dev:eth1
[  705.405569] ------------[ cut here ]------------
[  705.405575] kernel BUG at net/core/skbuff.c:214!
[  705.405589] Internal error: Oops - BUG: 00000000f2000800 [#1]  SMP

[ 6703.427690] Call trace:
[  705.925157]  skb_panic+0x58/0x68 (P)
[  705.928726]  skb_put+0x74/0x80
[  705.931772]  oa_tc6_update_rx_skb+0x44/0x98 [oa_tc6_mod]
[  705.937084]  oa_tc6_macphy_threaded_irq+0x3f4/0x900 [oa_tc6_mod]
[  705.943084]  irq_thread_fn+0x34/0xb8
[  705.946654]  irq_thread+0x1a0/0x300
[  705.950134]  kthread+0x138/0x150
[  705.953356]  ret_from_fork+0x10/0x20

Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
Selvamani Rajagopal (2):
      Protect skb pointer used by two different kernel instances
      net: ethernet: oa_tc6: Improvement in buffer overflow handling

 drivers/net/ethernet/oa_tc6.c | 75 +++++++++++++++++++++++++++----------------
 1 file changed, 48 insertions(+), 27 deletions(-)
---
base-commit: d07d80b6a129a44538cda1549b7acf95154fb197
change-id: 20260621-fix-race-condition-and-crash-94d055a665c4

Best regards,
-- 
Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>



^ permalink raw reply

* [PATCH 2/2] net: ethernet: oa_tc6: Improvement in buffer overflow handling
From: Selvamani Rajagopal via B4 Relay @ 2026-06-22  4:32 UTC (permalink / raw)
  To: Parthiban Veerasooran, Andrew Lunn, Piergiorgio Beruto,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: netdev, linux-kernel, Andrew Lunn, Parthiban Veerasooran,
	Selvamani Rajagopal
In-Reply-To: <20260621-fix-race-condition-and-crash-v1-0-87e290d9357f@onsemi.com>

From: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>

When oversubscribed traffic causes lot of buffer overflow errors,
probably due to loss of data chunks, driver fails to find a
data chunk with end_valid bit set, before it runs out of sk buffer
space. As a result, assert is seen during skb_put.

Now check is made if tail + len > end, driver abandons the current
data and starts look for a data chunk with start_valid bit,
that is a new frame.

Fixes: d70a0d8f2f2d ("net: ethernet: oa_tc6: implement receive path to receive rx ethernet frames")
Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
---
 drivers/net/ethernet/oa_tc6.c | 53 +++++++++++++++++++++++++++----------------
 1 file changed, 34 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
index 3fd4851ee66d..180fc47c30b3 100644
--- a/drivers/net/ethernet/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6.c
@@ -692,6 +692,12 @@ static void oa_tc6_free_pending_skbs(struct oa_tc6 *tc6)
 	oa_tc6_cleanup_waiting_tx_skb(tc6);
 }
 
+static void oa_tc6_look_for_new_frame(struct oa_tc6 *tc6)
+{
+	tc6->rx_buf_overflow = true;
+	oa_tc6_cleanup_ongoing_rx_skb(tc6);
+}
+
 /* If the failure is at SPI interface level, masking and clearing
  * the interrupt of the device won't work. Since SPI interrupt is
  * disabled, it should stop the repeated interrupts.
@@ -729,8 +735,7 @@ static int oa_tc6_process_extended_status(struct oa_tc6 *tc6)
 	}
 
 	if (FIELD_GET(STATUS0_RX_BUFFER_OVERFLOW_ERROR, value)) {
-		tc6->rx_buf_overflow = true;
-		oa_tc6_cleanup_ongoing_rx_skb(tc6);
+		oa_tc6_look_for_new_frame(tc6);
 		net_err_ratelimited("%s: Receive buffer overflow error\n",
 				    tc6->netdev->name);
 		return -EAGAIN;
@@ -811,9 +816,15 @@ static void oa_tc6_submit_rx_skb(struct oa_tc6 *tc6)
 	tc6->rx_skb = NULL;
 }
 
-static void oa_tc6_update_rx_skb(struct oa_tc6 *tc6, u8 *payload, u8 length)
+static int oa_tc6_update_rx_skb(struct oa_tc6 *tc6, u8 *payload, u8 length)
 {
+	if ((tc6->rx_skb->tail + length) > tc6->rx_skb->end) {
+		oa_tc6_look_for_new_frame(tc6);
+		return -EAGAIN;
+	}
+
 	memcpy(skb_put(tc6->rx_skb, length), payload, length);
+	return 0;
 }
 
 static int oa_tc6_allocate_rx_skb(struct oa_tc6 *tc6)
@@ -837,7 +848,9 @@ static int oa_tc6_prcs_complete_rx_frame(struct oa_tc6 *tc6, u8 *payload,
 	if (ret)
 		return ret;
 
-	oa_tc6_update_rx_skb(tc6, payload, size);
+	ret = oa_tc6_update_rx_skb(tc6, payload, size);
+	if (ret)
+		return ret;
 
 	oa_tc6_submit_rx_skb(tc6);
 
@@ -852,22 +865,24 @@ static int oa_tc6_prcs_rx_frame_start(struct oa_tc6 *tc6, u8 *payload, u16 size)
 	if (ret)
 		return ret;
 
-	oa_tc6_update_rx_skb(tc6, payload, size);
-
-	return 0;
+	return oa_tc6_update_rx_skb(tc6, payload, size);
 }
 
-static void oa_tc6_prcs_rx_frame_end(struct oa_tc6 *tc6, u8 *payload, u16 size)
+static int oa_tc6_prcs_rx_frame_end(struct oa_tc6 *tc6, u8 *payload, u16 size)
 {
-	oa_tc6_update_rx_skb(tc6, payload, size);
+	int ret;
 
-	oa_tc6_submit_rx_skb(tc6);
+	ret = oa_tc6_update_rx_skb(tc6, payload, size);
+	if (!ret)
+		oa_tc6_submit_rx_skb(tc6);
+	return ret;
 }
 
-static void oa_tc6_prcs_ongoing_rx_frame(struct oa_tc6 *tc6, u8 *payload,
-					 u32 footer)
+static int oa_tc6_prcs_ongoing_rx_frame(struct oa_tc6 *tc6, u8 *payload,
+					u32 footer)
 {
-	oa_tc6_update_rx_skb(tc6, payload, OA_TC6_CHUNK_PAYLOAD_SIZE);
+	return oa_tc6_update_rx_skb(tc6, payload,
+				    OA_TC6_CHUNK_PAYLOAD_SIZE);
 }
 
 static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *tc6, u8 *data,
@@ -880,6 +895,7 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *tc6, u8 *data,
 	bool start_valid = FIELD_GET(OA_TC6_DATA_FOOTER_START_VALID, footer);
 	bool end_valid = FIELD_GET(OA_TC6_DATA_FOOTER_END_VALID, footer);
 	u16 size;
+	int ret;
 
 	/* Restart the new rx frame after receiving rx buffer overflow error */
 	if (start_valid && tc6->rx_buf_overflow)
@@ -907,8 +923,7 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *tc6, u8 *data,
 	/* Process the chunk with only rx frame end */
 	if (end_valid && !start_valid) {
 		size = end_byte_offset + 1;
-		oa_tc6_prcs_rx_frame_end(tc6, data, size);
-		return 0;
+		return oa_tc6_prcs_rx_frame_end(tc6, data, size);
 	}
 
 	/* Process the chunk with previous rx frame end and next rx frame
@@ -921,7 +936,9 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *tc6, u8 *data,
 		 */
 		if (tc6->rx_skb) {
 			size = end_byte_offset + 1;
-			oa_tc6_prcs_rx_frame_end(tc6, data, size);
+			ret = oa_tc6_prcs_rx_frame_end(tc6, data, size);
+			if (ret)
+				return ret;
 		}
 		size = OA_TC6_CHUNK_PAYLOAD_SIZE - start_byte_offset;
 		return oa_tc6_prcs_rx_frame_start(tc6,
@@ -930,9 +947,7 @@ static int oa_tc6_prcs_rx_chunk_payload(struct oa_tc6 *tc6, u8 *data,
 	}
 
 	/* Process the chunk with ongoing rx frame data */
-	oa_tc6_prcs_ongoing_rx_frame(tc6, data, footer);
-
-	return 0;
+	return oa_tc6_prcs_ongoing_rx_frame(tc6, data, footer);
 }
 
 static u32 oa_tc6_get_rx_chunk_footer(struct oa_tc6 *tc6, u16 footer_offset)

-- 
2.43.0



^ permalink raw reply related

* [PATCH] net: meth: check skb allocation in meth_init_rx_ring()
From: Haoxiang Li @ 2026-06-22  4:49 UTC (permalink / raw)
  To: andrew+netdev, davem, edumazet, kuba, pabeni
  Cc: netdev, linux-kernel, Haoxiang Li, stable

meth_init_rx_ring() does not check the return value of alloc_skb().
If the allocation fails, the NULL skb is passed to skb_reserve() and
then dereferenced through skb->head.

Add check for alloc_skb() to prevent potential null pointer dereference.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Haoxiang Li <haoxiang_li2024@163.com>
---
 drivers/net/ethernet/sgi/meth.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/ethernet/sgi/meth.c b/drivers/net/ethernet/sgi/meth.c
index f7c3a5a766b7..ceff3cc937ad 100644
--- a/drivers/net/ethernet/sgi/meth.c
+++ b/drivers/net/ethernet/sgi/meth.c
@@ -228,6 +228,9 @@ static int meth_init_rx_ring(struct meth_private *priv)
 
 	for (i = 0; i < RX_RING_ENTRIES; i++) {
 		priv->rx_skbs[i] = alloc_skb(METH_RX_BUFF_SIZE, 0);
+		if (!priv->rx_skbs[i])
+			return -ENOMEM;
+
 		/* 8byte status vector + 3quad padding + 2byte padding,
 		 * to put data on 64bit aligned boundary */
 		skb_reserve(priv->rx_skbs[i],METH_RX_HEAD);
-- 
2.25.1


^ permalink raw reply related

* RE: [PATCH 0/2] Fix to possible skb leak due to race condtion in tx path
From: Selvamani Rajagopal @ 2026-06-22  4:57 UTC (permalink / raw)
  To: Selvamani Rajagopal, Parthiban Veerasooran, Andrew Lunn,
	Piergiorgio Beruto, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Andrew Lunn
In-Reply-To: <20260621-fix-race-condition-and-crash-v1-0-91987c2d4e56@onsemi.com>

Sorry that I missed to mention the target tree (net). Will wait for few days anyway and re-submit if needed.

Sincerely
Selva

> -----Original Message-----
> From: Selvamani Rajagopal via B4 Relay
> <devnull+Selvamani.Rajagopal.onsemi.com@kernel.org>
> Sent: Sunday, June 21, 2026 9:24 PM
> Subject: [PATCH 0/2] Fix to possible skb leak due to race condtion in tx path
> 
> 
> This Message Is From an External Sender
> This message came from outside your organization.
> 
> Due to the fact that traffic is handled in threaded IRQ,
> and the introduction of disable_traffic flag, introduced
> the race condition where sk buffer may leak if trasmit
> path is interrupted between the condition check and
> initializing the waiting_tx_skb pointer for transmission.
> 
> With this change, disable_traffic and waiting_tx_skb
> pointer are protected by spin lock/unlock pair.
> 
> This is highlighted in Sashiko review
> https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260611-level-trigger-v5-0-
> 4533a9e85ce2%40onsemi.com
> <https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260611-level-trigger-v5-0-4533a9e85ce2%40onsemi.com
> =netdev-ai.bots.linux.dev>
> 
> Also on buffer overrun condition, probably due to loss of
> SPI data chunks, receive path doesn't see the expected
> data chunk with end_valid bit set. As a result, driver
> keeps adding data chunks to the skb before running out
> of space and kernel panic is seen.
> 
> With this change, before adding data to the skb, if there
> is no space, skb is freed and driver starts looking for
> new frame by looking for a data chunk with start_valid
> bit set.
> 
> [ 705.405490] skbuff: skb_over_panic: text:ffffffd2eb72a264 len:1600 put:64
> head:ffffff804e5cdc40 data:ffffff804e5cdc80 tail:0x680 end:0x640 dev:eth1
> [ 705.405569] ------------[ cut here ]------------
> [ 705.405575] kernel BUG at net/core/skbuff.c:214!
> [ 705.405589] Internal error: Oops - BUG: 00000000f2000800 [#1] SMP
> 
> [ 6703.427690] Call trace:
> [ 705.925157] skb_panic+0x58/0x68 (P)
> [ 705.928726] skb_put+0x74/0x80
> [ 705.931772] oa_tc6_update_rx_skb+0x44/0x98 [oa_tc6_mod]
> [ 705.937084] oa_tc6_macphy_threaded_irq+0x3f4/0x900 [oa_tc6_mod]
> [ 705.943084] irq_thread_fn+0x34/0xb8
> [ 705.946654] irq_thread+0x1a0/0x300
> [ 705.950134] kthread+0x138/0x150
> [ 705.953356] ret_from_fork+0x10/0x20
> 
> Signed-off-by: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
> ---
> Selvamani Rajagopal (2):
> Protect skb pointer used by two different kernel instances
> net: ethernet: oa_tc6: Improvement in buffer overflow handling
> 
> drivers/net/ethernet/oa_tc6.c | 75 +++++++++++++++++++++++++++----------------
> 1 file changed, 48 insertions(+), 27 deletions(-)
> ---
> base-commit: d07d80b6a129a44538cda1549b7acf95154fb197
> change-id: 20260621-fix-race-condition-and-crash-94d055a665c4
> 
> Best regards,
> --
> Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>
> 


^ permalink raw reply

* RE: [PATCH net v5 1/4] net: ethernet: oa_tc6: Interrupt is active low, level triggered.
From: Selvamani Rajagopal @ 2026-06-22  5:14 UTC (permalink / raw)
  To: Parthiban.Veerasooran@microchip.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, Piergiorgio Beruto
  Cc: andrew@lunn.ch, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, Conor.Dooley@microchip.com,
	devicetree@vger.kernel.org
In-Reply-To: <CYYPR02MB9828CD98EEEB9B218A940E4483E32@CYYPR02MB9828.namprd02.prod.outlook.com>

> 
> AI review bot Sashiko suggested one potential issue where skb pointers aren't protected.
> But those
> concerns are in transmit path. This crash seems to be in receive path. If you think that
> might help,
> I can generate a patch for that.


Parthiban,

I just submitted a patch for "net" tree. I was able to see one crash though. Crash signature
was different from yours. As I remember, yours is NULL pointer access. Mine was due to 
trying to place the data beyond the "end" point.

Anyway, if you have time to spare and want to try and see if it fixes your crash, I would appreciate 
the feedback..

https://patchwork.kernel.org/project/netdevbpf/list/?series=1114495

> 
> What do you suggest? Since you are able to see the crash, would you have time to
> investigate?
> 
> Sincerely
> Selva

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox