* [PATCH 6.18 00/52] 6.18.58-rc1 review
@ 2026-10-17 15:54 Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 01/52] spi: mpc52xx: clean up interrupt handling Greg Kroah-Hartman
` (52 more replies)
0 siblings, 53 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, linux-kernel, torvalds, akpm, linux,
shuah, patches, lkft-triage, pavel, jonathanh, f.fainelli,
sudipm.mukherjee, rwarsow, conor, hargar, broonie, achill, sr
This is the start of the stable review cycle for the 6.18.58 release.
There are 52 patches in this series, all will be posted as a response
to this one. If anyone has any issues with these being applied, please
let me know.
Responses should be made by Mon, 19 Oct 2026 15:50:51 +0000.
Anything received after that time might be too late.
The whole patch series can be found in one patch at:
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.18.58-rc1.gz
or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.18.y
and the diffstat can be found below.
thanks,
greg k-h
-------------
Pseudo-Shortlog of commits:
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Linux 6.18.58-rc1
Toke Høiland-Jørgensen <toke@toke.dk>
wifi: atk9k: Revert "wifi: ath9k: reject short WMI command responses"
Mattia Meleleo <mattia.meleleo@coralogix.com>
bpf, sockmap: Account for receive queue in FIONREAD without a verdict program
Pratyush Yadav <pratyush@kernel.org>
kho: free chunks using free_page() instead of kfree()
Jens Axboe <axboe@kernel.dk>
io_uring/kbuf: don't charge provided buffer rings to RLIMIT_MEMLOCK
Hengyu Liang <hengyul@cs.unc.edu>
io_uring: do not charge the SQ/CQ rings to RLIMIT_MEMLOCK
Bernard Pidoux <bernard.f6bvp@gmail.com>
rose: hold a reference on incoming sockets queued for accept()
Alexander Lobakin <aleksander.lobakin@intel.com>
ice: fix broken Rx on VFs
Johan Hovold <johan@kernel.org>
USB: iowarrior: fix use-after-free on disconnect race
Oliver Neukum <oneukum@suse.com>
usb: iowarrior: remove inherent race with minor number
Stephen Smalley <stephen.smalley.work@gmail.com>
selinux: allow multiple opens of /sys/fs/selinux/policy
SeongJae Park <sj@kernel.org>
mm/damon/core: fix damos_walk() vs kdamond_fn() exit race
SeongJae Park <sj@kernel.org>
mm/damon/core: cancel damos_walk() before damon_ctx->kdamond reset
Long Li <leo.lilong@huawei.com>
xfs: close crash window in attr dabtree inactivation
Long Li <leo.lilong@huawei.com>
xfs: factor out xfs_attr3_leaf_init
Long Li <leo.lilong@huawei.com>
xfs: factor out xfs_attr3_node_entry_remove
Larysa Zaremba <larysa.zaremba@intel.com>
ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz
Larysa Zaremba <larysa.zaremba@intel.com>
ice: fix rxq info registering in mbuf packets
Michal Schmidt <mschmidt@redhat.com>
ice: fix crash in ethtool offline loopback test
Michal Kubiak <michal.kubiak@intel.com>
ice: drop page splitting and recycling
Michal Kubiak <michal.kubiak@intel.com>
ice: remove legacy Rx and construct SKB
Chris J Arges <carges@cloudflare.com>
ima: Fix stack-out-of-bounds in is_bprm_creds_for_exec()
Coiby Xu <coxu@redhat.com>
ima: Access decompressed kernel module to verify appended signature
Matteo Croce <technoboy85@gmail.com>
fat: stop reading directory entries past the end-of-directory marker
Frank Sorenson <sorenson@redhat.com>
cifs: fix time_last_write stamp placement in setattr/truncate paths
Fan Wu <fanwu01@zju.edu.cn>
drm/xe/i2c: cancel the client work on remove
Stanley Jhu <stanleyjhu@google.com>
scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock()
Bart Van Assche <bvanassche@acm.org>
scsi: ufs: core: Add a comment block above ufshcd_mcq_compl_all_cqes_lock()
Peter Wang <peter.wang@mediatek.com>
scsi: ufs: core: Add debug log for MCQ command timeout
Bart Van Assche <bvanassche@acm.org>
scsi: ufs: core: Move an assignment in ufshcd_mcq_process_cqe()
Ahmed Abdelhaleem Ahmed <ahmedhal@gmail.com>
scsi: ch: Do not keep references to data transfer element devices
Stanley Jhu <stanleyjhu@google.com>
scsi: ufs: core: Decouple CQ sweep from request iterator in MCQ
Wei-Jie Hung <imbigking12@gmail.com>
riscv: patch: fix handling of bpf-jit execmem addresses
Vivian Wang <wangruikang@iscas.ac.cn>
riscv: patch: Avoid early phys_to_page()
Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>
net: mana: reserve RX buffer headroom to fix forwarding performance
Suraj Gupta <suraj.gupta2@amd.com>
net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop
Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex
Tejun Heo <tj@kernel.org>
sched_ext: Fix CPU hotplug hang when a dying CPU's tasks sit in the BPF scheduler
Mikulas Patocka <mpatocka@redhat.com>
dm-integrity: validate the superblock on resume
Mikulas Patocka <mpatocka@redhat.com>
dm-integrity: fix NULL pointer dereference when the 'R' flag is used
Sean Wang <sean.wang@mediatek.com>
wifi: mt76: connac: tolerate inactive BSS deactivation
Lubos Rendek <l.rendek@proxmox.com>
nfsd: fix all-zero stateid in CB_OFFLOAD for async COPY
Lorenzo Stoakes (ARM) <ljs@kernel.org>
mm/mremap: fix locked_vm leak from MREMAP_DONTUNMAP self-merge
Lorenzo Stoakes (ARM) <ljs@kernel.org>
mm/mremap: fix locked_vm leak by splitting VMA for MREMAP_DONTUNMAP
Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
iavf: send MAC change request synchronously
Corinna Vinschen <vinschen@redhat.com>
iavf: iavf_virtchnl_completion: drop duplicate ether_addr_equal() test
Mario Limonciello <mario.limonciello@amd.com>
drm/amd: Create a device link between APU display and XHCI devices
Daehyeon Ko <4ncienth@gmail.com>
ip6_gre: remove obsolete ERSPAN PMTU update
Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
PCI: dwc: Return -EIO from dw_pcie_wait_for_link() if device is not active
Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
PCI: dwc: Return -ENODEV from dw_pcie_wait_for_link() if device is not found
Cheng Xu <chengyou@linux.alibaba.com>
RDMA/erdma: Use IRQ-safe XArray helpers for QP and CQ tables
Ethan Tidmore <ethantidmore06@gmail.com>
usb: gadget: f_hid: Add missing error code
Johan Hovold <johan@kernel.org>
spi: mpc52xx: clean up interrupt handling
-------------
Diffstat:
Makefile | 4 +-
arch/riscv/kernel/patch.c | 21 +-
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 12 ++
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 10 +
.../gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c | 45 ++++
drivers/gpu/drm/xe/xe_i2c.c | 5 +-
drivers/infiniband/hw/erdma/erdma_main.c | 4 +-
drivers/infiniband/hw/erdma/erdma_verbs.c | 18 +-
drivers/md/dm-integrity.c | 55 +++++
drivers/net/ethernet/intel/iavf/iavf.h | 11 +-
drivers/net/ethernet/intel/iavf/iavf_main.c | 85 ++++++--
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 111 ++++++++--
drivers/net/ethernet/intel/ice/ice.h | 3 +-
drivers/net/ethernet/intel/ice/ice_base.c | 79 ++-----
drivers/net/ethernet/intel/ice/ice_ethtool.c | 10 +-
drivers/net/ethernet/intel/ice/ice_lib.c | 15 +-
drivers/net/ethernet/intel/ice/ice_main.c | 11 +-
drivers/net/ethernet/intel/ice/ice_txrx.c | 233 ++-------------------
drivers/net/ethernet/intel/ice/ice_txrx.h | 88 --------
drivers/net/ethernet/intel/ice/ice_xsk.c | 75 +------
drivers/net/ethernet/intel/ice/virt/queues.c | 6 +-
drivers/net/ethernet/microsoft/mana/mana_bpf.c | 8 +-
drivers/net/ethernet/microsoft/mana/mana_en.c | 26 ++-
drivers/net/ethernet/xilinx/xilinx_axienet.h | 7 +-
drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 53 ++++-
drivers/net/wireless/ath/ath9k/wmi.c | 16 +-
drivers/net/wireless/ath/ath9k/wmi.h | 1 -
.../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 9 +-
.../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 23 ++
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 6 +-
drivers/pci/controller/dwc/pcie-designware.c | 31 ++-
drivers/scsi/ch.c | 30 +--
drivers/spi/spi-mpc52xx.c | 26 ++-
drivers/ufs/core/ufs-mcq.c | 35 +++-
drivers/ufs/core/ufshcd.c | 37 ++--
drivers/usb/gadget/function/f_hid.c | 4 +-
drivers/usb/misc/iowarrior.c | 74 +++----
fs/fat/dir.c | 44 +++-
fs/nfsd/nfs4proc.c | 2 +
fs/smb/client/inode.c | 27 ++-
fs/xfs/libxfs/xfs_attr_leaf.c | 22 ++
fs/xfs/libxfs/xfs_attr_leaf.h | 3 +
fs/xfs/libxfs/xfs_da_btree.c | 53 ++++-
fs/xfs/libxfs/xfs_da_btree.h | 2 +
fs/xfs/xfs_attr_inactive.c | 99 +++++----
include/linux/damon.h | 1 +
include/linux/kernel_read_file.h | 1 +
include/linux/skmsg.h | 14 --
include/net/bluetooth/rfcomm.h | 1 +
include/net/mana/mana.h | 4 +-
io_uring/io_uring.c | 12 +-
io_uring/kbuf.c | 6 +-
io_uring/memmap.c | 29 ++-
io_uring/memmap.h | 6 +-
io_uring/register.c | 15 +-
io_uring/zcrx.c | 4 +-
kernel/kexec_handover.c | 2 +-
kernel/module/main.c | 17 +-
kernel/sched/ext.c | 29 ++-
kernel/sched/sched.h | 5 +-
mm/damon/core.c | 24 ++-
mm/mremap.c | 38 +++-
mm/vma.c | 21 +-
mm/vma.h | 7 +-
net/bluetooth/rfcomm/core.c | 134 ++++++++----
net/ipv4/tcp_bpf.c | 17 +-
net/ipv6/ip6_gre.c | 7 -
net/rose/af_rose.c | 44 +++-
net/rose/rose_timer.c | 5 +
security/integrity/ima/ima.h | 6 +-
security/integrity/ima/ima_appraise.c | 16 +-
security/integrity/ima/ima_main.c | 30 ++-
security/integrity/ima/ima_policy.c | 3 +-
security/ipe/hooks.c | 1 +
security/selinux/hooks.c | 5 +-
security/selinux/selinuxfs.c | 27 +--
tools/testing/vma/vma.c | 4 +-
77 files changed, 1160 insertions(+), 914 deletions(-)
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 6.18 01/52] spi: mpc52xx: clean up interrupt handling
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 02/52] usb: gadget: f_hid: Add missing error code Greg Kroah-Hartman
` (51 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Johan Hovold, Mark Brown,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <johan@kernel.org>
[ Upstream commit 76645c1fd682c9df746c3f7c149b868ceff914fb ]
The driver is relying on the assumption that the invalid interrupt 0 can
be freed without any side effects, but that is not the case on
architectures like x86 where it would trigger a warning about freeing an
already free interrupt.
This should not cause any trouble on powerpc where this driver is used,
but make the code more portable (and obviously correct) by making sure
that the interrupts have been requested before freeing them.
Signed-off-by: Johan Hovold <johan@kernel.org>
Link: https://patch.msgid.link/20260423075801.2252318-1-johan@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/spi/spi-mpc52xx.c | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c
index 84aade1416068..36692aa62bbd4 100644
--- a/drivers/spi/spi-mpc52xx.c
+++ b/drivers/spi/spi-mpc52xx.c
@@ -475,13 +475,15 @@ static int mpc52xx_spi_probe(struct platform_device *op)
if (ms->irq0 && ms->irq1) {
rc = request_irq(ms->irq0, mpc52xx_spi_irq, 0,
"mpc5200-spi-modf", ms);
- rc |= request_irq(ms->irq1, mpc52xx_spi_irq, 0,
- "mpc5200-spi-spif", ms);
- if (rc) {
- free_irq(ms->irq0, ms);
- free_irq(ms->irq1, ms);
- ms->irq0 = ms->irq1 = 0;
+ if (rc == 0) {
+ rc = request_irq(ms->irq1, mpc52xx_spi_irq, 0,
+ "mpc5200-spi-spif", ms);
+ if (rc)
+ free_irq(ms->irq0, ms);
}
+
+ if (rc)
+ ms->irq0 = ms->irq1 = 0;
} else {
/* operate in polled mode */
ms->irq0 = ms->irq1 = 0;
@@ -501,8 +503,10 @@ static int mpc52xx_spi_probe(struct platform_device *op)
err_register:
dev_err(&ms->host->dev, "initialization failed\n");
- free_irq(ms->irq0, ms);
- free_irq(ms->irq1, ms);
+ if (ms->irq0) {
+ free_irq(ms->irq0, ms);
+ free_irq(ms->irq1, ms);
+ }
cancel_work_sync(&ms->work);
err_gpio:
while (i-- > 0)
@@ -525,8 +529,10 @@ static void mpc52xx_spi_remove(struct platform_device *op)
spi_unregister_controller(host);
- free_irq(ms->irq0, ms);
- free_irq(ms->irq1, ms);
+ if (ms->irq0) {
+ free_irq(ms->irq0, ms);
+ free_irq(ms->irq1, ms);
+ }
cancel_work_sync(&ms->work);
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 02/52] usb: gadget: f_hid: Add missing error code
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 01/52] spi: mpc52xx: clean up interrupt handling Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 03/52] RDMA/erdma: Use IRQ-safe XArray helpers for QP and CQ tables Greg Kroah-Hartman
` (50 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ethan Tidmore, Peter Korsgaard,
Michael Zimmermann, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ethan Tidmore <ethantidmore06@gmail.com>
[ Upstream commit 2c863dbbeac7b919d4634ad886978a6731916de3 ]
Currently in cdev_alloc() error path no error code is assigned.
Assign error code '-ENOMEM'.
Detected by Smatch:
drivers/usb/gadget/function/f_hid.c:1291 hidg_bind()
warn: missing error code 'status'
Fixes: 81ebd43cc0d6d ("usb: gadget: f_hid: don't call cdev_init while cdev in use")
Signed-off-by: Ethan Tidmore <ethantidmore06@gmail.com>
Acked-by: Peter Korsgaard <peter@korsgaard.com>
Reviewed-by: Michael Zimmermann <sigmaepsilon92@gmail.com>
Link: https://patch.msgid.link/20260402180008.64233-1-ethantidmore06@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/usb/gadget/function/f_hid.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index ee59e6516187c..4fe9c38dd2cab 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -1279,8 +1279,10 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
/* create char device */
hidg->cdev = cdev_alloc();
- if (!hidg->cdev)
+ if (!hidg->cdev) {
+ status = -ENOMEM;
goto fail_free_all;
+ }
hidg->cdev->ops = &f_hidg_fops;
status = cdev_device_add(hidg->cdev, &hidg->dev);
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 03/52] RDMA/erdma: Use IRQ-safe XArray helpers for QP and CQ tables
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 01/52] spi: mpc52xx: clean up interrupt handling Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 02/52] usb: gadget: f_hid: Add missing error code Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 04/52] PCI: dwc: Return -ENODEV from dw_pcie_wait_for_link() if device is not found Greg Kroah-Hartman
` (49 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Cheng Xu, Leon Romanovsky,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cheng Xu <chengyou@linux.alibaba.com>
[ Upstream commit 00baeade709fb66da647e8327e8398bb532e30f7 ]
Locked QP and CQ lookups from EQ interrupts can deadlock with
create-path XArray updates. If an interrupt arrives while the create
path holds the plain xa_lock, the lookup spins forever trying to
acquire the same lock.
Use IRQ-safe XArray helpers for all QP and CQ create-path updates,
including the GSI QP store and error paths. Initialize both arrays with
XA_FLAGS_LOCK_IRQ so sleeping allocations preserve interrupt state.
Fixes: 98df2aee1459 ("RDMA/erdma: Hold CQ references when processing EQ events")
Fixes: a52eeff32024 ("RDMA/erdma: Hold QP references for AE and CM processing")
Signed-off-by: Cheng Xu <chengyou@linux.alibaba.com>
Link: https://patch.msgid.link/20260828030344.88021-1-chengyou@linux.alibaba.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/erdma/erdma_main.c | 4 ++--
drivers/infiniband/hw/erdma/erdma_verbs.c | 18 +++++++++---------
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/infiniband/hw/erdma/erdma_main.c b/drivers/infiniband/hw/erdma/erdma_main.c
index f35b30235018b..f76da01a1d1fe 100644
--- a/drivers/infiniband/hw/erdma/erdma_main.c
+++ b/drivers/infiniband/hw/erdma/erdma_main.c
@@ -573,8 +573,8 @@ static int erdma_ib_device_add(struct pci_dev *pdev)
INIT_LIST_HEAD(&dev->cep_list);
spin_lock_init(&dev->lock);
- xa_init_flags(&dev->qp_xa, XA_FLAGS_ALLOC1);
- xa_init_flags(&dev->cq_xa, XA_FLAGS_ALLOC1);
+ xa_init_flags(&dev->qp_xa, XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_IRQ);
+ xa_init_flags(&dev->cq_xa, XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_IRQ);
dev->next_alloc_cqn = 1;
dev->next_alloc_qpn = 1;
diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c
index fdd67756f3bc3..6feac67d84721 100644
--- a/drivers/infiniband/hw/erdma/erdma_verbs.c
+++ b/drivers/infiniband/hw/erdma/erdma_verbs.c
@@ -1019,15 +1019,15 @@ int erdma_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
init_completion(&qp->safe_free);
if (qp->ibqp.qp_type == IB_QPT_GSI) {
- old_entry = xa_store(&dev->qp_xa, 1, qp, GFP_KERNEL);
+ old_entry = xa_store_irq(&dev->qp_xa, 1, qp, GFP_KERNEL);
if (xa_is_err(old_entry))
ret = xa_err(old_entry);
else
qp->ibqp.qp_num = 1;
} else {
- ret = xa_alloc_cyclic(&dev->qp_xa, &qp->ibqp.qp_num, qp,
- XA_LIMIT(1, dev->attrs.max_qp - 1),
- &dev->next_alloc_qpn, GFP_KERNEL);
+ ret = xa_alloc_cyclic_irq(&dev->qp_xa, &qp->ibqp.qp_num, qp,
+ XA_LIMIT(1, dev->attrs.max_qp - 1),
+ &dev->next_alloc_qpn, GFP_KERNEL);
}
if (ret < 0) {
@@ -1090,7 +1090,7 @@ int erdma_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
else
free_kernel_qp(qp);
err_out_xa:
- xa_erase(&dev->qp_xa, QP_ID(qp));
+ xa_erase_irq(&dev->qp_xa, QP_ID(qp));
err_out:
return ret;
}
@@ -1994,9 +1994,9 @@ int erdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
refcount_set(&cq->refcount, 1);
init_completion(&cq->free);
- ret = xa_alloc_cyclic(&dev->cq_xa, &cq->cqn, cq,
- XA_LIMIT(1, dev->attrs.max_cq - 1),
- &dev->next_alloc_cqn, GFP_KERNEL);
+ ret = xa_alloc_cyclic_irq(&dev->cq_xa, &cq->cqn, cq,
+ XA_LIMIT(1, dev->attrs.max_cq - 1),
+ &dev->next_alloc_cqn, GFP_KERNEL);
if (ret < 0)
return ret;
@@ -2044,7 +2044,7 @@ int erdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
}
err_out_xa:
- xa_erase(&dev->cq_xa, cq->cqn);
+ xa_erase_irq(&dev->cq_xa, cq->cqn);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 04/52] PCI: dwc: Return -ENODEV from dw_pcie_wait_for_link() if device is not found
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (2 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 03/52] RDMA/erdma: Use IRQ-safe XArray helpers for QP and CQ tables Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 05/52] PCI: dwc: Return -EIO from dw_pcie_wait_for_link() if device is not active Greg Kroah-Hartman
` (48 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Manivannan Sadhasivam, Richard Zhu,
Vincent Guittot, Shawn Lin, Niklas Cassel, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
[ Upstream commit 1bcf245c837bc66fdaddea222bab9eb5c978a9d7 ]
The dw_pcie_wait_for_link() function waits up to 1 second for the PCIe link
to come up and returns -ETIMEDOUT for all failures without distinguishing
cases where no device is present on the bus. But the callers may want to
just skip the failure if the device is not found on the bus and handle
failure for other reasons.
So after timeout, if the LTSSM is in Detect.Quiet or Detect.Active state,
return -ENODEV to indicate the callers that the device is not found on the
bus and return -ETIMEDOUT otherwise.
Also add kernel doc to document the parameter and return values.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Tested-by: Richard Zhu <hongxing.zhu@nxp.com>
Tested-by: Vincent Guittot <vincent.guittot@linaro.org>
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
Reviewed-by: Niklas Cassel <cassel@kernel.org>
Link: https://patch.msgid.link/20260120-pci-dwc-suspend-rework-v4-1-2f32d5082549@oss.qualcomm.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pci/controller/dwc/pcie-designware.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 2c1dd6ffa27db..8635d8921d9b3 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -692,9 +692,16 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index)
dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0);
}
+/**
+ * dw_pcie_wait_for_link - Wait for the PCIe link to be up
+ * @pci: DWC instance
+ *
+ * Returns: 0 if link is up, -ENODEV if device is not found, -ETIMEDOUT if the
+ * link fails to come up for other reasons.
+ */
int dw_pcie_wait_for_link(struct dw_pcie *pci)
{
- u32 offset, val;
+ u32 offset, val, ltssm;
int retries;
/* Check if the link is up or not */
@@ -706,6 +713,17 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
}
if (retries >= PCIE_LINK_WAIT_MAX_RETRIES) {
+ /*
+ * If the link is in Detect.Quiet or Detect.Active state, it
+ * indicates that no device is detected.
+ */
+ ltssm = dw_pcie_get_ltssm(pci);
+ if (ltssm == DW_PCIE_LTSSM_DETECT_QUIET ||
+ ltssm == DW_PCIE_LTSSM_DETECT_ACT) {
+ dev_info(pci->dev, "Device not found\n");
+ return -ENODEV;
+ }
+
dev_info(pci->dev, "Phy link never came up\n");
return -ETIMEDOUT;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 05/52] PCI: dwc: Return -EIO from dw_pcie_wait_for_link() if device is not active
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (3 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 04/52] PCI: dwc: Return -ENODEV from dw_pcie_wait_for_link() if device is not found Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 06/52] ip6_gre: remove obsolete ERSPAN PMTU update Greg Kroah-Hartman
` (47 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Manivannan Sadhasivam, Niklas Cassel,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
[ Upstream commit 01d16b8afb7afcc17f999f8b4a9b9cfe6c6fae71 ]
There are cases where the PCIe device would be physically connected to the
bus, but the device firmware might not be active. So the LTSSM will
get stuck in POLL.{Active/Compliance} states.
This behavior is common with endpoint devices controlled by the PCI
Endpoint framework, where the device will wait for the user to start its
operation through configfs.
For those cases, print the relevant log and return -EIO to indicate that
the device is present, but not active. This will allow the callers to skip
the failure as the device might become active in the future.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Reviewed-by: Niklas Cassel <cassel@kernel.org>
Link: https://patch.msgid.link/20260120-pci-dwc-suspend-rework-v4-2-2f32d5082549@oss.qualcomm.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pci/controller/dwc/pcie-designware.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 8635d8921d9b3..a77d7cde4524b 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -696,8 +696,9 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index)
* dw_pcie_wait_for_link - Wait for the PCIe link to be up
* @pci: DWC instance
*
- * Returns: 0 if link is up, -ENODEV if device is not found, -ETIMEDOUT if the
- * link fails to come up for other reasons.
+ * Returns: 0 if link is up, -ENODEV if device is not found, -EIO if the device
+ * is found but not active and -ETIMEDOUT if the link fails to come up for other
+ * reasons.
*/
int dw_pcie_wait_for_link(struct dw_pcie *pci)
{
@@ -722,6 +723,16 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
ltssm == DW_PCIE_LTSSM_DETECT_ACT) {
dev_info(pci->dev, "Device not found\n");
return -ENODEV;
+
+ /*
+ * If the link is in POLL.{Active/Compliance} state, then the
+ * device is found to be connected to the bus, but it is not
+ * active i.e., the device firmware might not yet initialized.
+ */
+ } else if (ltssm == DW_PCIE_LTSSM_POLL_ACTIVE ||
+ ltssm == DW_PCIE_LTSSM_POLL_COMPLIANCE) {
+ dev_info(pci->dev, "Device found, but not active\n");
+ return -EIO;
}
dev_info(pci->dev, "Phy link never came up\n");
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 06/52] ip6_gre: remove obsolete ERSPAN PMTU update
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (4 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 05/52] PCI: dwc: Return -EIO from dw_pcie_wait_for_link() if device is not active Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 07/52] drm/amd: Create a device link between APU display and XHCI devices Greg Kroah-Hartman
` (46 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ido Schimmel, Daehyeon Ko,
Jakub Kicinski, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <4ncienth@gmail.com>
[ Upstream commit 8bc60db48e8cba35488bbd6e1f94aa990afa275a ]
A tc tunnel_key action can attach a METADATA_IP_TUNNEL dst to an skb,
and mirred can redirect it to a native ip6erspan device. The legacy PMTU
update in ip6erspan_tunnel_xmit() treats that metadata dst as a route.
Since it has no output device, dst_dev(dst)->mtu dereferences NULL.
On v7.2 with KASAN, an initial UID/GID 65534 process with CapEff 0 used
self-created user and network namespaces to trigger:
KASAN: null-ptr-deref
RIP: ip6erspan_tunnel_xmit+0x10fc/0x2cc0
Kernel panic - not syncing: Fatal exception in interrupt
The update is obsolete. Commit fe1a4ca0a2b7 ("ip6_gre: process toobig
in a better way") changed IPv6 GRE Too Big handling to update the
underlay route and removed the equivalent block from __gre6_xmit().
ip6_tnl_xmit() then propagates the underlay PMTU to the overlay route.
Remove the stale ERSPAN copy and its now-unused dst variable. This
eliminates the metadata-dst dereference and keeps ERSPAN aligned with
IPv6 GRE PMTU handling.
Fixes: 5a963eb61b7c ("ip6_gre: Add ERSPAN native tunnel support")
Cc: stable@vger.kernel.org
Suggested-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Daehyeon Ko <4ncienth@gmail.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20261002033058.358137-1-4ncienth@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
[ sashal: Adjusted the deletion to match dst6_mtu() instead of dst_mtu(). ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv6/ip6_gre.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index ebd0198458cd3..e3aedef13ceed 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -922,7 +922,6 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
{
struct ip_tunnel_info *tun_info = NULL;
struct ip6_tnl *t = netdev_priv(dev);
- struct dst_entry *dst = skb_dst(skb);
IP_TUNNEL_DECLARE_FLAGS(flags) = { };
bool truncate = false;
int encap_limit = -1;
@@ -1058,12 +1057,6 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
gre_build_header(skb, 8, flags, proto, 0,
htonl(atomic_fetch_inc(&t->o_seqno)));
- /* TooBig packet may have updated dst->dev's mtu */
- if (!t->parms.collect_md && dst) {
- mtu = READ_ONCE(dst_dev(dst)->mtu);
- if (dst6_mtu(dst) > mtu)
- dst->ops->update_pmtu(dst, NULL, skb, mtu, false);
- }
err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
NEXTHDR_GRE);
if (err != 0) {
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 07/52] drm/amd: Create a device link between APU display and XHCI devices
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (5 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 06/52] ip6_gre: remove obsolete ERSPAN PMTU update Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 08/52] iavf: iavf_virtchnl_completion: drop duplicate ether_addr_equal() test Greg Kroah-Hartman
` (45 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Aaron Ma, mrh, Alex Deucher,
Mark Pearson, Alexander F, Francis DB, Mario Limonciello,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <mario.limonciello@amd.com>
[ Upstream commit 75c8746b9d0a0317d8a58aa0efa2ff2f7359908b ]
Some AMD APU multi-function devices expose an integrated USB xHCI
controller. In some circumstances (such as larger VRAM), the PM core
can resume can fail when the xHCI controller is resuming in parallel
with the GPU/display function.
On affected systems, the xHCI controller can complete pci_pm_resume
and start resuming USB devices while the GPU is still in its much
longer resume path. This race condition leads to USB device resume
failures followed by:
xhci_hcd ...: xHCI host not responding to stop endpoint command
xhci_hcd ...: HC died; cleaning up
Create a device link from any xHCI controller sharing the same PCIe
root port as the APU display function. The link uses DL_FLAG_STATELESS
and DL_FLAG_PM_RUNTIME to ensure the GPU completes its resume before
the xHCI controller begins resuming USB devices.
This device link is done specifically in amdgpu so that if the
platform firmware has been modified such that this issue doesn't happen
the version can be detected and the workaround skipped.
Suggested-by: Aaron Ma <aaron.ma@canonical.com>
Reported-by: mrh@frame.work
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221073
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Tested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Tested-by: Alexander F <superveridical@gmail.com>
Tested-by: Francis DB <francisdb@gmail.com>
Link: https://patch.msgid.link/20260713195313.1739762-1-mario.limonciello@amd.com
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 07c93d7eeb0d990bc1b8e3b1eafa464bc9feee97)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 12 +++++
drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 10 +++++
.../drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c | 45 +++++++++++++++++++
3 files changed, 67 insertions(+)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index 8473eaac1e7fc..31f194142bd3f 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -1342,6 +1342,14 @@ static void smu_feature_cap_init(struct smu_context *smu)
bitmap_zero(fea_cap->cap_map, SMU_FEATURE_CAP_ID__COUNT);
}
+static int smu_set_power_dep(struct smu_context *smu, bool enable)
+{
+ if (!smu->ppt_funcs->set_power_dep)
+ return 0;
+
+ return smu->ppt_funcs->set_power_dep(smu, enable);
+}
+
static int smu_sw_init(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
@@ -1405,6 +1413,8 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
if (!smu->ppt_funcs->get_fan_control_mode)
smu->adev->pm.no_fan = true;
+ smu_set_power_dep(smu, true);
+
return 0;
}
@@ -1427,6 +1437,8 @@ static int smu_sw_fini(struct amdgpu_ip_block *ip_block)
smu_fini_microcode(smu);
+ smu_set_power_dep(smu, false);
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index 582c186d8b623..e00beb901d906 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -599,6 +599,9 @@ struct smu_context {
bool pm_enabled;
bool is_apu;
+ /* Power dependency link from an integrated xHCI controller to the GPU */
+ struct device_link *usb_power_link;
+
uint32_t smc_driver_if_version;
uint32_t smc_fw_if_version;
uint32_t smc_fw_version;
@@ -1521,6 +1524,13 @@ struct pptable_funcs {
*/
ssize_t (*get_xcp_metrics)(struct smu_context *smu, int xcp_id,
void *table);
+ /**
+ * @set_power_dep: Create or destroy a power dependency link
+ * from an integrated xHCI controller to the GPU so that the GPU is
+ * resumed before the USB controller during PM resume. @enable is true
+ * to create the link and false to tear it down.
+ */
+ int (*set_power_dep)(struct smu_context *smu, bool enable);
};
typedef enum {
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
index 44cce9b636ca8..3a2b16a9998c6 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
@@ -1665,6 +1665,50 @@ static int smu_v14_0_common_set_mall_enable(struct smu_context *smu)
return ret;
}
+/*
+ * Link any xHCI controller sharing the GPU's PCIe root port as a consumer
+ * of the GPU so the GPU resumes first, avoiding an xHCI resume race.
+ */
+static int smu_v14_0_0_set_power_dep(struct smu_context *smu, bool enable)
+{
+ struct amdgpu_device *adev = smu->adev;
+ struct pci_dev *gpu_pdev = adev->pdev;
+ struct pci_dev *root_port, *usb_pdev = NULL;
+ struct device_link *link;
+
+ if (!enable) {
+ if (smu->usb_power_link) {
+ device_link_del(smu->usb_power_link);
+ smu->usb_power_link = NULL;
+ }
+ return 0;
+ }
+
+ root_port = pcie_find_root_port(gpu_pdev);
+ while ((usb_pdev = pci_get_class(PCI_CLASS_SERIAL_USB_XHCI, usb_pdev))) {
+ struct pci_dev *usb_root;
+
+ usb_root = pcie_find_root_port(usb_pdev);
+ if (usb_root != root_port)
+ continue;
+
+ /* Create device link: USB (consumer) depends on GPU (supplier) */
+ link = device_link_add(&usb_pdev->dev, &gpu_pdev->dev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
+ if (link) {
+ smu->usb_power_link = link;
+ drm_info(adev_to_drm(adev), "USB controller %s D0 power state depends on %s\n",
+ pci_name(usb_pdev), pci_name(gpu_pdev));
+ /* Only create one link for the first USB controller found */
+ break;
+ }
+ }
+
+ pci_dev_put(usb_pdev);
+
+ return 0;
+}
+
static const struct pptable_funcs smu_v14_0_0_ppt_funcs = {
.check_fw_status = smu_v14_0_check_fw_status,
.check_fw_version = smu_v14_0_check_fw_version,
@@ -1699,6 +1743,7 @@ static const struct pptable_funcs smu_v14_0_0_ppt_funcs = {
.dpm_set_umsch_mm_enable = smu_v14_0_0_set_umsch_mm_enable,
.get_dpm_clock_table = smu_v14_0_common_get_dpm_table,
.set_mall_enable = smu_v14_0_common_set_mall_enable,
+ .set_power_dep = smu_v14_0_0_set_power_dep,
};
static void smu_v14_0_0_set_smu_mailbox_registers(struct smu_context *smu)
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 08/52] iavf: iavf_virtchnl_completion: drop duplicate ether_addr_equal() test
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (6 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 07/52] drm/amd: Create a device link between APU display and XHCI devices Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 09/52] iavf: send MAC change request synchronously Greg Kroah-Hartman
` (44 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Corinna Vinschen,
Aleksandr Loktionov, Rafal Romanowski, Tony Nguyen,
Jakub Kicinski, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Corinna Vinschen <vinschen@redhat.com>
[ Upstream commit 8538aaea10e141457bcb13d51b0d278c697c422a ]
This is just a simple cleanup fix. Commit 35a2443d0910f ("iavf: Add
waiting for response from PF in set mac") introduced a duplicate
ether_addr_equal() check, so the current code tests the new MAC twice
against the former MAC.
Remove the outer ether_addr_equal() test, remnant of commit c5c922b3e09b
("iavf: fix MAC address setting for VFs when filter is rejected")
Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Link: https://patch.msgid.link/20260609213559.178657-4-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 436729a56dd4 ("iavf: send MAC change request synchronously")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index f1a01b8e2235c..ad906baa759d5 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -2546,13 +2546,11 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
case VIRTCHNL_OP_ADD_ETH_ADDR:
if (!v_retval)
iavf_mac_add_ok(adapter);
- if (!ether_addr_equal(netdev->dev_addr, adapter->hw.mac.addr))
- if (!ether_addr_equal(netdev->dev_addr,
- adapter->hw.mac.addr)) {
- netif_addr_lock_bh(netdev);
- eth_hw_addr_set(netdev, adapter->hw.mac.addr);
- netif_addr_unlock_bh(netdev);
- }
+ if (!ether_addr_equal(netdev->dev_addr, adapter->hw.mac.addr)) {
+ netif_addr_lock_bh(netdev);
+ eth_hw_addr_set(netdev, adapter->hw.mac.addr);
+ netif_addr_unlock_bh(netdev);
+ }
wake_up(&adapter->vc_waitqueue);
break;
case VIRTCHNL_OP_GET_STATS: {
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 09/52] iavf: send MAC change request synchronously
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (7 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 08/52] iavf: iavf_virtchnl_completion: drop duplicate ether_addr_equal() test Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 10/52] mm/mremap: fix locked_vm leak by splitting VMA for MREMAP_DONTUNMAP Greg Kroah-Hartman
` (43 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jose Ignacio Tornos Martinez,
Przemek Kitszel, Rafal Romanowski, Tony Nguyen, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
[ Upstream commit 436729a56dd4dac611d10b569c5359d2cf705b19 ]
After commit ad7c7b2172c3 ("net: hold netdev instance lock during sysfs
operations"), iavf_set_mac() is called with the netdev instance lock
already held.
The function queues a MAC address change request via
iavf_replace_primary_mac() and then waits for completion. However, in
the current flow, the actual virtchnl message is sent by the watchdog
task, which also needs to acquire the netdev lock to run. Additionally,
the adminq_task which processes virtchnl responses also needs the netdev
lock.
This creates a deadlock scenario:
1. iavf_set_mac() holds netdev lock and waits for MAC change
2. Watchdog needs netdev lock to send the request -> blocked
3. Even if request is sent, adminq_task needs netdev lock to process
PF response -> blocked
4. MAC change times out after 2.5 seconds
5. iavf_set_mac() returns -EAGAIN
This particularly affects VFs during bonding setup when multiple VFs are
enslaved in quick succession.
Fix by implementing a synchronous MAC change operation similar to the
approach used in commit fdadbf6e84c4 ("iavf: fix incorrect reset handling
in callbacks").
The solution:
1. Send the virtchnl ADD_ETH_ADDR message directly (not via watchdog)
2. Poll the admin queue hardware directly for responses
3. Process all received messages (including non-MAC messages)
4. Return when MAC change completes or times out
A new generic function iavf_poll_virtchnl_response() is introduced that
can be reused for any future synchronous virtchnl operations. It takes a
callback to check completion, allowing flexible condition checking.
This allows the operation to complete synchronously while holding
netdev_lock, without relying on watchdog or adminq_task. The function
can sleep for up to 2.5 seconds polling hardware, but this is acceptable
since netdev_lock is per-device and only serializes operations on the
same interface.
To support this, change iavf_add_ether_addrs() to return an error code
instead of void, allowing callers to detect failures. Additionally,
export iavf_mac_add_reject() to enable proper rollback on local failures
(timeouts, send errors) - PF rejections are already handled automatically
by iavf_virtchnl_completion().
Remove vc_waitqueue entirely because iavf_set_mac was the only waiter on
this waitqueue and after the changes it is not needed.
Fixes: ad7c7b2172c3 ("net: hold netdev instance lock during sysfs operations")
cc: stable@vger.kernel.org
Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/iavf/iavf.h | 11 ++-
drivers/net/ethernet/intel/iavf/iavf_main.c | 85 ++++++++++++----
.../net/ethernet/intel/iavf/iavf_virtchnl.c | 99 +++++++++++++++++--
3 files changed, 165 insertions(+), 30 deletions(-)
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index 050f8241ef5e6..5fcbfa0ca8553 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -259,7 +259,6 @@ struct iavf_adapter {
struct work_struct adminq_task;
struct work_struct finish_config;
wait_queue_head_t down_waitqueue;
- wait_queue_head_t vc_waitqueue;
struct iavf_q_vector *q_vectors;
struct list_head vlan_filter_list;
int num_vlan_filters;
@@ -588,8 +587,9 @@ void iavf_configure_queues(struct iavf_adapter *adapter);
void iavf_enable_queues(struct iavf_adapter *adapter);
void iavf_disable_queues(struct iavf_adapter *adapter);
void iavf_map_queues(struct iavf_adapter *adapter);
-void iavf_add_ether_addrs(struct iavf_adapter *adapter);
+int iavf_add_ether_addrs(struct iavf_adapter *adapter);
void iavf_del_ether_addrs(struct iavf_adapter *adapter);
+void iavf_mac_add_reject(struct iavf_adapter *adapter);
void iavf_add_vlans(struct iavf_adapter *adapter);
void iavf_del_vlans(struct iavf_adapter *adapter);
void iavf_set_promiscuous(struct iavf_adapter *adapter);
@@ -606,6 +606,13 @@ void iavf_disable_vlan_stripping(struct iavf_adapter *adapter);
void iavf_virtchnl_completion(struct iavf_adapter *adapter,
enum virtchnl_ops v_opcode,
enum iavf_status v_retval, u8 *msg, u16 msglen);
+int iavf_poll_virtchnl_response(struct iavf_adapter *adapter,
+ struct iavf_arq_event_info *event,
+ bool (*condition)(struct iavf_adapter *adapter,
+ const void *data,
+ enum virtchnl_ops v_op),
+ const void *cond_data,
+ unsigned int timeout_ms);
int iavf_config_rss(struct iavf_adapter *adapter);
void iavf_cfg_queues_bw(struct iavf_adapter *adapter);
void iavf_cfg_queues_quanta_size(struct iavf_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index d09add9a110ea..0c99e3909952e 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -1029,6 +1029,60 @@ static bool iavf_is_mac_set_handled(struct net_device *netdev,
return ret;
}
+/**
+ * iavf_mac_change_done - Check if MAC change completed
+ * @adapter: board private structure
+ * @data: MAC address being checked (as const void *)
+ * @v_op: virtchnl opcode from processed message
+ *
+ * Callback for iavf_poll_virtchnl_response() to check if MAC change completed.
+ *
+ * Return: true if MAC change completed, false otherwise
+ */
+static bool iavf_mac_change_done(struct iavf_adapter *adapter,
+ const void *data, enum virtchnl_ops v_op)
+{
+ const u8 *addr = data;
+
+ return iavf_is_mac_set_handled(adapter->netdev, addr);
+}
+
+/**
+ * iavf_set_mac_sync - Synchronously change MAC address
+ * @adapter: board private structure
+ * @addr: MAC address to set
+ *
+ * Send MAC change request to PF and poll admin queue for response.
+ * Caller must hold netdev_lock. This can sleep for up to 2.5 seconds.
+ * Event buffer is allocated before sending to avoid state mismatch if
+ * allocation fails after message is sent to PF.
+ *
+ * Return: 0 on success, negative on failure
+ */
+static int iavf_set_mac_sync(struct iavf_adapter *adapter, const u8 *addr)
+{
+ struct iavf_arq_event_info event;
+ int ret;
+
+ netdev_assert_locked(adapter->netdev);
+
+ event.buf_len = IAVF_MAX_AQ_BUF_SIZE;
+ event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
+ if (!event.msg_buf)
+ return -ENOMEM;
+
+ ret = iavf_add_ether_addrs(adapter);
+ if (ret)
+ goto out;
+
+ ret = iavf_poll_virtchnl_response(adapter, &event,
+ iavf_mac_change_done, addr, 2500);
+
+out:
+ kfree(event.msg_buf);
+ return ret;
+}
+
/**
* iavf_set_mac - NDO callback to set port MAC address
* @netdev: network interface device structure
@@ -1046,25 +1100,23 @@ static int iavf_set_mac(struct net_device *netdev, void *p)
return -EADDRNOTAVAIL;
ret = iavf_replace_primary_mac(adapter, addr->sa_data);
-
if (ret)
return ret;
- ret = wait_event_interruptible_timeout(adapter->vc_waitqueue,
- iavf_is_mac_set_handled(netdev, addr->sa_data),
- msecs_to_jiffies(2500));
-
- /* If ret < 0 then it means wait was interrupted.
- * If ret == 0 then it means we got a timeout.
- * else it means we got response for set MAC from PF,
- * check if netdev MAC was updated to requested MAC,
- * if yes then set MAC succeeded otherwise it failed return -EACCES
- */
- if (ret < 0)
+ ret = iavf_set_mac_sync(adapter, addr->sa_data);
+ if (ret) {
+ /* Rollback only if send failed (message never reached PF).
+ * Don't rollback on timeout (-EAGAIN) because the message was
+ * sent and PF will eventually respond. When the response arrives,
+ * iavf_virtchnl_completion() will handle rollback (on PF error)
+ * or acceptance (on PF success) automatically.
+ */
+ if (ret != -EAGAIN) {
+ iavf_mac_add_reject(adapter);
+ ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
+ }
return ret;
-
- if (!ret)
- return -EAGAIN;
+ }
if (!ether_addr_equal(netdev->dev_addr, addr->sa_data))
return -EACCES;
@@ -5388,9 +5440,6 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Setup the wait queue for indicating transition to down status */
init_waitqueue_head(&adapter->down_waitqueue);
- /* Setup the wait queue for indicating virtchannel events */
- init_waitqueue_head(&adapter->vc_waitqueue);
-
INIT_LIST_HEAD(&adapter->ptp.aq_cmds);
init_waitqueue_head(&adapter->ptp.phc_time_waitqueue);
mutex_init(&adapter->ptp.aq_cmd_lock);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index ad906baa759d5..6cf963b9c9109 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#include <linux/net/intel/libie/rx.h>
+#include <net/netdev_lock.h>
#include "iavf.h"
#include "iavf_ptp.h"
@@ -555,20 +556,23 @@ iavf_set_mac_addr_type(struct virtchnl_ether_addr *virtchnl_ether_addr,
* @adapter: adapter structure
*
* Request that the PF add one or more addresses to our filters.
- **/
-void iavf_add_ether_addrs(struct iavf_adapter *adapter)
+ *
+ * Return: 0 on success, negative on failure
+ */
+int iavf_add_ether_addrs(struct iavf_adapter *adapter)
{
struct virtchnl_ether_addr_list *veal;
struct iavf_mac_filter *f;
int i = 0, count = 0;
bool more = false;
size_t len;
+ int ret;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
dev_err(&adapter->pdev->dev, "Cannot add filters, command %d pending\n",
adapter->current_op);
- return;
+ return -EBUSY;
}
spin_lock_bh(&adapter->mac_vlan_list_lock);
@@ -580,7 +584,7 @@ void iavf_add_ether_addrs(struct iavf_adapter *adapter)
if (!count) {
adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_MAC_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- return;
+ return 0;
}
adapter->current_op = VIRTCHNL_OP_ADD_ETH_ADDR;
@@ -594,8 +598,9 @@ void iavf_add_ether_addrs(struct iavf_adapter *adapter)
veal = kzalloc(len, GFP_ATOMIC);
if (!veal) {
+ adapter->current_op = VIRTCHNL_OP_UNKNOWN;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- return;
+ return -ENOMEM;
}
veal->vsi_id = adapter->vsi_res->vsi_id;
@@ -615,8 +620,15 @@ void iavf_add_ether_addrs(struct iavf_adapter *adapter)
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_ETH_ADDR, (u8 *)veal, len);
+ ret = iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_ETH_ADDR, (u8 *)veal, len);
kfree(veal);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "Unable to send ADD_ETH_ADDR message to PF, error %d\n", ret);
+ adapter->current_op = VIRTCHNL_OP_UNKNOWN;
+ }
+
+ return ret;
}
/**
@@ -712,8 +724,8 @@ static void iavf_mac_add_ok(struct iavf_adapter *adapter)
* @adapter: adapter structure
*
* Remove filters from list based on PF response.
- **/
-static void iavf_mac_add_reject(struct iavf_adapter *adapter)
+ */
+void iavf_mac_add_reject(struct iavf_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct iavf_mac_filter *f, *ftmp;
@@ -2360,7 +2372,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
iavf_mac_add_reject(adapter);
/* restore administratively set MAC address */
ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
- wake_up(&adapter->vc_waitqueue);
break;
case VIRTCHNL_OP_DEL_ETH_ADDR:
dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n",
@@ -2551,7 +2562,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
eth_hw_addr_set(netdev, adapter->hw.mac.addr);
netif_addr_unlock_bh(netdev);
}
- wake_up(&adapter->vc_waitqueue);
break;
case VIRTCHNL_OP_GET_STATS: {
struct iavf_eth_stats *stats =
@@ -2946,3 +2956,72 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
} /* switch v_opcode */
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
}
+
+/**
+ * iavf_poll_virtchnl_response - Poll admin queue for virtchnl response
+ * @adapter: adapter structure
+ * @event: pre-allocated event buffer to use for polling
+ * @condition: callback to check if desired response received
+ * @cond_data: context data passed to condition callback
+ * @timeout_ms: maximum time to wait in milliseconds
+ *
+ * Polls the admin queue and processes all incoming virtchnl messages.
+ * After processing each valid message, calls the condition callback to check
+ * if the expected response has been received. The callback receives the opcode
+ * of the processed message to identify which response was received. Continues
+ * polling until the callback returns true or timeout expires.
+ *
+ * Caller must allocate event buffer before sending any messages to PF to avoid
+ * state mismatch if allocation fails after message is sent.
+ *
+ * Caller must hold netdev_lock. This can sleep for up to timeout_ms while
+ * polling hardware.
+ *
+ * Return: 0 on success (condition met), -EAGAIN on timeout, or error code
+ */
+int iavf_poll_virtchnl_response(struct iavf_adapter *adapter,
+ struct iavf_arq_event_info *event,
+ bool (*condition)(struct iavf_adapter *adapter,
+ const void *data,
+ enum virtchnl_ops v_op),
+ const void *cond_data,
+ unsigned int timeout_ms)
+{
+ struct iavf_hw *hw = &adapter->hw;
+ enum virtchnl_ops received_op;
+ unsigned long timeout;
+ int ret = -EAGAIN;
+ u16 pending = 0;
+ u32 v_retval;
+
+ netdev_assert_locked(adapter->netdev);
+
+ timeout = jiffies + msecs_to_jiffies(timeout_ms);
+ do {
+ if (!pending)
+ usleep_range(50, 75);
+
+ if (iavf_clean_arq_element(hw, event, &pending) == IAVF_SUCCESS) {
+ received_op = (enum virtchnl_ops)le32_to_cpu(event->desc.cookie_high);
+ if (received_op != VIRTCHNL_OP_UNKNOWN) {
+ v_retval = le32_to_cpu(event->desc.cookie_low);
+
+ iavf_virtchnl_completion(adapter, received_op,
+ (enum iavf_status)v_retval,
+ event->msg_buf, event->msg_len);
+
+ if (condition(adapter, cond_data, received_op)) {
+ ret = 0;
+ break;
+ }
+ }
+
+ memset(event->msg_buf, 0, IAVF_MAX_AQ_BUF_SIZE);
+
+ if (pending)
+ continue;
+ }
+ } while (time_before(jiffies, timeout));
+
+ return ret;
+}
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 10/52] mm/mremap: fix locked_vm leak by splitting VMA for MREMAP_DONTUNMAP
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (8 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 09/52] iavf: send MAC change request synchronously Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 11/52] mm/mremap: fix locked_vm leak from MREMAP_DONTUNMAP self-merge Greg Kroah-Hartman
` (42 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lorenzo Stoakes (ARM), Andrew Morton,
Pedro Falcato, Kiryl Shutsemau (Meta), Jose A. Perez de Azpillaga,
Anirudh Srinivasan, Liam R. Howlett, Vlastimil Babka, Jann Horn,
Brian Geffon, Minchan Kim, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes (ARM) <ljs@kernel.org>
[ Upstream commit 597e4b9ab48a3f841080f627722064853d3f650e ]
The MREMAP_DONTUNMAP feature is highly unusual in that it permits mremap()
operations that keep the original VMA in place.
Historically this has led to a lot of bugs where non-obvious interactions
occur between existing mremap() operations and the original VMA.
Fix another of these - partial copies.
The long-standing mremap() partial VMA logic has the baked-in assumption
that the originating VMA is unmapped and thus moved.
However MREMAP_DONTUNMAP defeats this by performing a partial copy
instead since it keeps the source VMA around.
An mremap(..., MREMAP_DONTUNMAP) operation disallows resizing of the VMA,
but the operation can be performed partially:
|-----------------|
| |
| v
<------> <------>
.new_sz. new_sz
|--.------.--| |------|
| .source. | | dest |
|--.------.--| |------|
<------------>
old_sz
The page tables in the specified range are moved, but the original VMA is
kept intact.
This interacts poorly with mlock()'d VMAs, as the VMA_LOCKED_BIT flag is
cleared for the entire source VMA and set for the entire destination VMA.
This results in an mm->locked_vm leak as the change is therefore not
accounted correctly.
The clear solution here is to make the portion of the source VMA which is
mremap()'d distinct from the rest of it, a.k.a. split it.
Therefore resolve this issue by splitting it ahead of the rest of the
mremap() operation if the VMA is mlock()'d.
This is valid, as the source VMA will lose its VMA_LOCKED_BIT flag, so if a
partial remap it will become distinct from the rest of the VMA.
In order to make this change re-expose split_vma() in vma.h for
CONFIG_MMU (nommu doesn't compile mremap.c and uses a static helper
instead).
Finally, update the sys_map_count check to account for this case.
Note that the early check does not use needs_pre_split() - this is because
the VMA has not been looked up by this point, so be conservative and assume
that the VMA is mlock()'d in this case for the purposes of the
sys_map_count check.
Link: https://lore.kernel.org/20260930-fix-dontunmap-partial-self-merge-v2-2-f388985a0f0a@kernel.org
Fixes: e346b3813067 ("mm/mremap: add MREMAP_DONTUNMAP to mremap()")
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>
Tested-by: Anirudh Srinivasan <asrinivasan@oss.tenstorrent.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Brian Geffon <bgeffon@google.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: <stable@vger.kernel.org>
[ sashal: adapted newer VMA and map-count helpers to direct flag access and existing map-count checks. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/mremap.c | 31 +++++++++++++++++++++++--------
mm/vma.c | 4 ++--
mm/vma.h | 5 +++++
3 files changed, 30 insertions(+), 10 deletions(-)
diff --git a/mm/mremap.c b/mm/mremap.c
index e60a63a36ea0b..5d1322dca0359 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -1025,8 +1025,8 @@ static void vrm_stat_account(struct vma_remap_struct *vrm,
}
/*
- * Perform checks before attempting to write a VMA prior to it being
- * moved.
+ * Perform checks and preparation before attempting to write a VMA prior to it
+ * being moved.
*/
static unsigned long prep_move_vma(struct vma_remap_struct *vrm)
{
@@ -1035,18 +1035,17 @@ static unsigned long prep_move_vma(struct vma_remap_struct *vrm)
unsigned long old_addr = vrm->addr;
unsigned long old_len = vrm->old_len;
vm_flags_t dummy = vma->vm_flags;
+ const bool split_before = vma->vm_start != old_addr;
+ const bool split_after = vma->vm_end != old_addr + old_len;
- /*
- * We'd prefer to avoid failure later on in do_munmap:
- * which may split one vma into three before unmapping.
- */
+ /* Avoid failure later on. */
if (current->mm->map_count >= sysctl_max_map_count - 3)
return -ENOMEM;
if (vma->vm_ops && vma->vm_ops->may_split) {
- if (vma->vm_start != old_addr)
+ if (split_before)
err = vma->vm_ops->may_split(vma, old_addr);
- if (!err && vma->vm_end != old_addr + old_len)
+ if (!err && split_after)
err = vma->vm_ops->may_split(vma, old_addr + old_len);
if (err)
return err;
@@ -1064,6 +1063,22 @@ static unsigned long prep_move_vma(struct vma_remap_struct *vrm)
if (err)
return err;
+ /*
+ * To account mlock()'d pages correctly in the MREMAP_DONTUNMAP
+ * case perform any split ahead of time for an mlock()'d VMA.
+ */
+ if ((vrm->flags & MREMAP_DONTUNMAP) &&
+ (vma->vm_flags & VM_LOCKED)) {
+ VMA_ITERATOR(vmi, vma->vm_mm, old_addr);
+
+ if (split_before)
+ err = split_vma(&vmi, vma, old_addr, 1);
+ if (!err && split_after)
+ err = split_vma(&vmi, vma, old_addr + old_len, 0);
+ vrm->vmi_needs_invalidate = true;
+ return err;
+ }
+
return 0;
}
diff --git a/mm/vma.c b/mm/vma.c
index d1158fdcde287..fd7e968ad707f 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -584,8 +584,8 @@ __split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
* Split a vma into two pieces at address 'addr', a new vma is allocated
* either for the first part or the tail.
*/
-static int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
- unsigned long addr, int new_below)
+int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
+ unsigned long addr, int new_below)
{
if (vma->vm_mm->map_count >= sysctl_max_map_count)
return -ENOMEM;
diff --git a/mm/vma.h b/mm/vma.h
index 4c7ea8b893ab7..5534216cea4d1 100644
--- a/mm/vma.h
+++ b/mm/vma.h
@@ -409,6 +409,11 @@ int do_brk_flags(struct vma_iterator *vmi, struct vm_area_struct *brkvma,
unsigned long unmapped_area(struct vm_unmapped_area_info *info);
unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info);
+#ifdef CONFIG_MMU
+int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
+ unsigned long addr, int new_below);
+#endif
+
static inline bool vma_wants_manual_pte_write_upgrade(struct vm_area_struct *vma)
{
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 11/52] mm/mremap: fix locked_vm leak from MREMAP_DONTUNMAP self-merge
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (9 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 10/52] mm/mremap: fix locked_vm leak by splitting VMA for MREMAP_DONTUNMAP Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 12/52] nfsd: fix all-zero stateid in CB_OFFLOAD for async COPY Greg Kroah-Hartman
` (41 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lorenzo Stoakes (ARM), Andrew Morton,
Pedro Falcato, Kiryl Shutsemau (Meta), Jose A. Perez de Azpillaga,
Anirudh Srinivasan, Liam R. Howlett, Vlastimil Babka, Jann Horn,
Brian Geffon, Minchan Kim, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes (ARM) <ljs@kernel.org>
[ Upstream commit 838bb60dc21553e32df90f2f3bac5b905376e7aa ]
Patch series "mm/mremap: fix two issues with MREMAP_DONTUNMAP", v2.
The MREMAP_DONTUNMAP feature is highly unusual in that it permits mremap()
operations that keep the original VMA in place.
Historically this has led to a lot of bugs where non-obvious interactions
occur between existing mremap() operations and the original VMA.
Commit 397432cab17b ("mm/mremap: account mm->locked_vm correctly for
MREMAP_DONTUNMAP") fixed an accidentally introduced bug around
mm->locked_vm accounting, but this wasn't the only issue.
And thus history repeats itself, as it turns out that mm->locked_vm
accounting is broken by MREMAP_DONTUNMAP yet again by two further cases,
and has been broken ever since the feature was introduced.
Both relate to the fact that VMA_LOCKED_BIT is cleared on the source VMA
(it has to be as all page tables are moved):
1. If an unfaulted VMA_LOCKONFAULT_BIT anonymous VMA self-merges it
clears the VMA_LOCKED_BIT flag and permanently leaks mm->locked_vm
pages.
2. If a partial mremap() is performed on a locked VMA there is a leak equal
to the number of pages not copied.
(Both for MREMAP_DONTUNMAP operations only)
Both issues can be fixed by treating the source range as distinct from the
destination range, which is the definition of what MREMAP_DONTUNMAP does
so is appropriate.
In case 1, simply disallow the self-merge, keeping adjacent source and
destination VMAs distinct.
In case 2, split the source range ahead of time if the VMA is mlock()'d,
so accounting is always correct.
Both changes were tested locally and confirmed to fix the issues.
For the purposes of a backport, the fixes are kept distinct, a follow-up
series can add self-tests.
This patch (of 2):
The MREMAP_DONTUNMAP feature is highly unusual in that it permits mremap()
operations that keep the original VMA in place.
Historically this has led to a lot of bugs where non-obvious interactions
occur between existing mremap() operations and the original VMA.
Fix another of these - self-merge.
Self-merge occurs when a VMA is moved in front of or behind itself and the
attributes of the VMA permit such a merge.
Practically this can only happen for unfaulted anonymous VMAs due to the
page offset equality requirement for merge:
|------------|
| |
| v
|...........||-----------||...........|
| || unfaulted || |
|...........||-----------||...........|
^ |
| |
|------------|
This becomes problematic if the VMA is configured by the user to
mlock-on-fault, i.e. the VMA_LOCKED_BIT, VMA_LOCKONFAULT_BIT VMA flags are
set.
MREMAP_DONTUNMAP clears mlock flags for the source VMA and maintains them
for the destination VMA.
Self-merge makes this impossible (there is only one VMA) and incorrectly
clears the destination VMA's mlock flags.
This causes a leak in mm->locked_vm as clearing this flag does not
decrement the counter and the VMA no longer has VMA_LOCKED_BIT set so it
is not decremented on unmap.
Resolve this by simply disallowing a self-merge in this case - the source
and destination VMAs are kept distinct and then are able to have distinct
mlock() flags.
Update dontunmap_complete() to make the now-redundant self-merge check a
VM_WARN_ON_ONCE() instead to guard against future regressions.
Also update the VMA userland tests to reflect the change.
Link: https://lore.kernel.org/20260930-fix-dontunmap-partial-self-merge-v2-0-f388985a0f0a@kernel.org
Link: https://lore.kernel.org/20260930-fix-dontunmap-partial-self-merge-v2-1-f388985a0f0a@kernel.org
Fixes: e346b3813067 ("mm/mremap: add MREMAP_DONTUNMAP to mremap()")
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>
Tested-by: Anirudh Srinivasan <asrinivasan@oss.tenstorrent.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Brian Geffon <bgeffon@google.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: <stable@vger.kernel.org>
[ sashal: Translated can_self_merge logic to the inverse faulted_in_anon_vma flag. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/mremap.c | 7 +++++--
mm/vma.c | 17 ++++++++++++++++-
mm/vma.h | 2 +-
tools/testing/vma/vma.c | 4 ++--
4 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/mm/mremap.c b/mm/mremap.c
index 5d1322dca0359..f0e63d3b3c148 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -1206,7 +1206,7 @@ static int copy_vma_and_data(struct vma_remap_struct *vrm,
PAGETABLE_MOVE(pmc, NULL, NULL, vrm->addr, vrm->new_addr, vrm->old_len);
new_vma = copy_vma(&vma, vrm->new_addr, vrm->new_len, new_pgoff,
- &pmc.need_rmap_locks);
+ &pmc.need_rmap_locks, vrm->flags & MREMAP_DONTUNMAP);
if (!new_vma) {
vrm_uncharge(vrm);
*new_vma_ptr = NULL;
@@ -1266,6 +1266,9 @@ static void dontunmap_complete(struct vma_remap_struct *vrm,
unsigned long old_start = vma->vm_start;
unsigned long old_end = vma->vm_end;
+ /* Self-merge is disallowed. */
+ VM_WARN_ON_ONCE(new_vma == vma);
+
/* We always clear VM_LOCKED[ONFAULT] on the old VMA. */
vm_flags_clear(vma, VM_LOCKED_MASK);
@@ -1273,7 +1276,7 @@ static void dontunmap_complete(struct vma_remap_struct *vrm,
* anon_vma links of the old vma is no longer needed after its page
* table has been moved.
*/
- if (new_vma != vma && start == old_start && end == old_end) {
+ if (start == old_start && end == old_end) {
const pgoff_t pgoff_unfaulted = vma->vm_start >> PAGE_SHIFT;
unlink_anon_vmas(vma);
diff --git a/mm/vma.c b/mm/vma.c
index fd7e968ad707f..d1627a8ef32b1 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -1852,7 +1852,7 @@ int vma_link(struct mm_struct *mm, struct vm_area_struct *vma)
*/
struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
unsigned long addr, unsigned long len, pgoff_t pgoff,
- bool *need_rmap_locks)
+ bool *need_rmap_locks, bool keep_source)
{
struct vm_area_struct *vma = *vmap;
unsigned long vma_start = vma->vm_start;
@@ -1885,6 +1885,21 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
vmg.pgoff = pgoff;
vmg.next = vma_iter_next_rewind(&vmi, NULL);
+
+ /*
+ * If the original VMA is kept (MREMAP_DONTUNMAP), the source and
+ * destination VMA must be treated distinctly.
+ *
+ * A merge violates this, so in this case disallow a self-merge.
+ */
+ if (!faulted_in_anon_vma && keep_source) {
+ if (vmg.prev == vma)
+ vmg.prev = NULL;
+ if (vmg.next == vma)
+ vmg.next = NULL;
+ faulted_in_anon_vma = true;
+ }
+
new_vma = vma_merge_copied_range(&vmg);
if (new_vma) {
diff --git a/mm/vma.h b/mm/vma.h
index 5534216cea4d1..ab6e5ff4633f2 100644
--- a/mm/vma.h
+++ b/mm/vma.h
@@ -389,7 +389,7 @@ int vma_link(struct mm_struct *mm, struct vm_area_struct *vma);
struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
unsigned long addr, unsigned long len, pgoff_t pgoff,
- bool *need_rmap_locks);
+ bool *need_rmap_locks, bool keep_source);
struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *vma);
diff --git a/tools/testing/vma/vma.c b/tools/testing/vma/vma.c
index fd37ce3b26280..db580c5d21515 100644
--- a/tools/testing/vma/vma.c
+++ b/tools/testing/vma/vma.c
@@ -1558,7 +1558,7 @@ static bool test_copy_vma(void)
/* Move backwards and do not merge. */
vma = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, vm_flags);
- vma_new = copy_vma(&vma, 0, 0x2000, 0, &need_locks);
+ vma_new = copy_vma(&vma, 0, 0x2000, 0, &need_locks, false);
ASSERT_NE(vma_new, vma);
ASSERT_EQ(vma_new->vm_start, 0);
ASSERT_EQ(vma_new->vm_end, 0x2000);
@@ -1571,7 +1571,7 @@ static bool test_copy_vma(void)
vma = alloc_and_link_vma(&mm, 0, 0x2000, 0, vm_flags);
vma_next = alloc_and_link_vma(&mm, 0x6000, 0x8000, 6, vm_flags);
- vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks);
+ vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks, false);
vma_assert_attached(vma_new);
ASSERT_EQ(vma_new, vma_next);
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 12/52] nfsd: fix all-zero stateid in CB_OFFLOAD for async COPY
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (10 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 11/52] mm/mremap: fix locked_vm leak from MREMAP_DONTUNMAP self-merge Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 13/52] wifi: mt76: connac: tolerate inactive BSS deactivation Greg Kroah-Hartman
` (40 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Lubos Rendek, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lubos Rendek <l.rendek@proxmox.com>
[ There is no upstream commit: this fixes the 6.18.y backport of
d0beaee498e1. Mainline fixed the problem as part of the async COPY
rework in commit f307b4f7ed17 ("nfsd: split nfsd4_copy into transient
and durable async copy objects"), which is too risky to backport. ]
Since commit 9b4e5e9ba5ae ("nfsd: fix stale s2s_cp_stateids IDR entry
for async COPY"), nfsd4_copy() calls dup_copy_fields() before the copy
stateid is created and then writes the new stateid only into the COPY
result. The async copy's own cp_res.cb_stateid stays zero, so
nfsd4_send_cb_offload() sends CB_OFFLOAD with an all-zero stateid. The
client cannot match it to its pending COPY and waits forever in
nfs42_proc_copy().
Also copy the new stateid into async_copy->cp_res.cb_stateid. Calling
dup_copy_fields() after nfs4_init_copy_state() instead is not an
option, because dup_copy_fields() also copies cp_stateid and would
overwrite the stateid that the backport moved to the async copy.
Tested on 6.18.56 with an NFSv4.2 server-side COPY between two
exports: with this change the copy completes and CB_OFFLOAD carries
the same stateid as the COPY reply. Without it, cp(1) hangs on
6.18.55; the affected code in nfsd4_copy() is the same in 6.18.56.
Fixes: 9b4e5e9ba5ae ("nfsd: fix stale s2s_cp_stateids IDR entry for async COPY")
Closes: https://lore.kernel.org/stable/7cc824c4-632d-49df-ae5e-cfcbb5bf76ad@proxmox.com/
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Lubos Rendek <l.rendek@proxmox.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfs4proc.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 898aaeea2059a..864eebb1f0760 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -2084,6 +2084,8 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out_dec_async_copy_err;
memcpy(&result->cb_stateid, &async_copy->cp_stateid.cs_stid,
sizeof(result->cb_stateid));
+ memcpy(&async_copy->cp_res.cb_stateid, &async_copy->cp_stateid.cs_stid,
+ sizeof(async_copy->cp_res.cb_stateid));
if ((READ_ONCE(copy->nf_dst->nf_file->f_mode) &
FMODE_NOCMTIME) != 0)
async_copy->attr_update = true;
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 13/52] wifi: mt76: connac: tolerate inactive BSS deactivation
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (11 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 12/52] nfsd: fix all-zero stateid in CB_OFFLOAD for async COPY Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 14/52] dm-integrity: fix NULL pointer dereference when the R flag is used Greg Kroah-Hartman
` (39 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Sean Wang, Felix Fietkau,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Wang <sean.wang@mediatek.com>
[ Upstream commit 04222f980301561edd77917edac570b1393ec45d ]
Firmware may return wlan_failure when deactivating a BSS that is already
inactive. This is a valid teardown case and should not fail the remove
path.
Keep activation failures unchanged since they still indicate that firmware
failed to create or activate the BSS state.
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Link: https://patch.msgid.link/20260425195011.790265-13-sean.wang@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../wireless/mediatek/mt76/mt76_connac_mcu.c | 9 +++++++-
.../wireless/mediatek/mt76/mt76_connac_mcu.h | 23 +++++++++++++++++++
.../net/wireless/mediatek/mt76/mt7925/mcu.c | 6 +++--
3 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index 46e337307c3d8..569b94b48926e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -1226,6 +1226,9 @@ int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy,
len = enable ? sizeof(dev_req) : sizeof(basic_req);
err = mt76_mcu_send_msg(dev, cmd, data, len, true);
+ if (err && cmd == MCU_UNI_CMD(BSS_INFO_UPDATE))
+ err = mt76_connac_mcu_bss_deact_err(dev, err, enable);
+
if (err < 0)
return err;
@@ -1233,7 +1236,11 @@ int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy,
data = enable ? (void *)&basic_req : (void *)&dev_req;
len = enable ? sizeof(basic_req) : sizeof(dev_req);
- return mt76_mcu_send_msg(dev, cmd, data, len, true);
+ err = mt76_mcu_send_msg(dev, cmd, data, len, true);
+ if (err && cmd == MCU_UNI_CMD(BSS_INFO_UPDATE))
+ err = mt76_connac_mcu_bss_deact_err(dev, err, enable);
+
+ return err;
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index 5ed2fffbe1074..a24979698a8d1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -1894,6 +1894,29 @@ mt76_connac_mcu_get_wlan_idx(struct mt76_dev *dev, struct mt76_wcid *wcid,
}
}
+#define MT76_CONNAC_MCU_STATUS_WLAN_FAILURE 0xc0000001
+
+static inline int
+mt76_connac_mcu_bss_deact_err(struct mt76_dev *mdev, int err, bool enable)
+{
+ if (err != (int)MT76_CONNAC_MCU_STATUS_WLAN_FAILURE)
+ return err;
+
+ /* Ignore wlan_failure state false alarm when deactivating an
+ * inactive network. It does not harm the firmware state.
+ */
+ if (!enable) {
+ dev_dbg(mdev->dev,
+ "ignore wlan_failure when bss is deactivated\n");
+ return 0;
+ }
+
+ dev_warn(mdev->dev,
+ "wlan_failure when bss is activated\n");
+
+ return err;
+}
+
struct sk_buff *
__mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif_link *mvif,
struct mt76_wcid *wcid, int len);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 8b1e1d2ed2546..75f105d224ed5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -2848,6 +2848,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
struct mt792x_dev *dev = phy->dev;
struct mt792x_link_sta *mlink_bc;
struct sk_buff *skb;
+ int err;
skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76,
MT7925_BSS_UPDATE_MAX_SIZE);
@@ -2875,8 +2876,9 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
mt7925_mcu_bss_mbssid_tlv(skb, link_conf, enable);
}
- return mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_UNI_CMD(BSS_INFO_UPDATE), true);
+ err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_UNI_CMD(BSS_INFO_UPDATE), true);
+ return mt76_connac_mcu_bss_deact_err(&dev->mt76, err, enable);
}
int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable)
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 14/52] dm-integrity: fix NULL pointer dereference when the R flag is used
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (12 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 13/52] wifi: mt76: connac: tolerate inactive BSS deactivation Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 15/52] dm-integrity: validate the superblock on resume Greg Kroah-Hartman
` (38 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Mikulas Patocka, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <mpatocka@redhat.com>
[ Upstream commit 7d4d4f3b668d708d94f62ecdd33ac330a6fd8a84 ]
If the dm-integrity device has the SB_FLAG_DIRTY_BITMAP flag set and the
user activates the device in the 'R' mode, a crash in dm_integrity_resume
happens because the function attempts to read the journal containing the
bitmap.
This patch makes dm-integrity skip any writes to the device in
dm_integrity_resume if the device is activated in the 'R' mode.
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Fixes: 468dfca38b1a ("dm integrity: add a bitmap mode")
Cc: stable@vger.kernel.org
Stable-dep-of: fc79aeb86a2c ("dm-integrity: validate the superblock on resume")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/dm-integrity.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index 415e763041bd2..5ad2b85cef049 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -3873,6 +3873,10 @@ static void dm_integrity_resume(struct dm_target *ti)
r = sync_rw_sb(ic, REQ_OP_READ);
if (r)
dm_integrity_io_error(ic, "reading superblock", r);
+
+ if (ic->mode == 'R')
+ goto skip_writes;
+
if ((ic->sb->flags & flags) != flags) {
ic->sb->flags |= flags;
r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA);
@@ -3982,6 +3986,7 @@ static void dm_integrity_resume(struct dm_target *ti)
}
}
+skip_writes:
ic->reboot_notifier.notifier_call = dm_integrity_reboot;
ic->reboot_notifier.next = NULL;
ic->reboot_notifier.priority = INT_MAX - 1; /* be notified after md and before hardware drivers */
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 15/52] dm-integrity: validate the superblock on resume
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (13 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 14/52] dm-integrity: fix NULL pointer dereference when the R flag is used Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 16/52] sched_ext: Fix CPU hotplug hang when a dying CPUs tasks sit in the BPF scheduler Greg Kroah-Hartman
` (37 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+675c91651049ad042c5f,
Mikulas Patocka, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <mpatocka@redhat.com>
[ Upstream commit fc79aeb86a2c244c1f1894e2d8f2966fe2b60fa2 ]
dm_integrity_resume() re-reads the superblock from the device so that it
picks up the flags and the recalculate position. It performs no
validation on the result, while the constructor validates the superblock
it reads and sizes all the in-memory structures according to it. The user
may modify the superblock on the underlying device while the dm-integrity
device is suspended, so that the two no longer agree.
In particular, access_journal_data() shifts the journal entry index by
ic->sb->log2_sectors_per_block, while ic->journal_section_sectors and the
journal page list were computed with the value that was present at
constructor time. Increasing log2_sectors_per_block makes the index run
past the end of the journal, and dm-integrity then writes 512 bytes
through lowmem_page_address(NULL).
Snapshot the validated superblock in the constructor and refuse to resume
if any of the fields that describe the on-disk geometry changed.
Reported-by: syzbot+675c91651049ad042c5f@syzkaller.appspotmail.com
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Cc: stable@vger.kernel.org
Fixes: 118ba36e446c ("dm-integrity: fix recalculation in bitmap mode")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/dm-integrity.c | 50 +++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index 5ad2b85cef049..24d2e76c21a9a 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -179,6 +179,7 @@ struct dm_integrity_c {
struct dm_bufio_client *bufio;
struct workqueue_struct *metadata_wq;
struct superblock *sb;
+ struct superblock *sb_copy;
unsigned int journal_pages;
unsigned int n_bitmap_blocks;
@@ -3856,6 +3857,35 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
ic->journal_uptodate = true;
}
+/*
+ * The superblock is re-read from the device on every resume, so that we pick
+ * up the flags and the recalculate position. The geometry described by the
+ * superblock must not change though - the in-memory structures (and the
+ * journal in particular) were sized according to the superblock that was
+ * validated in the constructor. Reject a superblock that was modified behind
+ * our back.
+ *
+ * Only the fields that the driver never rewrites may be tested here. In
+ * particular, "version" is recalculated by sb_set_version on every superblock
+ * write and it depends on SB_FLAG_RECALCULATING and SB_FLAG_DIRTY_BITMAP, and
+ * SB_FLAG_DISCARD_KEYED may be set by dm_integrity_resume itself.
+ */
+static bool superblock_changed(struct dm_integrity_c *ic)
+{
+ const __le32 immutable_flags = cpu_to_le32(SB_FLAG_HAVE_JOURNAL_MAC |
+ SB_FLAG_FIXED_PADDING |
+ SB_FLAG_FIXED_HMAC |
+ SB_FLAG_INLINE);
+
+ return memcmp(ic->sb->magic, ic->sb_copy->magic, sizeof(ic->sb->magic)) != 0 ||
+ ic->sb->log2_interleave_sectors != ic->sb_copy->log2_interleave_sectors ||
+ ic->sb->integrity_tag_size != ic->sb_copy->integrity_tag_size ||
+ ic->sb->journal_sections != ic->sb_copy->journal_sections ||
+ ic->sb->log2_sectors_per_block != ic->sb_copy->log2_sectors_per_block ||
+ ((ic->sb->flags ^ ic->sb_copy->flags) & immutable_flags) != 0 ||
+ memcmp(ic->sb->salt, ic->sb_copy->salt, SALT_SIZE) != 0;
+}
+
static void dm_integrity_resume(struct dm_target *ti)
{
struct dm_integrity_c *ic = ti->private;
@@ -3874,6 +3904,18 @@ static void dm_integrity_resume(struct dm_target *ti)
if (r)
dm_integrity_io_error(ic, "reading superblock", r);
+ if (unlikely(superblock_changed(ic))) {
+ /*
+ * Restore the superblock that we validated in the constructor,
+ * so that the rest of the driver doesn't operate on values
+ * that don't match the in-memory structures.
+ */
+ memcpy(ic->sb, ic->sb_copy, sizeof(struct superblock));
+ DMERR("The superblock was changed while the device was suspended");
+ dm_integrity_io_error(ic, "superblock check", -EINVAL);
+ goto skip_writes;
+ }
+
if (ic->mode == 'R')
goto skip_writes;
@@ -5411,6 +5453,13 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
ic->just_formatted = true;
}
+ ic->sb_copy = kmemdup(ic->sb, sizeof(struct superblock), GFP_KERNEL);
+ if (!ic->sb_copy) {
+ ti->error = "Cannot allocate superblock copy";
+ r = -ENOMEM;
+ goto bad;
+ }
+
if (!ic->meta_dev && ic->mode != 'I') {
r = dm_set_target_max_io_len(ti, 1U << ic->sb->log2_interleave_sectors);
if (r)
@@ -5509,6 +5558,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
kvfree(ic->journal_tree);
if (ic->sb)
free_pages_exact(ic->sb, SB_SECTORS << SECTOR_SHIFT);
+ kfree(ic->sb_copy);
if (ic->internal_shash)
crypto_free_shash(ic->internal_shash);
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 16/52] sched_ext: Fix CPU hotplug hang when a dying CPUs tasks sit in the BPF scheduler
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (14 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 15/52] dm-integrity: validate the superblock on resume Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 17/52] Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex Greg Kroah-Hartman
` (36 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alap Mohan, Joonwoo Park, Tejun Heo,
Andrea Righi, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tejun Heo <tj@kernel.org>
[ Upstream commit d35a535d3e3e71f92a051d94e415f43612c4edfc ]
A CPU going down has to empty its own rq. Its hotplug thread waits in
sched_cpu_wait_empty() until nothing else is left, and the only thing that
wakes it is balance_push(), which runs from __schedule() on the dying CPU
and pushes off the migratable tasks the CPU picks.
sched_ext breaks this. A task sitting on a user DSQ or held by the BPF
scheduler is still counted on its rq, but an inactive CPU no longer calls
ops.dispatch() and can't pull the task back. The dying CPU goes idle with
the task still counted, and one of two things happens:
- Another CPU consumes the task. The rq empties without a __schedule() on
the dying CPU, so the hotplug thread is never woken and cpu_down() hangs
holding cpu_hotplug_lock.
- The task is affine only to the dying CPU. Nothing can move it, and the
offline stalls until the watchdog ejects the BPF scheduler.
When the rq goes offline, re-enqueue every task on it that isn't already on
the local DSQ. An enqueue on an offline rq lands on the local DSQ, so the
dying CPU itself picks the tasks and balance_push() pushes them off, the
same as for the other sched classes. From then on no sched_ext path on
another CPU can pull a task off the rq.
ops.dispatch() currently stops as soon as the CPU goes inactive, and CPU
hotplug then waits for an RCU grace period before taking the rq offline. A
BPF-held task affine only to the dying CPU and preempted inside an RCU
read-side critical section would block that grace period, and the rq would
never go offline. Test SCX_RQ_ONLINE directly so that ops.dispatch() keeps
running until the rq goes offline. Only the dying CPU's own hotplug thread
clears the flag during teardown, and task_can_run_on_remote_rq() still keeps
other rqs' tasks off the CPU.
Fixes: f0e1a0643a59 ("sched_ext: Implement BPF extensible scheduler class")
Fixes: 991ef53a4832 ("sched_ext: Make scx_rq_online() also test cpu_active() in addition to SCX_RQ_ONLINE")
Cc: stable@vger.kernel.org # v6.12+
Reported-by: Alap Mohan <mohaalap@meta.com>
Reported-by: Joonwoo Park <joonwoo@meta.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
[ sashal: adapted scx_dispatch_sched() changes to balance_one() in the unsplit sched_ext implementation. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/sched/ext.c | 29 ++++++++++++++++++++++++++---
kernel/sched/sched.h | 5 +++--
2 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 189a4e0658eb5..55072a105cd6e 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -1369,8 +1369,8 @@ static void set_task_runnable(struct rq *rq, struct task_struct *p)
}
/*
- * list_add_tail() must be used. scx_bypass() depends on tasks being
- * appended to the runnable_list.
+ * list_add_tail() must be used. scx_bypass() and rq_offline_scx()
+ * depend on tasks being appended to the runnable_list.
*/
list_add_tail(&p->scx.runnable_node, &rq->scx.runnable_list);
}
@@ -2147,8 +2147,14 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
if (consume_global_dsq(sch, rq))
goto has_tasks;
+ /*
+ * scx_rq_online() can't be used. Its cpu_active() test goes false
+ * before CPU hotplug waits for an RCU grace period, and
+ * rq_offline_scx() moves this CPU's tasks to the local DSQ only after
+ * the wait. The grace period can depend on those tasks running.
+ */
if (unlikely(!SCX_HAS_OP(sch, dispatch)) ||
- scx_rq_bypassing(rq) || !scx_rq_online(rq))
+ scx_rq_bypassing(rq) || !(rq->scx.flags & SCX_RQ_ONLINE))
goto no_tasks;
dspc->rq = rq;
@@ -2677,7 +2683,24 @@ static void rq_online_scx(struct rq *rq)
static void rq_offline_scx(struct rq *rq)
{
+ struct task_struct *p, *n;
+
rq->scx.flags &= ~SCX_RQ_ONLINE;
+
+ /* sched domain rebuilds call rq_offline with the CPU staying alive */
+ if (cpu_active(cpu_of(rq)))
+ return;
+
+ /*
+ * An offline CPU no longer calls ops.dispatch(). Re-enqueue its tasks
+ * onto the local DSQ so that they run here and balance_push() moves
+ * them off.
+ */
+ list_for_each_entry_safe_reverse(p, n, &rq->scx.runnable_list, scx.runnable_node) {
+ if (p->scx.dsq == &rq->scx.local_dsq)
+ continue;
+ guard(sched_change)(p, DEQUEUE_SAVE | DEQUEUE_MOVE | DEQUEUE_NOCLOCK);
+ }
}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 4e58174d3d0b0..0f29def72877b 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -3905,8 +3905,9 @@ extern void balance_callbacks(struct rq *rq, struct balance_callback *head);
* after which it is enqueued again.
*
* Typically this must be called while holding task_rq_lock, since most/all
- * properties are serialized under those locks. There is currently one
- * exception to this rule in sched/ext which only holds rq->lock.
+ * properties are serialized under those locks. There are currently two
+ * exceptions to this rule in sched/ext which only hold rq->lock: scx_bypass()
+ * and rq_offline_scx().
*/
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 17/52] Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (15 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 16/52] sched_ext: Fix CPU hotplug hang when a dying CPUs tasks sit in the BPF scheduler Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 18/52] net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop Greg Kroah-Hartman
` (35 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pauli Virtanen,
syzbot+74071deb72339c215b2e, Jiaming Zhang, Mikhail Gavrilov,
Luiz Augusto von Dentz, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
[ Upstream commit ac022970e9fb0a5f7e7d1f6c8e104c1ed924dd1c ]
An RFCOMM connect() issued while a BR/EDR link is being authenticated
makes lockdep report a circular dependency, and the reported cycle is a
real AB/BA between rfcomm_mutex and hdev->lock.
rfcomm_security_cfm() is called from the HCI event path, which already
holds hdev->lock:
hci_rx_work()
hci_event_packet()
hci_cc_read_enc_key_size() [hdev->lock]
hci_encrypt_cfm() [hci_cb_list_lock]
rfcomm_security_cfm() [rfcomm_mutex]
while an RFCOMM connect() from userspace takes the same two locks the
other way round:
rfcomm_sock_connect()
rfcomm_dlc_open() [rfcomm_mutex]
__rfcomm_dlc_open()
rfcomm_session_create()
kernel_connect()
l2cap_sock_connect()
l2cap_chan_connect() [hdev->lock]
WARNING: possible circular locking dependency detected
kworker/u131:1/1128 is trying to acquire lock:
rfcomm_mutex, at: rfcomm_security_cfm+0x31/0x3e0 [rfcomm]
but task is already holding lock:
hci_cb_list_lock, at: hci_cc_read_enc_key_size+0x1d2/0xcc0
Chain exists of:
rfcomm_mutex --> &hdev->lock --> hci_cb_list_lock
hci_auth_complete_evt() and hci_encrypt_change_evt() reach the callback
the same way.
Both orders have to be seen in the same boot, which is why a BR/EDR
connection alone is not enough to show it: a session set up by the
remote side is created by rfcomm_accept_connection() in krfcommd, which
calls kernel_accept() and never takes hdev->lock under rfcomm_mutex.
Connecting a device that authenticates and encrypts the link and then
calling connect() on an RFCOMM socket towards any address - the connect
does not have to succeed, the order is recorded before the page timeout
- reports it every time.
Only the session socket has to be connected with the lock held, and it
does not: nothing else can see the socket before it is put on the
session list. So connect it first and take rfcomm_mutex afterwards,
which removes the rfcomm_mutex -> hdev->lock order for good, rather
than keeping the HCI event path out of rfcomm_mutex.
rfcomm_session_create() becomes rfcomm_session_connect(), which returns
the connected socket without touching the session list, and
rfcomm_dlc_open() adds the session once it holds the lock again. If
another opener added a session for the same pair while this socket was
connecting, that session is used and this socket is dropped.
__rfcomm_dlc_open() now takes the session it should use, and its state
check runs after the lock is re-acquired, so a DLC that was opened or
closed in the meantime is still handled.
Over an existing ACL link the connection can complete before the
session reaches the list, and the wakeup from the socket callback is
then lost, so krfcommd is woken once the session is visible.
Connecting without the lock opens a window in which the socket can be
closed. The DLC is not on a session yet, so rfcomm_dlc_close() finds
nothing to do and returns without touching it, and rfcomm_dlc_open()
would then attach a DLC whose owner is gone. rfcomm_dlc_close() now
marks such a DLC with RFCOMM_CLOSED, and rfcomm_dlc_open() checks the
mark once it holds rfcomm_mutex again and drops the socket instead of
attaching the DLC. The mark is cleared when an open starts, so a DLC
that is reused is not affected. This covers both callers of
rfcomm_dlc_open(), the socket and the tty layer.
Fixes: 759c185d0bbd ("Bluetooth: RFCOMM: serialize security confirmation handling")
Suggested-by: Pauli Virtanen <pav@iki.fi>
Reported-by: Pauli Virtanen <pav@iki.fi>
Closes: https://lore.kernel.org/linux-bluetooth/5e76a95e934e451e7006db28827c2d64af5a88be.camel@iki.fi/
Reported-by: syzbot+74071deb72339c215b2e@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/linux-bluetooth/6a92fadc.08e933ee.dbf97.008f.GAE@google.com/
Reported-by: Jiaming Zhang <r772577952@gmail.com>
Closes: https://lore.kernel.org/all/CANypQFabseTuRiyz2pGkc_Qj0moGDnY7KEp1qdTOqkw6gAL3hw@mail.gmail.com/
Cc: stable@vger.kernel.org
Signed-off-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Tested-by: syzbot+74071deb72339c215b2e@syzkaller.appspotmail.com
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
[ sashal: Retained the struct sockaddr * cast instead of struct sockaddr_unsized * to match kernel_connect()’s API. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/bluetooth/rfcomm.h | 1 +
net/bluetooth/rfcomm/core.c | 134 +++++++++++++++++++++++----------
2 files changed, 96 insertions(+), 39 deletions(-)
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index 7e40d3c5f5a97..e8e82869b2812 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -210,6 +210,7 @@ struct rfcomm_dlc {
#define RFCOMM_AUTH_REJECT 7
#define RFCOMM_DEFER_SETUP 8
#define RFCOMM_ENC_DROP 9
+#define RFCOMM_CLOSED 10
/* Scheduling flags and events */
#define RFCOMM_SCHED_WAKEUP 31
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index d45ea1807f8bd..59fb93be9c20e 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -65,10 +65,9 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);
static void rfcomm_process_connect(struct rfcomm_session *s);
-static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
- bdaddr_t *dst,
- u8 sec_level,
- int *err);
+static struct socket *rfcomm_session_connect(bdaddr_t *src, bdaddr_t *dst,
+ u8 sec_level, int *err);
+static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state);
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s);
@@ -368,28 +367,17 @@ static int rfcomm_check_channel(u8 channel)
return channel < 1 || channel > 30;
}
-static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
+static int __rfcomm_dlc_open(struct rfcomm_dlc *d, struct rfcomm_session *s,
+ u8 channel)
{
- struct rfcomm_session *s;
- int err = 0;
u8 dlci;
- BT_DBG("dlc %p state %ld %pMR -> %pMR channel %d",
- d, d->state, src, dst, channel);
-
- if (rfcomm_check_channel(channel))
- return -EINVAL;
+ BT_DBG("dlc %p state %ld session %p channel %d",
+ d, d->state, s, channel);
if (d->state != BT_OPEN && d->state != BT_CLOSED)
return 0;
- s = rfcomm_session_get(src, dst);
- if (!s) {
- s = rfcomm_session_create(src, dst, d->sec_level, &err);
- if (!s)
- return err;
- }
-
dlci = __dlci(__session_dir(s), channel);
/* Check if DLCI already exists */
@@ -424,14 +412,84 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
{
- int r;
+ struct rfcomm_session *s;
+ struct socket *sock;
+ int err;
+
+ BT_DBG("dlc %p state %ld %pMR -> %pMR channel %d",
+ d, d->state, src, dst, channel);
+
+ if (rfcomm_check_channel(channel))
+ return -EINVAL;
rfcomm_lock();
- r = __rfcomm_dlc_open(d, src, dst, channel);
+ clear_bit(RFCOMM_CLOSED, &d->flags);
+ /* Do not page the remote device for a DLC that cannot be opened
+ * anyway. __rfcomm_dlc_open() looks at the state again once the
+ * lock has been re-acquired below.
+ */
+ if (d->state != BT_OPEN && d->state != BT_CLOSED) {
+ rfcomm_unlock();
+ return 0;
+ }
+
+ s = rfcomm_session_get(src, dst);
+ if (s) {
+ err = __rfcomm_dlc_open(d, s, channel);
+ rfcomm_unlock();
+ return err;
+ }
rfcomm_unlock();
- return r;
+
+ /* There is no session for this pair yet. kernel_connect() ends up in
+ * l2cap_chan_connect(), which takes hdev->lock, and the HCI event
+ * path takes rfcomm_mutex while holding hdev->lock, so the socket has
+ * to be connected with rfcomm_mutex released.
+ */
+ sock = rfcomm_session_connect(src, dst, d->sec_level, &err);
+ if (!sock)
+ return err;
+
+ rfcomm_lock();
+
+ /* The DLC may have been closed while the socket was connecting. It
+ * was not on a session, so rfcomm_dlc_close() could only mark it;
+ * attaching it now would leave it with no owner.
+ */
+ if (test_bit(RFCOMM_CLOSED, &d->flags)) {
+ rfcomm_unlock();
+ sock_release(sock);
+ return -ECONNRESET;
+ }
+
+ /* Another opener may have added a session for the same pair in the
+ * meantime; that one is used and this socket is dropped.
+ */
+ s = rfcomm_session_get(src, dst);
+ if (!s) {
+ s = rfcomm_session_add(sock, BT_BOUND);
+ if (s) {
+ s->initiator = 1;
+ sock = NULL;
+ }
+ }
+
+ err = s ? __rfcomm_dlc_open(d, s, channel) : -ENOMEM;
+
+ rfcomm_unlock();
+
+ if (sock)
+ sock_release(sock);
+
+ /* Over an existing ACL link the connection can complete before the
+ * session reaches the list, and that wakeup is then lost, so let
+ * krfcommd look at the socket state now.
+ */
+ rfcomm_schedule();
+
+ return err;
}
static void __rfcomm_dlc_disconn(struct rfcomm_dlc *d)
@@ -511,8 +569,14 @@ int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
rfcomm_lock();
s = d->session;
- if (!s)
+ if (!s) {
+ /* Not on a session yet: rfcomm_dlc_open() may be connecting a
+ * socket for it with rfcomm_mutex released. Leave a mark so
+ * that it does not attach the DLC once it holds the lock again.
+ */
+ set_bit(RFCOMM_CLOSED, &d->flags);
goto no_session;
+ }
/* after waiting on the mutex check the session still exists
* then check the dlc still exists
@@ -760,12 +824,12 @@ static struct rfcomm_session *rfcomm_session_close(struct rfcomm_session *s,
return rfcomm_session_del(s);
}
-static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
- bdaddr_t *dst,
- u8 sec_level,
- int *err)
+/* Creates the L2CAP socket a new session will run on and starts connecting
+ * it. Must be called with rfcomm_mutex released.
+ */
+static struct socket *rfcomm_session_connect(bdaddr_t *src, bdaddr_t *dst,
+ u8 sec_level, int *err)
{
- struct rfcomm_session *s = NULL;
struct sockaddr_l2 addr;
struct socket *sock;
struct sock *sk;
@@ -795,24 +859,16 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
l2cap_pi(sk)->chan->mode = L2CAP_MODE_ERTM;
release_sock(sk);
- s = rfcomm_session_add(sock, BT_BOUND);
- if (!s) {
- *err = -ENOMEM;
- goto failed;
- }
-
- s->initiator = 1;
-
bacpy(&addr.l2_bdaddr, dst);
addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = cpu_to_le16(L2CAP_PSM_RFCOMM);
addr.l2_cid = 0;
addr.l2_bdaddr_type = BDADDR_BREDR;
*err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
- if (*err == 0 || *err == -EINPROGRESS)
- return s;
+ if (*err && *err != -EINPROGRESS)
+ goto failed;
- return rfcomm_session_del(s);
+ return sock;
failed:
sock_release(sock);
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 18/52] net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (16 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 17/52] Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 19/52] net: mana: reserve RX buffer headroom to fix forwarding performance Greg Kroah-Hartman
` (34 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Suraj Gupta, Jakub Kicinski,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Suraj Gupta <suraj.gupta2@amd.com>
[ Upstream commit bcf2573a68a808a5b54cadafa72b6672e662c2bf ]
In the dmaengine path the driver pre-submits RX buffers and holds
in-flight TX buffers whose SKBs are DMA-mapped by the driver and freed
only in the completion callbacks. On ndo_stop() dmaengine_terminate_sync()
aborts these descriptors without running their callbacks, and the driver
then frees only the ring shells, leaking every SKB still owned by the
engine and its DMA mapping on each ifdown. With 128 RX buffers pre-posted
per channel, the mapping leak can eventually exhaust a limited IOMMU
aperture.
Clear the slot's skb in the TX and RX callbacks so a non-NULL skb marks a
slot that still owns a live, DMA-mapped buffer, and on stop unmap and free
every such buffer.
axienet_dma_rx_cb() runs from the DMA tasklet and re-arms the RX ring on
each completion, so it can race axienet_stop(): a completion may submit a
fresh buffer after dmaengine_terminate_sync() has returned, leaving the
channel armed with a buffer the teardown then frees while the engine may
still write into it (dma_release_channel() does not stop it either). Add a
lock that axienet_dma_rx_cb() holds across the @stopping check and the
resubmit, and axienet_stop() holds to set @stopping before terminating.
Once @stopping is set no callback can arm a new buffer, and any armed just
before is aborted by the terminate, so teardown only frees buffers the
engine no longer owns.
Fixes: 6a91b846af85 ("net: axienet: Introduce dmaengine support")
Cc: stable@vger.kernel.org
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
Link: https://patch.msgid.link/20260928184207.2361931-1-suraj.gupta2@amd.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
[ sashal: Adjusted context to retain kcalloc() instead of upstream’s kzalloc_objs(). ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/xilinx/xilinx_axienet.h | 7 ++-
.../net/ethernet/xilinx/xilinx_axienet_main.c | 51 +++++++++++++++----
2 files changed, 47 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index fcd3aaef27fc3..c63d99686d0ba 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -523,8 +523,9 @@ struct skbuf_dma_descriptor {
* @stats_work: Work for reading the hardware statistics counters often enough
* to catch overflows.
* @dma_err_task: Work structure to process Axi DMA errors
- * @stopping: Set when @dma_err_task shouldn't do anything because we are
- * about to stop the device.
+ * @stopping: Set when we are about to stop the device: makes @dma_err_task
+ * a no-op (legacy DMA path) and fences RX descriptor
+ * resubmission in axienet_dma_rx_cb() (dmaengine path).
* @tx_irq: Axidma TX IRQ number
* @rx_irq: Axidma RX IRQ number
* @eth_irq: Ethernet core IRQ number
@@ -545,6 +546,7 @@ struct skbuf_dma_descriptor {
* @tx_ring_tail: TX skb ring buffer tail index.
* @rx_ring_head: RX skb ring buffer head index.
* @rx_ring_tail: RX skb ring buffer tail index.
+ * @rx_submit_lock: Protects RX ring resubmission vs teardown in dmaengine path.
*/
struct axienet_local {
struct net_device *ndev;
@@ -626,6 +628,7 @@ struct axienet_local {
int tx_ring_tail;
int rx_ring_head;
int rx_ring_tail;
+ spinlock_t rx_submit_lock;
};
/**
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index eefe54ce66852..50ddc7c53b630 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -881,6 +881,7 @@ static void axienet_dma_tx_cb(void *data, const struct dmaengine_result *result)
u64_stats_update_end(&lp->tx_stat_sync);
dma_unmap_sg(lp->dev, skbuf_dma->sgl, skbuf_dma->sg_len, DMA_TO_DEVICE);
dev_consume_skb_any(skbuf_dma->skb);
+ skbuf_dma->skb = NULL;
netif_txq_completed_wake(txq, 1, len,
CIRC_SPACE(lp->tx_ring_head, lp->tx_ring_tail, TX_BD_NUM_MAX),
2);
@@ -1171,6 +1172,7 @@ static void axienet_dma_rx_cb(void *data, const struct dmaengine_result *result)
&meta_max_len);
dma_unmap_single(lp->dev, skbuf_dma->dma_address, lp->max_frm_size,
DMA_FROM_DEVICE);
+ skbuf_dma->skb = NULL;
if (IS_ERR(app_metadata)) {
if (net_ratelimit())
@@ -1193,10 +1195,17 @@ static void axienet_dma_rx_cb(void *data, const struct dmaengine_result *result)
u64_stats_update_end(&lp->rx_stat_sync);
rx_submit:
+ spin_lock(&lp->rx_submit_lock);
+ if (lp->stopping) {
+ spin_unlock(&lp->rx_submit_lock);
+ return;
+ }
+
for (i = 0; i < CIRC_SPACE(lp->rx_ring_head, lp->rx_ring_tail,
RX_BUF_NUM_DEFAULT); i++)
axienet_rx_submit_desc(lp->ndev);
dma_async_issue_pending(lp->rx_chan);
+ spin_unlock(&lp->rx_submit_lock);
}
/**
@@ -1541,6 +1550,7 @@ static int axienet_init_dmaengine(struct net_device *ndev)
lp->tx_ring_head = 0;
lp->rx_ring_tail = 0;
lp->rx_ring_head = 0;
+ lp->stopping = false;
lp->tx_skb_ring = kcalloc(TX_BD_NUM_MAX, sizeof(*lp->tx_skb_ring),
GFP_KERNEL);
if (!lp->tx_skb_ring) {
@@ -1754,20 +1764,42 @@ static int axienet_stop(struct net_device *ndev)
free_irq(lp->rx_irq, ndev);
axienet_dma_bd_release(ndev);
} else {
+ struct skbuf_dma_descriptor *skbuf_dma;
+
+ spin_lock_bh(&lp->rx_submit_lock);
+ lp->stopping = true;
+ spin_unlock_bh(&lp->rx_submit_lock);
+
dmaengine_terminate_sync(lp->tx_chan);
- dmaengine_synchronize(lp->tx_chan);
dmaengine_terminate_sync(lp->rx_chan);
- dmaengine_synchronize(lp->rx_chan);
-
- for (i = 0; i < TX_BD_NUM_MAX; i++)
- kfree(lp->tx_skb_ring[i]);
- kfree(lp->tx_skb_ring);
- for (i = 0; i < RX_BUF_NUM_DEFAULT; i++)
- kfree(lp->rx_skb_ring[i]);
- kfree(lp->rx_skb_ring);
dma_release_channel(lp->rx_chan);
dma_release_channel(lp->tx_chan);
+
+ /* Unmap and free any buffer the terminate did not reclaim, so it
+ * is not leaked; a non-NULL skb marks such a slot.
+ */
+ for (i = 0; i < TX_BD_NUM_MAX; i++) {
+ skbuf_dma = lp->tx_skb_ring[i];
+ if (skbuf_dma && skbuf_dma->skb) {
+ dma_unmap_sg(lp->dev, skbuf_dma->sgl,
+ skbuf_dma->sg_len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(skbuf_dma->skb);
+ }
+ kfree(skbuf_dma);
+ }
+ kfree(lp->tx_skb_ring);
+
+ for (i = 0; i < RX_BUF_NUM_DEFAULT; i++) {
+ skbuf_dma = lp->rx_skb_ring[i];
+ if (skbuf_dma && skbuf_dma->skb) {
+ dma_unmap_single(lp->dev, skbuf_dma->dma_address,
+ lp->max_frm_size, DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skbuf_dma->skb);
+ }
+ kfree(skbuf_dma);
+ }
+ kfree(lp->rx_skb_ring);
}
netdev_reset_queue(ndev);
@@ -3060,6 +3092,7 @@ static int axienet_probe(struct platform_device *pdev)
spin_lock_init(&lp->rx_cr_lock);
spin_lock_init(&lp->tx_cr_lock);
+ spin_lock_init(&lp->rx_submit_lock);
INIT_WORK(&lp->rx_dim.work, axienet_rx_dim_work);
lp->rx_dim_enabled = true;
lp->rx_dim.profile_ix = 1;
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 19/52] net: mana: reserve RX buffer headroom to fix forwarding performance
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (17 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 18/52] net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 20/52] riscv: patch: Avoid early phys_to_page() Greg Kroah-Hartman
` (33 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Hamza Mahfooz, Simon Horman,
Jakub Kicinski, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>
[ Upstream commit 259c4a519100e9182f264f8009ee212b32774277 ]
Commit 730ff06d3f5c ("net: mana: Use page pool fragments for RX buffers
instead of full pages to improve memory efficiency.") started handing
out RX buffers with zero headroom so that two buffers fit into one page
at the default MTU.
The MANA TX path, however, stores the per scatter-gather entry DMA
mappings in `struct mana_skb_head` at skb->head, and mana_start_xmit()
therefore calls skb_cow_head(skb, MANA_HEADROOM). The port advertises
this requirement as ndev->needed_headroom = MANA_HEADROOM.
As a result every packet that is received and then forwarded out of a
MANA port fails the skb_cow() in ip_forward() and gets reallocated and
copied by pskb_expand_head(). This is invisible to a plain RX or TX
workload, but it puts a full skb reallocation plus memcpy on the hot
path of every single forwarded packet, which is exactly what a
router/NVA workload does.
Restore the headroom. Note that reserving MANA_HEADROOM (232) is not
enough: ip_forward() asks for LL_RESERVED_SPACE(dev), which rounds
hard_header_len + needed_headroom up to HH_DATA_MOD and is 256 bytes on
ethernet. Use LL_RESERVED_SPACE() directly so the value keeps tracking
both constants. Also, since LL_RESERVED_SPACE() tracks MANA_HEADROOM,
it grows with MAX_SKB_FRAGS and for MAX_SKB_FRAGS >= 19 it is greater
than 256, so we have to account for that by using the headroom the RX
queue actually uses (instead of assuming XDP_PACKET_HEADROOM) and
turning MANA_XDP_MTU_MAX into MANA_XDP_MTU_MAX(ndev) (note that at the
default CONFIG_MAX_SKB_FRAGS=17 they are equivalent).
At the default MTU on a 4K page this means a buffer no longer fits twice
into a page (SKB_DATA_ALIGN(1500 + MANA_RXBUF_PAD + 256) = 2112), so the
frag-vs-single decision is now made by computing the real buffer size
instead of comparing the MTU against PAGE_SIZE / 2. The page_pool
fragment path is still used wherever at least two buffers genuinely fit,
e.g. on 16K and 64K page sizes.
Measured on an Azure VM with a MANA NIC acting as a forwarding NVA (UDP,
1400 byte payload, 4 streams, 8 Gbps offered, only the forwarding
node's kernel differs), 8 runs each, median:
forwarded pps throughput
before 272,830 3.06 Gbps
after 390,560 4.37 Gbps (+43%)
perf on the forwarding node, same workload:
memset_orig __pi_memcpy pskb_expand_head
before 10.07% 3.96% present
after 0.94% 0.64% gone
Cc: stable@vger.kernel.org
Fixes: 730ff06d3f5c ("net: mana: Use page pool fragments for RX buffers instead of full pages to improve memory efficiency.")
Signed-off-by: Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20261003013647.2051416-1-hamzamahfooz@linux.microsoft.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
[ sashal: Kept headroom and buffer-sizing calculations in mana_get_rxbuf_cfg() because full-page RX flag support is absent. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../net/ethernet/microsoft/mana/mana_bpf.c | 8 +++---
drivers/net/ethernet/microsoft/mana/mana_en.c | 26 +++++++++----------
include/net/mana/mana.h | 4 ++-
3 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_bpf.c b/drivers/net/ethernet/microsoft/mana/mana_bpf.c
index 7bb8382940b38..caf77991a54e9 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_bpf.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_bpf.c
@@ -91,7 +91,7 @@ u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq,
goto out;
xdp_init_buff(xdp, PAGE_SIZE, &rxq->xdp_rxq);
- xdp_prepare_buff(xdp, buf_va, XDP_PACKET_HEADROOM, pkt_len, true);
+ xdp_prepare_buff(xdp, buf_va, rxq->headroom, pkt_len, true);
act = bpf_prog_run_xdp(prog, xdp);
@@ -183,9 +183,9 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog,
if (!old_prog && !prog)
return 0;
- if (prog && ndev->mtu > MANA_XDP_MTU_MAX) {
+ if (prog && ndev->mtu > MANA_XDP_MTU_MAX(ndev)) {
netdev_err(ndev, "XDP: mtu:%u too large, mtu_max:%lu\n",
- ndev->mtu, MANA_XDP_MTU_MAX);
+ ndev->mtu, MANA_XDP_MTU_MAX(ndev));
NL_SET_ERR_MSG_MOD(extack, "XDP: mtu too large");
return -EOPNOTSUPP;
@@ -238,7 +238,7 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog,
bpf_prog_put(old_prog);
if (prog)
- ndev->max_mtu = MANA_XDP_MTU_MAX;
+ ndev->max_mtu = MANA_XDP_MTU_MAX(ndev);
else
ndev->max_mtu = gc->adapter_mtu - ETH_HLEN;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 5cbe24a1596c8..befeb20fb7d59 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -749,7 +749,7 @@ static void *mana_get_rxbuf_pre(struct mana_rxq *rxq, dma_addr_t *da)
return va;
}
-/* Get RX buffer's data size, alloc size, XDP headroom based on MTU */
+/* Get RX buffer's data size, alloc size, headroom and frag count based on MTU */
static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
int mtu, u32 *datasize, u32 *alloc_size,
u32 *headroom, u32 *frag_count)
@@ -759,16 +759,20 @@ static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
/* Calculate datasize first (consistent across all cases) */
*datasize = mtu + ETH_HLEN;
- /* For xdp and jumbo frames make sure only one packet fits per page */
- if (mtu + MANA_RXBUF_PAD > PAGE_SIZE / 2 || mana_xdp_get(apc)) {
- if (mana_xdp_get(apc)) {
- *headroom = XDP_PACKET_HEADROOM;
+ *headroom = LL_RESERVED_SPACE(apc->ndev);
+ if (mana_xdp_get(apc))
+ *headroom = max_t(u32, *headroom, XDP_PACKET_HEADROOM);
+
+ len = SKB_DATA_ALIGN(mtu + MANA_RXBUF_PAD + *headroom);
+ buf_size = ALIGN(len, MANA_RX_FRAG_ALIGNMENT);
+
+ /* For xdp and large buffers make sure only one packet fits per page */
+ if (PAGE_SIZE / buf_size < 2 || mana_xdp_get(apc)) {
+ if (mana_xdp_get(apc))
*alloc_size = PAGE_SIZE;
- } else {
- *headroom = 0; /* no support for XDP */
+ else
*alloc_size = SKB_DATA_ALIGN(mtu + MANA_RXBUF_PAD +
*headroom);
- }
*frag_count = 1;
@@ -782,12 +786,6 @@ static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
}
/* Standard MTU case - optimize for multiple packets per page */
- *headroom = 0;
-
- /* Calculate base buffer size needed */
- len = SKB_DATA_ALIGN(mtu + MANA_RXBUF_PAD + *headroom);
- buf_size = ALIGN(len, MANA_RX_FRAG_ALIGNMENT);
-
/* Calculate how many packets can fit in a page */
*frag_count = PAGE_SIZE / buf_size;
*alloc_size = buf_size;
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index a134b12352797..f03438a4b1dbd 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -325,7 +325,9 @@ struct mana_recv_buf_oob {
#define MANA_RXBUF_PAD (SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) \
+ ETH_HLEN)
-#define MANA_XDP_MTU_MAX (PAGE_SIZE - MANA_RXBUF_PAD - XDP_PACKET_HEADROOM)
+#define MANA_XDP_MTU_MAX(ndev) \
+ (PAGE_SIZE - MANA_RXBUF_PAD - \
+ max_t(u32, LL_RESERVED_SPACE(ndev), XDP_PACKET_HEADROOM))
struct mana_rxq {
struct gdma_queue *gdma_rq;
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 20/52] riscv: patch: Avoid early phys_to_page()
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (18 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 19/52] net: mana: reserve RX buffer headroom to fix forwarding performance Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 21/52] riscv: patch: fix handling of bpf-jit execmem addresses Greg Kroah-Hartman
` (32 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Thomas Weißschuh, Mike Rapoport,
Vivian Wang, Paul Walmsley, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vivian Wang <wangruikang@iscas.ac.cn>
[ Upstream commit 6b60a128c2f43180664a614830f3c529497e0394 ]
Similarly to commit 8d09e2d569f6 ("arm64: patching: avoid early
page_to_phys()"), avoid using phys_to_page() for the kernel address case
in patch_map().
Since this is called from apply_boot_alternatives() in setup_arch(), and
commit 4267739cabb8 ("arch, mm: consolidate initialization of SPARSE
memory model") has moved sparse_init() to after setup_arch(),
phys_to_page() is not available there yet, and it panics on boot with
SPARSEMEM on RV32, which does not use SPARSEMEM_VMEMMAP.
Reported-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Closes: https://lore.kernel.org/r/20260223144108-dcace0b9-02e8-4b67-a7ce-f263bed36f26@linutronix.de/
Fixes: 4267739cabb8 ("arch, mm: consolidate initialization of SPARSE memory model")
Suggested-by: Mike Rapoport <rppt@kernel.org>
Signed-off-by: Vivian Wang <wangruikang@iscas.ac.cn>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Tested-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Link: https://patch.msgid.link/20260310-riscv-sparsemem-alternatives-fix-v1-1-659d5dd257e2@iscas.ac.cn
[pjw@kernel.org: fix the subject line to align with the patch description]
Signed-off-by: Paul Walmsley <pjw@kernel.org>
Stable-dep-of: a510e1ae8c90 ("riscv: patch: fix handling of bpf-jit execmem addresses")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/riscv/kernel/patch.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c
index db13c9ddf9e3d..16b243376f362 100644
--- a/arch/riscv/kernel/patch.c
+++ b/arch/riscv/kernel/patch.c
@@ -42,19 +42,20 @@ static inline bool is_kernel_exittext(uintptr_t addr)
static __always_inline void *patch_map(void *addr, const unsigned int fixmap)
{
uintptr_t uintaddr = (uintptr_t) addr;
- struct page *page;
+ phys_addr_t phys;
- if (core_kernel_text(uintaddr) || is_kernel_exittext(uintaddr))
- page = phys_to_page(__pa_symbol(addr));
- else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
- page = vmalloc_to_page(addr);
- else
- return addr;
+ if (core_kernel_text(uintaddr) || is_kernel_exittext(uintaddr)) {
+ phys = __pa_symbol(addr);
+ } else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) {
+ struct page *page = vmalloc_to_page(addr);
- BUG_ON(!page);
+ BUG_ON(!page);
+ phys = page_to_phys(page) + offset_in_page(addr);
+ } else {
+ return addr;
+ }
- return (void *)set_fixmap_offset(fixmap, page_to_phys(page) +
- offset_in_page(addr));
+ return (void *)set_fixmap_offset(fixmap, phys);
}
static void patch_unmap(int fixmap)
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 21/52] riscv: patch: fix handling of bpf-jit execmem addresses
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (19 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 20/52] riscv: patch: Avoid early phys_to_page() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 22/52] scsi: ufs: core: Decouple CQ sweep from request iterator in MCQ Greg Kroah-Hartman
` (31 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Wei-Jie Hung, Pu Lehui,
Paul Walmsley, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei-Jie Hung <imbigking12@gmail.com>
[ Upstream commit a510e1ae8c9030750c2edf7b0bc9b186cd8c7a06 ]
Commit 8718e5a3090b ("riscv: patch: skip fixmap mapping when kernel text
is already writable") gated the core_kernel_text() branch of patch_map()
on CONFIG_STRICT_KERNEL_RWX, and explicitly left the vmalloc branch
unchanged. That branch has a separate problem.
That branch only creates a temporary writable fixmap alias when
CONFIG_STRICT_MODULE_RWX is enabled, and otherwise assumes the target is
directly writable and returns the address unchanged. That assumption no
longer holds: bpf_prog_pack_alloc calls set_memory_rox() on every pack
unconditionally in alloc_new_pack(), independently of any
CONFIG_STRICT_*_RWX option, so BPF text in the vmalloc area is read-only
regardless of what CONFIG_STRICT_MODULE_RWX says.
With CONFIG_STRICT_MODULE_RWX=n, patch_map() returns the read-only
address directly, the subsequent copy_to_kernel_nofault() takes a
page fault and returns -EFAULT. bpf_arch_text_copy() turns that into
-EINVAL, which propagates through bpf_jit_binary_pack_finalize() to the
WARN_ON() in bpf_int_jit_compile() and leaves the program un-JITed.
Note that BPF cannot be fixed the way kprobes was in
commit bdc46e507b59 ("riscv: mm: make EXECMEM_KPROBES writable without
CONFIG_STRICT_MODULE_RWX"). EXECMEM_BPF is already PAGE_KERNEL, i.e.
writable at allocation time; the read-only mapping is established
afterwards by generic code in alloc_new_pack(), which arch code cannot
influence. The only place this can be handled is patch_map().
This is the same problem that was fixed on arm64 by commit b1480ed230ac
("arm64: patching: fix handling of execmem addresses"), and the fix is
the same: CONFIG_EXECMEM is what actually tracks whether the vmalloc
area can hold executable memory that needs a temporary alias to be
written. CONFIG_BPF_JIT, CONFIG_KPROBES and CONFIG_MODULES all select
it.
Note that this is not limited to CONFIG_MODULES=n. Unlike arm64, riscv
selects CONFIG_ARCH_OPTIONAL_KERNEL_RWX, so CONFIG_STRICT_MODULE_RWX can
be disabled with CONFIG_MODULES=y as well, and the bug is reachable in
that configuration too.
The !CONFIG_MMU build is unaffected: it has its own __patch_insn_set()
and __patch_insn_write() implementations and never calls patch_map().
Fixes: 2c9e5d4a0082 ("bpf: remove CONFIG_BPF_JIT dependency on CONFIG_MODULES of")
Signed-off-by: Wei-Jie Hung <imbigking12@gmail.com>
Reviewed-by: Pu Lehui <pulehui@huawei.com>
Tested-by: Pu Lehui <pulehui@huawei.com>
Link: https://patch.msgid.link/20260914115607.350097-1-imbigking12@gmail.com
Cc: stable@vger.kernel.org
Signed-off-by: Paul Walmsley <pjw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/riscv/kernel/patch.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c
index 16b243376f362..1e8f1ac5a755f 100644
--- a/arch/riscv/kernel/patch.c
+++ b/arch/riscv/kernel/patch.c
@@ -46,7 +46,7 @@ static __always_inline void *patch_map(void *addr, const unsigned int fixmap)
if (core_kernel_text(uintaddr) || is_kernel_exittext(uintaddr)) {
phys = __pa_symbol(addr);
- } else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) {
+ } else if (IS_ENABLED(CONFIG_EXECMEM)) {
struct page *page = vmalloc_to_page(addr);
BUG_ON(!page);
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 22/52] scsi: ufs: core: Decouple CQ sweep from request iterator in MCQ
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (20 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 21/52] riscv: patch: fix handling of bpf-jit execmem addresses Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 23/52] scsi: ch: Do not keep references to data transfer element devices Greg Kroah-Hartman
` (30 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bart Van Assche, Stanley Jhu,
Peter Wang, Martin K. Petersen (Oracle), Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanley Jhu <stanleyjhu@google.com>
[ Upstream commit 469fa055664bfd8717b087a80d59c03055789c17 ]
In MCQ mode, ufshcd_mcq_compl_pending_transfer() uses
blk_mq_tagset_busy_iter() to iterate over busy requests during error
recovery and host reset. However, both iterator callbacks perform
whole-queue operations redundantly for each visited request:
- force_compl == true: ufshcd_mcq_force_compl_one() calls
ufshcd_mcq_compl_all_cqes_lock() on every busy request, sweeping the
entire completion ring (hwq->max_entries slots) once per active request
under spin_lock_irqsave even though the first sweep already cleared all
completion entries.
- force_compl == false: ufshcd_mcq_compl_one() acquires cq_lock and polls
CQTPy over MMIO via ufshcd_mcq_poll_cqe_lock() for every busy request
without doing any per-request work.
Sweep or poll each hardware queue (hba->uhq[i]) once at the start of
ufshcd_mcq_compl_pending_transfer(). When force_compl is true, run
blk_mq_tagset_busy_iter() afterward to complete residual in-flight
requests with DID_REQUEUE, and remove the now-unused
ufshcd_mcq_compl_one() callback.
Fixes: ab248643d3d6 ("scsi: ufs: core: Add error handling for MCQ mode")
Cc: stable@vger.kernel.org
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Stanley Jhu <stanleyjhu@google.com>
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
Link: https://patch.msgid.link/20260928035816.1294326-3-stanleyjhu@google.com
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ufs/core/ufshcd.c | 37 +++++++++++++++++++++----------------
1 file changed, 21 insertions(+), 16 deletions(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 9d32e658ad60e..52df1df6333aa 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -5743,7 +5743,17 @@ static void ufshcd_mcq_compl_pending_transfer(struct ufs_hba *hba,
struct ufshcd_lrb *lrbp;
struct scsi_cmnd *cmd;
unsigned long flags;
- int tag;
+ int tag, i;
+
+ for (i = 0; i < hba->nr_hw_queues; i++) {
+ if (force_compl)
+ ufshcd_mcq_compl_all_cqes_lock(hba, &hba->uhq[i]);
+ else
+ ufshcd_mcq_poll_cqe_lock(hba, &hba->uhq[i]);
+ }
+
+ if (!force_compl)
+ return;
for (tag = 0; tag < hba->nutrs; tag++) {
lrbp = &hba->lrb[tag];
@@ -5756,22 +5766,17 @@ static void ufshcd_mcq_compl_pending_transfer(struct ufs_hba *hba,
if (!hwq)
continue;
- if (force_compl) {
- ufshcd_mcq_compl_all_cqes_lock(hba, hwq);
- /*
- * For those cmds of which the cqes are not present
- * in the cq, complete them explicitly.
- */
- spin_lock_irqsave(&hwq->cq_lock, flags);
- if (cmd && !test_bit(SCMD_STATE_COMPLETE, &cmd->state)) {
- set_host_byte(cmd, DID_REQUEUE);
- ufshcd_release_scsi_cmd(hba, lrbp);
- scsi_done(cmd);
- }
- spin_unlock_irqrestore(&hwq->cq_lock, flags);
- } else {
- ufshcd_mcq_poll_cqe_lock(hba, hwq);
+ /*
+ * For those cmds of which the cqes are not present
+ * in the cq, complete them explicitly.
+ */
+ spin_lock_irqsave(&hwq->cq_lock, flags);
+ if (cmd && !test_bit(SCMD_STATE_COMPLETE, &cmd->state)) {
+ set_host_byte(cmd, DID_REQUEUE);
+ ufshcd_release_scsi_cmd(hba, lrbp);
+ scsi_done(cmd);
}
+ spin_unlock_irqrestore(&hwq->cq_lock, flags);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 23/52] scsi: ch: Do not keep references to data transfer element devices
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (21 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 22/52] scsi: ufs: core: Decouple CQ sweep from request iterator in MCQ Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 24/52] scsi: ufs: core: Move an assignment in ufshcd_mcq_process_cqe() Greg Kroah-Hartman
` (29 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ahmed Abdelhaleem Ahmed,
Laurence Oberman, Martin K. Petersen (Oracle), Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahmed Abdelhaleem Ahmed <ahmedhal@gmail.com>
[ Upstream commit 27c0f718d3b3c99e6d315308e95d987d0382a8a8 ]
ch_readconfig() looks up the scsi_device of every data transfer element
whose SCSI id the changer reports in READ ELEMENT STATUS, and stores it in
ch->dt[]. scsi_device_lookup() takes a reference, and nothing ever drops
it: ch_destroy() frees the array with kfree(). ch->dt[] is read nowhere
else - it only supplies the vendor, model and revision printed in the same
loop.
Once such a drive is removed, its scsi_device can never be released. It
stays on the host's device list at its address, so a new device there is
refused by anything that walks the list - target_core_pscsi reports
"scsi_device_get() failed for H:C:T:L" - and the low-level driver's module
can no longer be unloaded. Only a reboot recovers.
It shows with any changer that reports its drives' ids; with the mhvtl
virtual library (IBM 3573-TL personality), each create and remove of a
library with four drives leaves four references behind, counted by the
module's use count in lsmod. With ch not bound the count is unchanged, and
with this patch applied it is unchanged too.
Drop the reference as soon as the name has been printed, and remove the now
unused dt[] array. That also removes the array leaked when ch_probe() fails
after ch_readconfig().
The same leak was reported with an RFC patch in 2022, which was not merged.
Fixes: daa6eda65a53 ("[SCSI] add scsi changer driver")
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/linux-scsi/20220719075442.6215-1-yanghao_ht@163.com/
Signed-off-by: Ahmed Abdelhaleem Ahmed <ahmedhal@gmail.com>
Reviewed-by: Laurence Oberman <loberman@redhat.com>
Fixes: daa6eda65a53 ("[SCSI] add scsi changer driver")
Link: https://patch.msgid.link/20260929-ch-dt-leak-v2-1-ddda8d635dca@gmail.com
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
[ sashal: Adapted allocation removal from kzalloc_objs() to the existing two-line kcalloc() call. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/scsi/ch.c | 30 +++++++++---------------------
1 file changed, 9 insertions(+), 21 deletions(-)
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index fa07a6f54003e..c2c018236517b 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -112,7 +112,6 @@ typedef struct {
int minor;
char name[8];
struct scsi_device *device;
- struct scsi_device **dt; /* ptrs to data transfer elements */
u_int firsts[CH_TYPES];
u_int counts[CH_TYPES];
u_int voltags;
@@ -363,16 +362,10 @@ ch_readconfig(scsi_changer *ch)
vendor_labels[i]);
}
- /* look up the devices of the data transfer elements */
- ch->dt = kcalloc(ch->counts[CHET_DT], sizeof(*ch->dt),
- GFP_KERNEL);
-
- if (!ch->dt) {
- kfree(buffer);
- return -ENOMEM;
- }
-
+ /* report the devices of the data transfer elements */
for (elem = 0; elem < ch->counts[CHET_DT]; elem++) {
+ struct scsi_device *sdev;
+
id = -1;
lun = 0;
if (elem < CH_DT_MAX && -1 != dt_id[elem]) {
@@ -388,10 +381,8 @@ ch_readconfig(scsi_changer *ch)
VPRINTK(KERN_INFO, "dt 0x%x: ",elem+ch->firsts[CHET_DT]);
if (data[6] & 0x80) {
VPRINTK(KERN_CONT, "not this SCSI bus\n");
- ch->dt[elem] = NULL;
} else if (0 == (data[6] & 0x30)) {
VPRINTK(KERN_CONT, "ID/LUN unknown\n");
- ch->dt[elem] = NULL;
} else {
id = ch->device->id;
lun = 0;
@@ -401,18 +392,16 @@ ch_readconfig(scsi_changer *ch)
}
if (-1 != id) {
VPRINTK(KERN_CONT, "ID %i, LUN %i, ",id,lun);
- ch->dt[elem] =
- scsi_device_lookup(ch->device->host,
- ch->device->channel,
- id,lun);
- if (!ch->dt[elem]) {
+ sdev = scsi_device_lookup(ch->device->host,
+ ch->device->channel,
+ id, lun);
+ if (!sdev) {
/* should not happen */
VPRINTK(KERN_CONT, "Huh? device not found!\n");
} else {
VPRINTK(KERN_CONT, "name: %8.8s %16.16s %4.4s\n",
- ch->dt[elem]->vendor,
- ch->dt[elem]->model,
- ch->dt[elem]->rev);
+ sdev->vendor, sdev->model, sdev->rev);
+ scsi_device_put(sdev);
}
}
}
@@ -576,7 +565,6 @@ static void ch_destroy(struct kref *ref)
scsi_changer *ch = container_of(ref, scsi_changer, ref);
ch->device = NULL;
- kfree(ch->dt);
kfree(ch);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 24/52] scsi: ufs: core: Move an assignment in ufshcd_mcq_process_cqe()
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (22 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 23/52] scsi: ch: Do not keep references to data transfer element devices Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 25/52] scsi: ufs: core: Add debug log for MCQ command timeout Greg Kroah-Hartman
` (28 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Avri Altman, Bart Van Assche,
Martin K. Petersen, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bart Van Assche <bvanassche@acm.org>
[ Upstream commit dd4299af9b049c0dcb28699327ebc1386aab4b2a ]
Since 'tag' is only used inside the if-statement, move the 'tag'
assignment into the if-statement. This patch prepares for introducing a
WARN_ON_ONCE() call in ufshcd_mcq_get_tag() if the tag lookup fails.
Reviewed-by: Avri Altman <avri.altman@sandisk.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Link: https://patch.msgid.link/20251031204029.2883185-9-bvanassche@acm.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Stable-dep-of: 375f3a5691dd ("scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ufs/core/ufs-mcq.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c
index c9bdd4140fd04..8780be79a0f84 100644
--- a/drivers/ufs/core/ufs-mcq.c
+++ b/drivers/ufs/core/ufs-mcq.c
@@ -307,9 +307,10 @@ static void ufshcd_mcq_process_cqe(struct ufs_hba *hba,
struct ufs_hw_queue *hwq)
{
struct cq_entry *cqe = ufshcd_mcq_cur_cqe(hwq);
- int tag = ufshcd_mcq_get_tag(hba, cqe);
if (cqe->command_desc_base_addr) {
+ int tag = ufshcd_mcq_get_tag(hba, cqe);
+
ufshcd_compl_one_cqe(hba, tag, cqe);
/* After processed the cqe, mark it empty (invalid) entry */
cqe->command_desc_base_addr = 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 25/52] scsi: ufs: core: Add debug log for MCQ command timeout
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (23 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 24/52] scsi: ufs: core: Move an assignment in ufshcd_mcq_process_cqe() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 26/52] scsi: ufs: core: Add a comment block above ufshcd_mcq_compl_all_cqes_lock() Greg Kroah-Hartman
` (27 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Peter Wang, Bart Van Assche,
Martin K. Petersen, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Wang <peter.wang@mediatek.com>
[ Upstream commit 3abe4113e784b4a1135fe0e89828afecbfebf862 ]
It is difficult to debug situations where an MCQ command timeout occurs,
the corresponding CQ tag response is received, but the request is not
completed. Add a one-line log to indicate when the CQ entry is abnormal.
Signed-off-by: Peter Wang <peter.wang@mediatek.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Link: https://patch.msgid.link/20260210070837.1820710-3-peter.wang@mediatek.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Stable-dep-of: 375f3a5691dd ("scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ufs/core/ufs-mcq.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c
index 8780be79a0f84..632f4522a4d63 100644
--- a/drivers/ufs/core/ufs-mcq.c
+++ b/drivers/ufs/core/ufs-mcq.c
@@ -314,6 +314,8 @@ static void ufshcd_mcq_process_cqe(struct ufs_hba *hba,
ufshcd_compl_one_cqe(hba, tag, cqe);
/* After processed the cqe, mark it empty (invalid) entry */
cqe->command_desc_base_addr = 0;
+ } else {
+ dev_err(hba->dev, "Abnormal CQ entry!\n");
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 26/52] scsi: ufs: core: Add a comment block above ufshcd_mcq_compl_all_cqes_lock()
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (24 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 25/52] scsi: ufs: core: Add debug log for MCQ command timeout Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 27/52] scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock() Greg Kroah-Hartman
` (26 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bart Van Assche, Peter Wang,
Martin K. Petersen, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bart Van Assche <bvanassche@acm.org>
[ Upstream commit 1373df88d53594a32534fd8960c51d1d09be8ecb ]
Document the aspects of ufshcd_mcq_compl_all_cqes_lock() that are
nontrivial in a comment block above this function.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
Link: https://patch.msgid.link/20260401202506.1445324-2-bvanassche@acm.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Stable-dep-of: 375f3a5691dd ("scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ufs/core/ufs-mcq.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c
index 632f4522a4d63..51e3c65ba94b1 100644
--- a/drivers/ufs/core/ufs-mcq.c
+++ b/drivers/ufs/core/ufs-mcq.c
@@ -319,6 +319,14 @@ static void ufshcd_mcq_process_cqe(struct ufs_hba *hba,
}
}
+/*
+ * This function is called from the UFS error handler with the UFS host
+ * controller disabled (HCE = 0). Reading host controller registers, e.g. the
+ * CQ tail pointer (CQTPy), may not be safe with the host controller disabled.
+ * Hence, iterate over all completion queue entries. This won't result in
+ * double completions because ufshcd_mcq_process_cqe() clears a CQE after it
+ * has been processed.
+ */
void ufshcd_mcq_compl_all_cqes_lock(struct ufs_hba *hba,
struct ufs_hw_queue *hwq)
{
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 27/52] scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock()
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (25 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 26/52] scsi: ufs: core: Add a comment block above ufshcd_mcq_compl_all_cqes_lock() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 28/52] drm/xe/i2c: cancel the client work on remove Greg Kroah-Hartman
` (25 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Peter Wang, Stanley Jhu,
Bart Van Assche, Martin K. Petersen (Oracle), Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanley Jhu <stanleyjhu@google.com>
[ Upstream commit 375f3a5691dd46b5d05b90a8968872ec8b2248c5 ]
During MCQ host reset, ufshcd_host_reset_and_restore() stops the host
controller via ufshcd_hba_stop() (HCE = 0) before calling
ufshcd_complete_requests(hba, true) ->
ufshcd_mcq_compl_pending_transfer(hba, true) ->
ufshcd_mcq_force_compl_one() -> ufshcd_mcq_compl_all_cqes_lock(). Because
ufshcd_mcq_force_compl_one() is its sole caller,
ufshcd_mcq_compl_all_cqes_lock() always runs with HCE = 0.
Despite the comment above ufshcd_mcq_compl_all_cqes_lock() stating that
reading CQTPy may not be safe with the controller disabled, the function
still calls ufshcd_mcq_update_cq_tail_slot() at the end of its sweep:
1. Unsafe CQTPy MMIO read:
Calling ufshcd_mcq_update_cq_tail_slot() at the end of the sweep reads
CQTPy over MMIO while HCE = 0, directly contradicting the function's
documented contract (commit 1373df88d535 ("scsi: ufs: core: Add a
comment block above ufshcd_mcq_compl_all_cqes_lock()")) that reading
CQTPy may not be safe with the controller disabled.
2. Spurious error logs on empty slots:
Sweeping all max_entries slots visits empty entries where
command_desc_base_addr is 0, causing ufshcd_mcq_process_cqe() to log
unguarded dev_err(hba->dev, "Abnormal CQ entry!\n") messages.
Fix both issues in ufshcd_mcq_compl_all_cqes_lock():
- Remove the ufshcd_mcq_update_cq_tail_slot() call and the redundant
hwq->cq_head_slot = hwq->cq_tail_slot assignment without replacement.
The two indices are already equal after the sweep: they are equal when
the sweep starts, since ufshcd_mcq_poll_cqe_lock() consumes entries
until cq_head_slot reaches cq_tail_slot, and the sweep advances
cq_head_slot by exactly one full ring. Both indices are also
reinitialized before the queue is reused.
- Extract ufshcd_mcq_compl_cqe() and invoke it only on non-empty slots
during full-ring sweeps, keeping "Abnormal CQ entry!" logging strictly
for unexpected empty entries in ufshcd_mcq_poll_cqe_lock().
Fixes: ab248643d3d6 ("scsi: ufs: core: Add error handling for MCQ mode")
Cc: stable@vger.kernel.org
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
Signed-off-by: Stanley Jhu <stanleyjhu@google.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Link: https://patch.msgid.link/20260928035816.1294326-2-stanleyjhu@google.com
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ufs/core/ufs-mcq.c | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c
index 51e3c65ba94b1..55a7647685b44 100644
--- a/drivers/ufs/core/ufs-mcq.c
+++ b/drivers/ufs/core/ufs-mcq.c
@@ -303,20 +303,24 @@ static int ufshcd_mcq_get_tag(struct ufs_hba *hba, struct cq_entry *cqe)
return div_u64(addr, ufshcd_get_ucd_size(hba));
}
+static void ufshcd_mcq_compl_cqe(struct ufs_hba *hba, struct cq_entry *cqe)
+{
+ int tag = ufshcd_mcq_get_tag(hba, cqe);
+
+ ufshcd_compl_one_cqe(hba, tag, cqe);
+ /* After processing the CQE, mark it as an empty (invalid) entry. */
+ cqe->command_desc_base_addr = 0;
+}
+
static void ufshcd_mcq_process_cqe(struct ufs_hba *hba,
struct ufs_hw_queue *hwq)
{
struct cq_entry *cqe = ufshcd_mcq_cur_cqe(hwq);
- if (cqe->command_desc_base_addr) {
- int tag = ufshcd_mcq_get_tag(hba, cqe);
-
- ufshcd_compl_one_cqe(hba, tag, cqe);
- /* After processed the cqe, mark it empty (invalid) entry */
- cqe->command_desc_base_addr = 0;
- } else {
+ if (cqe->command_desc_base_addr)
+ ufshcd_mcq_compl_cqe(hba, cqe);
+ else
dev_err(hba->dev, "Abnormal CQ entry!\n");
- }
}
/*
@@ -324,7 +328,7 @@ static void ufshcd_mcq_process_cqe(struct ufs_hba *hba,
* controller disabled (HCE = 0). Reading host controller registers, e.g. the
* CQ tail pointer (CQTPy), may not be safe with the host controller disabled.
* Hence, iterate over all completion queue entries. This won't result in
- * double completions because ufshcd_mcq_process_cqe() clears a CQE after it
+ * double completions because ufshcd_mcq_compl_cqe() clears a CQE after it
* has been processed.
*/
void ufshcd_mcq_compl_all_cqes_lock(struct ufs_hba *hba,
@@ -335,13 +339,13 @@ void ufshcd_mcq_compl_all_cqes_lock(struct ufs_hba *hba,
spin_lock_irqsave(&hwq->cq_lock, flags);
while (entries > 0) {
- ufshcd_mcq_process_cqe(hba, hwq);
+ struct cq_entry *cqe = ufshcd_mcq_cur_cqe(hwq);
+
+ if (cqe->command_desc_base_addr)
+ ufshcd_mcq_compl_cqe(hba, cqe);
ufshcd_mcq_inc_cq_head_slot(hwq);
entries--;
}
-
- ufshcd_mcq_update_cq_tail_slot(hwq);
- hwq->cq_head_slot = hwq->cq_tail_slot;
spin_unlock_irqrestore(&hwq->cq_lock, flags);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 28/52] drm/xe/i2c: cancel the client work on remove
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (26 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 27/52] scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 29/52] cifs: fix time_last_write stamp placement in setattr/truncate paths Greg Kroah-Hartman
` (24 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Song Li, Fan Wu, Heikki Krogerus,
Rodrigo Vivi, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <fanwu01@zju.edu.cn>
[ Upstream commit 611857adc9e7b0ee1239a0baf38498922ca5a12e ]
xe_i2c_notifier() stores the DesignWare adapter in i2c->adapter and
schedules i2c->work when the adapter is registered under the xe I2C
platform device, and xe_i2c_client_work() then instantiates the AMC
client device on that adapter.
xe_i2c_remove() tears down the AMC, unregisters the client devices,
the bus notifier and the adapter platform device, but it never drains
i2c->work. A work item that is still queued or running when the
adapter is unregistered dereferences i2c->adapter in
i2c_new_client_device() after platform_device_unregister() has
released the adapter. The work item is also embedded in the
devm-allocated struct xe_i2c, so a work item still queued after the
drm device devm unwind frees that allocation runs its callback on
freed memory.
The bus notifier is the only thing that schedules this work, and it is
unregistered after the client devices. An instance that is still queued
when the teardown runs can therefore write
i2c->client[XE_I2C_CLIENT_AMC] while the loop is unregistering and
clearing the same array, and an AMC client it instantiates late is only
cleaned up by the adapter's own child sweep in i2c_del_adapter().
Move bus_unregister_notifier() in front of the client teardown loop
and cancel the work right after it, so no new instance can be
scheduled and a queued instance is drained before the client array is
touched. A running instance still finds a live adapter, since the
adapter is unregistered later.
Fixes: f0e53aadd702 ("drm/xe: Support for I2C attached MCUs")
Link: https://lore.kernel.org/intel-xe/20260912085932.101598-1-fanwu01@zju.edu.cn/
Cc: stable@vger.kernel.org
Assisted-by: LLM, in-house static analysis tool
Co-developed-by: Song Li <songl@zju.edu.cn>
Signed-off-by: Song Li <songl@zju.edu.cn>
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://patch.msgid.link/20260928013030.612592-1-fanwu01@zju.edu.cn
Link: https://patch.msgid.link/20261006000413.318561-2-rodrigo.vivi@intel.com
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
(cherry picked from commit a23f27d5ec11c3f418c5e5531eea34ccda2b5b20)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
[ sashal: Adjusted xe_i2c_remove() context for the older teardown implementation. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/xe/xe_i2c.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c
index 25c7eb725ce26..43311886dbf81 100644
--- a/drivers/gpu/drm/xe/xe_i2c.c
+++ b/drivers/gpu/drm/xe/xe_i2c.c
@@ -330,10 +330,13 @@ static void xe_i2c_remove(void *data)
struct xe_i2c *i2c = data;
unsigned int i;
+ /* Stop the notifier from arming the client work before teardown. */
+ bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
+ cancel_work_sync(&i2c->work);
+
for (i = 0; i < XE_I2C_MAX_CLIENTS; i++)
i2c_unregister_device(i2c->client[i]);
- bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
xe_i2c_unregister_adapter(i2c);
xe_i2c_remove_irq(i2c);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 29/52] cifs: fix time_last_write stamp placement in setattr/truncate paths
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (27 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 28/52] drm/xe/i2c: cancel the client work on remove Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 30/52] fat: stop reading directory entries past the end-of-directory marker Greg Kroah-Hartman
` (23 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Frank Sorenson,
Paulo Alcantara (Red Hat), Steve French, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frank Sorenson <sorenson@redhat.com>
[ Upstream commit ecababf08905958ba8c125979c4e39fc2f1a8a05 ]
cifs_file_set_size() calls cifs_setsize() on success, which calls
i_size_write(), updating i_size to the new value. The subsequent
check attrs->ia_size != i_size_read() in both cifs_setattr_unix()
and cifs_setattr_nounix() therefore always evaluates false after a
successful cifs_file_set_size(), making the smp_store_release() of
time_last_write dead code. The truncate path was unprotected against
stale readdir size updates.
Move the stamp to before the cifs_file_set_size() RPC call, guarded
by attrs->ia_size != i_size_read() to exclude no-op same-size
ftruncate(2) calls from stamping time_last_write unnecessarily.
On the error path the stamp remains rather than being restored:
restoring a stale snapshot (prev_tlw) could silently erase a
concurrent _cifsFileInfo_put() close stamp if that close arrived
between the READ_ONCE and the smp_store_release. readdir is
suppressed until the stamp expires, which extends beyond one acregmax
if the caller retries failed truncations. stat() is unaffected: the
cifs_revalidate_dentry_attr() path calls cifs_fattr_to_inode() with
from_readdir=false, which bypasses the time_last_write check in
is_size_safe_to_change() entirely and always writes the authoritative
QUERY_INFO result to i_size.
Remove the now-unreachable stamp from the dead block in both functions.
Fixes: e8a8d54c2d50 ("cifs: prevent readdir from changing file size due to stale directory metadata")
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
[ sashal: removed the timestamp write from cifs_file_set_size() because the original size-update blocks were already deleted ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/inode.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index ec6d27ba4083d..995d6df9304f4 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -3135,11 +3135,8 @@ int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
cifs_put_tlink(tlink);
set_size_out:
- if (rc == 0) {
- /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */
- smp_store_release(&cifsInode->time_last_write, jiffies);
+ if (rc == 0)
cifs_resize_file_locked(inode, size);
- }
return rc;
}
@@ -3202,6 +3199,17 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
rc = 0;
if (attrs->ia_valid & ATTR_SIZE) {
+ if (attrs->ia_size != i_size_read(inode)) {
+ /* Stamp before RPC. On failure the stamp remains: restoring a
+ * stale snapshot could silently erase a concurrent
+ * _cifsFileInfo_put() close stamp. readdir is suppressed
+ * until the stamp expires; stat() bypasses this via the
+ * from_readdir=false path in is_size_safe_to_change() and
+ * always returns an authoritative QUERY_INFO result.
+ * Pairs with smp_load_acquire() in is_size_safe_to_change().
+ */
+ smp_store_release(&cifsInode->time_last_write, jiffies);
+ }
rc = cifs_file_set_size(xid, direntry, full_path,
open_file, attrs->ia_size);
if (rc != 0)
@@ -3378,6 +3386,17 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
}
if (attrs->ia_valid & ATTR_SIZE) {
+ if (attrs->ia_size != i_size_read(inode)) {
+ /* Stamp before RPC. On failure the stamp remains: restoring a
+ * stale snapshot could silently erase a concurrent
+ * _cifsFileInfo_put() close stamp. readdir is suppressed
+ * until the stamp expires; stat() bypasses this via the
+ * from_readdir=false path in is_size_safe_to_change() and
+ * always returns an authoritative QUERY_INFO result.
+ * Pairs with smp_load_acquire() in is_size_safe_to_change().
+ */
+ smp_store_release(&cifsInode->time_last_write, jiffies);
+ }
rc = cifs_file_set_size(xid, direntry, full_path,
cfile, attrs->ia_size);
if (rc != 0)
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 30/52] fat: stop reading directory entries past the end-of-directory marker
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (28 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 29/52] cifs: fix time_last_write stamp placement in setattr/truncate paths Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 31/52] ima: Access decompressed kernel module to verify appended signature Greg Kroah-Hartman
` (22 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Timothy Redaelli, OGAWA Hirofumi,
Matteo Croce, Christian Brauner (Amutable), Nicolai Buchwitz
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matteo Croce <technoboy85@gmail.com>
commit 6a2875517c778ac1111b6920e94cbab91cda8724 upstream.
The FAT specification[1] (FAT Directory Structure -> "DIR_Name[0]") states:
If DIR_Name[0] == 0x00, then the directory entry is free (same as for
0xE5), and there are no allocated directory entries after this one
(all of the DIR_Name[0] bytes in all of the entries after this one
are also set to 0).
The special 0 value, rather than the 0xE5 value, indicates to FAT
file system driver code that the rest of the entries in this
directory do not need to be examined because they are all free.
Linux did not honour this. fat_get_entry() kept advancing past the 0x00
terminator; if the trailing on-disk slots were not zero-filled (buggy
formatters, read-only media written by other operating systems, on-disk
corruption) the driver surfaced arbitrary bytes as real directory
entries. On a typical affected image, `ls /mnt` returns ~150 bogus
entries with random binary names, multi-gigabyte sizes, dates ranging
from 1980 to 2106, and a flood of -EIO from stat().
Earlier attempts (v1..v3, see [2][3][4]) added `de->name[0] == 0` guards
at each call site. As Hirofumi pointed out on v3, those guards reject
the entry but fat_get_entry() has already advanced *pos past it; the
next readdir() resumes after the marker and walks straight back into
the garbage. His suggestion was to centralise the check.
This patch:
* Adds fat_get_entry_eod(), a small wrapper around fat_get_entry()
that returns -1 when name[0] == 0 and seeks *pos to dir->i_size.
Per spec every slot after the 0x00 marker is also zero, so jumping
to the end of the directory is correct: subsequent reads return -1
from fat_bmap() without re-fetching trailing zero slots, and
callers persisting *pos across invocations (notably readdir's
ctx->pos) keep reporting end-of-directory on re-entry.
* Converts the read/search paths to use the new wrapper:
fat_parse_long(), fat_search_long(), __fat_readdir(),
and fat_get_short_entry() -- the last covers
fat_get_dotdot_entry(), fat_dir_empty(), fat_subdirs(),
fat_scan(), and fat_scan_logstart() transitively.
* Leaves fat_add_entries() and __fat_remove_entries() on raw
fat_get_entry(): the write paths legitimately need to operate on
free/zero slots. fat_add_entries() additionally detects an
allocated entry past a 0x00 marker (the spec violation that
produces the garbage) and treats it as filesystem corruption:
fat_fs_error_ratelimit() is called -- which honours the configured
errors= mount option (panic / remount-ro / continue) -- and the
operation returns -EIO so we don't write fresh entries into an
already-corrupt directory.
[1] https://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/fatgen103.doc
[2] https://lore.kernel.org/lkml/20181207013410.7050-1-mcroce@redhat.com/
[3] https://lore.kernel.org/lkml/20181216231510.26854-1-mcroce@redhat.com/
[4] https://lore.kernel.org/lkml/20190201001408.7453-1-mcroce@redhat.com/
Reported-by: Timothy Redaelli <tredaelli@redhat.com>
Suggested-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: Matteo Croce <teknoraver@meta.com>
Link: https://patch.msgid.link/20260616163346.32603-1-technoboy85@gmail.com
Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Cc: Nicolai Buchwitz <nb@tipi-net.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/fat/dir.c | 44 ++++++++++++++++++++++++++++++++++++++++----
1 file changed, 40 insertions(+), 4 deletions(-)
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -129,6 +129,31 @@ static inline int fat_get_entry(struct i
}
/*
+ * Like fat_get_entry(), but honour the FAT end-of-directory marker:
+ * a dirent whose first name byte is NUL terminates iteration per the
+ * spec, which also guarantees that every following slot is zeroed.
+ * Skip straight to the end of the directory so the next call returns
+ * -1 from fat_bmap() without re-reading the trailing zero slots, and
+ * so callers that persist *pos across invocations (e.g. readdir's
+ * ctx->pos) keep reporting EOD. Release *bh and set it to NULL to
+ * match fat_get_entry()'s contract that *bh is NULL on the -1 return.
+ */
+static int fat_get_entry_eod(struct inode *dir, loff_t *pos,
+ struct buffer_head **bh,
+ struct msdos_dir_entry **de)
+{
+ int err = fat_get_entry(dir, pos, bh, de);
+
+ if (err == 0 && (*de)->name[0] == 0) {
+ brelse(*bh);
+ *bh = NULL;
+ *pos = dir->i_size;
+ return -1;
+ }
+ return err;
+}
+
+/*
* Convert Unicode 16 to UTF-8, translated Unicode, or ASCII.
* If uni_xlate is enabled and we can't get a 1:1 conversion, use a
* colon as an escape character since it is normally invalid on the vfat
@@ -325,7 +350,7 @@ parse_long:
if (ds->id & 0x40)
(*unicode)[offset + 13] = 0;
- if (fat_get_entry(dir, pos, bh, de) < 0)
+ if (fat_get_entry_eod(dir, pos, bh, de) < 0)
return PARSE_EOF;
if (slot == 0)
break;
@@ -487,7 +512,7 @@ int fat_search_long(struct inode *inode,
err = -ENOENT;
while (1) {
- if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
+ if (fat_get_entry_eod(inode, &cpos, &bh, &de) == -1)
goto end_of_dir;
parse_record:
nr_slots = 0;
@@ -599,7 +624,7 @@ static int __fat_readdir(struct inode *i
bh = NULL;
get_new:
- if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
+ if (fat_get_entry_eod(inode, &cpos, &bh, &de) == -1)
goto end_of_dir;
parse_record:
nr_slots = 0;
@@ -882,7 +907,7 @@ static int fat_get_short_entry(struct in
struct buffer_head **bh,
struct msdos_dir_entry **de)
{
- while (fat_get_entry(dir, pos, bh, de) >= 0) {
+ while (fat_get_entry_eod(dir, pos, bh, de) >= 0) {
/* free entry or long name entry or volume label */
if (!IS_FREE((*de)->name) && !((*de)->attr & ATTR_VOLUME))
return 0;
@@ -1298,6 +1323,7 @@ int fat_add_entries(struct inode *dir, v
struct msdos_dir_entry *de;
int err, free_slots, i, nr_bhs;
loff_t pos;
+ bool saw_eod;
sinfo->nr_slots = nr_slots;
@@ -1306,12 +1332,15 @@ int fat_add_entries(struct inode *dir, v
bh = prev = NULL;
pos = 0;
err = -ENOSPC;
+ saw_eod = false;
while (fat_get_entry(dir, &pos, &bh, &de) > -1) {
/* check the maximum size of directory */
if (pos >= FAT_MAX_DIR_SIZE)
goto error;
if (IS_FREE(de->name)) {
+ if (de->name[0] == 0)
+ saw_eod = true;
if (prev != bh) {
get_bh(bh);
bhs[nr_bhs] = prev = bh;
@@ -1321,6 +1350,13 @@ int fat_add_entries(struct inode *dir, v
if (free_slots == nr_slots)
goto found;
} else {
+ if (saw_eod) {
+ fat_fs_error_ratelimit(sb,
+ "allocated dir entry found after end-of-directory marker (i_pos %lld)",
+ MSDOS_I(dir)->i_pos);
+ err = -EIO;
+ goto error;
+ }
for (i = 0; i < nr_bhs; i++)
brelse(bhs[i]);
prev = NULL;
^ permalink raw reply [flat|nested] 54+ messages in thread
* [PATCH 6.18 31/52] ima: Access decompressed kernel module to verify appended signature
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (29 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 30/52] fat: stop reading directory entries past the end-of-directory marker Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 32/52] ima: Fix stack-out-of-bounds in is_bprm_creds_for_exec() Greg Kroah-Hartman
` (21 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Karel Srot, Mimi Zohar, Paul Moore,
Coiby Xu, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Coiby Xu <coxu@redhat.com>
[ Upstream commit c200892b46ba3df3dd210b7117a463ec283600c3 ]
Currently, when in-kernel module decompression (CONFIG_MODULE_DECOMPRESS)
is enabled, IMA has no way to verify the appended module signature as it
can't decompress the module.
Define a new kernel_read_file_id enumerate READING_MODULE_COMPRESSED so
IMA can calculate the compressed kernel module data hash on
READING_MODULE_COMPRESSED and defer appraising/measuring it until on
READING_MODULE when the module has been decompressed.
Before enabling in-kernel module decompression, a kernel module in
initramfs can still be loaded with ima_policy=secure_boot. So adjust the
kernel module rule in secure_boot policy to allow either an IMA
signature OR an appended signature i.e. to use
"appraise func=MODULE_CHECK appraise_type=imasig|modsig".
Reported-by: Karel Srot <ksrot@redhat.com>
Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
Suggested-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Coiby Xu <coxu@redhat.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
Stable-dep-of: 377cae9851e8 ("ima: Fix stack-out-of-bounds in is_bprm_creds_for_exec()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/kernel_read_file.h | 1 +
kernel/module/main.c | 17 ++++++++++++++---
security/integrity/ima/ima_main.c | 24 ++++++++++++++++--------
security/integrity/ima/ima_policy.c | 3 ++-
security/ipe/hooks.c | 1 +
security/selinux/hooks.c | 5 +++--
6 files changed, 37 insertions(+), 14 deletions(-)
diff --git a/include/linux/kernel_read_file.h b/include/linux/kernel_read_file.h
index 90451e2e12bd1..d613a7b4dd35a 100644
--- a/include/linux/kernel_read_file.h
+++ b/include/linux/kernel_read_file.h
@@ -14,6 +14,7 @@
id(KEXEC_INITRAMFS, kexec-initramfs) \
id(POLICY, security-policy) \
id(X509_CERTIFICATE, x509-certificate) \
+ id(MODULE_COMPRESSED, kernel-module-compressed) \
id(MAX_ID, )
#define __fid_enumify(ENUM, dummy) READING_ ## ENUM,
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 769463d2b254b..fc5b17befb0b8 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -3692,24 +3692,35 @@ static int idempotent_wait_for_completion(struct idempotent *u)
static int init_module_from_file(struct file *f, const char __user * uargs, int flags)
{
+ bool compressed = !!(flags & MODULE_INIT_COMPRESSED_FILE);
struct load_info info = { };
void *buf = NULL;
int len;
+ int err;
- len = kernel_read_file(f, 0, &buf, INT_MAX, NULL, READING_MODULE);
+ len = kernel_read_file(f, 0, &buf, INT_MAX, NULL,
+ compressed ? READING_MODULE_COMPRESSED :
+ READING_MODULE);
if (len < 0) {
mod_stat_inc(&failed_kreads);
return len;
}
- if (flags & MODULE_INIT_COMPRESSED_FILE) {
- int err = module_decompress(&info, buf, len);
+ if (compressed) {
+ err = module_decompress(&info, buf, len);
vfree(buf); /* compressed data is no longer needed */
if (err) {
mod_stat_inc(&failed_decompress);
mod_stat_add_long(len, &invalid_decompress_bytes);
return err;
}
+ err = security_kernel_post_read_file(f, (char *)info.hdr, info.len,
+ READING_MODULE);
+ if (err) {
+ mod_stat_inc(&failed_kreads);
+ free_copy(&info, flags);
+ return err;
+ }
} else {
info.hdr = buf;
info.len = len;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index e51b53b7789b1..cda897267230d 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -235,7 +235,8 @@ static void ima_file_free(struct file *file)
static int process_measurement(struct file *file, const struct cred *cred,
struct lsm_prop *prop, char *buf, loff_t size,
- int mask, enum ima_hooks func)
+ int mask, enum ima_hooks func,
+ enum kernel_read_file_id read_id)
{
struct inode *real_inode, *inode = file_inode(file);
struct ima_iint_cache *iint = NULL;
@@ -406,6 +407,12 @@ static int process_measurement(struct file *file, const struct cred *cred,
if (rc != 0 && rc != -EBADF && rc != -EINVAL)
goto out_locked;
+ /* Defer measuring/appraising kernel modules to READING_MODULE */
+ if (read_id == READING_MODULE_COMPRESSED) {
+ must_appraise = 0;
+ goto out_locked;
+ }
+
if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */
pathname = ima_d_path(&file->f_path, &pathbuf, filename);
@@ -486,14 +493,14 @@ static int ima_file_mmap(struct file *file, unsigned long reqprot,
if (reqprot & PROT_EXEC) {
ret = process_measurement(file, current_cred(), &prop, NULL,
- 0, MAY_EXEC, MMAP_CHECK_REQPROT);
+ 0, MAY_EXEC, MMAP_CHECK_REQPROT, 0);
if (ret)
return ret;
}
if (prot & PROT_EXEC)
return process_measurement(file, current_cred(), &prop, NULL,
- 0, MAY_EXEC, MMAP_CHECK);
+ 0, MAY_EXEC, MMAP_CHECK, 0);
return 0;
}
@@ -577,7 +584,7 @@ static int ima_bprm_check(struct linux_binprm *bprm)
security_current_getlsmprop_subj(&prop);
return process_measurement(bprm->file, current_cred(),
- &prop, NULL, 0, MAY_EXEC, BPRM_CHECK);
+ &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0);
}
/**
@@ -607,7 +614,7 @@ static int ima_creds_check(struct linux_binprm *bprm, const struct file *file)
security_current_getlsmprop_subj(&prop);
return process_measurement((struct file *)file, bprm->cred, &prop, NULL,
- 0, MAY_EXEC, CREDS_CHECK);
+ 0, MAY_EXEC, CREDS_CHECK, 0);
}
/**
@@ -655,7 +662,7 @@ static int ima_file_check(struct file *file, int mask)
security_current_getlsmprop_subj(&prop);
return process_measurement(file, current_cred(), &prop, NULL, 0,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
- MAY_APPEND), FILE_CHECK);
+ MAY_APPEND), FILE_CHECK, 0);
}
/*
@@ -911,12 +918,13 @@ static int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
func = read_idmap[read_id] ?: FILE_CHECK;
security_current_getlsmprop_subj(&prop);
return process_measurement(file, current_cred(), &prop, NULL, 0,
- MAY_READ, func);
+ MAY_READ, func, 0);
}
const int read_idmap[READING_MAX_ID] = {
[READING_FIRMWARE] = FIRMWARE_CHECK,
[READING_MODULE] = MODULE_CHECK,
+ [READING_MODULE_COMPRESSED] = MODULE_CHECK,
[READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK,
[READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK,
[READING_POLICY] = POLICY_CHECK
@@ -954,7 +962,7 @@ static int ima_post_read_file(struct file *file, char *buf, loff_t size,
func = read_idmap[read_id] ?: FILE_CHECK;
security_current_getlsmprop_subj(&prop);
return process_measurement(file, current_cred(), &prop, buf, size,
- MAY_READ, func);
+ MAY_READ, func, read_id);
}
/**
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index db6d55af5a80b..d63af617d4586 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -241,7 +241,8 @@ static struct ima_rule_entry build_appraise_rules[] __ro_after_init = {
static struct ima_rule_entry secure_boot_rules[] __ro_after_init = {
{.action = APPRAISE, .func = MODULE_CHECK,
- .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
+ .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED |
+ IMA_CHECK_BLACKLIST},
{.action = APPRAISE, .func = FIRMWARE_CHECK,
.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
{.action = APPRAISE, .func = KEXEC_KERNEL_CHECK,
diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c
index d3092933abe21..7cbb1df0a76bc 100644
--- a/security/ipe/hooks.c
+++ b/security/ipe/hooks.c
@@ -119,6 +119,7 @@ int ipe_kernel_read_file(struct file *file, enum kernel_read_file_id id,
op = IPE_OP_FIRMWARE;
break;
case READING_MODULE:
+ case READING_MODULE_COMPRESSED:
op = IPE_OP_KERNEL_MODULE;
break;
case READING_KEXEC_INITRAMFS:
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 86c82a6df54c7..03ecfc6de2c3e 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4514,7 +4514,7 @@ static int selinux_kernel_read_file(struct file *file,
{
int rc = 0;
- BUILD_BUG_ON_MSG(READING_MAX_ID > 7,
+ BUILD_BUG_ON_MSG(READING_MAX_ID > 8,
"New kernel_read_file_id introduced; update SELinux!");
switch (id) {
@@ -4522,6 +4522,7 @@ static int selinux_kernel_read_file(struct file *file,
rc = selinux_kernel_load_from_file(file, SYSTEM__FIRMWARE_LOAD);
break;
case READING_MODULE:
+ case READING_MODULE_COMPRESSED:
rc = selinux_kernel_load_from_file(file, SYSTEM__MODULE_LOAD);
break;
case READING_KEXEC_IMAGE:
@@ -4550,7 +4551,7 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
{
int rc = 0;
- BUILD_BUG_ON_MSG(LOADING_MAX_ID > 7,
+ BUILD_BUG_ON_MSG(LOADING_MAX_ID > 8,
"New kernel_load_data_id introduced; update SELinux!");
switch (id) {
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 32/52] ima: Fix stack-out-of-bounds in is_bprm_creds_for_exec()
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (30 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 31/52] ima: Access decompressed kernel module to verify appended signature Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 33/52] ice: remove legacy Rx and construct SKB Greg Kroah-Hartman
` (20 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Chris J Arges, Mimi Zohar,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris J Arges <carges@cloudflare.com>
[ Upstream commit 377cae9851e8559e9d8b82a78c1ac0abeb18839c ]
KASAN reported a stack-out-of-bounds access in ima_appraise_measurement
from is_bprm_creds_for_exec:
BUG: KASAN: stack-out-of-bounds in ima_appraise_measurement+0x12dc/0x16a0
Read of size 1 at addr ffffc9000160f940 by task sudo/550
The buggy address belongs to stack of task sudo/550
and is located at offset 24 in frame:
ima_appraise_measurement+0x0/0x16a0
This frame has 2 objects:
[48, 56) 'file'
[80, 148) 'hash'
This is caused by using container_of on the *file pointer. This offset
calculation is what triggers the stack-out-of-bounds error.
In order to fix this, pass in a bprm_is_check boolean which can be set
depending on how process_measurement is called. If the caller has a
linux_binprm pointer and the function is BPRM_CHECK we can determine
is_check and set it then. Otherwise set it to false.
Fixes: 95b3cdafd7cb7 ("ima: instantiate the bprm_creds_for_exec() hook")
Signed-off-by: Chris J Arges <carges@cloudflare.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
security/integrity/ima/ima.h | 6 ++++--
security/integrity/ima/ima_appraise.c | 16 +++-------------
security/integrity/ima/ima_main.c | 22 +++++++++++++---------
3 files changed, 20 insertions(+), 24 deletions(-)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index e3d71d8d56e38..89ebe98ffc5e5 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -441,7 +441,8 @@ int ima_check_blacklist(struct ima_iint_cache *iint,
int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
- int xattr_len, const struct modsig *modsig);
+ int xattr_len, const struct modsig *modsig,
+ bool bprm_is_check);
int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode,
int mask, enum ima_hooks func);
void ima_update_xattr(struct ima_iint_cache *iint, struct file *file);
@@ -466,7 +467,8 @@ static inline int ima_appraise_measurement(enum ima_hooks func,
const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len,
- const struct modsig *modsig)
+ const struct modsig *modsig,
+ bool bprm_is_check)
{
return INTEGRITY_UNKNOWN;
}
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index a87ef7c05f11e..a3bdb7a0ab121 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -480,17 +480,6 @@ int ima_check_blacklist(struct ima_iint_cache *iint,
return rc;
}
-static bool is_bprm_creds_for_exec(enum ima_hooks func, struct file *file)
-{
- struct linux_binprm *bprm;
-
- if (func == BPRM_CHECK) {
- bprm = container_of(&file, struct linux_binprm, file);
- return bprm->is_check;
- }
- return false;
-}
-
/*
* ima_appraise_measurement - appraise file measurement
*
@@ -502,7 +491,8 @@ static bool is_bprm_creds_for_exec(enum ima_hooks func, struct file *file)
int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
- int xattr_len, const struct modsig *modsig)
+ int xattr_len, const struct modsig *modsig,
+ bool bprm_is_check)
{
static const char op[] = "appraise_data";
int audit_msgno = AUDIT_INTEGRITY_DATA;
@@ -524,7 +514,7 @@ int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
* of the script interpreter(userspace). Differentiate kernel and
* userspace enforced integrity audit messages.
*/
- if (is_bprm_creds_for_exec(func, file))
+ if (bprm_is_check)
audit_msgno = AUDIT_INTEGRITY_USERSPACE;
/* If reading the xattr failed and there's no modsig, error out. */
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index cda897267230d..d2a31b655822a 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -236,7 +236,8 @@ static void ima_file_free(struct file *file)
static int process_measurement(struct file *file, const struct cred *cred,
struct lsm_prop *prop, char *buf, loff_t size,
int mask, enum ima_hooks func,
- enum kernel_read_file_id read_id)
+ enum kernel_read_file_id read_id,
+ bool bprm_is_check)
{
struct inode *real_inode, *inode = file_inode(file);
struct ima_iint_cache *iint = NULL;
@@ -426,7 +427,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
inode_lock(inode);
rc = ima_appraise_measurement(func, iint, file,
pathname, xattr_value,
- xattr_len, modsig);
+ xattr_len, modsig,
+ bprm_is_check);
inode_unlock(inode);
}
if (!rc)
@@ -493,14 +495,15 @@ static int ima_file_mmap(struct file *file, unsigned long reqprot,
if (reqprot & PROT_EXEC) {
ret = process_measurement(file, current_cred(), &prop, NULL,
- 0, MAY_EXEC, MMAP_CHECK_REQPROT, 0);
+ 0, MAY_EXEC, MMAP_CHECK_REQPROT, 0,
+ false);
if (ret)
return ret;
}
if (prot & PROT_EXEC)
return process_measurement(file, current_cred(), &prop, NULL,
- 0, MAY_EXEC, MMAP_CHECK, 0);
+ 0, MAY_EXEC, MMAP_CHECK, 0, false);
return 0;
}
@@ -584,7 +587,8 @@ static int ima_bprm_check(struct linux_binprm *bprm)
security_current_getlsmprop_subj(&prop);
return process_measurement(bprm->file, current_cred(),
- &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0);
+ &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0,
+ bprm->is_check);
}
/**
@@ -614,7 +618,7 @@ static int ima_creds_check(struct linux_binprm *bprm, const struct file *file)
security_current_getlsmprop_subj(&prop);
return process_measurement((struct file *)file, bprm->cred, &prop, NULL,
- 0, MAY_EXEC, CREDS_CHECK, 0);
+ 0, MAY_EXEC, CREDS_CHECK, 0, false);
}
/**
@@ -662,7 +666,7 @@ static int ima_file_check(struct file *file, int mask)
security_current_getlsmprop_subj(&prop);
return process_measurement(file, current_cred(), &prop, NULL, 0,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
- MAY_APPEND), FILE_CHECK, 0);
+ MAY_APPEND), FILE_CHECK, 0, false);
}
/*
@@ -918,7 +922,7 @@ static int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
func = read_idmap[read_id] ?: FILE_CHECK;
security_current_getlsmprop_subj(&prop);
return process_measurement(file, current_cred(), &prop, NULL, 0,
- MAY_READ, func, 0);
+ MAY_READ, func, 0, false);
}
const int read_idmap[READING_MAX_ID] = {
@@ -962,7 +966,7 @@ static int ima_post_read_file(struct file *file, char *buf, loff_t size,
func = read_idmap[read_id] ?: FILE_CHECK;
security_current_getlsmprop_subj(&prop);
return process_measurement(file, current_cred(), &prop, buf, size,
- MAY_READ, func, read_id);
+ MAY_READ, func, read_id, false);
}
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 33/52] ice: remove legacy Rx and construct SKB
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (31 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 32/52] ima: Fix stack-out-of-bounds in is_bprm_creds_for_exec() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 34/52] ice: drop page splitting and recycling Greg Kroah-Hartman
` (19 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alexander Lobakin, Jacob Keller,
Michal Kubiak, Alexander Nowlin, Tony Nguyen, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michal Kubiak <michal.kubiak@intel.com>
[ Upstream commit 9e314a3c525c91c1e918546f472585cdbd44fbd1 ]
The commit 53844673d555 ("iavf: kill 'legacy-rx' for good") removed
the legacy Rx path in the iavf driver. This change applies the same
rationale to the ice driver.
The legacy Rx path relied on manual skb allocation and header copying,
which has become increasingly inefficient and difficult to maintain.
With the stabilization of build_skb() and the growing adoption of
features like XDP, page_pool, and multi-buffer support, the legacy
approach is no longer viable.
Key drawbacks of the legacy path included:
- Higher memory pressure due to direct page allocations and splitting;
- Redundant memcpy() operations for packet headers;
- CPU overhead from eth_get_headlen() and Flow Dissector usage;
- Compatibility issues with XDP, which imposes strict headroom and
tailroom requirements.
The ice driver, like iavf, does not benefit from the minimal headroom
savings that legacy Rx once offered, as it already splits pages into
fixed halves. Removing this path simplifies the Rx logic, eliminates
unnecessary branches in the hotpath, and prepares the driver for
upcoming enhancements.
In addition to removing the legacy Rx path, this change also eliminates
the custom construct_skb() functions from both the standard and
zero-copy (ZC) Rx paths. These are replaced with the build_skb()
and standardized xdp_build_skb_from_zc() helpers, aligning the driver
with the modern XDP infrastructure and reducing code duplication.
This cleanup also reduces code complexity and improves maintainability
as we move toward a more unified and modern Rx model across drivers.
Co-developed-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Reviewed-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Michal Kubiak <michal.kubiak@intel.com>
Tested-by: Alexander Nowlin <alexander.nowlin@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Stable-dep-of: e142dc4ef0f4 ("ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/ice/ice.h | 1 -
drivers/net/ethernet/intel/ice/ice_base.c | 23 +-----
drivers/net/ethernet/intel/ice/ice_ethtool.c | 5 --
drivers/net/ethernet/intel/ice/ice_main.c | 11 +--
drivers/net/ethernet/intel/ice/ice_txrx.c | 86 +-------------------
drivers/net/ethernet/intel/ice/ice_txrx.h | 16 ----
drivers/net/ethernet/intel/ice/ice_xsk.c | 72 +---------------
7 files changed, 6 insertions(+), 208 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 2b285ffa9d4b4..02c6e77db5447 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -509,7 +509,6 @@ enum ice_pf_flags {
ICE_FLAG_MOD_POWER_UNSUPPORTED,
ICE_FLAG_PHY_FW_LOAD_FAILED,
ICE_FLAG_ETHTOOL_CTXT, /* set when ethtool holds RTNL lock */
- ICE_FLAG_LEGACY_RX,
ICE_FLAG_VF_TRUE_PROMISC_ENA,
ICE_FLAG_MDD_AUTO_RESET_VF,
ICE_FLAG_VF_VLAN_PRUNING,
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index 2d35a278c555c..b3eb9f5125003 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -461,19 +461,6 @@ u16 ice_calc_ts_ring_count(struct ice_tx_ring *tx_ring)
return tx_ring->count + max_fetch_desc;
}
-/**
- * ice_rx_offset - Return expected offset into page to access data
- * @rx_ring: Ring we are requesting offset of
- *
- * Returns the offset value for ring into the data buffer.
- */
-static unsigned int ice_rx_offset(struct ice_rx_ring *rx_ring)
-{
- if (ice_ring_uses_build_skb(rx_ring))
- return ICE_SKB_PAD;
- return 0;
-}
-
/**
* ice_setup_rx_ctx - Configure a receive ring context
* @ring: The Rx ring to configure
@@ -586,13 +573,7 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
if (vsi->type == ICE_VSI_VF)
return 0;
- /* configure Rx buffer alignment */
- if (!vsi->netdev || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags))
- ice_clear_ring_build_skb_ena(ring);
- else
- ice_set_ring_build_skb_ena(ring);
-
- ring->rx_offset = ice_rx_offset(ring);
+ ring->rx_offset = ICE_SKB_PAD;
/* init queue specific tail register */
ring->tail = hw->hw_addr + QRX_TAIL(pf_q);
@@ -753,7 +734,7 @@ int ice_vsi_cfg_single_rxq(struct ice_vsi *vsi, u16 q_idx)
*/
static void ice_vsi_cfg_frame_size(struct ice_vsi *vsi, struct ice_rx_ring *ring)
{
- if (!vsi->netdev || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags)) {
+ if (!vsi->netdev) {
ring->max_frame = ICE_MAX_FRAME_LEGACY_RX;
ring->rx_buf_len = ICE_RXBUF_1664;
#if (PAGE_SIZE < 8192)
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index ec33586b6da52..706e9a5e83755 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -340,7 +340,6 @@ static const struct ice_priv_flag ice_gstrings_priv_flags[] = {
ICE_FLAG_VF_TRUE_PROMISC_ENA),
ICE_PRIV_FLAG("mdd-auto-reset-vf", ICE_FLAG_MDD_AUTO_RESET_VF),
ICE_PRIV_FLAG("vf-vlan-pruning", ICE_FLAG_VF_VLAN_PRUNING),
- ICE_PRIV_FLAG("legacy-rx", ICE_FLAG_LEGACY_RX),
};
#define ICE_PRIV_FLAG_ARRAY_SIZE ARRAY_SIZE(ice_gstrings_priv_flags)
@@ -1848,10 +1847,6 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags)
ice_nway_reset(netdev);
}
}
- if (test_bit(ICE_FLAG_LEGACY_RX, change_flags)) {
- /* down and up VSI so that changes of Rx cfg are reflected. */
- ice_down_up(vsi);
- }
/* don't allow modification of this flag when a single VF is in
* promiscuous mode because it's not supported
*/
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index f85051072ba2c..b6bbbaa85c925 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -2957,10 +2957,7 @@ int ice_vsi_determine_xdp_res(struct ice_vsi *vsi)
*/
static int ice_max_xdp_frame_size(struct ice_vsi *vsi)
{
- if (test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags))
- return ICE_RXBUF_1664;
- else
- return ICE_RXBUF_3072;
+ return ICE_RXBUF_3072;
}
/**
@@ -7879,12 +7876,6 @@ int ice_change_mtu(struct net_device *netdev, int new_mtu)
frame_size - ICE_ETH_PKT_HDR_PAD);
return -EINVAL;
}
- } else if (test_bit(ICE_FLAG_LEGACY_RX, pf->flags)) {
- if (new_mtu + ICE_ETH_PKT_HDR_PAD > ICE_MAX_FRAME_LEGACY_RX) {
- netdev_err(netdev, "Too big MTU for legacy-rx; Max is %d\n",
- ICE_MAX_FRAME_LEGACY_RX - ICE_ETH_PKT_HDR_PAD);
- return -EINVAL;
- }
}
/* if a reset is in progress, wait for some time for it to complete */
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 4831b9a5ac83b..9494fccf95a09 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -1170,87 +1170,6 @@ ice_build_skb(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp)
return skb;
}
-/**
- * ice_construct_skb - Allocate skb and populate it
- * @rx_ring: Rx descriptor ring to transact packets on
- * @xdp: xdp_buff pointing to the data
- *
- * This function allocates an skb. It then populates it with the page
- * data from the current receive descriptor, taking care to set up the
- * skb correctly.
- */
-static struct sk_buff *
-ice_construct_skb(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp)
-{
- unsigned int size = xdp->data_end - xdp->data;
- struct skb_shared_info *sinfo = NULL;
- struct ice_rx_buf *rx_buf;
- unsigned int nr_frags = 0;
- unsigned int headlen;
- struct sk_buff *skb;
-
- /* prefetch first cache line of first page */
- net_prefetch(xdp->data);
-
- if (unlikely(xdp_buff_has_frags(xdp))) {
- sinfo = xdp_get_shared_info_from_buff(xdp);
- nr_frags = sinfo->nr_frags;
- }
-
- /* allocate a skb to store the frags */
- skb = napi_alloc_skb(&rx_ring->q_vector->napi, ICE_RX_HDR_SIZE);
- if (unlikely(!skb))
- return NULL;
-
- rx_buf = &rx_ring->rx_buf[rx_ring->first_desc];
- skb_record_rx_queue(skb, rx_ring->q_index);
- /* Determine available headroom for copy */
- headlen = size;
- if (headlen > ICE_RX_HDR_SIZE)
- headlen = eth_get_headlen(skb->dev, xdp->data, ICE_RX_HDR_SIZE);
-
- /* align pull length to size of long to optimize memcpy performance */
- memcpy(__skb_put(skb, headlen), xdp->data, ALIGN(headlen,
- sizeof(long)));
-
- /* if we exhaust the linear part then add what is left as a frag */
- size -= headlen;
- if (size) {
- /* besides adding here a partial frag, we are going to add
- * frags from xdp_buff, make sure there is enough space for
- * them
- */
- if (unlikely(nr_frags >= MAX_SKB_FRAGS - 1)) {
- dev_kfree_skb(skb);
- return NULL;
- }
- skb_add_rx_frag(skb, 0, rx_buf->page,
- rx_buf->page_offset + headlen, size,
- xdp->frame_sz);
- } else {
- /* buffer is unused, restore biased page count in Rx buffer;
- * data was copied onto skb's linear part so there's no
- * need for adjusting page offset and we can reuse this buffer
- * as-is
- */
- rx_buf->pagecnt_bias++;
- }
-
- if (unlikely(xdp_buff_has_frags(xdp))) {
- struct skb_shared_info *skinfo = skb_shinfo(skb);
-
- memcpy(&skinfo->frags[skinfo->nr_frags], &sinfo->frags[0],
- sizeof(skb_frag_t) * nr_frags);
-
- xdp_update_skb_frags_info(skb, skinfo->nr_frags + nr_frags,
- sinfo->xdp_frags_size,
- nr_frags * xdp->frame_sz,
- xdp_buff_get_skb_flags(xdp));
- }
-
- return skb;
-}
-
/**
* ice_put_rx_buf - Clean up used buffer and either recycle or free
* @rx_ring: Rx descriptor ring to transact packets on
@@ -1465,10 +1384,7 @@ static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
continue;
construct_skb:
- if (likely(ice_ring_uses_build_skb(rx_ring)))
- skb = ice_build_skb(rx_ring, xdp);
- else
- skb = ice_construct_skb(rx_ring, xdp);
+ skb = ice_build_skb(rx_ring, xdp);
/* exit if we failed to retrieve a buffer */
if (!skb) {
rx_ring->ring_stats->rx_stats.alloc_buf_failed++;
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index 51b23ec1953ed..c8f6c976a7db4 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -381,7 +381,6 @@ struct ice_rx_ring {
dma_addr_t dma; /* physical address of ring */
u8 dcb_tc; /* Traffic class of ring */
u8 ptp_rx;
-#define ICE_RX_FLAGS_RING_BUILD_SKB BIT(1)
#define ICE_RX_FLAGS_CRC_STRIP_DIS BIT(2)
#define ICE_RX_FLAGS_MULTIDEV BIT(3)
#define ICE_RX_FLAGS_RING_GCS BIT(4)
@@ -439,21 +438,6 @@ struct ice_tx_ring {
__cacheline_group_end_aligned(cold);
} ____cacheline_internodealigned_in_smp;
-static inline bool ice_ring_uses_build_skb(struct ice_rx_ring *ring)
-{
- return !!(ring->flags & ICE_RX_FLAGS_RING_BUILD_SKB);
-}
-
-static inline void ice_set_ring_build_skb_ena(struct ice_rx_ring *ring)
-{
- ring->flags |= ICE_RX_FLAGS_RING_BUILD_SKB;
-}
-
-static inline void ice_clear_ring_build_skb_ena(struct ice_rx_ring *ring)
-{
- ring->flags &= ~ICE_RX_FLAGS_RING_BUILD_SKB;
-}
-
static inline bool ice_ring_ch_enabled(struct ice_tx_ring *ring)
{
return !!ring->ch;
diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c
index 575fd48f485f1..b25bc5ba40abf 100644
--- a/drivers/net/ethernet/intel/ice/ice_xsk.c
+++ b/drivers/net/ethernet/intel/ice/ice_xsk.c
@@ -392,69 +392,6 @@ bool ice_alloc_rx_bufs_zc(struct ice_rx_ring *rx_ring,
return __ice_alloc_rx_bufs_zc(rx_ring, xsk_pool, leftover);
}
-/**
- * ice_construct_skb_zc - Create an sk_buff from zero-copy buffer
- * @rx_ring: Rx ring
- * @xdp: Pointer to XDP buffer
- *
- * This function allocates a new skb from a zero-copy Rx buffer.
- *
- * Returns the skb on success, NULL on failure.
- */
-static struct sk_buff *
-ice_construct_skb_zc(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp)
-{
- unsigned int totalsize = xdp->data_end - xdp->data_meta;
- unsigned int metasize = xdp->data - xdp->data_meta;
- struct skb_shared_info *sinfo = NULL;
- struct sk_buff *skb;
- u32 nr_frags = 0;
-
- if (unlikely(xdp_buff_has_frags(xdp))) {
- sinfo = xdp_get_shared_info_from_buff(xdp);
- nr_frags = sinfo->nr_frags;
- }
- net_prefetch(xdp->data_meta);
-
- skb = napi_alloc_skb(&rx_ring->q_vector->napi, totalsize);
- if (unlikely(!skb))
- return NULL;
-
- memcpy(__skb_put(skb, totalsize), xdp->data_meta,
- ALIGN(totalsize, sizeof(long)));
-
- if (metasize) {
- skb_metadata_set(skb, metasize);
- __skb_pull(skb, metasize);
- }
-
- if (likely(!xdp_buff_has_frags(xdp)))
- goto out;
-
- for (int i = 0; i < nr_frags; i++) {
- struct skb_shared_info *skinfo = skb_shinfo(skb);
- skb_frag_t *frag = &sinfo->frags[i];
- struct page *page;
- void *addr;
-
- page = dev_alloc_page();
- if (!page) {
- dev_kfree_skb(skb);
- return NULL;
- }
- addr = page_to_virt(page);
-
- memcpy(addr, skb_frag_page(frag), skb_frag_size(frag));
-
- __skb_fill_page_desc_noacc(skinfo, skinfo->nr_frags++,
- addr, 0, skb_frag_size(frag));
- }
-
-out:
- xsk_buff_free(xdp);
- return skb;
-}
-
/**
* ice_clean_xdp_irq_zc - produce AF_XDP descriptors to CQ
* @xdp_ring: XDP Tx ring
@@ -757,20 +694,15 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring,
construct_skb:
/* XDP_PASS path */
- skb = ice_construct_skb_zc(rx_ring, first);
+ skb = xdp_build_skb_from_zc(first);
if (!skb) {
+ xsk_buff_free(first);
rx_ring->ring_stats->rx_stats.alloc_buf_failed++;
break;
}
first = NULL;
rx_ring->first_desc = ntc;
-
- if (eth_skb_pad(skb)) {
- skb = NULL;
- continue;
- }
-
total_rx_bytes += skb->len;
total_rx_packets++;
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 34/52] ice: drop page splitting and recycling
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (32 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 33/52] ice: remove legacy Rx and construct SKB Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 35/52] ice: fix crash in ethtool offline loopback test Greg Kroah-Hartman
` (18 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alexander Lobakin, Jacob Keller,
Michal Kubiak, Alexander Nowlin, Tony Nguyen, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michal Kubiak <michal.kubiak@intel.com>
[ Upstream commit 3a4f419f750946181e3d6a339a1ef1942c5b5685 ]
As part of the transition toward Page Pool integration, remove the
legacy page splitting and recycling logic from the ice driver. This
mirrors the approach taken in commit 920d86f3c552 ("iavf: drop page
splitting and recycling").
The previous model attempted to reuse partially consumed pages by
splitting them and tracking their usage across descriptors. While
this was once a memory optimization, it introduced significant
complexity and overhead in the Rx path, including:
- Manual refcount management and page reuse heuristics;
- Per-descriptor buffer shuffling, which could involve moving dozens
of `ice_rx_buf` structures per NAPI cycle;
- Increased branching and cache pressure in the hotpath.
This change simplifies the Rx logic by always allocating fresh pages
and letting the networking stack handle their lifecycle. Although this
may temporarily reduce performance (up to ~98% in some XDP cases), it
greatly improves maintainability and paves the way for Page Pool,
which will restore and exceed previous performance levels.
The `ice_rx_buf` array is retained for now to minimize diffstat and
ease future replacement with a shared buffer abstraction.
Co-developed-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Reviewed-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Michal Kubiak <michal.kubiak@intel.com>
Tested-by: Alexander Nowlin <alexander.nowlin@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Stable-dep-of: e142dc4ef0f4 ("ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/ice/ice.h | 2 +
drivers/net/ethernet/intel/ice/ice_base.c | 29 ++--
drivers/net/ethernet/intel/ice/ice_txrx.c | 139 ++-----------------
drivers/net/ethernet/intel/ice/ice_txrx.h | 72 ----------
drivers/net/ethernet/intel/ice/virt/queues.c | 5 +-
5 files changed, 24 insertions(+), 223 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 02c6e77db5447..c2332a7a8c87e 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -374,6 +374,8 @@ struct ice_vsi {
spinlock_t arfs_lock; /* protects aRFS hash table and filter state */
atomic_t *arfs_last_fltr_id;
+ u16 max_frame;
+
struct ice_aqc_vsi_props info; /* VSI properties */
struct ice_vsi_vlan_info vlan_info; /* vlan config to be restored */
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index b3eb9f5125003..fee58f879d9e1 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -495,7 +495,7 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
/* Receive Packet Data Buffer Size.
* The Packet Data Buffer Size is defined in 128 byte units.
*/
- rlan_ctx.dbuf = DIV_ROUND_UP(ring->rx_buf_len,
+ rlan_ctx.dbuf = DIV_ROUND_UP(ICE_RXBUF_3072,
BIT_ULL(ICE_RLAN_CTX_DBUF_S));
/* use 32 byte descriptors */
@@ -536,8 +536,8 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
/* Max packet size for this queue - must not be set to a larger value
* than 5 x DBUF
*/
- rlan_ctx.rxmax = min_t(u32, ring->max_frame,
- ICE_MAX_CHAINED_RX_BUFS * ring->rx_buf_len);
+ rlan_ctx.rxmax = min_t(u32, vsi->max_frame,
+ ICE_MAX_CHAINED_RX_BUFS * ICE_RXBUF_3072);
/* Rx queue threshold in units of 64 */
rlan_ctx.lrxqthresh = 1;
@@ -608,7 +608,7 @@ static unsigned int ice_get_frame_sz(struct ice_rx_ring *rx_ring)
#if (PAGE_SIZE >= 8192)
frame_sz = rx_ring->rx_buf_len;
#else
- frame_sz = ice_rx_pg_size(rx_ring) / 2;
+ frame_sz = PAGE_SIZE;
#endif
return frame_sz;
@@ -624,6 +624,7 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
{
struct device *dev = ice_pf_to_dev(ring->vsi->back);
u32 num_bufs = ICE_RX_DESC_UNUSED(ring);
+ u32 rx_buf_len;
int err;
if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF) {
@@ -631,7 +632,7 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->q_index,
ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
+ ICE_RXBUF_3072);
if (err)
return err;
}
@@ -640,12 +641,12 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
if (ring->xsk_pool) {
xdp_rxq_info_unreg(&ring->xdp_rxq);
- ring->rx_buf_len =
+ rx_buf_len =
xsk_pool_get_rx_frame_size(ring->xsk_pool);
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->q_index,
ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
+ rx_buf_len);
if (err)
return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
@@ -663,7 +664,7 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->q_index,
ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
+ ICE_RXBUF_3072);
if (err)
return err;
}
@@ -735,17 +736,9 @@ int ice_vsi_cfg_single_rxq(struct ice_vsi *vsi, u16 q_idx)
static void ice_vsi_cfg_frame_size(struct ice_vsi *vsi, struct ice_rx_ring *ring)
{
if (!vsi->netdev) {
- ring->max_frame = ICE_MAX_FRAME_LEGACY_RX;
- ring->rx_buf_len = ICE_RXBUF_1664;
-#if (PAGE_SIZE < 8192)
- } else if (!ICE_2K_TOO_SMALL_WITH_PADDING &&
- (vsi->netdev->mtu <= ETH_DATA_LEN)) {
- ring->max_frame = ICE_RXBUF_1536 - NET_IP_ALIGN;
- ring->rx_buf_len = ICE_RXBUF_1536 - NET_IP_ALIGN;
-#endif
+ vsi->max_frame = ICE_MAX_FRAME_LEGACY_RX;
} else {
- ring->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX;
- ring->rx_buf_len = ICE_RXBUF_3072;
+ vsi->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX;
}
}
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 9494fccf95a09..2447cccaeafd9 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -544,13 +544,13 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
*/
dma_sync_single_range_for_cpu(dev, rx_buf->dma,
rx_buf->page_offset,
- rx_ring->rx_buf_len,
+ ICE_RXBUF_3072,
DMA_FROM_DEVICE);
/* free resources associated with mapping */
- dma_unmap_page_attrs(dev, rx_buf->dma, ice_rx_pg_size(rx_ring),
+ dma_unmap_page_attrs(dev, rx_buf->dma, PAGE_SIZE,
DMA_FROM_DEVICE, ICE_RX_DMA_ATTR);
- __page_frag_cache_drain(rx_buf->page, rx_buf->pagecnt_bias);
+ __free_page(rx_buf->page);
rx_buf->page = NULL;
rx_buf->page_offset = 0;
@@ -804,10 +804,6 @@ ice_alloc_mapped_page(struct ice_rx_ring *rx_ring, struct ice_rx_buf *bi)
struct page *page = bi->page;
dma_addr_t dma;
- /* since we are recycling buffers we should seldom need to alloc */
- if (likely(page))
- return true;
-
/* alloc new page for storage */
page = dev_alloc_pages(ice_rx_pg_order(rx_ring));
if (unlikely(!page)) {
@@ -816,7 +812,7 @@ ice_alloc_mapped_page(struct ice_rx_ring *rx_ring, struct ice_rx_buf *bi)
}
/* map page for use */
- dma = dma_map_page_attrs(rx_ring->dev, page, 0, ice_rx_pg_size(rx_ring),
+ dma = dma_map_page_attrs(rx_ring->dev, page, 0, PAGE_SIZE,
DMA_FROM_DEVICE, ICE_RX_DMA_ATTR);
/* if mapping failed free memory back to system since
@@ -832,7 +828,6 @@ ice_alloc_mapped_page(struct ice_rx_ring *rx_ring, struct ice_rx_buf *bi)
bi->page = page;
bi->page_offset = rx_ring->rx_offset;
page_ref_add(page, USHRT_MAX - 1);
- bi->pagecnt_bias = USHRT_MAX;
return true;
}
@@ -903,7 +898,7 @@ bool ice_alloc_rx_bufs(struct ice_rx_ring *rx_ring, unsigned int cleaned_count)
/* sync the buffer for use by the device */
dma_sync_single_range_for_device(rx_ring->dev, bi->dma,
bi->page_offset,
- rx_ring->rx_buf_len,
+ ICE_RXBUF_3072,
DMA_FROM_DEVICE);
/* Refresh the desc even if buffer_addrs didn't change
@@ -932,69 +927,6 @@ bool ice_alloc_rx_bufs(struct ice_rx_ring *rx_ring, unsigned int cleaned_count)
return !!cleaned_count;
}
-/**
- * ice_rx_buf_adjust_pg_offset - Prepare Rx buffer for reuse
- * @rx_buf: Rx buffer to adjust
- * @size: Size of adjustment
- *
- * Update the offset within page so that Rx buf will be ready to be reused.
- * For systems with PAGE_SIZE < 8192 this function will flip the page offset
- * so the second half of page assigned to Rx buffer will be used, otherwise
- * the offset is moved by "size" bytes
- */
-static void
-ice_rx_buf_adjust_pg_offset(struct ice_rx_buf *rx_buf, unsigned int size)
-{
-#if (PAGE_SIZE < 8192)
- /* flip page offset to other buffer */
- rx_buf->page_offset ^= size;
-#else
- /* move offset up to the next cache line */
- rx_buf->page_offset += size;
-#endif
-}
-
-/**
- * ice_can_reuse_rx_page - Determine if page can be reused for another Rx
- * @rx_buf: buffer containing the page
- *
- * If page is reusable, we have a green light for calling ice_reuse_rx_page,
- * which will assign the current buffer to the buffer that next_to_alloc is
- * pointing to; otherwise, the DMA mapping needs to be destroyed and
- * page freed
- */
-static bool
-ice_can_reuse_rx_page(struct ice_rx_buf *rx_buf)
-{
- unsigned int pagecnt_bias = rx_buf->pagecnt_bias;
- struct page *page = rx_buf->page;
-
- /* avoid re-using remote and pfmemalloc pages */
- if (!dev_page_is_reusable(page))
- return false;
-
- /* if we are only owner of page we can reuse it */
- if (unlikely(rx_buf->pgcnt - pagecnt_bias > 1))
- return false;
-#if (PAGE_SIZE >= 8192)
-#define ICE_LAST_OFFSET \
- (SKB_WITH_OVERHEAD(PAGE_SIZE) - ICE_RXBUF_3072)
- if (rx_buf->page_offset > ICE_LAST_OFFSET)
- return false;
-#endif /* PAGE_SIZE >= 8192) */
-
- /* If we have drained the page fragment pool we need to update
- * the pagecnt_bias and page count so that we fully restock the
- * number of references the driver holds.
- */
- if (unlikely(pagecnt_bias == 1)) {
- page_ref_add(page, USHRT_MAX - 1);
- rx_buf->pagecnt_bias = USHRT_MAX;
- }
-
- return true;
-}
-
/**
* ice_add_xdp_frag - Add contents of Rx buffer to xdp buf as a frag
* @rx_ring: Rx descriptor ring to transact packets on
@@ -1033,35 +965,6 @@ ice_add_xdp_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
return 0;
}
-/**
- * ice_reuse_rx_page - page flip buffer and store it back on the ring
- * @rx_ring: Rx descriptor ring to store buffers on
- * @old_buf: donor buffer to have page reused
- *
- * Synchronizes page for reuse by the adapter
- */
-static void
-ice_reuse_rx_page(struct ice_rx_ring *rx_ring, struct ice_rx_buf *old_buf)
-{
- u16 nta = rx_ring->next_to_alloc;
- struct ice_rx_buf *new_buf;
-
- new_buf = &rx_ring->rx_buf[nta];
-
- /* update, and store next to alloc */
- nta++;
- rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
-
- /* Transfer page from old buffer to new buffer.
- * Move each member individually to avoid possible store
- * forwarding stalls and unnecessary copy of skb.
- */
- new_buf->dma = old_buf->dma;
- new_buf->page = old_buf->page;
- new_buf->page_offset = old_buf->page_offset;
- new_buf->pagecnt_bias = old_buf->pagecnt_bias;
-}
-
/**
* ice_get_rx_buf - Fetch Rx buffer and synchronize data for use
* @rx_ring: Rx descriptor ring to transact packets on
@@ -1087,9 +990,6 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size,
rx_buf->page_offset, size,
DMA_FROM_DEVICE);
- /* We have pulled a buffer for use, so decrement pagecnt_bias */
- rx_buf->pagecnt_bias--;
-
return rx_buf;
}
@@ -1184,16 +1084,10 @@ ice_put_rx_buf(struct ice_rx_ring *rx_ring, struct ice_rx_buf *rx_buf)
if (!rx_buf)
return;
- if (ice_can_reuse_rx_page(rx_buf)) {
- /* hand second half of page back to the ring */
- ice_reuse_rx_page(rx_ring, rx_buf);
- } else {
- /* we are not reusing the buffer so unmap it */
- dma_unmap_page_attrs(rx_ring->dev, rx_buf->dma,
- ice_rx_pg_size(rx_ring), DMA_FROM_DEVICE,
- ICE_RX_DMA_ATTR);
- __page_frag_cache_drain(rx_buf->page, rx_buf->pagecnt_bias);
- }
+ /* we are not reusing the buffer so unmap it */
+ dma_unmap_page_attrs(rx_ring->dev, rx_buf->dma,
+ PAGE_SIZE, DMA_FROM_DEVICE,
+ ICE_RX_DMA_ATTR);
/* clear contents of buffer_info */
rx_buf->page = NULL;
@@ -1219,27 +1113,12 @@ static void ice_put_rx_mbuf(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
u32 idx = rx_ring->first_desc;
u32 cnt = rx_ring->count;
struct ice_rx_buf *buf;
- u32 xdp_frags = 0;
- int i = 0;
-
- if (unlikely(xdp_buff_has_frags(xdp)))
- xdp_frags = xdp_get_shared_info_from_buff(xdp)->nr_frags;
while (idx != ntc) {
buf = &rx_ring->rx_buf[idx];
if (++idx == cnt)
idx = 0;
- /* An XDP program could release fragments from the end of the
- * buffer. For these, we need to keep the pagecnt_bias as-is.
- * To do this, only adjust pagecnt_bias for fragments up to
- * the total remaining after the XDP program has run.
- */
- if (verdict != ICE_XDP_CONSUMED)
- ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz);
- else if (i++ <= xdp_frags)
- buf->pagecnt_bias++;
-
ice_put_rx_buf(rx_ring, buf);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index c8f6c976a7db4..0a3961535e407 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -27,71 +27,7 @@
#define ICE_MAX_TXQ_PER_TXQG 128
-/* Attempt to maximize the headroom available for incoming frames. We use a 2K
- * buffer for MTUs <= 1500 and need 1536/1534 to store the data for the frame.
- * This leaves us with 512 bytes of room. From that we need to deduct the
- * space needed for the shared info and the padding needed to IP align the
- * frame.
- *
- * Note: For cache line sizes 256 or larger this value is going to end
- * up negative. In these cases we should fall back to the legacy
- * receive path.
- */
-#if (PAGE_SIZE < 8192)
-#define ICE_2K_TOO_SMALL_WITH_PADDING \
- ((unsigned int)(NET_SKB_PAD + ICE_RXBUF_1536) > \
- SKB_WITH_OVERHEAD(ICE_RXBUF_2048))
-
-/**
- * ice_compute_pad - compute the padding
- * @rx_buf_len: buffer length
- *
- * Figure out the size of half page based on given buffer length and
- * then subtract the skb_shared_info followed by subtraction of the
- * actual buffer length; this in turn results in the actual space that
- * is left for padding usage
- */
-static inline int ice_compute_pad(int rx_buf_len)
-{
- int half_page_size;
-
- half_page_size = ALIGN(rx_buf_len, PAGE_SIZE / 2);
- return SKB_WITH_OVERHEAD(half_page_size) - rx_buf_len;
-}
-
-/**
- * ice_skb_pad - determine the padding that we can supply
- *
- * Figure out the right Rx buffer size and based on that calculate the
- * padding
- */
-static inline int ice_skb_pad(void)
-{
- int rx_buf_len;
-
- /* If a 2K buffer cannot handle a standard Ethernet frame then
- * optimize padding for a 3K buffer instead of a 1.5K buffer.
- *
- * For a 3K buffer we need to add enough padding to allow for
- * tailroom due to NET_IP_ALIGN possibly shifting us out of
- * cache-line alignment.
- */
- if (ICE_2K_TOO_SMALL_WITH_PADDING)
- rx_buf_len = ICE_RXBUF_3072 + SKB_DATA_ALIGN(NET_IP_ALIGN);
- else
- rx_buf_len = ICE_RXBUF_1536;
-
- /* if needed make room for NET_IP_ALIGN */
- rx_buf_len -= NET_IP_ALIGN;
-
- return ice_compute_pad(rx_buf_len);
-}
-
-#define ICE_SKB_PAD ice_skb_pad()
-#else
-#define ICE_2K_TOO_SMALL_WITH_PADDING false
#define ICE_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
-#endif
/* We are assuming that the cache line is always 64 Bytes here for ice.
* In order to make sure that is a correct assumption there is a check in probe
@@ -202,7 +138,6 @@ struct ice_rx_buf {
struct page *page;
unsigned int page_offset;
unsigned int pgcnt;
- unsigned int pagecnt_bias;
};
struct ice_q_stats {
@@ -376,7 +311,6 @@ struct ice_rx_ring {
struct ice_tx_ring *xdp_ring;
struct ice_rx_ring *next; /* pointer to next ring in q_vector */
struct xsk_buff_pool *xsk_pool;
- u16 max_frame;
u16 rx_buf_len;
dma_addr_t dma; /* physical address of ring */
u8 dcb_tc; /* Traffic class of ring */
@@ -492,15 +426,9 @@ struct ice_coalesce_stored {
static inline unsigned int ice_rx_pg_order(struct ice_rx_ring *ring)
{
-#if (PAGE_SIZE < 8192)
- if (ring->rx_buf_len > (PAGE_SIZE / 2))
- return 1;
-#endif
return 0;
}
-#define ice_rx_pg_size(_ring) (PAGE_SIZE << ice_rx_pg_order(_ring))
-
union ice_32b_rx_flex_desc;
void ice_init_ctrl_rx_descs(struct ice_rx_ring *rx_ring, u32 num_descs);
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c b/drivers/net/ethernet/intel/ice/virt/queues.c
index 0765ee901b7c7..771434ec881e2 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.c
+++ b/drivers/net/ethernet/intel/ice/virt/queues.c
@@ -863,18 +863,17 @@ int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg)
(qpi->rxq.databuffer_size > ((16 * 1024) - 128) ||
qpi->rxq.databuffer_size < 128))
goto error_param;
- ring->rx_buf_len = qpi->rxq.databuffer_size;
if (qpi->rxq.max_pkt_size > max_frame_size ||
qpi->rxq.max_pkt_size < 64)
goto error_param;
- ring->max_frame = qpi->rxq.max_pkt_size;
+ vsi->max_frame = qpi->rxq.max_pkt_size;
/* add space for the port VLAN since the VF driver is
* not expected to account for it in the MTU
* calculation
*/
if (ice_vf_is_port_vlan_ena(vf))
- ring->max_frame += VLAN_HLEN;
+ vsi->max_frame += VLAN_HLEN;
if (ice_vsi_cfg_single_rxq(vsi, q_idx)) {
dev_warn(ice_pf_to_dev(pf), "VF-%d failed to configure RX queue %d\n",
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 35/52] ice: fix crash in ethtool offline loopback test
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (33 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 34/52] ice: drop page splitting and recycling Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 36/52] ice: fix rxq info registering in mbuf packets Greg Kroah-Hartman
` (17 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Michal Schmidt, Aleksandr Loktionov,
Tony Nguyen, Sasha Levin, Rinitha S
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michal Schmidt <mschmidt@redhat.com>
[ Upstream commit a9c354e656597aededa027d63d2ff0973f6b033f ]
Since the conversion of ice to page pool, the ethtool loopback test
crashes:
BUG: kernel NULL pointer dereference, address: 000000000000000c
#PF: supervisor write access in kernel mode
#PF: error_code(0x0002) - not-present page
PGD 1100f1067 P4D 0
Oops: Oops: 0002 [#1] SMP NOPTI
CPU: 23 UID: 0 PID: 5904 Comm: ethtool Kdump: loaded Not tainted 6.19.0-0.rc7.260128g1f97d9dcf5364.49.eln154.x86_64 #1 PREEMPT(lazy)
Hardware name: [...]
RIP: 0010:ice_alloc_rx_bufs+0x1cd/0x310 [ice]
Code: 83 6c 24 30 01 66 41 89 47 08 0f 84 c0 00 00 00 41 0f b7 dc 48 8b 44 24 18 48 c1 e3 04 41 bb 00 10 00 00 48 8d 2c 18 8b 04 24 <89> 45 0c 41 8b 4d 00 49 d3 e3 44 3b 5c 24 24 0f 83 ac fe ff ff 44
RSP: 0018:ff7894738aa1f768 EFLAGS: 00010246
RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 0000000000000700 RDI: 0000000000000000
RBP: 0000000000000000 R08: ff16dcae79880200 R09: 0000000000000019
R10: 0000000000000001 R11: 0000000000001000 R12: 0000000000000000
R13: 0000000000000000 R14: 0000000000000000 R15: ff16dcae6c670000
FS: 00007fcf428850c0(0000) GS:ff16dcb149710000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000000000000000c CR3: 0000000121227005 CR4: 0000000000773ef0
PKRU: 55555554
Call Trace:
<TASK>
ice_vsi_cfg_rxq+0xca/0x460 [ice]
ice_vsi_cfg_rxqs+0x54/0x70 [ice]
ice_loopback_test+0xa9/0x520 [ice]
ice_self_test+0x1b9/0x280 [ice]
ethtool_self_test+0xe5/0x200
__dev_ethtool+0x1106/0x1a90
dev_ethtool+0xbe/0x1a0
dev_ioctl+0x258/0x4c0
sock_do_ioctl+0xe3/0x130
__x64_sys_ioctl+0xb9/0x100
do_syscall_64+0x7c/0x700
entry_SYSCALL_64_after_hwframe+0x76/0x7e
[...]
It crashes because we have not initialized libeth for the rx ring.
Fix it by treating ICE_VSI_LB VSIs slightly more like normal PF VSIs and
letting them have a q_vector. It's just a dummy, because the loopback
test does not use interrupts, but it contains a napi struct that can be
passed to libeth_rx_fq_create() called from ice_vsi_cfg_rxq() ->
ice_rxq_pp_create().
Fixes: 93f53db9f9dc ("ice: switch to Page Pool")
Signed-off-by: Michal Schmidt <mschmidt@redhat.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Stable-dep-of: e142dc4ef0f4 ("ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/ice/ice_base.c | 5 ++++-
drivers/net/ethernet/intel/ice/ice_ethtool.c | 4 ++++
drivers/net/ethernet/intel/ice/ice_lib.c | 15 ++++++++++-----
3 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index fee58f879d9e1..f0aa26144deb5 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -123,6 +123,8 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, u16 v_idx)
if (vsi->type == ICE_VSI_VF) {
ice_calc_vf_reg_idx(vsi->vf, q_vector);
goto out;
+ } else if (vsi->type == ICE_VSI_LB) {
+ goto skip_alloc;
} else if (vsi->type == ICE_VSI_CTRL && vsi->vf) {
struct ice_vsi *ctrl_vsi = ice_get_vf_ctrl_vsi(pf, vsi);
@@ -627,7 +629,8 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
u32 rx_buf_len;
int err;
- if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF) {
+ if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF ||
+ ring->vsi->type == ICE_VSI_LB) {
if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->q_index,
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 706e9a5e83755..5490c5e547b4d 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -1277,6 +1277,10 @@ static u64 ice_loopback_test(struct net_device *netdev)
test_vsi->netdev = netdev;
tx_ring = test_vsi->tx_rings[0];
rx_ring = test_vsi->rx_rings[0];
+ /* Dummy q_vector and napi. Fill the minimum required for
+ * ice_rxq_pp_create().
+ */
+ rx_ring->q_vector->napi.dev = netdev;
if (ice_lbtest_prepare_rings(test_vsi)) {
ret = 2;
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 6de55d2424f45..1795b935636ec 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -107,10 +107,6 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi)
if (!vsi->rxq_map)
goto err_rxq_map;
- /* There is no need to allocate q_vectors for a loopback VSI. */
- if (vsi->type == ICE_VSI_LB)
- return 0;
-
/* allocate memory for q_vector pointers */
vsi->q_vectors = devm_kcalloc(dev, vsi->num_q_vectors,
sizeof(*vsi->q_vectors), GFP_KERNEL);
@@ -239,6 +235,8 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi)
case ICE_VSI_LB:
vsi->alloc_txq = 1;
vsi->alloc_rxq = 1;
+ /* A dummy q_vector, no actual IRQ. */
+ vsi->num_q_vectors = 1;
break;
default:
dev_warn(ice_pf_to_dev(pf), "Unknown VSI type %d\n", vsi_type);
@@ -2425,14 +2423,21 @@ static int ice_vsi_cfg_def(struct ice_vsi *vsi)
}
break;
case ICE_VSI_LB:
- ret = ice_vsi_alloc_rings(vsi);
+ ret = ice_vsi_alloc_q_vectors(vsi);
if (ret)
goto unroll_vsi_init;
+ ret = ice_vsi_alloc_rings(vsi);
+ if (ret)
+ goto unroll_alloc_q_vector;
+
ret = ice_vsi_alloc_ring_stats(vsi);
if (ret)
goto unroll_vector_base;
+ /* Simply map the dummy q_vector to the only rx_ring */
+ vsi->rx_rings[0]->q_vector = vsi->q_vectors[0];
+
break;
default:
/* clean up the resources and exit */
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 36/52] ice: fix rxq info registering in mbuf packets
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (34 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 35/52] ice: fix crash in ethtool offline loopback test Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 37/52] ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz Greg Kroah-Hartman
` (16 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Aleksandr Loktionov, Larysa Zaremba,
Jakub Kicinski, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Larysa Zaremba <larysa.zaremba@intel.com>
[ Upstream commit 02852b47c706772af795d3e28fca99fc9b923b2c ]
XDP RxQ info contains frag_size, which depends on the MTU. This makes the
old way of registering RxQ info before calculating new buffer sizes
invalid. Currently, it leads to frag_size being outdated, making it
sometimes impossible to grow tailroom in a mbuf packet. E.g. fragments are
actually 3K+, but frag size is still as if MTU was 1500.
Always register new XDP RxQ info after reconfiguring memory pools.
Fixes: 2fba7dc5157b ("ice: Add support for XDP multi-buffer on Rx side")
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
Link: https://patch.msgid.link/20260305111253.2317394-4-larysa.zaremba@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: e142dc4ef0f4 ("ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/ice/ice_base.c | 25 +++++---------------
drivers/net/ethernet/intel/ice/ice_ethtool.c | 1 +
drivers/net/ethernet/intel/ice/ice_txrx.c | 8 +++++++
drivers/net/ethernet/intel/ice/ice_xsk.c | 3 +++
4 files changed, 18 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index f0aa26144deb5..9436bdff607e5 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -631,19 +631,8 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF ||
ring->vsi->type == ICE_VSI_LB) {
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
- err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->q_index,
- ring->q_vector->napi.napi_id,
- ICE_RXBUF_3072);
- if (err)
- return err;
- }
-
ice_rx_xsk_pool(ring);
if (ring->xsk_pool) {
- xdp_rxq_info_unreg(&ring->xdp_rxq);
-
rx_buf_len =
xsk_pool_get_rx_frame_size(ring->xsk_pool);
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
@@ -663,14 +652,12 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
dev_info(dev, "Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring %d\n",
ring->q_index);
} else {
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
- err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->q_index,
- ring->q_vector->napi.napi_id,
- ICE_RXBUF_3072);
- if (err)
- return err;
- }
+ err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->q_index,
+ ring->q_vector->napi.napi_id,
+ ICE_RXBUF_3072);
+ if (err)
+ return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_PAGE_SHARED,
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 5490c5e547b4d..558733788cc1f 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -3309,6 +3309,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
rx_rings[i].cached_phctime = pf->ptp.cached_phc_time;
rx_rings[i].desc = NULL;
rx_rings[i].rx_buf = NULL;
+ rx_rings[i].xdp_rxq = (struct xdp_rxq_info){ };
/* this is to allow wr32 to have something to write to
* during early allocation of Rx buffers
*/
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 2447cccaeafd9..df5083f588611 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -556,6 +556,14 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
rx_buf->page_offset = 0;
}
+ if ((rx_ring->vsi->type == ICE_VSI_PF ||
+ rx_ring->vsi->type == ICE_VSI_SF ||
+ rx_ring->vsi->type == ICE_VSI_LB) &&
+ xdp_rxq_info_is_reg(&rx_ring->xdp_rxq)) {
+ xdp_rxq_info_detach_mem_model(&rx_ring->xdp_rxq);
+ xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+ }
+
rx_skip_free:
if (rx_ring->xsk_pool)
memset(rx_ring->xdp_buf, 0, array_size(rx_ring->count, sizeof(*rx_ring->xdp_buf)));
diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c
index b25bc5ba40abf..4a7f999f4355d 100644
--- a/drivers/net/ethernet/intel/ice/ice_xsk.c
+++ b/drivers/net/ethernet/intel/ice/ice_xsk.c
@@ -936,6 +936,9 @@ void ice_xsk_clean_rx_ring(struct ice_rx_ring *rx_ring)
u16 ntc = rx_ring->next_to_clean;
u16 ntu = rx_ring->next_to_use;
+ if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
+ xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+
while (ntc != ntu) {
struct xdp_buff *xdp = *ice_xdp_buf(rx_ring, ntc);
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 37/52] ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (35 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 36/52] ice: fix rxq info registering in mbuf packets Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 38/52] xfs: factor out xfs_attr3_node_entry_remove Greg Kroah-Hartman
` (15 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Aleksandr Loktionov, Larysa Zaremba,
Jakub Kicinski, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Larysa Zaremba <larysa.zaremba@intel.com>
[ Upstream commit e142dc4ef0f451b7ef99d09aaa84e9389af629d7 ]
The only user of frag_size field in XDP RxQ info is
bpf_xdp_frags_increase_tail(). It clearly expects whole buff size instead
of DMA write size. Different assumptions in ice driver configuration lead
to negative tailroom.
This allows to trigger kernel panic, when using
XDP_ADJUST_TAIL_GROW_MULTI_BUFF xskxceiver test and changing packet size to
6912 and the requested offset to a huge value, e.g.
XSK_UMEM__MAX_FRAME_SIZE * 100.
Due to other quirks of the ZC configuration in ice, panic is not observed
in ZC mode, but tailroom growing still fails when it should not.
Use fill queue buffer truesize instead of DMA write size in XDP RxQ info.
Fix ZC mode too by using the new helper.
Fixes: 2fba7dc5157b ("ice: Add support for XDP multi-buffer on Rx side")
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
Link: https://patch.msgid.link/20260305111253.2317394-5-larysa.zaremba@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/ice/ice_base.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index 9436bdff607e5..0adcc3e1dbfb4 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -626,19 +626,18 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
{
struct device *dev = ice_pf_to_dev(ring->vsi->back);
u32 num_bufs = ICE_RX_DESC_UNUSED(ring);
- u32 rx_buf_len;
int err;
if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF ||
ring->vsi->type == ICE_VSI_LB) {
ice_rx_xsk_pool(ring);
if (ring->xsk_pool) {
- rx_buf_len =
- xsk_pool_get_rx_frame_size(ring->xsk_pool);
+ u32 frag_size =
+ xsk_pool_get_rx_frag_step(ring->xsk_pool);
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->q_index,
ring->q_vector->napi.napi_id,
- rx_buf_len);
+ frag_size);
if (err)
return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
@@ -655,7 +654,7 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->q_index,
ring->q_vector->napi.napi_id,
- ICE_RXBUF_3072);
+ ice_get_frame_sz(ring));
if (err)
return err;
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 38/52] xfs: factor out xfs_attr3_node_entry_remove
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (36 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 37/52] ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 39/52] xfs: factor out xfs_attr3_leaf_init Greg Kroah-Hartman
` (14 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Long Li,
Carlos Maiolino, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <leo.lilong@huawei.com>
[ Upstream commit ce4e789cf3561c9fac73cc24445bfed9ea0c514b ]
Factor out wrapper xfs_attr3_node_entry_remove function, which
exported for external use.
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Long Li <leo.lilong@huawei.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Stable-dep-of: b854e1c4eff3 ("xfs: close crash window in attr dabtree inactivation")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/libxfs/xfs_da_btree.c | 53 ++++++++++++++++++++++++++++--------
fs/xfs/libxfs/xfs_da_btree.h | 2 ++
2 files changed, 44 insertions(+), 11 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
index 90fbdef23def1..ca5f99c0878f2 100644
--- a/fs/xfs/libxfs/xfs_da_btree.c
+++ b/fs/xfs/libxfs/xfs_da_btree.c
@@ -1506,21 +1506,20 @@ xfs_da3_fixhashpath(
}
/*
- * Remove an entry from an intermediate node.
+ * Internal implementation to remove an entry from an intermediate node.
*/
STATIC void
-xfs_da3_node_remove(
- struct xfs_da_state *state,
- struct xfs_da_state_blk *drop_blk)
+__xfs_da3_node_remove(
+ struct xfs_trans *tp,
+ struct xfs_inode *dp,
+ struct xfs_da_geometry *geo,
+ struct xfs_da_state_blk *drop_blk)
{
struct xfs_da_intnode *node;
struct xfs_da3_icnode_hdr nodehdr;
struct xfs_da_node_entry *btree;
int index;
int tmp;
- struct xfs_inode *dp = state->args->dp;
-
- trace_xfs_da_node_remove(state->args);
node = drop_blk->bp->b_addr;
xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
@@ -1536,17 +1535,17 @@ xfs_da3_node_remove(
tmp = nodehdr.count - index - 1;
tmp *= (uint)sizeof(xfs_da_node_entry_t);
memmove(&btree[index], &btree[index + 1], tmp);
- xfs_trans_log_buf(state->args->trans, drop_blk->bp,
+ xfs_trans_log_buf(tp, drop_blk->bp,
XFS_DA_LOGRANGE(node, &btree[index], tmp));
index = nodehdr.count - 1;
}
memset(&btree[index], 0, sizeof(xfs_da_node_entry_t));
- xfs_trans_log_buf(state->args->trans, drop_blk->bp,
+ xfs_trans_log_buf(tp, drop_blk->bp,
XFS_DA_LOGRANGE(node, &btree[index], sizeof(btree[index])));
nodehdr.count -= 1;
xfs_da3_node_hdr_to_disk(dp->i_mount, node, &nodehdr);
- xfs_trans_log_buf(state->args->trans, drop_blk->bp,
- XFS_DA_LOGRANGE(node, &node->hdr, state->args->geo->node_hdr_size));
+ xfs_trans_log_buf(tp, drop_blk->bp,
+ XFS_DA_LOGRANGE(node, &node->hdr, geo->node_hdr_size));
/*
* Copy the last hash value from the block to propagate upwards.
@@ -1554,6 +1553,38 @@ xfs_da3_node_remove(
drop_blk->hashval = be32_to_cpu(btree[index - 1].hashval);
}
+/*
+ * Remove an entry from an intermediate node.
+ */
+STATIC void
+xfs_da3_node_remove(
+ struct xfs_da_state *state,
+ struct xfs_da_state_blk *drop_blk)
+{
+ trace_xfs_da_node_remove(state->args);
+
+ __xfs_da3_node_remove(state->args->trans, state->args->dp,
+ state->args->geo, drop_blk);
+}
+
+/*
+ * Remove an entry from an intermediate attr node at the specified index.
+ */
+void
+xfs_attr3_node_entry_remove(
+ struct xfs_trans *tp,
+ struct xfs_inode *dp,
+ struct xfs_buf *bp,
+ int index)
+{
+ struct xfs_da_state_blk blk = {
+ .index = index,
+ .bp = bp,
+ };
+
+ __xfs_da3_node_remove(tp, dp, dp->i_mount->m_attr_geo, &blk);
+}
+
/*
* Unbalance the elements between two intermediate nodes,
* move all Btree elements from one node into another.
diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
index cd2e213f5e74f..a718b1ceb0aab 100644
--- a/fs/xfs/libxfs/xfs_da_btree.h
+++ b/fs/xfs/libxfs/xfs_da_btree.h
@@ -184,6 +184,8 @@ int xfs_da3_split(xfs_da_state_t *state);
int xfs_da3_join(xfs_da_state_t *state);
void xfs_da3_fixhashpath(struct xfs_da_state *state,
struct xfs_da_state_path *path_to_to_fix);
+void xfs_attr3_node_entry_remove(struct xfs_trans *tp, struct xfs_inode *dp,
+ struct xfs_buf *bp, int index);
/*
* Routines used for finding things in the Btree.
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 39/52] xfs: factor out xfs_attr3_leaf_init
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (37 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 38/52] xfs: factor out xfs_attr3_node_entry_remove Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 40/52] xfs: close crash window in attr dabtree inactivation Greg Kroah-Hartman
` (13 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Long Li,
Carlos Maiolino, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <leo.lilong@huawei.com>
[ Upstream commit e65bb55d7f8c2041c8fdb73cd29b0b4cad4ed847 ]
Factor out wrapper xfs_attr3_leaf_init function, which exported for
external use.
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Long Li <leo.lilong@huawei.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Stable-dep-of: b854e1c4eff3 ("xfs: close crash window in attr dabtree inactivation")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/libxfs/xfs_attr_leaf.c | 22 ++++++++++++++++++++++
fs/xfs/libxfs/xfs_attr_leaf.h | 3 +++
2 files changed, 25 insertions(+)
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 14dddee4f8fa6..dd3923fdcb205 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -1330,6 +1330,28 @@ xfs_attr3_leaf_create(
return 0;
}
+/*
+ * Reinitialize an existing attr fork block as an empty leaf, and attach
+ * the buffer to tp.
+ */
+int
+xfs_attr3_leaf_init(
+ struct xfs_trans *tp,
+ struct xfs_inode *dp,
+ xfs_dablk_t blkno)
+{
+ struct xfs_buf *bp = NULL;
+ struct xfs_da_args args = {
+ .trans = tp,
+ .dp = dp,
+ .owner = dp->i_ino,
+ .geo = dp->i_mount->m_attr_geo,
+ };
+
+ ASSERT(tp != NULL);
+
+ return xfs_attr3_leaf_create(&args, blkno, &bp);
+}
/*
* Split the leaf node, rebalance, then add the new entry.
*
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
index 589f810eedc0d..deb62b544ac54 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.h
+++ b/fs/xfs/libxfs/xfs_attr_leaf.h
@@ -86,6 +86,9 @@ int xfs_attr3_leaf_list_int(struct xfs_buf *bp,
/*
* Routines used for shrinking the Btree.
*/
+
+int xfs_attr3_leaf_init(struct xfs_trans *tp, struct xfs_inode *dp,
+ xfs_dablk_t blkno);
int xfs_attr3_leaf_toosmall(struct xfs_da_state *state, int *retval);
void xfs_attr3_leaf_unbalance(struct xfs_da_state *state,
struct xfs_da_state_blk *drop_blk,
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 40/52] xfs: close crash window in attr dabtree inactivation
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (38 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 39/52] xfs: factor out xfs_attr3_leaf_init Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 41/52] mm/damon/core: cancel damos_walk() before damon_ctx->kdamond reset Greg Kroah-Hartman
` (12 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Long Li, Darrick J. Wong,
Carlos Maiolino, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <leo.lilong@huawei.com>
[ Upstream commit b854e1c4eff3473b6d3a9ae74129ac5c48bc0b61 ]
When inactivating an inode with node-format extended attributes,
xfs_attr3_node_inactive() invalidates all child leaf/node blocks via
xfs_trans_binval(), but intentionally does not remove the corresponding
entries from their parent node blocks. The implicit assumption is that
xfs_attr_inactive() will truncate the entire attr fork to zero extents
afterwards, so log recovery will never reach the root node and follow
those stale pointers.
However, if a log shutdown occurs after the leaf/node block cancellations
commit but before the attr bmap truncation commits, this assumption
breaks. Recovery replays the attr bmap intact (the inode still has
attr fork extents), but suppresses replay of all cancelled leaf/node
blocks, maybe leaving them as stale data on disk. On the next mount,
xlog_recover_process_iunlinks() retries inactivation and attempts to
read the root node via the attr bmap. If the root node was not replayed,
reading the unreplayed root block triggers a metadata verification
failure immediately; if it was replayed, following its child pointers
to unreplayed child blocks triggers the same failure:
XFS (pmem0): Metadata corruption detected at
xfs_da3_node_read_verify+0x53/0x220, xfs_da3_node block 0x78
XFS (pmem0): Unmount and run xfs_repair
XFS (pmem0): First 128 bytes of corrupted metadata buffer:
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
XFS (pmem0): metadata I/O error in "xfs_da_read_buf+0x104/0x190" at daddr 0x78 len 8 error 117
Fix this in two places:
In xfs_attr3_node_inactive(), after calling xfs_trans_binval() on a
child block, immediately remove the entry that references it from the
parent node in the same transaction. This eliminates the window where
the parent holds a pointer to a cancelled block. Once all children are
removed, the now-empty root node is converted to a leaf block within the
same transaction. This node-to-leaf conversion is necessary for crash
safety. If the system shutdown after the empty node is written to the
log but before the second-phase bmap truncation commits, log recovery
will attempt to verify the root block on disk. xfs_da3_node_verify()
does not permit a node block with count == 0; such a block will fail
verification and trigger a metadata corruption shutdown. on the other
hand, leaf blocks are allowed to have this transient state.
In xfs_attr_inactive(), split the attr fork truncation into two explicit
phases. First, truncate all extents beyond the root block (the child
extents whose parent references have already been removed above).
Second, invalidate the root block and truncate the attr bmap to zero in
a single transaction. The two operations in the second phase must be
atomic: as long as the attr bmap has any non-zero length, recovery can
follow it to the root block, so the root block invalidation must commit
together with the bmap-to-zero truncation.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Long Li <leo.lilong@huawei.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/xfs_attr_inactive.c | 95 +++++++++++++++++++++++---------------
1 file changed, 57 insertions(+), 38 deletions(-)
diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
index 319004bf089fa..2305ddad8a13a 100644
--- a/fs/xfs/xfs_attr_inactive.c
+++ b/fs/xfs/xfs_attr_inactive.c
@@ -140,7 +140,7 @@ xfs_attr3_node_inactive(
xfs_daddr_t parent_blkno, child_blkno;
struct xfs_buf *child_bp;
struct xfs_da3_icnode_hdr ichdr;
- int error, i;
+ int error;
/*
* Since this code is recursive (gasp!) we must protect ourselves.
@@ -152,7 +152,7 @@ xfs_attr3_node_inactive(
return -EFSCORRUPTED;
}
- xfs_da3_node_hdr_from_disk(dp->i_mount, &ichdr, bp->b_addr);
+ xfs_da3_node_hdr_from_disk(mp, &ichdr, bp->b_addr);
parent_blkno = xfs_buf_daddr(bp);
if (!ichdr.count) {
xfs_trans_brelse(*trans, bp);
@@ -167,7 +167,7 @@ xfs_attr3_node_inactive(
* over the leaves removing all of them. If this is higher up
* in the tree, recurse downward.
*/
- for (i = 0; i < ichdr.count; i++) {
+ while (ichdr.count > 0) {
/*
* Read the subsidiary block to see what we have to work with.
* Don't do this in a transaction. This is a depth-first
@@ -218,29 +218,32 @@ xfs_attr3_node_inactive(
xfs_trans_binval(*trans, child_bp);
child_bp = NULL;
+ error = xfs_da3_node_read_mapped(*trans, dp,
+ parent_blkno, &bp, XFS_ATTR_FORK);
+ if (error)
+ return error;
+
/*
- * If we're not done, re-read the parent to get the next
- * child block number.
+ * Remove entry from parent node, prevents being indexed to.
*/
- if (i + 1 < ichdr.count) {
- struct xfs_da3_icnode_hdr phdr;
+ xfs_attr3_node_entry_remove(*trans, dp, bp, 0);
+
+ xfs_da3_node_hdr_from_disk(mp, &ichdr, bp->b_addr);
+ bp = NULL;
- error = xfs_da3_node_read_mapped(*trans, dp,
- parent_blkno, &bp, XFS_ATTR_FORK);
+ if (ichdr.count > 0) {
+ /*
+ * If we're not done, get the next child block number.
+ */
+ child_fsb = be32_to_cpu(ichdr.btree[0].before);
+
+ /*
+ * Atomically commit the whole invalidate stuff.
+ */
+ error = xfs_trans_roll_inode(trans, dp);
if (error)
return error;
- xfs_da3_node_hdr_from_disk(dp->i_mount, &phdr,
- bp->b_addr);
- child_fsb = be32_to_cpu(phdr.btree[i + 1].before);
- xfs_trans_brelse(*trans, bp);
- bp = NULL;
}
- /*
- * Atomically commit the whole invalidate stuff.
- */
- error = xfs_trans_roll_inode(trans, dp);
- if (error)
- return error;
}
return 0;
@@ -257,10 +260,8 @@ xfs_attr3_root_inactive(
struct xfs_trans **trans,
struct xfs_inode *dp)
{
- struct xfs_mount *mp = dp->i_mount;
struct xfs_da_blkinfo *info;
struct xfs_buf *bp;
- xfs_daddr_t blkno;
int error;
/*
@@ -272,7 +273,6 @@ xfs_attr3_root_inactive(
error = xfs_da3_node_read(*trans, dp, 0, &bp, XFS_ATTR_FORK);
if (error)
return error;
- blkno = xfs_buf_daddr(bp);
/*
* Invalidate the tree, even if the "tree" is only a single leaf block.
@@ -283,10 +283,26 @@ xfs_attr3_root_inactive(
case cpu_to_be16(XFS_DA_NODE_MAGIC):
case cpu_to_be16(XFS_DA3_NODE_MAGIC):
error = xfs_attr3_node_inactive(trans, dp, bp, 1);
+ /*
+ * Empty root node block are not allowed, convert it to leaf.
+ */
+ if (!error)
+ error = xfs_attr3_leaf_init(*trans, dp, 0);
+ if (!error)
+ error = xfs_trans_roll_inode(trans, dp);
break;
case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):
case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
error = xfs_attr3_leaf_inactive(trans, dp, bp);
+ /*
+ * Reinit the leaf before truncating extents so that a crash
+ * mid-truncation leaves an empty leaf rather than one with
+ * entries that may reference freed remote value blocks.
+ */
+ if (!error)
+ error = xfs_attr3_leaf_init(*trans, dp, 0);
+ if (!error)
+ error = xfs_trans_roll_inode(trans, dp);
break;
default:
xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
@@ -295,21 +311,6 @@ xfs_attr3_root_inactive(
xfs_trans_brelse(*trans, bp);
break;
}
- if (error)
- return error;
-
- /*
- * Invalidate the incore copy of the root block.
- */
- error = xfs_trans_get_buf(*trans, mp->m_ddev_targp, blkno,
- XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0, &bp);
- if (error)
- return error;
- xfs_trans_binval(*trans, bp); /* remove from cache */
- /*
- * Commit the invalidate and start the next transaction.
- */
- error = xfs_trans_roll_inode(trans, dp);
return error;
}
@@ -328,6 +329,7 @@ xfs_attr_inactive(
{
struct xfs_trans *trans;
struct xfs_mount *mp;
+ struct xfs_buf *bp;
int lock_mode = XFS_ILOCK_SHARED;
int error = 0;
@@ -363,10 +365,27 @@ xfs_attr_inactive(
* removal below.
*/
if (dp->i_af.if_nextents > 0) {
+ /*
+ * Invalidate and truncate all blocks but leave the root block.
+ */
error = xfs_attr3_root_inactive(&trans, dp);
if (error)
goto out_cancel;
+ error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK,
+ XFS_FSB_TO_B(mp, mp->m_attr_geo->fsbcount));
+ if (error)
+ goto out_cancel;
+
+ /*
+ * Invalidate and truncate the root block and ensure that the
+ * operation is completed within a single transaction.
+ */
+ error = xfs_da_get_buf(trans, dp, 0, &bp, XFS_ATTR_FORK);
+ if (error)
+ goto out_cancel;
+
+ xfs_trans_binval(trans, bp);
error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);
if (error)
goto out_cancel;
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 41/52] mm/damon/core: cancel damos_walk() before damon_ctx->kdamond reset
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (39 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 40/52] xfs: close crash window in attr dabtree inactivation Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 42/52] mm/damon/core: fix damos_walk() vs kdamond_fn() exit race Greg Kroah-Hartman
` (11 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, SeongJae Park, Andrew Morton,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: SeongJae Park <sj@kernel.org>
[ Upstream commit 69714a74c19f5ae8b21e25558d62d893d48a3f18 ]
damos_walk() request is canceled after damon_ctx->kdamond is reset. This
can make weird situations where damon_is_running() returns false but the
DAMON context has the damos_walk() request linked. There was a similar
situation for damon_call() requests handling [1], which _was_ able to
cause a racy use-after-free bug. Unlike the case of damon_call(), because
damos_walk() is always synchronously handled and allows only single
request at time, there is no such problematic race cases. But, keeping it
as is could stem another subtle race condition bug in future.
Avoid that by cancelling the requests before the ->kdamond reset. Note
that this change also makes all damon_ctx dependent resource cleanups
consistently done before the damon_ctx->kdamond reset.
Link: https://lkml.kernel.org/r/20260117175256.82826-4-sj@kernel.org
Link: https://lore.kernel.org/20251230014532.47563-1-sj@kernel.org [1]
Signed-off-by: SeongJae Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Stable-dep-of: 33c3f6c2b48c ("mm/damon/core: fix damos_walk() vs kdamond_fn() exit race")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/damon/core.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 016d38c127d61..c77d17cb7a68b 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -2838,14 +2838,13 @@ static int kdamond_fn(void *data)
ctx->call_controls_obsolete = true;
mutex_unlock(&ctx->call_controls_lock);
kdamond_call(ctx, true);
+ damos_walk_cancel(ctx);
pr_debug("kdamond (%d) finishes\n", current->pid);
mutex_lock(&ctx->kdamond_lock);
ctx->kdamond = NULL;
mutex_unlock(&ctx->kdamond_lock);
- damos_walk_cancel(ctx);
-
mutex_lock(&damon_lock);
nr_running_ctxs--;
if (!nr_running_ctxs && running_exclusive_ctxs)
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 42/52] mm/damon/core: fix damos_walk() vs kdamond_fn() exit race
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (40 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 41/52] mm/damon/core: cancel damos_walk() before damon_ctx->kdamond reset Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 43/52] selinux: allow multiple opens of /sys/fs/selinux/policy Greg Kroah-Hartman
` (10 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, SeongJae Park, Andrew Morton,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: SeongJae Park <sj@kernel.org>
[ Upstream commit 33c3f6c2b48cd84b441dba1ee3e62290e53930f4 ]
When kdamond_fn() main loop is finished, the function cancels remaining
damos_walk() request and unset the damon_ctx->kdamond so that API callers
and API functions themselves can show the context is terminated.
damos_walk() adds the caller's request to the queue first. After that, it
shows if the kdamond of the damon_ctx is still running (damon_ctx->kdamond
is set). Only if the kdamond is running, damos_walk() starts waiting for
the kdamond's handling of the newly added request.
The damos_walk() requests registration and damon_ctx->kdamond unset are
protected by different mutexes, though. Hence, damos_walk() could race
with damon_ctx->kdamond unset, and result in deadlocks.
For example, let's suppose kdamond successfully finished the damow_walk()
request cancelling. Right after that, damos_walk() is called for the
context. It registers the new request, and shows the context is still
running, because damon_ctx->kdamond unset is not yet done. Hence the
damos_walk() caller starts waiting for the handling of the request.
However, the kdamond is already on the termination steps, so it never
handles the new request. As a result, the damos_walk() caller thread
infinitely waits.
Fix this by introducing another damon_ctx field, namely
walk_control_obsolete. It is protected by the
damon_ctx->walk_control_lock, which protects damos_walk() request
registration. Initialize (unset) it in kdamond_fn() before letting
damon_start() returns and set it just before the cancelling of the
remaining damos_walk() request is executed. damos_walk() reads the
obsolete field under the lock and avoids adding a new request.
After this change, only requests that are guaranteed to be handled or
cancelled are registered. Hence the after-registration DAMON context
termination check is no longer needed. Remove it together.
The issue is found by sashiko [1].
Link: https://lore.kernel.org/20260327233319.3528-3-sj@kernel.org
Link: https://lore.kernel.org/20260325141956.87144-1-sj@kernel.org [1]
Fixes: bf0eaba0ff9c ("mm/damon/core: implement damos_walk()")
Signed-off-by: SeongJae Park <sj@kernel.org>
Cc: <stable@vger.kernel.org> # 6.14.x
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
and API functions themselves can show the context is terminated.
damos_walk() adds the caller's request to the queue first. After that, it
shows if the kdamond of the damon_ctx is still running (damon_ctx->kdamond
is set). Only if the kdamond is running, damos_walk() starts waiting for
the kdamond's handling of the newly added request.
The damos_walk() requests registration and damon_ctx->kdamond unset are
protected by different mutexes, though. Hence, damos_walk() could race
with damon_ctx->kdamond unset, and result in deadlocks.
For example, let's suppose kdamond successfully finished the damow_walk()
request cancelling. Right after that, damos_walk() is called for the
context. It registers the new request, and shows the context is still
running, because damon_ctx->kdamond unset is not yet done. Hence the
damos_walk() caller starts waiting for the handling of the request.
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/damon.h | 1 +
mm/damon/core.c | 21 ++++++++++++++-------
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index bb4dd13984d39..656a314ad2159 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -785,6 +785,7 @@ struct damon_ctx {
struct mutex call_controls_lock;
struct damos_walk_control *walk_control;
+ bool walk_control_obsolete;
struct mutex walk_control_lock;
/*
diff --git a/mm/damon/core.c b/mm/damon/core.c
index c77d17cb7a68b..4e6e3d7d0a5c0 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1568,6 +1568,10 @@ int damon_call(struct damon_ctx *ctx, struct damon_call_control *control)
* passed at least one &damos->apply_interval_us, kdamond marks the request as
* completed so that damos_walk() can wakeup and return.
*
+ * Note that this function should be called only after damon_start() with the
+ * @ctx has succeeded. Otherwise, this function could fall into an indefinite
+ * wait.
+ *
* Return: 0 on success, negative error code otherwise.
*/
int damos_walk(struct damon_ctx *ctx, struct damos_walk_control *control)
@@ -1575,19 +1579,16 @@ int damos_walk(struct damon_ctx *ctx, struct damos_walk_control *control)
init_completion(&control->completion);
control->canceled = false;
mutex_lock(&ctx->walk_control_lock);
+ if (ctx->walk_control_obsolete) {
+ mutex_unlock(&ctx->walk_control_lock);
+ return -ECANCELED;
+ }
if (ctx->walk_control) {
mutex_unlock(&ctx->walk_control_lock);
return -EBUSY;
}
ctx->walk_control = control;
mutex_unlock(&ctx->walk_control_lock);
- if (!damon_is_running(ctx)) {
- mutex_lock(&ctx->walk_control_lock);
- if (ctx->walk_control == control)
- ctx->walk_control = NULL;
- mutex_unlock(&ctx->walk_control_lock);
- return -EINVAL;
- }
wait_for_completion(&control->completion);
if (control->canceled)
return -ECANCELED;
@@ -2725,6 +2726,9 @@ static int kdamond_fn(void *data)
mutex_lock(&ctx->call_controls_lock);
ctx->call_controls_obsolete = false;
mutex_unlock(&ctx->call_controls_lock);
+ mutex_lock(&ctx->walk_control_lock);
+ ctx->walk_control_obsolete = false;
+ mutex_unlock(&ctx->walk_control_lock);
complete(&ctx->kdamond_started);
kdamond_init_ctx(ctx);
@@ -2838,6 +2842,9 @@ static int kdamond_fn(void *data)
ctx->call_controls_obsolete = true;
mutex_unlock(&ctx->call_controls_lock);
kdamond_call(ctx, true);
+ mutex_lock(&ctx->walk_control_lock);
+ ctx->walk_control_obsolete = true;
+ mutex_unlock(&ctx->walk_control_lock);
damos_walk_cancel(ctx);
pr_debug("kdamond (%d) finishes\n", current->pid);
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 43/52] selinux: allow multiple opens of /sys/fs/selinux/policy
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (41 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 42/52] mm/damon/core: fix damos_walk() vs kdamond_fn() exit race Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 44/52] usb: iowarrior: remove inherent race with minor number Greg Kroah-Hartman
` (9 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Stephen Smalley, Paul Moore,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Smalley <stephen.smalley.work@gmail.com>
[ Upstream commit a02cd6805562305f936e807da83e253b719dd965 ]
Currently there can only be a single open of /sys/fs/selinux/policy at
any time. This allows any process to block any other process from
reading the kernel policy. The original motivation seems to have been
a mix of preventing an inconsistent view of the policy size and
preventing userspace from allocating kernel memory without bound, but
this is arguably equally bad. Eliminate the policy_opened flag and
shrink the critical section that the policy mutex is held. While we
are making changes here, drop a couple of extraneous BUG_ONs.
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/selinux/20100726193414.19538.64028.stgit@paris.rdu.redhat.com/
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
security/selinux/selinuxfs.c | 27 ++++-----------------------
1 file changed, 4 insertions(+), 23 deletions(-)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index e821519205978..9ad11246ad1f4 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -74,7 +74,6 @@ struct selinux_fs_info {
int *bool_pending_values;
struct dentry *class_dir;
unsigned long last_class_ino;
- bool policy_opened;
struct dentry *policycap_dir;
unsigned long last_ino;
struct super_block *sb;
@@ -340,44 +339,31 @@ struct policy_load_memory {
static int sel_open_policy(struct inode *inode, struct file *filp)
{
- struct selinux_fs_info *fsi = inode->i_sb->s_fs_info;
struct policy_load_memory *plm = NULL;
int rc;
- BUG_ON(filp->private_data);
-
- mutex_lock(&selinux_state.policy_mutex);
-
rc = avc_has_perm(current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
if (rc)
- goto err;
-
- rc = -EBUSY;
- if (fsi->policy_opened)
- goto err;
+ return rc;
- rc = -ENOMEM;
plm = kzalloc(sizeof(*plm), GFP_KERNEL);
if (!plm)
- goto err;
+ return -ENOMEM;
+ mutex_lock(&selinux_state.policy_mutex);
rc = security_read_policy(&plm->data, &plm->len);
if (rc)
goto err;
-
if ((size_t)i_size_read(inode) != plm->len) {
inode_lock(inode);
i_size_write(inode, plm->len);
inode_unlock(inode);
}
-
- fsi->policy_opened = 1;
+ mutex_unlock(&selinux_state.policy_mutex);
filp->private_data = plm;
- mutex_unlock(&selinux_state.policy_mutex);
-
return 0;
err:
mutex_unlock(&selinux_state.policy_mutex);
@@ -390,13 +376,8 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
static int sel_release_policy(struct inode *inode, struct file *filp)
{
- struct selinux_fs_info *fsi = inode->i_sb->s_fs_info;
struct policy_load_memory *plm = filp->private_data;
- BUG_ON(!plm);
-
- fsi->policy_opened = 0;
-
vfree(plm->data);
kfree(plm);
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 44/52] usb: iowarrior: remove inherent race with minor number
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (42 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 43/52] selinux: allow multiple opens of /sys/fs/selinux/policy Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 45/52] USB: iowarrior: fix use-after-free on disconnect race Greg Kroah-Hartman
` (8 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Oliver Neukum, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oliver Neukum <oneukum@suse.com>
[ Upstream commit 56dd29088c9d9510c48a8ebad2465248fde36551 ]
The driver saves the minor number it gets upon registration
in its descriptor for debugging purposes. However, there is
inevitably a window between registration and saving the correct
minor in a descriptor. During this window the debugging output
will be wrong.
As wrong debug output is worse than no debug output, just
remove it.
Signed-off-by: Oliver Neukum <oneukum@suse.com>
Link: https://patch.msgid.link/20260312094619.1590556-1-oneukum@suse.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: c602254ba4c1 ("USB: iowarrior: fix use-after-free on disconnect race")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/usb/misc/iowarrior.c | 17 +++--------------
1 file changed, 3 insertions(+), 14 deletions(-)
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 38f6dcdfd7fb9..f9266ae816410 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -74,7 +74,6 @@ struct iowarrior {
struct mutex mutex; /* locks this structure */
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface; /* the interface for this device */
- unsigned char minor; /* the starting minor number for this device */
struct usb_endpoint_descriptor *int_out_endpoint; /* endpoint for reading (needed for IOW56 only) */
struct usb_endpoint_descriptor *int_in_endpoint; /* endpoint for reading */
struct urb *int_in_urb; /* the urb for reading data */
@@ -246,7 +245,6 @@ static void iowarrior_write_callback(struct urb *urb)
*/
static inline void iowarrior_delete(struct iowarrior *dev)
{
- dev_dbg(&dev->interface->dev, "minor %d\n", dev->minor);
kfree(dev->int_in_buffer);
usb_free_urb(dev->int_in_urb);
kfree(dev->read_queue);
@@ -297,9 +295,6 @@ static ssize_t iowarrior_read(struct file *file, char __user *buffer,
goto exit;
}
- dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n",
- dev->minor, count);
-
/* read count must be packet size (+ time stamp) */
if ((count != dev->report_size)
&& (count != (dev->report_size + 1))) {
@@ -379,8 +374,6 @@ static ssize_t iowarrior_write(struct file *file,
retval = -ENODEV;
goto exit;
}
- dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n",
- dev->minor, count);
/* if count is 0 we're already done */
if (count == 0) {
retval = 0;
@@ -523,9 +516,6 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
goto error_out;
}
- dev_dbg(&dev->interface->dev, "minor %d, cmd 0x%.4x, arg %ld\n",
- dev->minor, cmd, arg);
-
retval = 0;
switch (cmd) {
case IOW_WRITE:
@@ -671,8 +661,6 @@ static int iowarrior_release(struct inode *inode, struct file *file)
if (!dev)
return -ENODEV;
- dev_dbg(&dev->interface->dev, "minor %d\n", dev->minor);
-
/* lock our device */
mutex_lock(&dev->mutex);
@@ -775,6 +763,7 @@ static int iowarrior_probe(struct usb_interface *interface,
struct usb_host_interface *iface_desc;
int retval = -ENOMEM;
int res;
+ int minor;
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL);
@@ -890,12 +879,12 @@ static int iowarrior_probe(struct usb_interface *interface,
goto error;
}
- dev->minor = interface->minor;
+ minor = interface->minor;
/* let the user know what node this device is now attached to */
dev_info(&interface->dev, "IOWarrior product=0x%x, serial=%s interface=%d "
"now attached to iowarrior%d\n", dev->product_id, dev->chip_serial,
- iface_desc->desc.bInterfaceNumber, dev->minor - IOWARRIOR_MINOR_BASE);
+ iface_desc->desc.bInterfaceNumber, minor - IOWARRIOR_MINOR_BASE);
return retval;
error:
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 45/52] USB: iowarrior: fix use-after-free on disconnect race
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (43 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 44/52] usb: iowarrior: remove inherent race with minor number Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 46/52] ice: fix broken Rx on VFs Greg Kroah-Hartman
` (7 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable, Yue Sun, Johan Hovold,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <johan@kernel.org>
[ Upstream commit c602254ba4c10f60a73cd99d147874f86a3f485c ]
mutex_unlock() may access the mutex structure after releasing the lock
and therefore cannot be used to manage lifetime of objects directly
(unlike spinlocks and refcounts). [1][2]
Use a kref to release the driver data to avoid use-after-free in
mutex_unlock() when release() races with disconnect().
[1] a51749ab34d9 ("locking/mutex: Document that mutex_unlock() is non-atomic")
[2] 2b9d9e0a9ba0 ("locking/mutex: Clarify that mutex_unlock(), and most
other sleeping locks, can still use the lock object
after it's unlocked")
Fixes: 946b960d13c1 ("USB: add driver for iowarrior devices.")
Cc: stable <stable@kernel.org>
Reported-by: Yue Sun <samsun1006219@gmail.com>
Link: https://lore.kernel.org/r/20260618080204.38322-1-samsun1006219@gmail.com
Signed-off-by: Johan Hovold <johan@kernel.org>
Link: https://patch.msgid.link/20260622152612.116422-2-johan@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/usb/misc/iowarrior.c | 57 +++++++++++++++---------------------
1 file changed, 24 insertions(+), 33 deletions(-)
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index f9266ae816410..827b364c9f5db 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -71,6 +71,7 @@ static struct usb_driver iowarrior_driver;
/* Structure to hold all of our device specific stuff */
struct iowarrior {
+ struct kref kref;
struct mutex mutex; /* locks this structure */
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface; /* the interface for this device */
@@ -243,8 +244,10 @@ static void iowarrior_write_callback(struct urb *urb)
/*
* iowarrior_delete
*/
-static inline void iowarrior_delete(struct iowarrior *dev)
+static inline void iowarrior_delete(struct kref *kref)
{
+ struct iowarrior *dev = container_of(kref, struct iowarrior, kref);
+
kfree(dev->int_in_buffer);
usb_free_urb(dev->int_in_urb);
kfree(dev->read_queue);
@@ -640,6 +643,9 @@ static int iowarrior_open(struct inode *inode, struct file *file)
}
/* increment our usage count for the driver */
++dev->opened;
+
+ kref_get(&dev->kref);
+
/* save our object in the file's private structure */
file->private_data = dev;
retval = 0;
@@ -655,7 +661,6 @@ static int iowarrior_open(struct inode *inode, struct file *file)
static int iowarrior_release(struct inode *inode, struct file *file)
{
struct iowarrior *dev;
- int retval = 0;
dev = file->private_data;
if (!dev)
@@ -663,29 +668,18 @@ static int iowarrior_release(struct inode *inode, struct file *file)
/* lock our device */
mutex_lock(&dev->mutex);
+ dev->opened = 0; /* we're closing now */
- if (dev->opened <= 0) {
- retval = -ENODEV; /* close called more than once */
- mutex_unlock(&dev->mutex);
- } else {
- dev->opened = 0; /* we're closing now */
- retval = 0;
- if (dev->present) {
- /*
- The device is still connected so we only shutdown
- pending read-/write-ops.
- */
- usb_kill_urb(dev->int_in_urb);
- wake_up_interruptible(&dev->read_wait);
- wake_up_interruptible(&dev->write_wait);
- mutex_unlock(&dev->mutex);
- } else {
- /* The device was unplugged, cleanup resources */
- mutex_unlock(&dev->mutex);
- iowarrior_delete(dev);
- }
+ if (dev->present) {
+ usb_kill_urb(dev->int_in_urb);
+ wake_up_interruptible(&dev->read_wait);
+ wake_up_interruptible(&dev->write_wait);
}
- return retval;
+ mutex_unlock(&dev->mutex);
+
+ kref_put(&dev->kref, iowarrior_delete);
+
+ return 0;
}
static __poll_t iowarrior_poll(struct file *file, poll_table * wait)
@@ -770,6 +764,7 @@ static int iowarrior_probe(struct usb_interface *interface,
if (!dev)
return retval;
+ kref_init(&dev->kref);
mutex_init(&dev->mutex);
atomic_set(&dev->intr_idx, 0);
@@ -888,7 +883,8 @@ static int iowarrior_probe(struct usb_interface *interface,
return retval;
error:
- iowarrior_delete(dev);
+ kref_put(&dev->kref, iowarrior_delete);
+
return retval;
}
@@ -912,19 +908,14 @@ static void iowarrior_disconnect(struct usb_interface *interface)
usb_kill_anchored_urbs(&dev->submitted);
if (dev->opened) {
- /* There is a process that holds a filedescriptor to the device ,
- so we only shutdown read-/write-ops going on.
- Deleting the device is postponed until close() was called.
- */
usb_kill_urb(dev->int_in_urb);
wake_up_interruptible(&dev->read_wait);
wake_up_interruptible(&dev->write_wait);
- mutex_unlock(&dev->mutex);
- } else {
- /* no process is using the device, cleanup now */
- mutex_unlock(&dev->mutex);
- iowarrior_delete(dev);
}
+
+ mutex_unlock(&dev->mutex);
+
+ kref_put(&dev->kref, iowarrior_delete);
}
/* usb specific object needed to register this driver with the usb subsystem */
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 46/52] ice: fix broken Rx on VFs
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (44 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 45/52] USB: iowarrior: fix use-after-free on disconnect race Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 47/52] rose: hold a reference on incoming sockets queued for accept() Greg Kroah-Hartman
` (6 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jakub Slepecki, Tony Nguyen,
Alexander Lobakin, Aleksandr Loktionov, Jakub Kicinski,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Lobakin <aleksander.lobakin@intel.com>
[ Upstream commit 436fa8e7d1a119ec90f39e7c2ce0f3a146652899 ]
Since the tagged commit, ice stopped respecting Rx buffer length
passed from VFs.
At that point, the buffer length was hardcoded in ice, so VFs still
worked up to some point (until, for example, a VF wanted an MTU
larger than its PF).
The next commit 93f53db9f9dc ("ice: switch to Page Pool"), broke
Rx on VFs completely since ice started accounting per-queue buffer
lengths again, but now VF queues always had their length zeroed, as
ice was already ignoring what iavf was passing to it.
Restore the line that initializes the buffer length on VF queues
basing on the virtchnl messages.
Fixes: 3a4f419f7509 ("ice: drop page splitting and recycling")
Reported-by: Jakub Slepecki <jakub.slepecki@intel.com>
Reviewed-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Jakub Slepecki <jakub.slepecki@intel.com>
Link: https://patch.msgid.link/20251124170735.3077425-1-aleksander.lobakin@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/ice/virt/queues.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c b/drivers/net/ethernet/intel/ice/virt/queues.c
index 771434ec881e2..431c9c546b04f 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.c
+++ b/drivers/net/ethernet/intel/ice/virt/queues.c
@@ -863,6 +863,9 @@ int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg)
(qpi->rxq.databuffer_size > ((16 * 1024) - 128) ||
qpi->rxq.databuffer_size < 128))
goto error_param;
+
+ ring->rx_buf_len = qpi->rxq.databuffer_size;
+
if (qpi->rxq.max_pkt_size > max_frame_size ||
qpi->rxq.max_pkt_size < 64)
goto error_param;
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 47/52] rose: hold a reference on incoming sockets queued for accept()
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (45 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 46/52] ice: fix broken Rx on VFs Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 48/52] io_uring: do not charge the SQ/CQ rings to RLIMIT_MEMLOCK Greg Kroah-Hartman
` (5 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Bernard Pidoux, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bernard Pidoux <bernard.f6bvp@gmail.com>
commit 6b0223a4795f5db52dee038a7a29e9906122b0f7 upstream.
rose_rx_call_request() creates the socket for an incoming call and
queues the call's skb on the listening socket with skb->sk pointing at
it, without taking a reference. If the caller clears the call before
it is accepted, rose_disconnect() leaves that socket in STATE_0 with
SOCK_DEAD set, and since commit "rose: release netdev ref and destroy
orphaned incoming sockets" rose_heartbeat_expiry() reaps such orphaned
sockets and frees them. The skb stays on the listener's queue, so:
- closing the listener makes rose_destroy_socket() walk its queue and
set flags and restart the heartbeat on the freed socket;
- accept() can hand the freed socket to user space.
On a live node running a KASAN kernel, stopping the FPAC daemons shortly
after a local (loopback) call had been set up and dropped gave:
BUG: KASAN: slab-use-after-free in rose_destroy_socket+0x24a/0x570 [rose]
Write of size 8 ... by task fpacwpd
rose_destroy_socket
rose_release
Allocated by task 0: ... rose_rx_call_request <- rose_loopback_timer
Freed by task ...: ... sk_free <- rose_heartbeat_expiry
refcount_t: addition on 0; use-after-free.
rose_start_heartbeat <- rose_destroy_socket <- rose_release
followed a few seconds later by a page fault in the re-armed heartbeat
and a kernel panic.
Make the listener's queue own a reference on each pending socket,
taken when the call is queued and dropped by rose_accept() or by the
listener's rose_destroy_socket() once the skb is off the queue. Have
the heartbeat set SOCK_DESTROY under the socket lock before reaping a
dead socket, as the other reaping paths already do, and make both
consumers check it under the child's lock: rose_accept() skips a
reaped socket and waits for the next call, and rose_destroy_socket()
no longer re-arms the heartbeat of a socket that is gone.
Fixes: df12be096302 ("rose: release netdev ref and destroy orphaned incoming sockets")
Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/rose/af_rose.c | 44 ++++++++++++++++++++++++++++++++++++++-----
net/rose/rose_timer.c | 5 +++++
2 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 97893498e6111..48b82fe3bee18 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -390,11 +390,25 @@ void rose_destroy_socket(struct sock *sk)
rose_clear_queues(sk); /* Flush the queues */
while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
- if (skb->sk != sk) { /* A pending connection */
- /* Queue the unaccepted socket for death */
- sock_set_flag(skb->sk, SOCK_DEAD);
- rose_start_heartbeat(skb->sk);
- rose_sk(skb->sk)->state = ROSE_STATE_0;
+ struct sock *child = skb->sk;
+
+ if (child != sk) { /* A pending connection */
+ /* Queue the unaccepted socket for death, unless
+ * rose_heartbeat_expiry() has already reaped it or is
+ * about to (SOCK_DESTROY).
+ */
+ local_bh_disable();
+ bh_lock_sock_nested(child);
+ if (!sock_flag(child, SOCK_DESTROY)) {
+ sock_set_flag(child, SOCK_DEAD);
+ rose_start_heartbeat(child);
+ rose_sk(child)->state = ROSE_STATE_0;
+ }
+ bh_unlock_sock(child);
+ local_bh_enable();
+
+ skb->sk = NULL;
+ sock_put(child); /* the queue's reference */
}
kfree_skb(skb);
@@ -980,6 +994,7 @@ static int rose_accept(struct socket *sock, struct socket *newsock,
* The write queue this time is holding sockets ready to use
* hooked into the SABM we saved
*/
+again:
for (;;) {
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
@@ -1005,12 +1020,27 @@ static int rose_accept(struct socket *sock, struct socket *newsock,
goto out_release;
newsk = skb->sk;
+ lock_sock_nested(newsk, SINGLE_DEPTH_NESTING);
+ if (sock_flag(newsk, SOCK_DESTROY)) {
+ /* The call went away and rose_heartbeat_expiry() reaped (or
+ * is about to reap) the socket before it was accepted: drop
+ * it and wait for the next one.
+ */
+ release_sock(newsk);
+ skb->sk = NULL;
+ kfree_skb(skb);
+ sk_acceptq_removed(sk);
+ sock_put(newsk); /* the queue's reference */
+ goto again;
+ }
sock_graft(newsk, newsock);
+ release_sock(newsk);
/* Now attach up the new socket */
skb->sk = NULL;
kfree_skb(skb);
sk_acceptq_removed(sk);
+ sock_put(newsk); /* the queue's reference */
out_release:
release_sock(sk);
@@ -1124,6 +1154,10 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
rose_insert_socket(make);
+ /* The listener's queue holds a reference on the pending socket
+ * until rose_accept() or rose_destroy_socket() takes it off.
+ */
+ sock_hold(make);
skb_queue_head(&sk->sk_receive_queue, skb);
rose_start_heartbeat(make);
diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c
index d967cbc1db3db..4130ddf848504 100644
--- a/net/rose/rose_timer.c
+++ b/net/rose/rose_timer.c
@@ -188,6 +188,11 @@ static void rose_heartbeat_expiry(struct timer_list *t)
rose_neigh_put(rose->neighbour);
rose->neighbour = NULL;
}
+ /* Tell rose_accept() and the listener's teardown, which
+ * may still hold this socket on their queue, that it is
+ * gone.
+ */
+ sock_set_flag(sk, SOCK_DESTROY);
bh_unlock_sock(sk);
rose_destroy_socket(sk);
sock_put(sk);
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 48/52] io_uring: do not charge the SQ/CQ rings to RLIMIT_MEMLOCK
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (46 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 47/52] rose: hold a reference on incoming sockets queued for accept() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 49/52] io_uring/kbuf: dont charge provided buffer " Greg Kroah-Hartman
` (4 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Hengyu Liang, Jens Axboe,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hengyu Liang <hengyul@cs.unc.edu>
commit b59cabf9b4acb65f3f9968087ca0e18010d85076 upstream.
Commit 8078486e1d53 ("io_uring: use region api for SQ") and commit
81a4058e0cd0 ("io_uring: use region api for CQ") made io_uring_setup()
allocate the rings with io_create_region().
However, io_create_region() charges the memory to RLIMIT_MEMLOCK, and
the rings had been exempt from that limit since commit 26bfa89e25f4
("io_uring: place ring SQ/CQ arrays under memcg memory limits"). As of
now, a user without CAP_IPC_LOCK gets ENOMEM from io_uring_setup() when
their rings exceed the limit, which is 8 MiB by default. PostgreSQL
developers have already hit this in their io_uring tests [1].
The issue can be reproduced with a simple liburing program, run as an
unprivileged user:
#include <liburing.h>
#include <stdio.h>
int main(void)
{
static struct io_uring ring[64];
int i;
for (i = 0; i < 64; i++)
if (io_uring_queue_init(4096, &ring[i], 0) < 0)
break;
printf("%d rings\n", i);
return 0;
}
Before those commits (v6.13), it prints "64 rings". After those commits
(v6.14), it prints "21 rings".
This patch makes io_create_region() take the user to charge, and passes
no user for the SQ/CQ rings.
Link: https://www.postgresql.org/message-id/flat/667f7dcf-404b-4898-a426-57ca6e0617f6@gmail.com [1]
Fixes: 8078486e1d53 ("io_uring: use region api for SQ")
Fixes: 81a4058e0cd0 ("io_uring: use region api for CQ")
Cc: stable@vger.kernel.org
Signed-off-by: Hengyu Liang <hengyul@cs.unc.edu>
Link: https://lore.kernel.org/io-uring/20261006125732.3425762-1-hengyul@cs.unc.edu/
[axboe: 6.18 still has the ctx based region API. Convert
io_create_region() and io_free_region() to take the user_struct,
and add a user argument to io_create_region_mmap_safe()]
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/io_uring.c | 12 +++++++-----
io_uring/kbuf.c | 6 +++---
io_uring/memmap.c | 29 ++++++++++++++---------------
io_uring/memmap.h | 6 +++---
io_uring/register.c | 15 ++++++++-------
io_uring/zcrx.c | 4 ++--
6 files changed, 37 insertions(+), 35 deletions(-)
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 524669ee19982..ad5e203e0d5ff 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -2832,8 +2832,9 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events, u32 flags,
static void io_rings_free(struct io_ring_ctx *ctx)
{
- io_free_region(ctx, &ctx->sq_region);
- io_free_region(ctx, &ctx->ring_region);
+ /* ring memory is not charged to RLIMIT_MEMLOCK, hence no user */
+ io_free_region(NULL, &ctx->sq_region);
+ io_free_region(NULL, &ctx->ring_region);
ctx->rings = NULL;
RCU_INIT_POINTER(ctx->rings_rcu, NULL);
ctx->sq_sqes = NULL;
@@ -2915,7 +2916,7 @@ static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx)
io_eventfd_unregister(ctx);
io_free_alloc_caches(ctx);
io_destroy_buffers(ctx);
- io_free_region(ctx, &ctx->param_region);
+ io_free_region(ctx->user, &ctx->param_region);
mutex_unlock(&ctx->uring_lock);
if (ctx->sq_creds)
put_cred(ctx->sq_creds);
@@ -3688,7 +3689,8 @@ static __cold int io_allocate_scq_urings(struct io_ring_ctx *ctx,
rd.user_addr = p->cq_off.user_addr;
rd.flags |= IORING_MEM_REGION_TYPE_USER;
}
- ret = io_create_region(ctx, &ctx->ring_region, &rd, IORING_OFF_CQ_RING);
+ /* ring memory is not charged to RLIMIT_MEMLOCK, hence no user */
+ ret = io_create_region(NULL, &ctx->ring_region, &rd, IORING_OFF_CQ_RING);
if (ret)
return ret;
ctx->rings = rings = io_region_get_ptr(&ctx->ring_region);
@@ -3711,7 +3713,7 @@ static __cold int io_allocate_scq_urings(struct io_ring_ctx *ctx,
rd.user_addr = p->sq_off.user_addr;
rd.flags |= IORING_MEM_REGION_TYPE_USER;
}
- ret = io_create_region(ctx, &ctx->sq_region, &rd, IORING_OFF_SQES);
+ ret = io_create_region(NULL, &ctx->sq_region, &rd, IORING_OFF_SQES);
if (ret) {
io_rings_free(ctx);
return ret;
diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c
index c260d5f34cf36..48e599996ab3f 100644
--- a/io_uring/kbuf.c
+++ b/io_uring/kbuf.c
@@ -444,7 +444,7 @@ static int io_remove_buffers_legacy(struct io_ring_ctx *ctx,
static void io_put_bl(struct io_ring_ctx *ctx, struct io_buffer_list *bl)
{
if (bl->flags & IOBL_BUF_RING)
- io_free_region(ctx, &bl->region);
+ io_free_region(ctx->user, &bl->region);
else
io_remove_buffers_legacy(ctx, bl, -1U);
@@ -661,7 +661,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
rd.user_addr = reg.ring_addr;
rd.flags |= IORING_MEM_REGION_TYPE_USER;
}
- ret = io_create_region_mmap_safe(ctx, &bl->region, &rd, mmap_offset);
+ ret = io_create_region_mmap_safe(ctx, ctx->user, &bl->region, &rd, mmap_offset);
if (ret)
goto fail;
br = io_region_get_ptr(&bl->region);
@@ -695,7 +695,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
if (!ret)
return 0;
fail:
- io_free_region(ctx, &bl->region);
+ io_free_region(ctx->user, &bl->region);
kfree(bl);
return ret;
}
diff --git a/io_uring/memmap.c b/io_uring/memmap.c
index add03ca75cb90..3855452f48e29 100644
--- a/io_uring/memmap.c
+++ b/io_uring/memmap.c
@@ -88,7 +88,7 @@ enum {
IO_REGION_F_SINGLE_REF = 4,
};
-void io_free_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr)
+void io_free_region(struct user_struct *user, struct io_mapped_region *mr)
{
if (mr->pages) {
long nr_refs = mr->nr_pages;
@@ -105,8 +105,8 @@ void io_free_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr)
}
if ((mr->flags & IO_REGION_F_VMAP) && mr->ptr)
vunmap(mr->ptr);
- if (mr->nr_pages && ctx->user)
- __io_unaccount_mem(ctx->user, mr->nr_pages);
+ if (mr->nr_pages && user)
+ __io_unaccount_mem(user, mr->nr_pages);
memset(mr, 0, sizeof(*mr));
}
@@ -131,8 +131,7 @@ static int io_region_init_ptr(struct io_mapped_region *mr)
return 0;
}
-static int io_region_pin_pages(struct io_ring_ctx *ctx,
- struct io_mapped_region *mr,
+static int io_region_pin_pages(struct io_mapped_region *mr,
struct io_uring_region_desc *reg)
{
unsigned long size = (size_t) mr->nr_pages << PAGE_SHIFT;
@@ -150,8 +149,7 @@ static int io_region_pin_pages(struct io_ring_ctx *ctx,
return 0;
}
-static int io_region_allocate_pages(struct io_ring_ctx *ctx,
- struct io_mapped_region *mr,
+static int io_region_allocate_pages(struct io_mapped_region *mr,
struct io_uring_region_desc *reg,
unsigned long mmap_offset)
{
@@ -185,7 +183,7 @@ static int io_region_allocate_pages(struct io_ring_ctx *ctx,
return 0;
}
-int io_create_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr,
+int io_create_region(struct user_struct *user, struct io_mapped_region *mr,
struct io_uring_region_desc *reg,
unsigned long mmap_offset)
{
@@ -211,17 +209,17 @@ int io_create_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr,
return -EOVERFLOW;
nr_pages = reg->size >> PAGE_SHIFT;
- if (ctx->user) {
- ret = __io_account_mem(ctx->user, nr_pages);
+ if (user) {
+ ret = __io_account_mem(user, nr_pages);
if (ret)
return ret;
}
mr->nr_pages = nr_pages;
if (reg->flags & IORING_MEM_REGION_TYPE_USER)
- ret = io_region_pin_pages(ctx, mr, reg);
+ ret = io_region_pin_pages(mr, reg);
else
- ret = io_region_allocate_pages(ctx, mr, reg, mmap_offset);
+ ret = io_region_allocate_pages(mr, reg, mmap_offset);
if (ret)
goto out_free;
@@ -230,11 +228,12 @@ int io_create_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr,
goto out_free;
return 0;
out_free:
- io_free_region(ctx, mr);
+ io_free_region(user, mr);
return ret;
}
-int io_create_region_mmap_safe(struct io_ring_ctx *ctx, struct io_mapped_region *mr,
+int io_create_region_mmap_safe(struct io_ring_ctx *ctx, struct user_struct *user,
+ struct io_mapped_region *mr,
struct io_uring_region_desc *reg,
unsigned long mmap_offset)
{
@@ -242,7 +241,7 @@ int io_create_region_mmap_safe(struct io_ring_ctx *ctx, struct io_mapped_region
int ret;
memcpy(&tmp_mr, mr, sizeof(tmp_mr));
- ret = io_create_region(ctx, &tmp_mr, reg, mmap_offset);
+ ret = io_create_region(user, &tmp_mr, reg, mmap_offset);
if (ret)
return ret;
diff --git a/io_uring/memmap.h b/io_uring/memmap.h
index 08419684e4bc9..8128be8e5ebc3 100644
--- a/io_uring/memmap.h
+++ b/io_uring/memmap.h
@@ -16,12 +16,12 @@ unsigned long io_uring_get_unmapped_area(struct file *file, unsigned long addr,
unsigned long flags);
int io_uring_mmap(struct file *file, struct vm_area_struct *vma);
-void io_free_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr);
-int io_create_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr,
+void io_free_region(struct user_struct *user, struct io_mapped_region *mr);
+int io_create_region(struct user_struct *user, struct io_mapped_region *mr,
struct io_uring_region_desc *reg,
unsigned long mmap_offset);
-int io_create_region_mmap_safe(struct io_ring_ctx *ctx,
+int io_create_region_mmap_safe(struct io_ring_ctx *ctx, struct user_struct *user,
struct io_mapped_region *mr,
struct io_uring_region_desc *reg,
unsigned long mmap_offset);
diff --git a/io_uring/register.c b/io_uring/register.c
index 6c4ef485212d9..741cd294773e1 100644
--- a/io_uring/register.c
+++ b/io_uring/register.c
@@ -383,8 +383,9 @@ static void io_register_free_rings(struct io_ring_ctx *ctx,
struct io_uring_params *p,
struct io_ring_ctx_rings *r)
{
- io_free_region(ctx, &r->sq_region);
- io_free_region(ctx, &r->ring_region);
+ /* ring memory is not charged to RLIMIT_MEMLOCK, hence no user */
+ io_free_region(NULL, &r->sq_region);
+ io_free_region(NULL, &r->ring_region);
}
#define swap_old(ctx, o, n, field) \
@@ -433,7 +434,7 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
rd.user_addr = p.cq_off.user_addr;
rd.flags |= IORING_MEM_REGION_TYPE_USER;
}
- ret = io_create_region_mmap_safe(ctx, &n.ring_region, &rd, IORING_OFF_CQ_RING);
+ ret = io_create_region_mmap_safe(ctx, NULL, &n.ring_region, &rd, IORING_OFF_CQ_RING);
if (ret) {
io_register_free_rings(ctx, &p, &n);
return ret;
@@ -473,7 +474,7 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
rd.user_addr = p.sq_off.user_addr;
rd.flags |= IORING_MEM_REGION_TYPE_USER;
}
- ret = io_create_region_mmap_safe(ctx, &n.sq_region, &rd, IORING_OFF_SQES);
+ ret = io_create_region_mmap_safe(ctx, NULL, &n.sq_region, &rd, IORING_OFF_SQES);
if (ret) {
io_register_free_rings(ctx, &p, &n);
return ret;
@@ -633,13 +634,13 @@ static int io_register_mem_region(struct io_ring_ctx *ctx, void __user *uarg)
!(ctx->flags & IORING_SETUP_R_DISABLED))
return -EINVAL;
- ret = io_create_region_mmap_safe(ctx, &ctx->param_region, &rd,
- IORING_MAP_OFF_PARAM_REGION);
+ ret = io_create_region_mmap_safe(ctx, ctx->user, &ctx->param_region,
+ &rd, IORING_MAP_OFF_PARAM_REGION);
if (ret)
return ret;
if (copy_to_user(rd_uptr, &rd, sizeof(rd))) {
guard(mutex)(&ctx->mmap_lock);
- io_free_region(ctx, &ctx->param_region);
+ io_free_region(ctx->user, &ctx->param_region);
return -EFAULT;
}
diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c
index 56a6a0e52e51e..b44d8ba53e59d 100644
--- a/io_uring/zcrx.c
+++ b/io_uring/zcrx.c
@@ -371,7 +371,7 @@ static int io_allocate_rbuf_ring(struct io_zcrx_ifq *ifq,
mmap_offset = IORING_MAP_OFF_ZCRX_REGION;
mmap_offset += id << IORING_OFF_PBUF_SHIFT;
- ret = io_create_region(ifq->ctx, &ifq->region, rd, mmap_offset);
+ ret = io_create_region(ifq->ctx->user, &ifq->region, rd, mmap_offset);
if (ret < 0)
return ret;
@@ -387,7 +387,7 @@ static int io_allocate_rbuf_ring(struct io_zcrx_ifq *ifq,
static void io_free_rbuf_ring(struct io_zcrx_ifq *ifq)
{
- io_free_region(ifq->ctx, &ifq->region);
+ io_free_region(ifq->ctx->user, &ifq->region);
ifq->rq_ring = NULL;
ifq->rqes = NULL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 49/52] io_uring/kbuf: dont charge provided buffer rings to RLIMIT_MEMLOCK
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (47 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 48/52] io_uring: do not charge the SQ/CQ rings to RLIMIT_MEMLOCK Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 50/52] kho: free chunks using free_page() instead of kfree() Greg Kroah-Hartman
` (3 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Hengyu Liang, Jens Axboe,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <axboe@kernel.dk>
commit cde56daf4b93f474dc256dbcc5205035223ae6f5 upstream.
Just like with the SQ and CQ rings, the provided buffer rings were also
not charged against the memlock limit prior to the below mentioned
commit. Restore that behavior.
Fixes: ef62de3c4ad5 ("io_uring/kbuf: use region api for pbuf rings")
Reported-by: Hengyu Liang <hengyul@cs.unc.edu>
Cc: stable@vger.kernel.org
Tested-by: Hengyu Liang <hengyul@cs.unc.edu>
[axboe: 6.18 uses io_create_region_mmap_safe() for the pbuf ring]
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/kbuf.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c
index 48e599996ab3f..9b9f0d369847c 100644
--- a/io_uring/kbuf.c
+++ b/io_uring/kbuf.c
@@ -444,7 +444,7 @@ static int io_remove_buffers_legacy(struct io_ring_ctx *ctx,
static void io_put_bl(struct io_ring_ctx *ctx, struct io_buffer_list *bl)
{
if (bl->flags & IOBL_BUF_RING)
- io_free_region(ctx->user, &bl->region);
+ io_free_region(NULL, &bl->region);
else
io_remove_buffers_legacy(ctx, bl, -1U);
@@ -661,7 +661,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
rd.user_addr = reg.ring_addr;
rd.flags |= IORING_MEM_REGION_TYPE_USER;
}
- ret = io_create_region_mmap_safe(ctx, ctx->user, &bl->region, &rd, mmap_offset);
+ ret = io_create_region_mmap_safe(ctx, NULL, &bl->region, &rd, mmap_offset);
if (ret)
goto fail;
br = io_region_get_ptr(&bl->region);
@@ -695,7 +695,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
if (!ret)
return 0;
fail:
- io_free_region(ctx->user, &bl->region);
+ io_free_region(NULL, &bl->region);
kfree(bl);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 50/52] kho: free chunks using free_page() instead of kfree()
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (48 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 49/52] io_uring/kbuf: dont charge provided buffer " Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 51/52] bpf, sockmap: Account for receive queue in FIONREAD without a verdict program Greg Kroah-Hartman
` (2 subsequent siblings)
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pratyush Yadav, Pasha Tatashin,
Mike Rapoport (Microsoft), Alexander Graf, David Matlack,
Andrew Morton, Federico Parola, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pratyush Yadav <pratyush@kernel.org>
[ Upstream commit b15515155af735a86e5bcd67ed739162f0de27f5 ]
Before commit fa759cd75bce5 ("kho: allocate metadata directly from the
buddy allocator"), the chunks were allocated from the slab allocator using
kzalloc(). Those were rightly freed using kfree().
When the commit switched to using the buddy allocator directly, it missed
updating kho_mem_ser_free() to use free_page() instead of kfree().
Link: https://lkml.kernel.org/r/20251118182218.63044-1-pratyush@kernel.org
Fixes: fa759cd75bce5 ("kho: allocate metadata directly from the buddy allocator")
Signed-off-by: Pratyush Yadav <pratyush@kernel.org>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Cc: Alexander Graf <graf@amazon.com>
Cc: David Matlack <dmatlack@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Federico Parola <fparola@amazon.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/kexec_handover.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/kexec_handover.c b/kernel/kexec_handover.c
index ac9fa7727b5ff..9fe5d14f1ec54 100644
--- a/kernel/kexec_handover.c
+++ b/kernel/kexec_handover.c
@@ -365,7 +365,7 @@ static void kho_mem_ser_free(struct khoser_mem_chunk *first_chunk)
struct khoser_mem_chunk *tmp = chunk;
chunk = KHOSER_LOAD_PTR(chunk->hdr.next);
- kfree(tmp);
+ free_page((unsigned long)tmp);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 51/52] bpf, sockmap: Account for receive queue in FIONREAD without a verdict program
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (49 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 50/52] kho: free chunks using free_page() instead of kfree() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 52/52] wifi: atk9k: Revert "wifi: ath9k: reject short WMI command responses" Greg Kroah-Hartman
2026-10-17 17:19 ` [PATCH 6.18 00/52] 6.18.58-rc1 review Brett A C Sheffield
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Mattia Meleleo, Jiayuan Chen,
Emil Tsalapatis, John Fastabend, Kumar Kartikeya Dwivedi,
Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mattia Meleleo <mattia.meleleo@coralogix.com>
[ Upstream commit 04af4efde58a4a4ef4feab7360c46af9ec0b83a0 ]
tcp_bpf_ioctl() answers SIOCINQ from psock->msg_tot_len, which only
counts bytes in ingress_msg. Without a stream/skb verdict program
nothing is diverted there: data stays in sk_receive_queue, so FIONREAD
returns 0 even though read() returns data.
Add tcp_inq() to the reported value when the psock has no verdict
program. The two queues are disjoint, so bytes redirected into
ingress_msg from other sockets stay correctly accounted through
msg_tot_len.
Remove unused sk_psock_msg_inq().
Fixes: 929e30f93125 ("bpf, sockmap: Fix FIONREAD for sockmap")
Signed-off-by: Mattia Meleleo <mattia.meleleo@coralogix.com>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Reviewed-by: John Fastabend <john.fastabend@gmail.com>
Link: https://lore.kernel.org/bpf/20260708-fionread-no-verdict-v3-1-b4ee31b3af53@coralogix.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/skmsg.h | 14 --------------
net/ipv4/tcp_bpf.c | 17 ++++++++++++++++-
2 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h
index 4ee7e4680a6e1..718351acd0230 100644
--- a/include/linux/skmsg.h
+++ b/include/linux/skmsg.h
@@ -561,20 +561,6 @@ static inline bool sk_psock_strp_enabled(struct sk_psock *psock)
return !!psock->saved_data_ready;
}
-/* for tcp only, sk is locked */
-static inline ssize_t sk_psock_msg_inq(struct sock *sk)
-{
- struct sk_psock *psock;
- ssize_t inq = 0;
-
- psock = sk_psock_get(sk);
- if (likely(psock)) {
- inq = sk_psock_get_msg_len_nolock(psock);
- sk_psock_put(sk, psock);
- }
- return inq;
-}
-
/* for udp only, sk is not locked */
static inline ssize_t sk_msg_first_len(struct sock *sk)
{
diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
index ca51756d8aa47..6027cd33a9fdc 100644
--- a/net/ipv4/tcp_bpf.c
+++ b/net/ipv4/tcp_bpf.c
@@ -334,6 +334,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk,
static int tcp_bpf_ioctl(struct sock *sk, int cmd, int *karg)
{
+ struct sk_psock *psock;
bool slow;
if (cmd != SIOCINQ)
@@ -344,7 +345,21 @@ static int tcp_bpf_ioctl(struct sock *sk, int cmd, int *karg)
return -EINVAL;
slow = lock_sock_fast(sk);
- *karg = sk_psock_msg_inq(sk);
+ psock = sk_psock_get(sk);
+ if (unlikely(!psock)) {
+ unlock_sock_fast(sk, slow);
+ return tcp_ioctl(sk, cmd, karg);
+ }
+ *karg = sk_psock_get_msg_len_nolock(psock);
+ /* Without a verdict program, ingress data is never diverted to
+ * ingress_msg: it stays in sk_receive_queue and is read through
+ * the fallback to tcp_recvmsg(), so account for it like
+ * tcp_ioctl() does.
+ */
+ if (!READ_ONCE(psock->progs.stream_verdict) &&
+ !READ_ONCE(psock->progs.skb_verdict))
+ *karg += tcp_inq(sk);
+ sk_psock_put(sk, psock);
unlock_sock_fast(sk, slow);
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* [PATCH 6.18 52/52] wifi: atk9k: Revert "wifi: ath9k: reject short WMI command responses"
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (50 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 51/52] bpf, sockmap: Account for receive queue in FIONREAD without a verdict program Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 17:19 ` [PATCH 6.18 00/52] 6.18.58-rc1 review Brett A C Sheffield
52 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Mehmet Fide,
Toke Høiland-Jørgensen, Linus Torvalds, Sasha Levin
6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Toke Høiland-Jørgensen <toke@toke.dk>
[ Upstream commit 90201351a862182bdabfc1ad1c97b1e1b6ed5931 ]
This reverts commit 93ce8ea70451e800601bc9444aa33043de15d67b.
Mehmet reported that the offending commit breaks his AR9271 USB adapter
which uses zero-length replies to commands that don't return a value.
Revert the whole thing to restore the functionality.
Cc: stable@vger.kernel.org # the offending commit is in 6.12.113
Reported-by: Mehmet Fide <mehmet.fide@gmail.com>
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath9k/wmi.c | 16 ++--------------
drivers/net/wireless/ath/ath9k/wmi.h | 1 -
2 files changed, 2 insertions(+), 15 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 610717fb83f57..805ad31edba2b 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -206,16 +206,9 @@ static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
{
skb_pull(skb, sizeof(struct wmi_cmd_hdr));
- if (wmi->cmd_rsp_buf && wmi->cmd_rsp_len) {
- if (skb->len < wmi->cmd_rsp_len) {
- wmi->cmd_rsp_status = -EMSGSIZE;
- goto complete;
- }
+ if (wmi->cmd_rsp_buf != NULL && wmi->cmd_rsp_len != 0)
memcpy(wmi->cmd_rsp_buf, skb->data, wmi->cmd_rsp_len);
- }
- wmi->cmd_rsp_status = 0;
-complete:
complete(&wmi->cmd_wait);
}
@@ -307,7 +300,6 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi,
/* record the rsp buffer and length */
wmi->cmd_rsp_buf = rsp_buf;
wmi->cmd_rsp_len = rsp_len;
- wmi->cmd_rsp_status = 0;
wmi->last_seq_id = wmi->tx_seq_id;
spin_unlock_irqrestore(&wmi->wmi_lock, flags);
@@ -364,13 +356,9 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
return -ETIMEDOUT;
}
- spin_lock_irqsave(&wmi->wmi_lock, flags);
- ret = wmi->cmd_rsp_status;
- spin_unlock_irqrestore(&wmi->wmi_lock, flags);
-
mutex_unlock(&wmi->op_mutex);
- return ret;
+ return 0;
out:
ath_dbg(common, WMI, "WMI failure for: %s\n", wmi_cmd_to_name(cmd_id));
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index 0bb9d31f1a1cc..5c3b710b8f319 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -157,7 +157,6 @@ struct wmi {
u16 tx_seq_id;
u8 *cmd_rsp_buf;
u32 cmd_rsp_len;
- int cmd_rsp_status;
bool stopped;
struct list_head pending_tx_events;
--
2.53.0
^ permalink raw reply related [flat|nested] 54+ messages in thread
* Re: [PATCH 6.18 00/52] 6.18.58-rc1 review
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
` (51 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.18 52/52] wifi: atk9k: Revert "wifi: ath9k: reject short WMI command responses" Greg Kroah-Hartman
@ 2026-10-17 17:19 ` Brett A C Sheffield
52 siblings, 0 replies; 54+ messages in thread
From: Brett A C Sheffield @ 2026-10-17 17:19 UTC (permalink / raw)
To: gregkh
Cc: stable, patches, linux-kernel, torvalds, akpm, linux, shuah,
patches, lkft-triage, pavel, jonathanh, f.fainelli,
sudipm.mukherjee, rwarsow, conor, hargar, broonie, achill, sr,
Brett A C Sheffield
# Librecast Test Results
044/044 [ OK ] liblcrq
010/010 [ OK ] libmld
120/120 [ OK ] liblibrecast
CPU/kernel: Linux auntie 6.18.58-rc1-g73d1ddb7c097 #1 SMP PREEMPT_DYNAMIC Sat Oct 17 16:43:32 -00 2026 x86_64 AMD Ryzen 9 9950X 16-Core Processor AuthenticAMD GNU/Linux
Tested-by: Brett A C Sheffield <bacs@librecast.net>
^ permalink raw reply [flat|nested] 54+ messages in thread
end of thread, other threads:[~2026-10-17 17:19 UTC | newest]
Thread overview: 54+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-17 15:54 [PATCH 6.18 00/52] 6.18.58-rc1 review Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 01/52] spi: mpc52xx: clean up interrupt handling Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 02/52] usb: gadget: f_hid: Add missing error code Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 03/52] RDMA/erdma: Use IRQ-safe XArray helpers for QP and CQ tables Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 04/52] PCI: dwc: Return -ENODEV from dw_pcie_wait_for_link() if device is not found Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 05/52] PCI: dwc: Return -EIO from dw_pcie_wait_for_link() if device is not active Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 06/52] ip6_gre: remove obsolete ERSPAN PMTU update Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 07/52] drm/amd: Create a device link between APU display and XHCI devices Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 08/52] iavf: iavf_virtchnl_completion: drop duplicate ether_addr_equal() test Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 09/52] iavf: send MAC change request synchronously Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 10/52] mm/mremap: fix locked_vm leak by splitting VMA for MREMAP_DONTUNMAP Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 11/52] mm/mremap: fix locked_vm leak from MREMAP_DONTUNMAP self-merge Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 12/52] nfsd: fix all-zero stateid in CB_OFFLOAD for async COPY Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 13/52] wifi: mt76: connac: tolerate inactive BSS deactivation Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 14/52] dm-integrity: fix NULL pointer dereference when the R flag is used Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 15/52] dm-integrity: validate the superblock on resume Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 16/52] sched_ext: Fix CPU hotplug hang when a dying CPUs tasks sit in the BPF scheduler Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 17/52] Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 18/52] net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 19/52] net: mana: reserve RX buffer headroom to fix forwarding performance Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 20/52] riscv: patch: Avoid early phys_to_page() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 21/52] riscv: patch: fix handling of bpf-jit execmem addresses Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 22/52] scsi: ufs: core: Decouple CQ sweep from request iterator in MCQ Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 23/52] scsi: ch: Do not keep references to data transfer element devices Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 24/52] scsi: ufs: core: Move an assignment in ufshcd_mcq_process_cqe() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 25/52] scsi: ufs: core: Add debug log for MCQ command timeout Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 26/52] scsi: ufs: core: Add a comment block above ufshcd_mcq_compl_all_cqes_lock() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 27/52] scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 28/52] drm/xe/i2c: cancel the client work on remove Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 29/52] cifs: fix time_last_write stamp placement in setattr/truncate paths Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 30/52] fat: stop reading directory entries past the end-of-directory marker Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 31/52] ima: Access decompressed kernel module to verify appended signature Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 32/52] ima: Fix stack-out-of-bounds in is_bprm_creds_for_exec() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 33/52] ice: remove legacy Rx and construct SKB Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 34/52] ice: drop page splitting and recycling Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 35/52] ice: fix crash in ethtool offline loopback test Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 36/52] ice: fix rxq info registering in mbuf packets Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 37/52] ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 38/52] xfs: factor out xfs_attr3_node_entry_remove Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 39/52] xfs: factor out xfs_attr3_leaf_init Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 40/52] xfs: close crash window in attr dabtree inactivation Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 41/52] mm/damon/core: cancel damos_walk() before damon_ctx->kdamond reset Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 42/52] mm/damon/core: fix damos_walk() vs kdamond_fn() exit race Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 43/52] selinux: allow multiple opens of /sys/fs/selinux/policy Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 44/52] usb: iowarrior: remove inherent race with minor number Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 45/52] USB: iowarrior: fix use-after-free on disconnect race Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 46/52] ice: fix broken Rx on VFs Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 47/52] rose: hold a reference on incoming sockets queued for accept() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 48/52] io_uring: do not charge the SQ/CQ rings to RLIMIT_MEMLOCK Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 49/52] io_uring/kbuf: dont charge provided buffer " Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 50/52] kho: free chunks using free_page() instead of kfree() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 51/52] bpf, sockmap: Account for receive queue in FIONREAD without a verdict program Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.18 52/52] wifi: atk9k: Revert "wifi: ath9k: reject short WMI command responses" Greg Kroah-Hartman
2026-10-17 17:19 ` [PATCH 6.18 00/52] 6.18.58-rc1 review Brett A C Sheffield
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox