* [PATCH 6.12 000/869] 6.12.114-rc1 review
@ 2026-10-17 15:47 Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 001/869] spi: mpc52xx: clean up interrupt handling Greg Kroah-Hartman
` (869 more replies)
0 siblings, 870 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 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.12.114 release.
There are 869 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:59:15 +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.12.114-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.12.y
and the diffstat can be found below.
thanks,
greg k-h
-------------
Pseudo-Shortlog of commits:
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Linux 6.12.114-rc1
Philipp Stanner <phasta@kernel.org>
drm/panfrost: Fix scheduler workqueue bug
David Hildenbrand <david@redhat.com>
s390/uv: Don't return 0 from make_hva_secure() if the operation was not successful
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
Thomas Gleixner <tglx@linutronix.de>
irqwork: Move data struct to a types header
Suren Baghdasaryan <surenb@google.com>
types: move struct rcuwait into types.h
Ben Cressey <ben@cressey.dev>
dm-integrity: fix buffer overflow with keyed discard
Steven Rostedt <rostedt@goodmis.org>
tracing: Fix comment in tracing_buffers_splice_read()
Karl Mehltretter <kmehltretter@gmail.com>
tracing: Fix ring_buffer_read_page_size() kernel-doc
Stanley Chu <yschu@nuvoton.com>
i3c: master: svc: Fix i3c_master_get_free_addr return check
Stanley Chu <yschu@nuvoton.com>
i3c: master: svc: Fix npcm845 FIFO_EMPTY quirk
Stanley Chu <yschu@nuvoton.com>
i3c: master: svc: Fix missed IBI after false SLVSTART on NPCM845
Ruoyu Wang <ruoyuw560@gmail.com>
gpiolib: initialize return value in gpiochip_set_multiple()
Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
gpiolib: Allow to use setters with return value for output-only gpios
Rafael J. Wysocki <rafael.j.wysocki@intel.com>
soundwire: intel_auxdevice: Fix system suspend/resume handling
Shibo Zhu <3499129952@qq.com>
PM: sleep: Unblock runtime PM when device prepare fails
Muchun Song <muchun.song@linux.dev>
mm/hugetlb_vmemmap: fix incorrect vmemmap restore in rollback
Steffen Klassert <steffen.klassert@secunet.com>
Revert "esp: do not unref managed frag pages in esp_ssg_unref()"
Qiuxu Zhuo <qiuxu.zhuo@intel.com>
EDAC/igen6: Fix NULL pointer dereference
Pablo Neira Ayuso <pablo@netfilter.org>
netfilter: ctnetlink: do not expose expectation DEAD flag
Qiuxu Zhuo <qiuxu.zhuo@intel.com>
EDAC/igen6: Fix the flood of invalid error reports
Harald Freudenberger <freude@linux.ibm.com>
s390/zcrypt: Fix memory leak with CCA cards used as accelerator
Eric Dumazet <edumazet@google.com>
net: do not acquire dev->tx_global_lock in netdev_watchdog_up()
David Howells <dhowells@redhat.com>
netfs: Fix folio state after ENOMEM whilst under writeback iteration
Yichong Chen <chenyichong@uniontech.com>
netfs: release readahead folios on iterator preparation failure
Joseph Qi <joseph.qi@linux.alibaba.com>
ocfs2: use correct endian in ocfs2_dinode_has_extents
Tejun Heo <tj@kernel.org>
sched/psi: Create the psimon kthread outside of cgroup_mutex
Conor Dooley <conor.dooley@microchip.com>
spi: microchip-core-qspi: stop checking viability of op->max_freq in supports_op callback
Max Kellermann <max.kellermann@ionos.com>
ceph: always call ceph_shift_unused_folios_left()
Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
ceph: introduce ceph_submit_write() method
Max Kellermann <max.kellermann@ionos.com>
ceph: fix crash after fscrypt_encrypt_pagecache_blocks() error
Hristo Venev <hristo@venev.name>
ceph: do not skip the first folio of the next object in writeback
Adrian Hunter <adrian.hunter@intel.com>
i3c: mipi-i3c-hci: Preserve RUN bit when aborting DMA ring
Jon Hunter <jonathanh@nvidia.com>
soc/tegra: pmc: Add kerneldoc for wake-up variables
Thierry Reding <treding@nvidia.com>
soc/tegra: pmc: Document tegra_pmc.syscore field
Ming Qian <ming.qian@oss.nxp.com>
media: verisilicon: Fix kernel panic due to __initconst misuse
Kuniyuki Iwashima <kuniyu@google.com>
mpls: Set rt->rt_nhn just before returning from mpls_nh_build_multi().
Kuniyuki Iwashima <kuniyu@amazon.com>
net: Fix wild-memory-access in __register_pernet_operations() when CONFIG_NET_NS=n.
Pankaj Gupta <pankaj.gupta@amd.com>
KVM: SEV: Drop FOLL_WRITE for encrypted region registration
Wludzik, Jozef <jozef.wludzik@intel.com>
accel/ivpu: Fix race condition when mapping dmabuf
Nitin Rawat <quic_nitirawa@quicinc.com>
scsi: ufs: qcom : Fix NULL pointer dereference in ufs_qcom_setup_clocks
Claudio Imbrenda <imbrenda@linux.ibm.com>
s390/kvm: Mask extra bits from program interrupt code
Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: Fix FOLL_*/FAULT_FLAG_* confusion
Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: pv: fix race when making a page secure
Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: move gmap_shadow_pgt_lookup() into kvm
Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: use __kvm_faultin_pfn()
Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: move pv gmap functions into kvm
Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: wrapper for KVM_BUG
Claudio Imbrenda <imbrenda@linux.ibm.com>
s390/kvm: Initialize uninitialized flags variable
Cyril Bur <cyrilbur@tenstorrent.com>
riscv: uaccess: Only restore the CSR_STATUS SUM bit
Ming Lei <ming.lei@redhat.com>
ublk: fix dead loop when canceling io command
Steven Rostedt <rostedt@goodmis.org>
xfs: remove unused trace event xfs_dqreclaim_dirty
Adrian Hunter <adrian.hunter@intel.com>
i3c: master: Fix recursive locking during device registration
Zide Chen <zide.chen@intel.com>
perf/x86/intel/uncore: Fix uncore_box ref/unref ordering
Shukai Ni <shukai.ni@kuleuven.be>
dm-integrity: replace forgeable discard filler with a keyed sector marker
Cen Zhang <zzzccc427@gmail.com>
ocfs2: validate external xattr entries when reading metadata
Kaitao Cheng <chengkaitao@kylinos.cn>
bpf: Clear rb node linkage when freeing bpf_rb_root
Hou Tao <houtao1@huawei.com>
bpf: Remove migrate_{disable|enable} in bpf_obj_free_fields()
Dan Williams <djbw@kernel.org>
cxl/region: Resolve region deletion races
Guoniu Zhou <guoniu.zhou@oss.nxp.com>
pmdomain: imx93-blk-ctrl: Extract PHY as shared domain for DSI/CSI
Sebastian Ene <sebastianene@google.com>
firmware: arm_ffa: Fix Endpoint Memory Access Descriptor offset calculation
Sudeep Holla <sudeep.holla@arm.com>
firmware: arm_ffa: Add support for IMPDEF value in the memory access descriptor
Damien Riégel <damien.riegel@silabs.com>
greybus: raw: fix use-after-free if write is called after disconnect
Yosry Ahmed <yosry@kernel.org>
KVM: nSVM: Triple fault if restore host CR3 fails on nested #VMEXIT
Rafael J. Wysocki <rafael.j.wysocki@intel.com>
ACPI: platform: Use acpi_bus_get_primary_device()
Al Viro <viro@zeniv.linux.org.uk>
functionfs: fix the open/removal races
Benjamin Leggett <benjamin@edera.io>
drm/virtio: use the DMA API for resource backing on Xen
Vivek Kasireddy <vivek.kasireddy@intel.com>
drm/virtio: Add a helper to map and note the dma addrs and lengths
Dongwon Kim <dongwon.kim@intel.com>
drm/virtio: Use drm_gem_plane_helper_prepare_fb()
Sajal Gupta <sajal2005gupta@gmail.com>
drm/gud: validate GUD_ROTATION_0 is present in supported rotations
Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
printk: Don't WARN on kthread_run failure.
Eduard Zingerman <eddyz87@gmail.com>
bpf: check_cond_jmp_op(): properly infer if register is null
Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
net: stmmac: fix dma mapping leak in stmmac_tso_xmit()
Huiwen He <hehuiwen@kylinos.cn>
smb/client: invalidate fscache for fallocate range operations
Eric Dumazet <edumazet@google.com>
ipv6: mcast: use rcu_assign_pointer() for __rcu list updates
Eduard Zingerman <eddyz87@gmail.com>
bpf: backtrack_insn(): Handle ld_{abs,ind} subprog exit edge
Eduard Zingerman <eddyz87@gmail.com>
bpf: backtracking shouldn't clear outer frame R1-R5 for callbacks
FAN YE <fy15309206903@gmail.com>
btrfs: zstd: fix lost wakeup when waiting for a workspace
Kuniyuki Iwashima <kuniyu@google.com>
net: Remove conflicting altnames for dying netns in __dev_change_net_namespace().
Nicolas Dichtel <nicolas.dichtel@6wind.com>
net: plumb extack in __dev_change_net_namespace()
Nicolas Dichtel <nicolas.dichtel@6wind.com>
net: rename netns_local to netns_immutable
Gao Xiang <xiang@kernel.org>
erofs: disable LZ4 rolling decompression for now
Kumar Kartikeya Dwivedi <memxor@gmail.com>
bpf: Mark signal tracepoint siginfo arguments as scalar
Kumar Kartikeya Dwivedi <memxor@gmail.com>
bpf: Mark syscall helpers as sleepable
Cezary Rojewski <cezary.rojewski@intel.com>
ASoC: Intel: avs: Refactor and fix init_config access
Eduard Zingerman <eddyz87@gmail.com>
bpf: zero extend the result of an arena 32-bit cmpxchg
Eduard Zingerman <eddyz87@gmail.com>
bpf: don't rewrite bpf_fastcall patterns entered by a jump
Kumar Kartikeya Dwivedi <memxor@gmail.com>
bpf: Check ancestor frames for rbtree callbacks
Kumar Kartikeya Dwivedi <memxor@gmail.com>
bpf: Reject legacy packet loads from callbacks
Eduard Zingerman <eddyz87@gmail.com>
bpf: Don't infer non-NULL from a pointer with an unbounded offset
Ning Ding <dingning04@gmail.com>
bpf: Keep refcount_acquire nullable for borrowed RCU kptrs
Kumar Kartikeya Dwivedi <memxor@gmail.com>
bpf: Mark NULL kptr stores precise
Kumar Kartikeya Dwivedi <memxor@gmail.com>
bpf: Preserve inner map identity in callback frames
Vincent Donnefort <vdonnefort@google.com>
tracing: Fix subbuf resize races with trace_pipe_raw readers
Eduard Zingerman <eddyz87@gmail.com>
bpf: mark a NULL call argument precise
Karl Mehltretter <kmehltretter@gmail.com>
iommu/amd: Do not reallocate GA log buffers on resume
Alexander Graf <graf@amazon.com>
virtio_ring: fix stale descriptor flags after a failed packed add
Jia Jia <physicalmtea@gmail.com>
vduse: validate virtqueue alignment
Jia Jia <physicalmtea@gmail.com>
vhost: invalidate vring access on IOTLB transitions
Krystian Kaniewski <krystianmkaniewski@gmail.com>
Bluetooth: hci_sysfs: Fix NULL pointer dereference in device_del()
Carolina Jubran <cjubran@nvidia.com>
net/mlx5e: Move representor vnic reporter to eswitch devlink port
Dapeng Mi <dapeng1.mi@linux.intel.com>
perf/x86/intel: Prevent drain_pebs() reentry
Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
drm/amdgpu: skip the VMID 0 flush for VRAM
Paulo Alcantara <pc@manguebit.org>
smb: client: honor forceuid/forcegid when mapping SIDs to uid/gid
Paulo Alcantara <pc@manguebit.org>
smb: client: avoid using uninitialized SIDs in cifs_posix_to_fattr()
Arie Miller <renari@arimil.com>
hwmon: (asus_rog_ryujin) Validate HID report lengths
Arie Miller <renari@arimil.com>
hwmon: (asus_rog_ryujin) Add per-device configuration
Guenter Roeck <linux@roeck-us.net>
hwmon: (asus_rog_ryujin) Rely on subsystem locking
Stanley Chu <yschu@nuvoton.com>
i3c: master: svc: Prevent IRQ storm from false SLVSTART on NPCM845
Stanley Chu <yschu@nuvoton.com>
i3c: master: svc: Fix npcm845 invalid slvstart event
Stanley Chu <yschu@nuvoton.com>
i3c: master: svc: Fix npcm845 FIFO empty issue
Brandon Brnich <b-brnich@ti.com>
media: chips-media: wave5: Release m2m_ctx after Instance Removed from List
Pengpeng Hou <pengpeng@iscas.ac.cn>
genirq/proc: Size interrupt directory names for 10-digit interrupt numbers
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
genirq: Consistently use '%u' format specifier for unsigned int variables
Thomas Gleixner <tglx@linutronix.de>
genirq/proc: Switch to lock guards
Chen-Yu Tsai <wenst@chromium.org>
pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction
Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
pinctrl: mediatek: paris: use new GPIO line value setter callbacks
Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
pinctrl: mediatek: paris: don't double-check the GPIO number
Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
gpiolib: introduce gpio_chip setters that return values
Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
gpiolib: rework the wrapper around gpio_chip::set_multiple()
Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
gpiolib: wrap gpio_chip::set()
Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
gpiolib: make value setters have return values
Candice Li <candice.li@amd.com>
drm/amdgpu: Bound GPIO I2C table entry count from VBIOS
Alex Deucher <alexander.deucher@amd.com>
drm/amdgpu: rework i2c init and fini
Alex Deucher <alexander.deucher@amd.com>
drm/amdgpu/atombios: drop empty function
Dr. David Alan Gilbert <linux@treblig.org>
drm/amdgpu: Remove unused amdgpu_i2c functions
Stepan Ionichev <sozdayvek@gmail.com>
tty: serial: 8250: protect against NULL uart->port.dev in register
Jiri Slaby (SUSE) <jirislaby@kernel.org>
serial: 8250: invert serial8250_register_8250_port() CIR condition
Herve Codina <herve.codina@bootlin.com>
driver core: Avoid warning when removing a device while its supplier is unbinding
Rafael J. Wysocki <rafael.j.wysocki@intel.com>
driver core: Add device_link_test() for testing device link flags
Colin Ian King <colin.i.king@gmail.com>
PM: sleep: Fix bit masking operation
Rafael J. Wysocki <rafael.j.wysocki@intel.com>
PM: sleep: Use DPM_FLAG_SMART_SUSPEND conditionally
Rafael J. Wysocki <rafael.j.wysocki@intel.com>
PM: runtime: Introduce pm_runtime_blocked()
Rafael J. Wysocki <rafael.j.wysocki@intel.com>
PM: Block enabling of runtime PM during system suspend
Rafael J. Wysocki <rafael.j.wysocki@intel.com>
PM: Rearrange documentation related to __pm_runtime_disable()
Rafael J. Wysocki <rafael.j.wysocki@intel.com>
PM: sleep: core: Restrict power.set_active propagation
Rafael J. Wysocki <rafael.j.wysocki@intel.com>
PM: sleep: core: Synchronize runtime PM status of parents and children
Sicong Huang <congei42@163.com>
virt: acrn: Fix irqfd use-after-free during eventfd shutdown
Dr. David Alan Gilbert <linux@treblig.org>
virt: acrn: Remove unused list 'acrn_irqfd_clients'
Tao Cui <cuitao@kylinos.cn>
RDMA/counter: Fix num_counters leak on bind_qp failure in alloc_and_bind()
Johannes Berg <johannes.berg@intel.com>
wifi: iwlwifi: mvm: fix P2P-Device binding handling
Johannes Berg <johannes.berg@intel.com>
wifi: iwlwifi: simplify nested if checks
Yunxiang Li <Yunxiang.Li@amd.com>
drm/amdgpu/ras: add ras_suspend callback and use it for cp_ecc_error_irq
Victor Skvortsov <victor.skvortsov@amd.com>
drm/amdgpu: Update SRIOV Exchange Headers for RAS Telemetry Support
Yongqiang Sun <Yongqiang.Sun@amd.com>
drm/amdkfd: fix SMI event cross-process information leak
Namjae Jeon <linkinjeon@kernel.org>
ksmbd: fix maximum allowed access checks
Alexey Velichayshiy <a.velichayshiy@ispras.ru>
ksmbd: remove redundant DACL check in smb_check_perm_dacl
Val Packett <val@packett.cool>
remoteproc: qcom_wcnss: Fix handling the lack of PD regulators in v3
Gou Hao <gouhao@uniontech.com>
powerpc/xive: propagate IPI init errors to prevent use-after-free
Gou Hao <gouhao@uniontech.com>
powerpc/xive: add error return value to xive_smp_probe()
Rafael J. Wysocki <rafael.j.wysocki@intel.com>
ACPI: bus: Introduce acpi_bus_get_primary_device()
Muchun Song <muchun.song@linux.dev>
mm/hugetlb: initialize gigantic bootmem hugepage struct pages earlier
Kiryl Shutsemau <kas@kernel.org>
mm/hugetlb: refactor code around vmemmap_walk
Chris Mason <clm@meta.com>
nfsd: convert nfsd_net boolean flags to unsigned long flags word
Ye Liu <ye.liu@linux.dev>
mm/page_owner: use memcg_data snapshot to avoid TOCTOU in print_page_owner_memcg()
Evgenii Burenchev <evg28bur@yandex.ru>
drm/amd/display: Fix dangling pointer in plane reset function
Evgenii Burenchev <evg28bur@yandex.ru>
drm/amd/display: Fix dangling pointer in CRTC reset function
Alex Bereza <alex@bereza.email>
dmaengine: xilinx_dma: Fix CPU stall in xilinx_dma_poll_timeout
Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
bpf: Reject MEM_ALLOC BTF accesses past object bounds
Malaya Kumar Rout <malayarout91@gmail.com>
time/namespace: Validate nanosecond field in proc_timens_set_offset()
Nicholas Dudar <main.kalliope@gmail.com>
bpf: Reject writes through untrusted BTF pointers
Armin Wolf <W_Armin@gmx.de>
platform/x86: dell-wmi-base: Fix handling of ultra performance key
Nicholas Dudar <main.kalliope@gmail.com>
bpf: Reject rdonly/rdwr_buf_size kfunc arguments that exceed u32 max
Qing Ming <a0yami@mailbox.org>
usb: gadget: uac: validate rate list length before storing
Marco Scardovi <scardracs@disroot.org>
platform/x86: asus-wmi: fix resource leaks on probe failure
Maher Azzouzi <maherazz04@gmail.com>
esp: do not unref managed frag pages in esp_ssg_unref()
Leon Romanovsky <leon@kernel.org>
RDMA/rvt: Return NULL after port allocation failure
Reinette Chatre <reinette.chatre@intel.com>
fs/resctrl: Prevent use-after-free in rdtgroup_kn_put()
Sudeep Holla <sudeep.holla@kernel.org>
firmware: arm_scmi: Fix SCMI device destroy lifetimes
Ruoyu Wang <ruoyuw560@gmail.com>
drm/msm: Only fini scheduler after successful init
Philipp Stanner <phasta@kernel.org>
drm/sched: Use struct for drm_sched_init() params
Kumar Kartikeya Dwivedi <memxor@gmail.com>
bpf: Zero queue and stack outputs on lock failure
Pu Lehui <pulehui@huawei.com>
riscv, bpf: Fix kernel stack corruption in tailcall with CFI
Kees Cook <kees@kernel.org>
kcfi: Rename CONFIG_CFI_CLANG to CONFIG_CFI
Aditya Prakash Srivastava <aditya.ansh182@gmail.com>
ext4: fix ABBA deadlock in ext4_xattr_inode_cache_find()
Leon Hwang <leon.hwang@linux.dev>
bpf: Fix WARNING in bpf_tracing_link_release
Justin Yeh <justin.yeh@mediatek.com>
pinctrl: mediatek: use devm_gpiochip_add_data() for GPIO chip
Li Qiang <liqiang01@kylinos.cn>
scsi: ufs: core: Validate string descriptors
Bean Huo <beanhuo@micron.com>
scsi: ufs: core: Convert string descriptor format macros to enum
Nicolin Chen <nicolinc@nvidia.com>
iommu/tegra241-cmdqv: Don't fall back to a freed smmu after devm_krealloc()
Nicolin Chen <nicolinc@nvidia.com>
iommu/tegra241-cmdqv: Fix VINTF0 leak on the init-failure path
Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
clk: mediatek: pllfh: Fix IO remapping leak in register_pllfhs error path
Gary Guo <gary@garyguo.net>
PCI: Fix UAF when probe runs concurrent to dyn ID removal
Gary Guo <gary@garyguo.net>
PCI: Fix dyn_id add TOCTOU
Gary Guo <gary@garyguo.net>
PCI: Make pci_match_one_device() match on ID instead of device
Leon Romanovsky <leon@kernel.org>
RDMA/cxgb4: Fix dereg_skb leak and double free in write_tpt_entry()
Adrián Larumbe <adrian.larumbe@collabora.com>
drm/panthor: Add vm_bind region with kbo range overlap check
Jani Nikula <jani.nikula@intel.com>
overflow: add range_overflows() and range_end_overflows()
Jani Nikula <jani.nikula@intel.com>
drm/i915: document range_overflows() and range_end_overflows() macros
Jani Nikula <jani.nikula@intel.com>
drm/i915: rename range_overflows_end() to range_end_overflows()
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
wifi: ath12k: fix overreads in ath12k_wmi_process_csa_switch_count_event()
Felix Fietkau <nbd@nbd.name>
wifi: mt76: mt7996: hold dev->mt76.mutex while disabling tx worker in SER
Felix Fietkau <nbd@nbd.name>
wifi: mt76: cancel reset and rc work on device unregister
Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
drm/msm: don't tear down KMS twice when KMS init fails
Yonghong Song <yonghong.song@linux.dev>
bpf: Reject >8 byte return values on return-reading trampoline paths
Felix Fietkau <nbd@nbd.name>
wifi: mt76: mt7996: do not attach hif2 WED when the main WED attach failed
Will Deacon <will@kernel.org>
arm64: ptrace: Keep 'orig_x0' in-sync with x0 on syscall entry
Zhao Li <enderaoelyther@gmail.com>
wifi: nl80211: clean up color-change beacon data on errors
Johannes Berg <johannes.berg@intel.com>
wifi: nl80211: check link is beaconing for color change
Jason Huang <jason.huang2@infineon.com>
wifi: brcmfmac: fix P2P action frame handling without device vif
Zhao Li <enderaoelyther@gmail.com>
wifi: cfg80211: stop PMSR before P2P and NAN teardown
Karl Mehltretter <kmehltretter@gmail.com>
serial: core: do fallible allocations before the console can be registered
Karl Mehltretter <kmehltretter@gmail.com>
serial: core: clear freed pointers on uart_register_driver() failure
Karl Mehltretter <kmehltretter@gmail.com>
tty: skip cdev_del() when no cdev is registered
Haoxiang Li <haoxiang_li2024@163.com>
HID: logitech-hidpp: Fix FF device cleanup on init failure
Vicki Pfau <vi@endrift.com>
HID: steam: Reject short reads
Zheng Qixing <zhengqixing@huawei.com>
blk-cgroup: fix race between policy activation and blkg destruction
Caleb Sander Mateos <csander@purestorage.com>
ublk: check import_ubuf() return value
Cen Zhang <zzzccc427@gmail.com>
ocfs2: validate inline xattrs during inode block validation
Rafael J. Wysocki <rafael.j.wysocki@intel.com>
thermal: hwmon: Remove hwmon class device along with its parent
Linus Walleij <linusw@kernel.org>
ARM: 9481/2: breakpoint: CFI breakpoints only on demand
Cen Zhang <zzzccc427@gmail.com>
ocfs2: o2hb: quiesce negotiate handlers and timeout work
Yufan Chen <ericterminal@gmail.com>
ocfs2/heartbeat: fix slot mapping rollback leaks on error paths
Jiri Olsa <jolsa@kernel.org>
bpf: Clear buf on error in __bpf_get_task_stack
Jiri Olsa <jolsa@kernel.org>
bpf: Remove trace_in argument from __bpf_get_stack
Jiri Olsa <jolsa@kernel.org>
bpf: Factor callchain_finalize function from __bpf_get_stack
Jiri Olsa <jolsa@kernel.org>
bpf: Factor callchain_store function from __bpf_get_stack
Harry Wentland <harry.wentland@amd.com>
drm/amd/display: Resize MST HDCP per-connector arrays to 32
Ray Wu <ray.wu@amd.com>
drm/amd/display: disable replay when crc source is enabled
Yeoreum Yun <yeoreum.yun@arm.com>
coresight: etm4x: missing cscfg_csdev_disable_active_config() in perf enable
Yang Xiuwei <yangxiuwei@kylinos.cn>
scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails
Bart Van Assche <bvanassche@acm.org>
scsi: sd: Move the sd_config_discard() function definition
Filipe Manana <fdmanana@suse.com>
btrfs: defrag: fix deadlock between defrag and delalloc space reservation
Qu Wenruo <wqu@suse.com>
btrfs: always wait for ordered extents to avoid OE races
Sun YangKai <sunyangkai@fnnas.com>
btrfs: check if root is readonly when setting posix acl
Johannes Thumshirn <johannes.thumshirn@wdc.com>
btrfs: zoned: don't clobber the extent buffer when zeroing it out
Qu Wenruo <wqu@suse.com>
btrfs: qgroup: fix a wrong length calculation in qgroup_free_reserved_data()
Pauli Virtanen <pav@iki.fi>
Bluetooth: L2CAP: use proto_lock for l2cap_data to fix l2cap_disconn_ind
Pauli Virtanen <pav@iki.fi>
Bluetooth: ISO: fix race of kfree vs kref_get_unless_zero
Sanghyun Park <sanghyun.park.cnu@gmail.com>
bpf: Fix mmap_lock leak in irq_work path
Lu Baolu <baolu.lu@linux.intel.com>
iommu/vt-d: Flush context cache with correct SID when tearing down aliases
Chuck Lever <chuck.lever@oracle.com>
NFS: Return a delegation the client fails to record
Kuniyuki Iwashima <kuniyu@google.com>
amt: Don't support cross-netns setup.
John Johansen <john.johansen@canonical.com>
apparmor: fix unconfined user namespace restriction forced stack
Ning Ding <dingning04@gmail.com>
bpf: Compare iterator types during state pruning
Daniel Borkmann <daniel@iogearbox.net>
bpf, s390: Clear fetch destination on faulting arena atomic
Marek Szyprowski <m.szyprowski@samsung.com>
clocksource/drivers/samsung_pwm: Switch to raw_spinlock_t type
Maurizio Lombardi <mlombard@redhat.com>
nvmet: fix max_qid race between configfs and controller allocation
ZhengYuan Huang <gality369@gmail.com>
ocfs2: validate orphan slot during inode read
ZhengYuan Huang <gality369@gmail.com>
ocfs2: validate DIO orphan slot during inode read
Usama Arif <usama.arif@linux.dev>
blk-iolatency: clear delay state when freeing policy data
Usama Arif <usama.arif@linux.dev>
blk-iocost: clear delay state when freeing policy data
Yu Kuai <yukuai@fygo.io>
blk-cgroup: delay freeing policy data after rcu grace period
John Johansen <john.johansen@canonical.com>
apparmor: fix deadlock in complain-mode change_hat
Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
bpf: Check pointer type for all atomic RMW paths
Yunseong Kim <yunseong.kim@est.tech>
ksmbd: fix slab-out-of-bounds read in ksmbd_alloc_user()
Namjae Jeon <linkinjeon@kernel.org>
ksmbd: serialize oplock close with pending break ownership
Ilan Dudnik <ilan.dudnik@safebreach.com>
ksmbd: defer publishing granted locks to prevent UAF/double-free race
Gao Xiang <xiang@kernel.org>
erofs: fix interlaced ztailpacking pclusters
Namjae Jeon <linkinjeon@kernel.org>
ksmbd: safely discard unregistered deferred locks
Namjae Jeon <linkinjeon@kernel.org>
ksmbd: detach blocked lock requests before freeing
Namjae Jeon <linkinjeon@kernel.org>
ksmbd: scope session state changes to bound connections
Jeuk Kim <jeuk20.kim@gmail.com>
NFSv4/flexfiles: fix NULL dereference for NFSv4.0 data servers
Jiayuan Chen <jiayuan.chen@linux.dev>
bpf, xdp: move offload check into dev_xdp_install()
Petr Oros <poros@redhat.com>
dpll: fix NULL deref in dpll_device_ops() during teardown race
Anton Protopopov <a.s.protopopov@gmail.com>
virtio_net: Fix resize of the RX ring
Runyu Xiao <runyu.xiao@seu.edu.cn>
ALSA: mtpav: shut down output timer before card teardown
Eric Dumazet <edumazet@google.com>
ip6mr: do not clone dst in ip6mr_cache_report()
Nikolay Aleksandrov <razor@blackwall.org>
net: bridge: arp/nd proxy: fix reading neigh ha
Nikolay Aleksandrov <razor@blackwall.org>
vxlan: fix reading neigh ha
Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
NFSv4.1: zero referring call lists before decoding
Jamal Hadi Salim <jhs@mojatatu.com>
net/sched: account classifier filter allocations to memcg
Michael Kelley <mhkelley58@gmail.com>
Drivers: hv: vmbus: Skip VMBus module cleanup for non-nested root partition
Pauli Virtanen <pav@iki.fi>
Bluetooth: L2CAP: access chan->conn safely in get/setsockopt
Breno Leitao <leitao@debian.org>
Bluetooth: L2CAP: convert to getsockopt_iter
Breno Leitao <leitao@debian.org>
net: add getsockopt_iter callback to proto_ops
Radek Podgorny <radek@podgorny.cz>
Bluetooth: do not leak an hci_conn when a second LE connect is rejected
Stanislav Fomichev <sdf.kernel@gmail.com>
xsk: honor XDP_TX_METADATA in zero-copy path
Anshumali Gaur <agaur@marvell.com>
octeontx2-vf: fix workqueue and netdev race in probe/remove
Victor Nogueira <victor@mojatatu.com>
net/sched: act_ife: Only operate on Ethernet frames
Eric Dumazet <edumazet@google.com>
net/sched: add qstats_cpu_drop_inc() helper
Eric Dumazet <edumazet@google.com>
net_sched: sch_fq: add three drop_reason
Pablo Neira Ayuso <pablo@netfilter.org>
netfilter: nf_tables: skip double clone set expressions on element insert
Florian Westphal <fw@strlen.de>
netfilter: nf_tables: prepare for multiple elements in nft_trans_elem structure
Florian Westphal <fw@strlen.de>
netfilter: nf_tables: add nft_trans_commit_list_add_elem helper
Florian Westphal <fw@strlen.de>
netfilter: nf_tables: prefer nft_trans_elem_alloc helper
Usama Arif <usama.arif@linux.dev>
mm/huge_memory: transfer the pmd dirty bit to the folio on zap
Christian Borntraeger <borntraeger@linux.ibm.com>
KVM: s390: Fix memory corruption by not reinjecting CK machine checks
Qihang <q.h.hack.winter@gmail.com>
KVM: arm64: vgic-v3: take an LPI reference in vgic_v3_save_pending_tables
Tiezhu Yang <yangtiezhu@loongson.cn>
LoongArch: BPF: Refactor jump offset calculation in tail call
Chao Yu <chao@kernel.org>
f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()
Jesse Zhang <Jesse.Zhang@amd.com>
drm/amdgpu: force complete the KIQ ring fences on reset
Jesse Zhang <Jesse.Zhang@amd.com>
drm/amdgpu: force complete the MES ring fences on reset
Priya Hosur <Priya.Hosur@amd.com>
drm/amdkfd: Add TLB flush after MES queue eviction/suspension
Xiaogang Chen <xiaogang.chen@amd.com>
drm/amdkfd: Fix error path at svm_migrate_copy_to_ram
James Zhu <James.Zhu@amd.com>
drm/amdkfd: return migration pages from copy function - again
Xiaogang Chen <xiaogang.chen@amd.com>
drm/amdkfd: Fix the case that vm range is hole at svm_migrate_copy_to_vram
James Zhu <James.Zhu@amd.com>
Revert "drm/amdkfd: return migration pages from copy function"
James Zhu <James.Zhu@amd.com>
drm/amdkfd: return migration pages from copy function
Emily Deng <Emily.Deng@amd.com>
drm/amdkfd: Fix partial migrate issue
Cen Zhang (Microsoft Security FORGE Labs) <cenzhang@linux.microsoft.com>
ksmbd: fix tree connection use-after-free in smb2_tree_connect()
Kairui Song <kasong@tencent.com>
mm/mglru: fix and remove redundant unevictable folio handling
Kairui Song <kasong@tencent.com>
mm/mglru: use the common routine for dirty/writeback reactivation
Wei Xu <weixugc@google.com>
mm/mglru: reset page lru tier bits when activating
Jeff Layton <jlayton@kernel.org>
lockd, nfsd: RCU-protect nlmsvc_ops dispatch
Jeff Layton <jlayton@kernel.org>
nfsd: restore rq_status_counter to even on all nfsd_dispatch() exit paths
Jeff Layton <jlayton@kernel.org>
nfsd: fix fcache_disposal UAF by inlining dispose state into nfsd_net
Xiubo Li <xiubo.li@clyso.com>
ceph: fix UAF in check_new_map() on session freed during unlock
Michael Bommarito <michael.bommarito@gmail.com>
ceph: cap delegated inode count in ceph_parse_deleg_inos()
Frank Sorenson <sorenson@redhat.com>
cifs: call pagecache_isize_extended() in cifs_setsize() when extending
Bryam Vargas <hexlabsecurity@proton.me>
smb: client: reject a tree connect response whose byte count is too small
Jan Kara <jack@suse.cz>
ext2: Fix lost inode updates for IS_SYNC inodes
Chuck Lever <chuck.lever@oracle.com>
SUNRPC: Reject short RFC 4121 MIC tokens in gss_krb5_verify_mic_v2
Chuck Lever <chuck.lever@oracle.com>
svcrdma: Clear sc_cm_id when ADDR_CHANGE replacement fails
Chuck Lever <chuck.lever@oracle.com>
svcrdma: wake sq waiters when the transport closes
Chuck Lever <chuck.lever@oracle.com>
svcrdma: Add Write chunk WRs to the RPC's Send WR chain
Chuck Lever <chuck.lever@oracle.com>
svcrdma: Reject Read lists that exceed the page budget
Dawei Feng <dawei.feng@seu.edu.cn>
wifi: iwlwifi: dvm: fix memory leak in iwl_op_mode_dvm_start()
Johannes Berg <johannes.berg@intel.com>
wifi: iwlwifi: dvm: pair transport op-mode enter/leave
Jens Axboe <axboe@kernel.dk>
io_uring: defer eventfd signaling when queued from a wakeup handler
Wei Fang <wei.fang@nxp.com>
net: tap: fix wrong transport_header when sending VLAN-tagged frame
Akihiko Odaki <akihiko.odaki@daynix.com>
tap: Keep hdr_len in tap_get_user()
Leon Romanovsky <leon@kernel.org>
ntb: Store original DMA address for future release
Koichiro Den <den@valinux.co.jp>
NTB: ntb_transport: Use ntb_get_dma_dev() for DMA buffers
Koichiro Den <den@valinux.co.jp>
NTB: core: Add .get_dma_dev() callback to ntb_dev_ops
Eric Dumazet <edumazet@google.com>
tipc: avoid busy looping in tipc_exit_net()
Thomas Zimmermann <tzimmermann@suse.de>
fbdev: Wrap user-invoked calls to fb_set_var() in helper
Ali Ahmet Memis <ali@iusegentoo.com>
Bluetooth: ISO: zero the sockaddr before returning it in getname
William Palacek <William.Palacek@amd.com>
drm/amdkfd: Add bounds check for CRAT subtype length
Yongqiang Sun <Yongqiang.Sun@amd.com>
drm/amdkfd: Fix infinite loop parsing CRAT with zero subtype length
Luxiao Xu <rakukuip@gmail.com>
bpf: Check sk_state before sk_protocol in bpf_tcp_*_syncookie
Qu Wenruo <wqu@suse.com>
btrfs: initialize inode mapping flags for cached inodes
Alex Deucher <alexander.deucher@amd.com>
drm/amd/display: check if dml21_add_phantom_plane() is successful
Yuho Choi <dbgh9129@gmail.com>
dmaengine: idxd: fix double free of wq, engine, and group structs
Michael Bommarito <michael.bommarito@gmail.com>
idpf: bound interrupt-vector register fill to the allocated array
Pauli Virtanen <pav@iki.fi>
Bluetooth: hci_sync: hold conn in hci_connect_acl/le_sync() callbacks
Arnaldo Carvalho de Melo <acme@redhat.com>
perf tools: Use perf_env__get_cpu_topology() in machine__resolve()
Pablo Neira Ayuso <pablo@netfilter.org>
netfilter: nf_conntrack_expect: use conntrack GC to reap expectations
Terry Bowman <terry.bowman@amd.com>
cxl: Fix CXL_HEADERLOG_SIZE to match RAS Capability size
Prasanna Kumar T S M <ptsm@linux.microsoft.com>
soc: xilinx: Fix race condition in event registration
Yihang Li <liyihang9@huawei.com>
scsi: hisi_sas: Add slave_destroy interface for v3 hw
Qiuxu Zhuo <qiuxu.zhuo@intel.com>
EDAC/igen6: Fix call trace due to missing release()
Qiuxu Zhuo <qiuxu.zhuo@intel.com>
EDAC/igen6: Skip absent memory controllers
Orange Kao <orange@aiven.io>
EDAC/igen6: Add polling support
Qiuxu Zhuo <qiuxu.zhuo@intel.com>
EDAC/igen6: Initialize edac_op_state according to the configuration data
David Carlier <devnexen@gmail.com>
netfilter: flowtable: avoid num_encaps underflow on bridge VLAN untag
Weiming Shi <bestswngs@gmail.com>
btrfs: lzo: reject compressed segment that overflows the compressed input
Cen Zhang <zzzccc427@gmail.com>
ALSA: seq: oss: Serialize readq reset state with q->lock
James Clark <james.clark@linaro.org>
coresight: ete: Always save state on power down
Ivan Abramov <i.abramov@mt-integration.ru>
ieee802154: Avoid calling WARN_ON() on -ENOMEM in cfg802154_switch_netns()
Rosen Penev <rosenp@gmail.com>
net: emac: Fix NULL pointer dereference in emac_probe
Rosen Penev <rosenp@gmail.com>
net: ibm: emac: use platform_get_irq
Rosen Penev <rosenp@gmail.com>
net: ibm: emac: use devm_platform_ioremap_resource
Masami Hiramatsu (Google) <mhiramat@kernel.org>
tracing/probes: Remove WARN_ON_ONCE from parse_btf_arg
Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
ASoC: SOF: ipc4-pcm: Continue the pipeline trigger in case of IPC timeout
Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
ASoC: SOF: pcm: Add snd_sof_pcm specific wrappers for dev_dbg() and dev_err()
Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
ASoC: SOF: pcm: Move period/buffer configuration print after platform open
Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
ASoC: SOF: Relocate and rework functionality for PCM stream freeing
Hongjie Fang <hongjiefang@asrmicro.com>
scsi: core: pair EH runtime PM get and put
Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
sctp: validate cookie AUTH state before use
Julian Anastasov <ja@ssi.bg>
ipvs: revalidate ihl to prevent out-of-bounds access
Aleksandr Nogikh <nogikh@google.com>
firewire: ohci: fix NULL pointer dereference in ar_context_release
Mark Tomlinson <mark.tomlinson@alliedtelesis.co.nz>
gpio: pca953x: fix pca953x_irq_bus_sync_unlock regmap lock
Karthikeyan KS <karthiproffesional@gmail.com>
soc: aspeed: lpc-snoop: Fix usercopy overflow in snoop_file_read
Yun Zhou <yun.zhou@windriver.com>
xfs: handle NULL b_addr in xfs_buf_free
David Lee <david.lee@trailofbits.com>
btrfs: lzo: reject inline extents without valid headers
Chengfeng Ye <nicoyip.dev@gmail.com>
bpf: Fix netns reference imbalance in conntrack kfuncs
Linfeng Sun <linfeng.sun.dev@gamil.com>
vhost_iotlb: bound map allocation in add_range
Guenter Roeck <linux@roeck-us.net>
hwmon: (pmbus) Fix type confusion in notification logic
Michael Chan <michael.chan@broadcom.com>
bnxt_en: Disable EOP for TPA on all chips to prevent data corruption
Eric Dumazet <edumazet@google.com>
netfilter: nf_flow_table: drop existing skb dst before skb_dst_set_noref()
Alexandra Winter <wintera@linux.ibm.com>
s390/ism: Fix UAF of sba and ieq during ism_dev_exit()
Hongyan Xu <getshell@seu.edu.cn>
watchdog: at91sam9_wdt: prevent timer rearm during teardown
Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
tls: rx: restore msg_iter before TLS 1.3 optimistic retry
Sabrina Dubroca <sd@queasysnail.net>
selftests: tls: add rekey tests
Steven Rostedt <rostedt@goodmis.org>
eventfs: Use children field for rcu head and add memory barriers
Zhiling Zou <zhilinz@nebusec.ai>
mm/page_table_check: skip special zero mappings
Dongjiang Zhu <zhudongjiang@fnnas.com>
btrfs: skip global block reserve accounting for rescue mounts
Maciej Fijalkowski <maciej.fijalkowski@intel.com>
xsk: reclaim invalid Tx descriptors in ZC batch path
Maciej Fijalkowski <maciej.fijalkowski@intel.com>
xsk: provide sufficient space in pool->tx_descs
Jason Xing <kernelxing@tencent.com>
xsk: drain continuation descs after overflow in xsk_build_skb()
Cen Zhang (Microsoft) <blbllhy@gmail.com>
net/sched: cls_u32: validate offshift to prevent shift-out-of-bounds
David Howells <dhowells@redhat.com>
netfs: Fix folio_queue ENOMEM in writeback by adding a mempool
Pauli Virtanen <pav@iki.fi>
Bluetooth: ISO: lock sk in iso_connect_ind
Pauli Virtanen <pav@iki.fi>
Bluetooth: ISO: hold sk properly in iso_conn_ready
Pauli Virtanen <pav@iki.fi>
Bluetooth: hci_sync: hold conn in hci_connect_big_sync() callback
Pauli Virtanen <pav@iki.fi>
Bluetooth: hci_sync: hold conn in hci_connect_pa_sync() callback
Hariprasad Kelam <hkelam@marvell.com>
octeontx2-af: Block VFs from clobbering special CGX PKIND state
Peiyang He <peiyang_he@smail.nju.edu.cn>
iommu/iommufd: Fix IOPF group ownership UAF
Hidayath Khan <hidayath@linux.ibm.com>
dibs: fix use-after-free of dmb_node in loopback attach/detach/unregister
David Howells <dhowells@redhat.com>
afs: Fix UAF when sending a message
Harald Freudenberger <freude@linux.ibm.com>
s390/zcrypt: Close speculative mem read possibility
Harald Freudenberger <freude@linux.ibm.com>
s390/zcrypt: Rework domain processing within zcrypt device driver
Harald Freudenberger <freude@linux.ibm.com>
s390/zcrypt: Move inline function rng_type6cprb_msgx from header to code
Harald Freudenberger <freude@linux.ibm.com>
s390/ap/zcrypt: New xflag parameter
Harald Freudenberger <freude@linux.ibm.com>
s390/ap: Introduce ap message buffer pool
Harald Freudenberger <freude@linux.ibm.com>
s390/ap/zcrypt: Rework AP message buffer allocation
Harald Freudenberger <freude@linux.ibm.com>
s390/ap: Move response_type struct into ap_msg struct
George Zhang <george.zhang@amd.com>
drm/amd/display: Fix divide-by-zero in calculate_mcache_setting on zero viewport
Wei Zhang <wei.zhang@oss.qualcomm.com>
wifi: ath11k: cancel SSR work items during PCI shutdown
Di Shen <di.shen@unisoc.com>
OPP: Fix race between OPP addition and lookup
Takashi Iwai <tiwai@suse.de>
ALSA: seq: oss: Fix UAF at handling events with embedded SysEx data
Geliang Tang <geliang@kernel.org>
nvmet-tcp: check return value of nvmet_tcp_set_queue_sock
Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
md/raid1,raid10: fix error-path detection with md_cloned_bio()
Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
md/raid1,raid10: fix bio accounting for split md cloned bios
Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
md/raid1,raid10: fix deadlock in read error recovery path
Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
md: replace wait loop with wait_event() in md_handle_request()
Miaoqing Pan <miaoqing.pan@oss.qualcomm.com>
wifi: ath12k: fix memory leak in ath12k_wifi7_dp_rx_h_verify_tkip_mic()
Zhang Cen <rollkingzzc@gmail.com>
ocfs2: validate fast symlink target during inode read
David Windsor <dwindsor@gmail.com>
bpf: Reject sleepable BPF_LSM_CGROUP programs at load time
Larysa Zaremba <larysa.zaremba@intel.com>
ixgbe: do not configure xps for XDP queues
Dan Williams <djbw@kernel.org>
cxl/region: Block region delete during region creation
Joe Damato <joe@dama.to>
bnxt: fix head underflow on XDP head-grow
Eric Dumazet <edumazet@google.com>
net: watchdog: fix refcount tracking races
Cen Zhang <zzzccc427@gmail.com>
ALSA: seq: avoid stale FIFO cells during resize
Takashi Iwai <tiwai@suse.de>
ALSA: seq: Clean up fifo locking with guard
Kuniyuki Iwashima <kuniyu@google.com>
sockmap: Fix use-after-free in udp_bpf_recvmsg()
Selvin Xavier <selvin.xavier@broadcom.com>
RDMA/bnxt_re: Initialize dpi variable to zero
Selvin Xavier <selvin.xavier@broadcom.com>
RDMA/bnxt_re: Free SRQ toggle page after firmware teardown
Leon Romanovsky <leon@kernel.org>
RDMA/bnxt_re: Remove unusable nq variable
Kashyap Desai <kashyap.desai@broadcom.com>
RDMA/bnxt_re: Fix budget handling of notification queue
Selvin Xavier <selvin.xavier@broadcom.com>
RDMA/bnxt_re: Free CQ toggle page after firmware teardown
Selvin Xavier <selvin.xavier@broadcom.com>
RDMA/bnxt_re: Add a max slot check for SQ
Selvin Xavier <selvin.xavier@broadcom.com>
RDMA/bnxt_re: Avoid repeated requests to allocate WC pages
Jacob Moroni <jmoroni@google.com>
RDMA/irdma: Replace waitqueue and flag with completion
Eric Dumazet <edumazet@google.com>
net: serialize netif_running() check in enqueue_to_backlog()
Baoli.Zhang <baoli.zhang@linux.intel.com>
soundwire: fix bug in sdw_add_element_group_count found by syzkaller
Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
md/raid1: fix writes_pending and barrier reference leaks on write failures
Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
md/raid10: fix writes_pending leak on write request failures
Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
bpf: Guard conntrack opts error writes
Eric Dumazet <edumazet@google.com>
tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy()
Xin Long <lucien.xin@gmail.com>
sctp: add INIT verification after cookie unpacking
Abdurrahman Hussain <abdurrahman@nexthop.ai>
hwmon: (pmbus/core) honor vrm_version in pmbus_data2reg_vid()
Boris Brezillon <boris.brezillon@collabora.com>
drm/panthor: Always use the IRQ-safe variant when acquiring the fence lock
Xin Long <lucien.xin@gmail.com>
sctp: fix addr_wq_timer race in sctp_free_addr_wq()
Michael Bommarito <michael.bommarito@gmail.com>
xen/pvcalls: bound backend response req_id before indexing rsp[]
David Howells <dhowells@redhat.com>
afs: Fix reinitialisation of the inode, in particular ->lock_work
Morduan Zang <zhangdandan@uniontech.com>
iomap: guard io_size EOF trim against concurrent truncate underflow
David Howells <dhowells@redhat.com>
netfs: Fix netfs_create_write_req() to handle async cache object creation
David Howells <dhowells@redhat.com>
netfs: Drop the was_async arg from netfs_read_subreq_terminated()
David Howells <dhowells@redhat.com>
netfs: Abstract out a rolling folio buffer implementation
David Howells <dhowells@redhat.com>
netfs: Add a tracepoint to log the lifespan of folio_queue structs
David Howells <dhowells@redhat.com>
netfs: Use a folio_queue allocation and free functions
David Howells <dhowells@redhat.com>
netfs: Clean up some whitespace in trace header
Feng Liu <feliu@nvidia.com>
net/mlx5e: Fix publication race for priv->channel_stats[]
Cen Zhang <zzzccc427@gmail.com>
Bluetooth: 6lowpan: avoid untracked enable work
Yuho Choi <dbgh9129@gmail.com>
net/liquidio: drop cached VF pci_dev LUT
Eric Dumazet <edumazet@google.com>
ipv4: igmp: Fix potential memory leaks in igmp_mod_timer() and igmp_stop_timer()
Marc Zyngier <maz@kernel.org>
KVM: arm64: vgic: Handle race between interrupt affinity change and LPI disabling
Ian Bridges <icb@fastmail.org>
ocfs2: fix UBSAN array-index-out-of-bounds in ocfs2_sum_rightmost_rec
Deepanshu Kartikey <kartikey406@gmail.com>
ocfs2: validate i_refcount_loc when refcount flag is set
Dmitry Antipov <dmantipov@yandex.ru>
ocfs2: add extra consistency checks for chain allocator dinodes
Dmitry Antipov <dmantipov@yandex.ru>
ocfs2: add suballoc slot check in ocfs2_validate_inode_block()
Julian Sun <sunjunchao2870@gmail.com>
ocfs2: correct l_next_free_rec in online check
Mikulas Patocka <mpatocka@redhat.com>
dm-verity: fix buffer overflow in FEC calculation
Guangshuo Li <lgs201920130244@gmail.com>
mmc: vub300: fix use-after-free on probe failure
Johan Hovold <johan@kernel.org>
mmc: vub300: rename probe error labels
Johan Hovold <johan@kernel.org>
mmc: vub300: fix use-after-free on disconnect
Binbin Zhou <zhoubinbin@loongson.cn>
mmc: vub300: Use devm_mmc_alloc_host() helper
Bryam Vargas <hexlabsecurity@proton.me>
ata: libata-core: Add NOLPM quirk for PNY CS900 1TB SSD
Niklas Cassel <cassel@kernel.org>
ata: libata-core: Disable LPM on Silicon Motion MD619{H,G}XCLDE3TC
Zhao Li <enderaoelyther@gmail.com>
wifi: ieee80211: validate MLE common info length
Zhao Li <enderaoelyther@gmail.com>
wifi: mac80211: validate extension-frame layout before RX
Harald Freudenberger <freude@linux.ibm.com>
s390/zcrypt: Fix buffer over-read in cca_cipher2protkey
Amir Goldstein <amir73il@gmail.com>
ovl: check access to copy_file_range source with src mounter creds
Yongqiang Sun <Yongqiang.Sun@amd.com>
drm/amdkfd: clamp v9 CRIU control stack checkpoint copy to BO size
Jamal Hadi Salim <jhs@mojatatu.com>
net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains
Honglei Huang <honghuan@amd.com>
drm/amd/display: use kvzalloc to allocate struct dc
George Guo <guodongtai@kylinos.cn>
LoongArch: Fix address space mismatch in kexec command line lookup
Petr Wozniak <petr.wozniak@gmail.com>
xfrm: fix stale skb->prev after async crypto steals a GSO segment
Tejun Heo <tj@kernel.org>
sched_ext: Don't warn on core-sched forced idle in put_prev_task_scx()
Jacob Moroni <jmoroni@google.com>
RDMA/irdma: Prevent user-triggered null deref on QP create
Christophe JAILLET <christophe.jaillet@wanadoo.fr>
wifi: cfg80211: Fix an error handling path in cfg80211_wext_siwscan()
Maoyi Xie <maoyixie.tju@gmail.com>
wifi: mac80211: defer link RX stats percpu free to RCU
Sarika Sharma <quic_sarishar@quicinc.com>
wifi: cfg80211: add link_station_info structure to support MLO statistics
Sarika Sharma <quic_sarishar@quicinc.com>
wifi: mac80211: refactor populating mesh related fields in sinfo
Cen Zhang <zzzccc427@gmail.com>
wifi: cfg80211: use wiphy work for socket owner autodisconnect
Mostafa Saleh <smostafa@google.com>
firmware: arm_ffa: Fix out-of-bound writes in ffa_setup_and_transmit()
Matt Bobrowski <mattbobrowski@google.com>
bpf: Fix UAF in sock clone early bailouts
Fushuai Wang <wangfushuai@baidu.com>
bpf: Use rcu_read_lock_dont_migrate in bpf_sk_storage.c
Menglong Dong <menglong8.dong@gmail.com>
rcu: add rcu_read_lock_dont_migrate()
Hou Tao <houtao1@huawei.com>
bpf: Disable migration when cloning sock storage
Hou Tao <houtao1@huawei.com>
bpf: Disable migration when destroying sock storage
Pauli Virtanen <pav@iki.fi>
Bluetooth: hci_sync: extend conn_hash lookup critical sections
Arvind Yadav <arvind.yadav@intel.com>
drm/xe/guc: Keep scheduler timeline name alive
Ruoyu Wang <ruoyuw560@gmail.com>
bnxt_en: Handle partially initialized auxiliary devices
Pavan Chebbi <pavan.chebbi@broadcom.com>
fwctl/bnxt_en: Refactor aux bus functions to be more generic
Weiming Shi <bestswngs@gmail.com>
tipc: serialize udp bearer replicast list updates
Frank Sorenson <sorenson@redhat.com>
cifs: fix cifsFileInfo leak on kmalloc failure in deferred close drain paths
Frank Sorenson <sorenson@redhat.com>
cifs: prevent readdir from changing file size due to stale directory metadata
Nicholas Dudar <main.kalliope@gmail.com>
LoongArch: BPF: Zero-extend signed ALU32 div/mod results
Emil Tantilov <emil.s.tantilov@intel.com>
idpf: fix max_vport related crash on allocation error during init
David Francis <David.Francis@amd.com>
drm/amdkfd: Check bounds on CRIU restore queue type and mqd size
Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
drm/i915/gt: Fix NULL deref on sched_engine alloc failure
Jani Nikula <jani.nikula@intel.com>
drm/i915/mst: limit DP MST ESI service loop
Mario Limonciello <mario.limonciello@amd.com>
drm/amdgpu: Release VFCT ACPI table reference
Lijo Lazar <lijo.lazar@amd.com>
drm/amdgpu: Add wrapper for freeing vbios memory
Lijo Lazar <lijo.lazar@amd.com>
drm/amdgpu: Use dbg level for VBIOS check messages
Linmao Li <lilinmao@kylinos.cn>
drm/vc4: Shut down BO cache timer before teardown
Valery Borovsky <vebohr@gmail.com>
media: stm32-dcmipp: Return queued buffers on start_streaming() failure
Alain Volmat <alain.volmat@foss.st.com>
media: stm32: dcmipp: replace s_stream with enable/disable_streams
Alain Volmat <alain.volmat@foss.st.com>
media: stm32: dcmipp: use v4l2_subdev_is_streaming
Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com>
drm/amdgpu: Fix kernel panic during driver load failure
Sean Christopherson <seanjc@google.com>
KVM: nVMX: Put vmcs12 pages if nested VM-Enter fails due to invalid guest state
Carlos López <clopez@suse.de>
KVM: x86: Unconditionally recompute CR8 intercept on PPR update
Sean Christopherson <seanjc@google.com>
KVM: x86: Move update_cr8_intercept() to lapic.c
Sean Christopherson <seanjc@google.com>
KVM: x86: Rename APIC base setters to better capture their relationship
Sean Christopherson <seanjc@google.com>
KVM: x86: Move kvm_set_apic_base() implementation to lapic.c (from x86.c)
Sean Christopherson <seanjc@google.com>
KVM: x86: Drop superfluous kvm_lapic_set_base() call when setting APIC state
Namjae Jeon <linkinjeon@kernel.org>
ksmbd: prevent path traversal bypass by restricting caseless retry
Haofeng Li <lihaofeng@kylinos.cn>
ksmbd: validate NTLMv2 response before updating session key
Ralph Boehme <slow@samba.org>
smb/client: fix chown/chgrp with SMB3 POSIX Extensions
Sean Christopherson <seanjc@google.com>
KVM: guest_memfd: Treat memslot binding offset+size as unsigned values
Guenter Roeck <linux@roeck-us.net>
hwmon: (lm90) Add lock protection to lm90_alert
David Howells <dhowells@redhat.com>
netfs: Fix zeropoint update where i_size > remote_i_size
Felix Gu <ustc.gu@gmail.com>
drm/msm/adreno: Fix a reference leak in a6xx_gpu_init()
Jia Zhu <zhujia.zj@bytedance.com>
erofs: fix metabuf leak in inode xattr initialization
Zhao Li <enderaoelyther@gmail.com>
wifi: mac80211: capture fast-RX rate before mesh reuses skb->cb
Sarika Sharma <sarika.sharma@oss.qualcomm.com>
wifi: mac80211: fix missing RX bitrate update for mesh forwarding path
Florian Westphal <fw@strlen.de>
netfilter: x_tables: allocate hook ops while under mutex
Florian Westphal <fw@strlen.de>
netfilter: x_tables: allow initial table replace without emitting audit log message
Florian Westphal <fw@strlen.de>
netfilter: ebtables: move to two-stage removal scheme
Florian Westphal <fw@strlen.de>
netfilter: bridge: eb_tables: close module init race
David Howells <dhowells@redhat.com>
netfs: Fix missing locking around retry adding new subreqs
David Howells <dhowells@redhat.com>
netfs: Fix leak of request in netfs_write_begin() error handling
Guenter Roeck <linux@roeck-us.net>
hwmon: (lm90) Stop work before releasing hwmon device
Qing Ming <a0yami@mailbox.org>
cgroup/rstat: validate cpu before css_rstat_cpu() access
Eric Dumazet <edumazet@google.com>
tcp: fix stale per-CPU tcp_tw_isn leak enabling ISN prediction
Kuniyuki Iwashima <kuniyu@google.com>
tcp: Remove sk->sk_prot->orphan_count.
Fernando Fernandez Mancera <fmancera@suse.de>
netfilter: nf_tables: fix dst corruption in same register operation
Jakub Kicinski <kuba@kernel.org>
ethtool: rss: fix indir_table and hkey leak on get_rxfh failure
Jakub Kicinski <kuba@kernel.org>
ethtool: module: call ethnl_ops_complete() on module flash errors
Chuck Lever <chuck.lever@oracle.com>
net/handshake: hand off the pinned file reference to accept_doit
Christian König <christian.koenig@amd.com>
drm/amdgpu: fix amdgpu_hmm_range_get_pages
Lorenzo Bianconi <lorenzo@kernel.org>
net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue()
Lorenzo Bianconi <lorenzo@kernel.org>
net: airoha: Do not read uninitialized fragment address in airoha_dev_xmit()
Yinjie Yao <yinjie.yao@amd.com>
drm/amdgpu/vcn: set no_user_fence for VCN v4.0 enc ring
Jiajia Liu <liujiajia@kylinos.cn>
wifi: mt76: add wcid publish check in mt76_sta_add
Konstantin Khorenko <khorenko@virtuozzo.com>
gcov: use atomic counter updates to fix concurrent access crashes
Mikhail Lobanov <m.lobanov@rosa.ru>
f2fs: read COW data with the original inode during atomic write
Hongling Zeng <zenghongling@kylinos.cn>
fbdev: omap2: fix use-after-free in omapfb_mmap
Hongling Zeng <zenghongling@kylinos.cn>
fbdev: omap2: fix inconsistent lock returns in omapfb_mmap
Anna Maniscalco <anna.maniscalco2000@gmail.com>
drm/msm: always recover the gpu
Yongpeng Yang <yangyongpeng@xiaomi.com>
f2fs: fix fsck inconsistency caused by incorrect nat_entry flag usage
Harry Wentland <harry.wentland@amd.com>
drm/amd/display: Fix out-of-bounds read in dp_get_eq_aux_rd_interval()
Jens Axboe <axboe@kernel.dk>
io_uring/napi: cap busy_poll_to 10 msec
Olivier Langlois <olivier@trillion01.com>
io_uring/napi: clean up __io_napi_do_busy_loop
Olivier Langlois <olivier@trillion01.com>
io_uring/napi: Use lock guards
Olivier Langlois <olivier@trillion01.com>
io_uring/napi: improve __io_napi_add
Olivier Langlois <olivier@trillion01.com>
io_uring/napi: protect concurrent io_napi_entry timeout accesses
Erni Sri Satya Vennela <ernis@linux.microsoft.com>
net: mana: Guard mana_remove against double invocation
Morduan Zang <zhangdandan@uniontech.com>
net: phonet: do not BUG_ON() in pn_socket_autobind() on failed bind
Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
drm/amd/display: Wrap DCN32 phantom-plane allocation in DC_RUN_WITH_PREEMPTION_ENABLED
Qu Wenruo <wqu@suse.com>
btrfs: only release the dirty pages io tree after successful writes
Zhenzhong Duan <zhenzhong.duan@intel.com>
iommu/vt-d: Avoid NULL pointer dereference or refcount corruption
Hyunwoo Kim <imv4bel@gmail.com>
KVM: arm64: Take the SRCU lock for page table walks in fault injection and AT emulation
Fedor Pchelkin <pchelkin@ispras.ru>
wifi: fix leak if split 6 GHz scanning fails
Xin Long <lucien.xin@gmail.com>
sctp: validate embedded INIT chunk and address list lengths in cookie
Salman Alghamdi <me@cipherat.com>
staging: rtl8723bs: rtw_mlme: add bounds checks before ie_length subtraction
Danilo Krummrich <dakr@kernel.org>
vdpa: use generic driver_override infrastructure
Ritesh Harjani (IBM) <ritesh.list@gmail.com>
powerpc/pgtable-frag: Fix bad page state in pte_frag_destroy
Ritesh Harjani (IBM) <ritesh.list@gmail.com>
powerpc/64s: Fix unmap race with PMD migration entries
Lorenzo Bianconi <lorenzo@kernel.org>
wifi: mt76: Fix memory leak destroying device
Sean Wang <sean.wang@mediatek.com>
wifi: mt76: mt7925: fix potential deadlock in mt7925_roc_abort_sync
Eric Dumazet <edumazet@google.com>
net: pull headers in qdisc_pkt_len_segs_init()
Damien Riégel <damien.riegel@silabs.com>
greybus: raw: fix use-after-free on cdev close
Jianan Huang <huangjianan@xiaomi.com>
f2fs: avoid reading already updated pages during GC
Yongpeng Yang <yangyongpeng@xiaomi.com>
f2fs: fix data loss caused by incorrect use of nat_entry flag
Michal Schmidt <mschmidt@redhat.com>
ice: fix double-free of tx_buf skb
Pablo Neira Ayuso <pablo@netfilter.org>
netfilter: nat: use kfree_rcu to release ops
Edward Adam Davis <eadavis@qq.com>
sched/psi: fix race between file release and pressure write
Lorenzo Bianconi <lorenzo@kernel.org>
net: airoha: fix BQL imbalance in TX path
Raphael Zimmer <raphael.zimmer@tu-ilmenau.de>
libceph: Fix potential out-of-bounds access in __ceph_x_decrypt()
Weiming Shi <bestswngs@gmail.com>
tap: fix stack info leak in tap_ioctl() SIOCGIFHWADDR
D. Wythe <alibuda@linux.alibaba.com>
Revert "net/smc: Introduce TCP ULP support"
Li Zhijian <lizhijian@fujitsu.com>
RDMA/rxe: Fix iova-to-va conversion for MR page sizes != PAGE_SIZE
Daisuke Matsuda <matsuda-daisuke@fujitsu.com>
RDMA/rxe: Move some code to rxe_loc.h in preparation for ODP
Florian Westphal <fw@strlen.de>
netfilter: nf_tables: use list_del_rcu for netlink hooks
Stephen Smalley <stephen.smalley.work@gmail.com>
selinux: allow multiple opens of /sys/fs/selinux/policy
Yicong Yang <yangyicong@hisilicon.com>
coresight: tmc-etr: Fix race condition between sysfs and perf mode
Mike Snitzer <snitzer@hammerspace.com>
NFS/localio: prevent direct reclaim recursion into NFS via nfs_writepages
Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
drm/amd/display: Fix dc_link NULL handling in HPD init
Johan Hovold <johan@kernel.org>
spi: ch341: fix devres lifetime
Yang Yingliang <yangyingliang@huawei.com>
spi: ch341: switch to use devm_spi_alloc_host()
Jason Gunthorpe <jgg@ziepe.ca>
RDMA/mlx4: Fix mis-use of RCU in mlx4_srq_event()
Suren Baghdasaryan <surenb@google.com>
refcount: provide ops for cases when object's memory can be reused
Yongpeng Yang <yangyongpeng@xiaomi.com>
f2fs: fix fsck inconsistency caused by FGGC of node block
Osama Abdelkader <osama.abdelkader@gmail.com>
riscv: kvm: fix vector context allocation leak
Conor Dooley <conor.dooley@microchip.com>
spi: microchip-core-qspi: control built-in cs manually
Conor Dooley <conor.dooley@microchip.com>
spi: microchip-core-qspi: remove unused param from mchp_coreqspi_write_op()
Conor Dooley <conor.dooley@microchip.com>
spi: microchip-core-qspi: set min_speed_hz during probe
Miquel Raynal <miquel.raynal@bootlin.com>
spi: microchip-core-qspi: Support per spi-mem operation frequency switches
Eric Biggers <ebiggers@kernel.org>
dm-verity-fec: fix reading parity bytes split across blocks (take 3)
Yosry Ahmed <yosry@kernel.org>
KVM: nSVM: Avoid clearing VMCB_LBR in vmcb12
Sam Edwards <cfsworks@gmail.com>
ceph: fix num_ops off-by-one when crypto allocation fails
Matthew Wilcox (Oracle) <willy@infradead.org>
ceph: Remove uses of page from ceph_process_folio_batch()
Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
ceph: introduce ceph_process_folio_batch() method
Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
ceph: extend ceph_writeback_ctl for ceph_writepages_start() refactoring
Matthew Wilcox (Oracle) <willy@infradead.org>
ceph: Remove call to PagePrivate2()
Yosry Ahmed <yosry@kernel.org>
KVM: nSVM: Always use NextRIP as vmcb02's NextRIP after first L2 VMRUN
Sean Christopherson <seanjc@google.com>
KVM: x86: Rename "governed features" helpers to use "guest_cpu_cap"
Corey Minyard <corey@minyard.net>
ipmi:ssif: Clean up kthread on errors
Yosry Ahmed <yosry@kernel.org>
KVM: SVM: Add missing save/restore handling of LBR MSRs
Deepanshu Kartikey <kartikey406@gmail.com>
gfs2: fix memory leaks in gfs2_fill_super error path
Jeongjun Park <aha310510@gmail.com>
drm/exynos: vidi: use priv->vidi_dev for ctx lookup in vidi_connection_ioctl()
Jie Zhang <jzhang918@gmail.com>
net: stmmac: fix oops when split header is enabled
Boris Burkov <boris@bur.io>
btrfs: fix EEXIST abort due to non-consecutive gaps in chunk allocation
Guillaume Gonnet <ggonnet.linux@gmail.com>
bpf: Fix tcx/netkit detach permissions when prog fd isn't given
Dave Airlie <airlied@redhat.com>
nouveau/gsp: drop WARN_ON in ACPI probes
Dragos Tatulea <dtatulea@nvidia.com>
net/mlx5e: RX, Fix XDP multi-buf frag counting for striding RQ
Dragos Tatulea <dtatulea@nvidia.com>
net/mlx5e: RX, Fix XDP multi-buf frag counting for legacy RQ
Miaoqian Lin <linmq006@gmail.com>
rxrpc, afs: Fix missing error pointer check after rxrpc_kernel_lookup_peer()
David Howells <dhowells@redhat.com>
rxrpc: kdoc: Update function descriptions and add link from rxrpc.rst
Chen Ni <nichen@iscas.ac.cn>
ASoC: amd: acp-mach-common: Add missing error check for clock acquisition
Vladimir Riabchun <ferr.lambarginio@gmail.com>
scsi: qla2xxx: Completely fix fcport double free
Adrian Hunter <adrian.hunter@intel.com>
i3c: mipi-i3c-hci: Fix race in DMA ring dequeue
Adrian Hunter <adrian.hunter@intel.com>
i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue
Kohei Enju <kohei@enjuk.jp>
ice: ptp: don't WARN when controlling PF is unavailable
Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
drm/amd/display: Fix NULL pointer dereference in dcn401_init_hw()
Emmanuel Grumbach <emmanuel.grumbach@intel.com>
wifi: iwlwifi: mvm: don't send a 6E related command when not supported
Prathamesh Shete <pshete@nvidia.com>
soc/tegra: pmc: Fix unsafe generic_handle_irq() call
Thierry Reding <treding@nvidia.com>
syscore: Pass context data to callbacks
Kai Huang <kai.huang@intel.com>
KVM: Export hardware virtualization enabling/disabling functions
Ming Qian <ming.qian@oss.nxp.com>
media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC
Nicolas Dufresne <nicolas.dufresne@collabora.com>
media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure
Heinz Mauelshagen <heinzm@redhat.com>
md raid: fix hang when stopping arrays with metadata through dm-raid
Filipe Manana <fdmanana@suse.com>
btrfs: don't BUG() on unexpected delayed ref type in run_one_delayed_ref()
Filipe Manana <fdmanana@suse.com>
btrfs: remove 'reserved' argument from btrfs_pin_extent()
Qu Wenruo <wqu@suse.com>
btrfs: do not ASSERT() when the fs flips RO inside btrfs_repair_io_failure()
Lijo Lazar <lijo.lazar@amd.com>
drm/amdgpu: Skip vcn poison irq release on VF
Hugo Villeneuve <hvilleneuve@dimonoff.com>
drm: renesas: rz-du: mipi_dsi: fix kernel panic when rebooting for some panels
Daniil Dulov <d.dulov@aladdin.ru>
ring-buffer: Fix possible dereference of uninitialized pointer
Jackson Lee <jackson.lee@chipsnmedia.com>
media: chips-media: wave5: Fix Null reference while testing fluster
Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
team: avoid NETDEV_CHANGEMTU event when unregistering slave
Ping-Ke Shih <pkshih@realtek.com>
wifi: rtw89: pci: validate sequence number of TX release report
Cédric Bellegarde <cedric.bellegarde@adishatz.org>
ASoC: qcom: q6asm: drop DSP responses for closed data streams
Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
ASoC: qcom: q6asm: handle the responses after closing
Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
drm/amd/display: Adjust PHY FSM transition to TX_EN-to-PLL_ON for TMDS on DCN35
Nicholas Carlini <nicholas@carlini.com>
ksmbd: fix signededness bug in smb_direct_prepare_negotiation()
Johannes Berg <johannes.berg@intel.com>
wifi: iwlwifi: fix 22000 series SMEM parsing
Szymon Wilczek <swilczek.lx@gmail.com>
ntfs3: fix circular locking dependency in run_unpack_ex
Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
fs/ntfs3: Accumulated refactoring changes
Filipe Manana <fdmanana@suse.com>
btrfs: fix zero size inode with non-zero size after log replay
David Sterba <dsterba@suse.com>
btrfs: tree-log: don't use token set/get accessors in fill_inode_item()
Joel Fernandes <joelagnelf@nvidia.com>
srcu: Use irq_work to start GP in tiny SRCU
Eric Dumazet <edumazet@google.com>
ipv6: ioam: fix potential NULL dereferences in __ioam6_fill_trace_data()
Justin Iurman <justin.iurman@gmail.com>
net: ioam6: fix OOB and missing lock
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_node_entry_remove
Long Li <leo.lilong@huawei.com>
xfs: remove bp->b_error check in xfs_attr3_root_inactive
Lee Jones <lee@kernel.org>
HID: core: Mitigate potential OOB by removing bogus memset()
Li Chen <chenl311@chinatelecom.cn>
HID: rate-limit hid_warn to prevent log flooding
Tatsuya S <tatsuya.s2862@gmail.com>
HID: core: Add reserved item tag for main items
Sabrina Dubroca <sd@queasysnail.net>
mpls: add seqcount to protect the platform_label{,s} pair
Kuniyuki Iwashima <kuniyu@google.com>
mpls: Protect net->mpls.platform_label with a per-netns mutex.
Kuniyuki Iwashima <kuniyu@google.com>
mpls: Convert mpls_dump_routes() to RCU.
Kuniyuki Iwashima <kuniyu@google.com>
mpls: Add mpls_route_input().
Kuniyuki Iwashima <kuniyu@google.com>
mpls: Pass net to mpls_dev_get().
Kuniyuki Iwashima <kuniyu@google.com>
mpls: Add mpls_dev_rcu().
Kuniyuki Iwashima <kuniyu@google.com>
mpls: Unify return paths in mpls_dev_notify().
Kuniyuki Iwashima <kuniyu@google.com>
mpls: Hold dev refcnt for mpls_nh.
Pengpeng Hou <pengpeng@iscas.ac.cn>
bnxt_en: set backing store type from query type
Michael Chan <michael.chan@broadcom.com>
bnxt_en: Update firmware interface spec to 1.10.3.85
Li Xiasong <lixiasong1@huawei.com>
mptcp: fix soft lockup in mptcp_recvmsg()
Geliang Tang <geliang@kernel.org>
mptcp: add eat_recv_skb helper
Paolo Abeni <pabeni@redhat.com>
mptcp: leverage skb deferral free
Paolo Abeni <pabeni@redhat.com>
mptcp: cleanup mem accounting
Paolo Abeni <pabeni@redhat.com>
mptcp: move the whole rx path under msk socket lock protection
Pauli Virtanen <pav@iki.fi>
Bluetooth: hci_sync: hci_cmd_sync_queue_once() return -EEXIST if exists
Daniel Borkmann <daniel@iogearbox.net>
bpf: Fix incorrect pruning due to atomic fetch precision tracking
Peilin Ye <yepeilin@google.com>
bpf: Factor out check_load_mem() and check_store_reg()
Peilin Ye <yepeilin@google.com>
bpf: Factor out check_atomic_rmw()
Peilin Ye <yepeilin@google.com>
bpf: Factor out atomic_ptr_type_ok()
Takashi Iwai <tiwai@suse.de>
ALSA: ctxfi: Check the error for index mapping
Harin Lee <me@harin.net>
ALSA: ctxfi: Refactor resource alloc for sparse mappings
Harin Lee <me@harin.net>
ALSA: ctxfi: Use explicit output flag for DAIO resources
Harin Lee <me@harin.net>
ALSA: ctxfi: Add hw parameter to daio_mgr_dao_init()
Oleh Konko <security@1seal.org>
Bluetooth: hci_event: move wake reason storage into validated event handlers
Pengpeng Hou <pengpeng@iscas.ac.cn>
rxrpc: proc: size address buffers for %pISpc output
Sean Christopherson <seanjc@google.com>
KVM: SEV: Protect *all* of sev_mem_enc_register_region() with kvm->lock
Ge Yang <yangge1116@126.com>
KVM: SEV: Use long-term pin when registering encrypted memory regions
Shardul Bankar <shardul.b@mpiricsoftware.com>
wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit
Kuniyuki Iwashima <kuniyu@amazon.com>
net: Add ->exit_rtnl() hook to struct pernet_operations.
Kuniyuki Iwashima <kuniyu@amazon.com>
net: Add ops_undo_single for module load/unload.
Kuniyuki Iwashima <kuniyu@amazon.com>
net: Factorise setup_net() and cleanup_net().
Kory Maincent (TI.com) <kory.maincent@bootlin.com>
drm/tilcdc: Fix removal actions in case of failed probe
Benjamin Marzinski <bmarzins@redhat.com>
dm: limit swapping tables for devices with zone write plugs
Janosch Frank <frankja@linux.ibm.com>
s390/mm: Add missing secure storage access fixups for donated memory
Luca Leonardo Scorcia <l.scorcia@gmail.com>
drm/mediatek: dsi: Store driver data before invoking mipi_dsi_host_register
Ihor Solodrai <ihor.solodrai@linux.dev>
bpf: Fix exception exit lock checking for subprogs
Yonatan Nachum <ynachum@amazon.com>
RDMA/efa: Fix use of completion ctx after free
Jiayuan Chen <jiayuan.chen@shopee.com>
serial: core: fix infinite loop in handle_tx() for PORT_UNKNOWN
Jiri Slaby (SUSE) <jirislaby@kernel.org>
serial: rename local uart_port_lock() -> uart_port_ref_lock()
Pablo Neira Ayuso <pablo@netfilter.org>
netfilter: nf_tables: clone set on flush only
Larysa Zaremba <larysa.zaremba@intel.com>
ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz
Juri Lelli <juri.lelli@redhat.com>
sched/deadline: Fix missing ENQUEUE_REPLENISH during PI de-boosting
Davidlohr Bueso <dave@stgolabs.net>
cxl/mbox: validate payload size before accessing contents in cxl_payload_from_user_allowed()
Jens Axboe <axboe@kernel.dk>
io_uring/rw: free potentially allocated iovec on cache put failure
Martin Kaiser <martin@kaiser.cx>
riscv: trace: fix snapshot deadlock with sbi ecall
Edward Adam Davis <eadavis@qq.com>
ALSA: usb-audio: Prevent excessive number of frames
Gustavo A. R. Silva <gustavoars@kernel.org>
virtio_net: Fix misalignment bug in struct virtnet_info
Gustavo A. R. Silva <gustavoars@kernel.org>
stddef: Introduce TRAILING_OVERLAP() helper macro
Emil Tantilov <emil.s.tantilov@intel.com>
idpf: fix error handling in the init_task on load
Caleb Sander Mateos <csander@purestorage.com>
block: zero non-PI portion of auto integrity buffer
Jie Zhang <jie.zhang@oss.qualcomm.com>
drm/msm: Recover HW before retire hung submit
Cong Nguyen <congnt264@gmail.com>
staging: rtl8723bs: fix xmit_frame/xmit_buf leaks on mgnt-frame error paths
Kumar Kartikeya Dwivedi <memxor@gmail.com>
bpf: Mark bpf_refcount field as unique
Haotian Zhang <vulab@iscas.ac.cn>
PCI: endpoint: Add missing NULL check for alloc_workqueue()
Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
net: qrtr: Drop the MHI auto_queue feature for IPCR DL channels
Jeffrey Hugo <quic_jhugo@quicinc.com>
accel/qaic: Add config structs for supported cards
Johannes Berg <johannes.berg@intel.com>
wifi: mac80211: don't WARN for connections on invalid channels
Benjamin Berg <benjamin.berg@intel.com>
wifi: mac80211: log link information in ieee80211_determine_chan_mode
Benjamin Berg <benjamin.berg@intel.com>
wifi: mac80211: fix typo in HE MCS check
Johan Hovold <johan@kernel.org>
staging: most: remove broken i2c driver
Aleksei Nikiforov <aleksei.nikiforov@linux.ibm.com>
s390/fpu: Fix false-positive kmsan report in fpu_vstl()
Tony Battersby <tonyb@cybernetics.com>
scsi: qla2xxx: Clear cmds after chip reset
Akash Goel <akash.goel@arm.com>
drm/panthor: Prevent potential UAF in group creation
Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
accel/ivpu: Fix page fault in ivpu_bo_unbind_all_bos_from_context()
Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
accel/ivpu: Rework bind/unbind of imported buffers
Tomasz Rusinowicz <tomasz.rusinowicz@intel.com>
accel/ivpu: Allow to import single buffer into multiple contexts
Sarika Sharma <sarika.sharma@oss.qualcomm.com>
wifi: ath12k: Fix MSDU buffer types handling in RX error path
Xiaoqi Zhuang <xiaoqi.zhuang@oss.qualcomm.com>
coresight: ETR: Fix ETR buffer use-after-free issue
Yeoreum Yun <yeoreum.yun@arm.com>
coresight-tmc: change tmc_drvdata spinlock's type to raw_spinlock_t
Li Nan <linan122@huawei.com>
md: init bioset in mddev_init
Lorenzo Bianconi <lorenzo@kernel.org>
wifi: mt76: wed: use proper wed reference in mt76 wed driver callabacks
Miquel Sabaté Solà <mssola@mssola.com>
btrfs: fix double free of qgroup record after failure to add delayed ref head
Antoine Tenart <atenart@kernel.org>
net: vxlan: prevent NULL deref in vxlan_xmit_one
Gustavo Luiz Duarte <gustavold@gmail.com>
netconsole: Acquire su_mutex before navigating configs hierarchy
Icenowy Zheng <uwu@icenowy.me>
clk: thead: th1520-ap: set all AXI clocks to CLK_IS_CRITICAL
Nitin Rawat <nitin.rawat@oss.qualcomm.com>
scsi: ufs: ufs-qcom: Fix UFS OCP issue during UFS power down (PC=3)
Nitin Rawat <quic_nitirawa@quicinc.com>
scsi: ufs: qcom : Refactor phy_power_on/off calls
Akiva Goldberger <agoldberger@nvidia.com>
mlx5: Fix default values in create CQ
Cosmin Ratiu <cratiu@nvidia.com>
net/mlx5e: Prepare for using different CQ doorbells
Cosmin Ratiu <cratiu@nvidia.com>
net/mlx5: Store the global doorbell in mlx5_priv
Cosmin Ratiu <cratiu@nvidia.com>
net/mlx5: Fix typo of MLX5_EQ_DOORBEL_OFFSET
Yevgeny Kliteynik <kliteyn@nvidia.com>
net/mlx5: HWS, fix bad parameter in CQ creation
Yishai Hadas <yishaih@nvidia.com>
RDMA/mlx5: Remove the redundant MLX5_IB_STAGE_UAR stage
Satyanarayana K V P <satyanarayana.k.v.p@intel.com>
drm/xe/guc: Add devm release action to safely tear down CT
Yifan Zhang <yifan1.zhang@amd.com>
amd/amdkfd: enhance kfd process check in switch partition
Fernando Fernandez Mancera <fmancera@suse.de>
sysfs: check visibility before changing group attribute ownership
Cezary Rojewski <cezary.rojewski@intel.com>
ASoC: Intel: avs: Do not share the name pointer between components
Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
ASoC: Intel: avs: Use topology information for endpoint numbers
Weili Qian <qianweili@huawei.com>
crypto: hisilicon/qm - request reserved interrupt for virtual function
Weili Qian <qianweili@huawei.com>
crypto: hisilicon/hpre - enable all clusters clock gating
Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
scsi: ufs: core: Fix data race in CPU latency PM QoS request handling
Stephan Gerhold <stephan.gerhold@linaro.org>
remoteproc: qcom: pas: Shutdown lite ADSP DTB on X1E
Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
remoteproc: qcom: pas: Conclude the rename from adsp
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
remoteproc: qcom_q6v5_pas: Simplify with dev_err_probe()
Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
remoteproc: qcom: pas: Make remoteproc name human friendly
Uwe Kleine-König <u.kleine-koenig@baylibre.com>
remoteproc: Switch back to struct platform_driver::remove()
Matthew Brost <matthew.brost@intel.com>
drm/xe: Don't allow evicting of BOs in same VM in array of VM binds
Fangyu Yu <fangyu.yu@linux.alibaba.com>
RISC-V: KVM: Write hgatp register with valid mode bits
Niklas Schnelle <schnelle@linux.ibm.com>
iommu/s390: Make attach succeed when the device was surprise removed
Matthew Rosato <mjrosato@linux.ibm.com>
iommu/s390: set appropriate IOTA region type
Matthew Rosato <mjrosato@linux.ibm.com>
iommu/s390: handle IOAT registration based on domain
Stefan Metzmacher <metze@samba.org>
smb: client: let recv_done verify data_offset, data_length and remaining_data_length
Uladzislau Rezki (Sony) <urezki@gmail.com>
mm/vmalloc, mm/kasan: respect gfp mask in kasan_populate_vmalloc()
Felix Fietkau <nbd@nbd.name>
wifi: mt76: mt7915: fix list corruption after hardware restart
Duoming Zhou <duoming@zju.edu.cn>
ptp: ocp: fix use-after-free bugs causing by ptp_ocp_watchdog
Lama Kayal <lkayal@nvidia.com>
net/mlx5: HWS, Fix memory leak in hws_action_get_shared_stc_nic error flow
Lama Kayal <lkayal@nvidia.com>
net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path
Vlad Dogaru <vdogaru@nvidia.com>
net/mlx5: HWS, Refactor pool implementation
Vlad Dogaru <vdogaru@nvidia.com>
net/mlx5: HWS, Make pool single resource
Vlad Dogaru <vdogaru@nvidia.com>
net/mlx5: HWS, Remove unused element array
Yevgeny Kliteynik <kliteyn@nvidia.com>
net/mlx5: HWS, update flow - remove the use of dual RTCs
Vlad Dogaru <vdogaru@nvidia.com>
net/mlx5: HWS, handle returned error value in pool alloc
Yevgeny Kliteynik <kliteyn@nvidia.com>
net/mlx5: HWS, simplify allocations as we support only FDB
Yevgeny Kliteynik <kliteyn@nvidia.com>
net/mlx5: HWS, denote how refcounts are protected
Eric Biggers <ebiggers@kernel.org>
crypto: x86/aegis - Add missing error checks
Eric Biggers <ebiggers@kernel.org>
crypto: x86/aegis - Fix sleeping when disallowed on PREEMPT_RT
Eric Biggers <ebiggers@google.com>
crypto: x86/aegis128 - improve assembly function prototypes
Eric Biggers <ebiggers@google.com>
crypto: x86/aegis128 - optimize length block preparation using SSE4.1
Eric Biggers <ebiggers@google.com>
crypto: x86/aegis128 - eliminate some indirect calls
David Hildenbrand <david@redhat.com>
mm/mremap: fix WARN with uffd that has remap events disabled
William Liu <will@willsroot.io>
net/sched: Fix backlog accounting in qdisc_dequeue_internal
Dan Carpenter <dan.carpenter@linaro.org>
wifi: iwlwifi: Fix error code in iwl_op_mode_dvm_start()
Johannes Berg <johannes.berg@intel.com>
wifi: iwlwifi: return ERR_PTR from opmode start()
Gabriele Monaco <gmonaco@redhat.com>
rv: Use strings in da monitors tracepoints
Gabriele Monaco <gmonaco@redhat.com>
rv: Remove trailing whitespace from tracepoint string
Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
wifi: ath12k: Pass ab pointer directly to ath12k_dp_tx_get_encap_type()
Heiko Stuebner <heiko@sntech.de>
drm/rockchip: vop2: fail cleanly if missing a primary plane for a video-port
Andy Yan <andy.yan@rock-chips.com>
drm/rockchip: vop2: Register the primary plane and overlay plane separately
Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
drm/rockchip: vop2: Consistently use dev_err_probe()
Mario Limonciello <mario.limonciello@amd.com>
platform/x86/amd: pmf: Use device managed allocations
Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
platform/x86/amd/pmf: Switch to platform_get_resource() and devm_ioremap_resource()
Heiko Carstens <hca@linux.ibm.com>
s390/mm: Fix in_atomic() handling in do_secure_storage_access()
Heiko Carstens <hca@linux.ibm.com>
s390/mm: Get rid of fault type switch statements
Heiko Carstens <hca@linux.ibm.com>
s390/mm: Simplify get_fault_type()
Claudio Imbrenda <imbrenda@linux.ibm.com>
s390/mm/fault: Handle guest-related program interrupts in KVM
Claudio Imbrenda <imbrenda@linux.ibm.com>
s390/kvm: Remove kvm_arch_fault_in_page()
Claudio Imbrenda <imbrenda@linux.ibm.com>
s390/entry: Remove __GMAP_ASCE and use _PIF_GUEST_FAULT again
Ping-Ke Shih <pkshih@realtek.com>
wifi: rtw89: pci: configure manual DAC mode via PCI config API only
Ben Dooks <ben.dooks@codethink.co.uk>
riscv: save the SR_SUM status over switches
Samuel Holland <samuel.holland@sifive.com>
riscv: Add support for per-thread envcfg CSR values
Samuel Holland <samuel.holland@sifive.com>
riscv: Enable cbo.zero only when all harts support Zicboz
Pu Lehui <pulehui@huawei.com>
mm: fix uprobe pte be overwritten when expanding vma
Sidhanta Sahu <sidhanta.sahu@oss.qualcomm.com>
wifi: ath12k: Fix memory leak due to multiple rx_stats allocation
Sriram R <quic_srirrama@quicinc.com>
wifi: ath12k: prepare vif data structure for MLO handling
Kalle Valo <quic_kvalo@quicinc.com>
wifi: ath12k: ath12k_mac_op_sta_state(): clean up update_wk cancellation
Kalle Valo <quic_kvalo@quicinc.com>
wifi: ath12k: convert struct ath12k_sta::update_wk to use struct wiphy_work
Zhi Wang <zhiw@nvidia.com>
drm/nouveau: fix a use-after-free in r535_gsp_rpc_push()
Brian Norris <briannorris@google.com>
PCI/pwrctrl: Cancel outstanding rescan work when unregistering
Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
PCI/pwrctl: Create pwrctl device only if at least one power supply is present
Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
PCI/pwrctl: Use of_platform_device_create() to create pwrctl devices
Yeoreum Yun <yeoreum.yun@arm.com>
coresight: holding cscfg_csdev_lock while removing cscfg from csdev
Michael S. Tsirkin <mst@redhat.com>
virtio: break and reset virtio devices on device_shutdown()
Roger Quadros <rogerq@kernel.org>
dmaengine: ti: k3-udma-glue: Drop skip_fdq argument from k3_udma_glue_reset_rx_chn
Roger Quadros <rogerq@kernel.org>
net: ethernet: ti: am65-cpsw: streamline RX queue creation and cleanup
Philippe Simons <simons.philippe@gmail.com>
clk: sunxi-ng: h616: Reparent GPU clock during frequency changes
Andre Przywara <andre.przywara@arm.com>
clk: sunxi-ng: h616: Reparent CPU clock during frequency changes
Alexander Gordeev <agordeev@linux.ibm.com>
kasan: avoid sleepable page allocation from atomic context
Ming Lei <ming.lei@redhat.com>
ublk: fix race between io_uring_cmd_complete_in_task and ublk_cancel_cmd
Yunhui Cui <cuiyunhui@bytedance.com>
perf/dwc_pcie: fix duplicate pci_dev devices
Bjorn Helgaas <bhelgaas@google.com>
perf/dwc_pcie: Qualify RAS DES VSEC Capability by Vendor, Revision
P Praneesh <quic_ppranees@quicinc.com>
wifi: ath12k: Avoid memory leak while enabling statistics
Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
wifi: ath12k: Avoid explicit type cast in monitor status parse handler
Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
wifi: ath12k: fix incorrect TID updation in DP monitor status path
Kang Yang <quic_kangyang@quicinc.com>
wifi: ath12k: fix struct hal_rx_phyrx_rssi_legacy_info
Atish Patra <atishp@rivosinc.com>
RISC-V: KVM: Teardown riscv specific bits after kvm_exit
Chao Yu <chao@kernel.org>
f2fs: quota: fix to avoid warning in dquot_writeback_dquots()
Murad Masimov <m.masimov@mt-integration.ru>
ax25: Remove broken autobind
Ville Syrjälä <ville.syrjala@linux.intel.com>
drm/i915: Grab intel_display from the encoder to avoid potential oopsies
Jani Nikula <jani.nikula@intel.com>
drm/i915/crt: convert to struct intel_display
Jani Nikula <jani.nikula@intel.com>
drm/i915/gmbus: convert to struct intel_display
Jani Nikula <jani.nikula@intel.com>
drm/i915/display: convert I915_STATE_WARN() to struct intel_display
Ville Syrjälä <ville.syrjala@linux.intel.com>
drm/i915/vga: Convert VGA code to intel_display
Jani Nikula <jani.nikula@intel.com>
drm/i915/display: pass display to intel_crtc_for_pipe()
Benjamin Berg <benjamin.berg@intel.com>
um: work around sched_yield not yielding in time-travel mode
Paulo Alcantara <pc@manguebit.org>
smb: client: fix compound alignment with encryption
Paulo Alcantara <pc@manguebit.com>
smb: client: get rid of bounds check in SMB2_ioctl_init()
Paulo Alcantara <pc@manguebit.com>
smb: client: improve compound padding in encryption
Christian Brauner <brauner@kernel.org>
namespace: handle mount locking for automounts correctly
Christian Brauner <brauner@kernel.org>
fcntl: refuse F_SET_RW_HINT on an immutable inode
Christian Brauner <brauner@kernel.org>
namespace: check the target before walking it in do_mount_setattr()
Christian Brauner <brauner@kernel.org>
namespace: unhash a dentry before detaching the mounts on it
Wentao Liang <vulab@iscas.ac.cn>
drm/vc4: Fix firmware reference leak in vc4_drm_bind()
Thomas Zimmermann <tzimmermann@suse.de>
drm/vc4: Use video aperture helpers
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()
Suraj Gupta <suraj.gupta2@amd.com>
net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop
Ben Cressey <ben@cressey.dev>
dm-integrity: fix buffer overflow in inline mode with large tag size
Mikulas Patocka <mpatocka@redhat.com>
dm-integrity: rename internal_hash
Mikulas Patocka <mpatocka@redhat.com>
dm-integrity: use internal variable for digestsize
Christian Brauner <brauner@kernel.org>
namespace: check the mounts before reading their parents in pivot_root()
Christian Brauner <brauner@kernel.org>
namespace: don't inherit MNT_UMOUNT in clone_mnt()
Zack Rusin <zack.rusin@broadcom.com>
drm/vmwgfx: validate pitch coming from userspace
Maaz Mombasawala <maaz.mombasawala@broadcom.com>
drm/vmwgfx: Stop using dev_private to store driver data.
Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex
Chengfeng Ye <nicoyip.dev@gmail.com>
Bluetooth: hci_sync: Fix command skb lifetime during scan setup
Tejun Heo <tj@kernel.org>
sched_ext: Fix CPU hotplug hang when a dying CPU's tasks sit in the BPF scheduler
Weiming Shi <bestswngs@gmail.com>
net: team: stop reusing skb after queue override
Weiming Shi <bestswngs@gmail.com>
net: team: fix NULL pointer dereference in team_xmit during mode change
Marc Harvey <marcharvey@google.com>
net: team: Rename port_disabled team mode op to port_tx_disabled
Marc Harvey <marcharvey@google.com>
net: team: Remove unused team_mode_op, port_enabled
Sean Wang <sean.wang@mediatek.com>
wifi: mt76: connac: tolerate inactive BSS deactivation
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
Hengyu Liang <hengyul@cs.unc.edu>
ata: libata-scsi: do not lose CHECK CONDITION for failed ATAPI commands
Mario Limonciello <mario.limonciello@amd.com>
drm/amd: Create a device link between APU display and XHCI devices
Dave Chinner <dchinner@redhat.com>
xfs: fix unmount hang with unflushable inodes stuck in the AIL
Dave Chinner <dchinner@redhat.com>
xfs: factor out stale buffer item completion
Dave Chinner <dchinner@redhat.com>
xfs: rearrange code in xfs_buf_item.c
Dave Chinner <dchinner@redhat.com>
xfs: avoid dquot buffer pin deadlock
Dave Chinner <dchinner@redhat.com>
xfs: catch stale AGF/AGF metadata
Dave Chinner <dchinner@redhat.com>
xfs: xfs_ifree_cluster vs xfs_iflush_shutdown_abort deadlock
Daehyeon Ko <4ncienth@gmail.com>
ip6_gre: remove obsolete ERSPAN PMTU update
Darrick J. Wong <djwong@kernel.org>
xfs: fix exchange-range-to-eof file size exchange
Norbert Szetei <norbert@doyensec.com>
xfs: stop exchanging reflink flags when exchanging mappings
Xuanqiang Luo <luoxuanqiang@kylinos.cn>
ice: fix use-after-free in dynamic port cleanup
Zhen Ni <zhen.ni@easystack.cn>
iommu/amd: Fix ivrs_base memleak in early_amd_iommu_init()
Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
iommu/amd: Disable AMD IOMMU if CMPXCHG16B feature is not supported
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:
Documentation/RCU/whatisRCU.rst | 10 +
Documentation/admin-guide/device-mapper/dm-ima.rst | 7 +-
.../admin-guide/device-mapper/dm-integrity.rst | 13 +
Documentation/core-api/refcount-vs-atomic.rst | 37 +-
Documentation/networking/af_xdp.rst | 54 +-
.../networking/net_cachelines/net_device.rst | 2 +-
Documentation/networking/rxrpc.rst | 11 +
Documentation/networking/switchdev.rst | 2 +-
Makefile | 33 +-
arch/Kconfig | 26 +-
arch/arm/Kconfig | 2 +-
arch/arm/kernel/hw_breakpoint.c | 13 +-
arch/arm/mach-exynos/mcpm-exynos.c | 12 +-
arch/arm/mach-exynos/suspend.c | 48 +-
arch/arm/mach-pxa/generic.h | 6 +-
arch/arm/mach-pxa/irq.c | 10 +-
arch/arm/mach-pxa/mfp-pxa2xx.c | 10 +-
arch/arm/mach-pxa/mfp-pxa3xx.c | 10 +-
arch/arm/mach-pxa/pxa25x.c | 4 +-
arch/arm/mach-pxa/pxa27x.c | 4 +-
arch/arm/mach-pxa/pxa3xx.c | 4 +-
arch/arm/mach-pxa/smemc.c | 12 +-
arch/arm/mach-s3c/irq-pm-s3c64xx.c | 12 +-
arch/arm/mach-s5pv210/pm.c | 10 +-
arch/arm/mach-versatile/integrator_ap.c | 12 +-
arch/arm/mm/Makefile | 2 +-
arch/arm/mm/cache-b15-rac.c | 12 +-
arch/arm/mm/cache-fa.S | 2 +-
arch/arm/mm/cache-v4.S | 2 +-
arch/arm/mm/cache-v4wb.S | 4 +-
arch/arm/mm/cache-v4wt.S | 2 +-
arch/arm/mm/cache-v6.S | 2 +-
arch/arm/mm/cache-v7.S | 2 +-
arch/arm/mm/cache-v7m.S | 2 +-
arch/arm/mm/proc-arm1020.S | 2 +-
arch/arm/mm/proc-arm1020e.S | 2 +-
arch/arm/mm/proc-arm1022.S | 2 +-
arch/arm/mm/proc-arm1026.S | 2 +-
arch/arm/mm/proc-arm920.S | 2 +-
arch/arm/mm/proc-arm922.S | 2 +-
arch/arm/mm/proc-arm925.S | 2 +-
arch/arm/mm/proc-arm926.S | 2 +-
arch/arm/mm/proc-arm940.S | 2 +-
arch/arm/mm/proc-arm946.S | 2 +-
arch/arm/mm/proc-feroceon.S | 2 +-
arch/arm/mm/proc-mohawk.S | 2 +-
arch/arm/mm/proc-xsc3.S | 2 +-
arch/arm/mm/tlb-v4.S | 2 +-
arch/arm64/Kconfig | 4 +-
arch/arm64/kernel/debug-monitors.c | 2 +-
arch/arm64/kernel/ptrace.c | 50 +
arch/arm64/kernel/traps.c | 4 +-
arch/arm64/kvm/at.c | 3 +-
arch/arm64/kvm/handle_exit.c | 2 +-
arch/arm64/kvm/vgic/vgic-v3.c | 12 +-
arch/arm64/kvm/vgic/vgic.c | 9 +-
arch/loongarch/kernel/machine_kexec.c | 5 +-
arch/loongarch/kernel/smp.c | 12 +-
arch/loongarch/net/bpf_jit.c | 20 +-
arch/mips/alchemy/common/dbdma.c | 12 +-
arch/mips/alchemy/common/irq.c | 24 +-
arch/mips/alchemy/common/usb.c | 12 +-
arch/mips/pci/pci-alchemy.c | 16 +-
arch/powerpc/include/asm/book3s/64/pgtable.h | 15 +
arch/powerpc/include/asm/xive.h | 4 +-
arch/powerpc/mm/book3s64/pgtable.c | 13 +-
arch/powerpc/mm/pgtable-frag.c | 1 +
arch/powerpc/platforms/cell/spu_base.c | 10 +-
arch/powerpc/platforms/powermac/pic.c | 12 +-
arch/powerpc/platforms/powernv/smp.c | 8 +-
arch/powerpc/platforms/pseries/smp.c | 8 +-
arch/powerpc/sysdev/fsl_lbc.c | 12 +-
arch/powerpc/sysdev/fsl_pci.c | 12 +-
arch/powerpc/sysdev/ipic.c | 12 +-
arch/powerpc/sysdev/mpic.c | 14 +-
arch/powerpc/sysdev/mpic_timer.c | 10 +-
arch/powerpc/sysdev/xive/common.c | 10 +-
arch/riscv/Kconfig | 4 +-
arch/riscv/include/asm/cfi.h | 4 +-
arch/riscv/include/asm/processor.h | 2 +
arch/riscv/include/asm/switch_to.h | 8 +
arch/riscv/kernel/Makefile | 17 +-
arch/riscv/kernel/asm-offsets.c | 5 +
arch/riscv/kernel/cfi.c | 2 +-
arch/riscv/kernel/cpufeature.c | 9 +-
arch/riscv/kernel/entry.S | 9 +
arch/riscv/kernel/patch.c | 21 +-
arch/riscv/kernel/suspend.c | 4 +-
arch/riscv/kvm/main.c | 4 +-
arch/riscv/kvm/vcpu_vector.c | 5 +-
arch/riscv/kvm/vmid.c | 2 +-
arch/riscv/net/bpf_jit_comp64.c | 9 +-
arch/riscv/purgatory/Makefile | 2 +-
arch/s390/include/asm/fpu-insn.h | 3 +
arch/s390/include/asm/gmap.h | 3 +-
arch/s390/include/asm/kvm_host.h | 3 +
arch/s390/include/asm/nmi.h | 3 +
arch/s390/include/asm/pci.h | 2 +
arch/s390/include/asm/pci_insn.h | 10 +-
arch/s390/include/asm/processor.h | 5 +-
arch/s390/include/asm/ptrace.h | 2 +
arch/s390/include/asm/uv.h | 6 +-
arch/s390/kernel/asm-offsets.c | 2 -
arch/s390/kernel/entry.S | 44 +-
arch/s390/kernel/nmi.c | 5 +-
arch/s390/kernel/traps.c | 24 +-
arch/s390/kernel/uv.c | 383 +++----
arch/s390/kvm/Makefile | 2 +-
arch/s390/kvm/gaccess.c | 42 +-
arch/s390/kvm/gmap.c | 121 +++
arch/s390/kvm/gmap.h | 19 +
arch/s390/kvm/intercept.c | 7 +-
arch/s390/kvm/interrupt.c | 24 +-
arch/s390/kvm/kvm-s390.c | 222 +++-
arch/s390/kvm/kvm-s390.h | 14 +-
arch/s390/kvm/pci.c | 17 +-
arch/s390/kvm/pv.c | 21 +
arch/s390/kvm/vsie.c | 15 +-
arch/s390/mm/fault.c | 189 +---
arch/s390/mm/gmap.c | 45 +-
arch/s390/net/bpf_jit_comp.c | 11 +
arch/s390/pci/pci.c | 35 +-
arch/s390/pci/pci_sysfs.c | 11 +-
arch/sh/mm/pmb.c | 10 +-
arch/um/include/linux/time-internal.h | 2 +
arch/um/kernel/skas/syscall.c | 11 +
arch/x86/Kconfig | 12 +-
arch/x86/crypto/Kconfig | 4 +-
arch/x86/crypto/aegis128-aesni-asm.S | 110 +-
arch/x86/crypto/aegis128-aesni-glue.c | 156 +--
arch/x86/events/amd/ibs.c | 12 +-
arch/x86/events/intel/core.c | 32 +-
arch/x86/events/intel/ds.c | 8 +-
arch/x86/events/intel/uncore.c | 46 +-
arch/x86/events/perf_event.h | 3 +
arch/x86/hyperv/hv_init.c | 12 +-
arch/x86/include/asm/cfi.h | 4 +-
arch/x86/kernel/Makefile | 2 +-
arch/x86/kernel/alternative.c | 4 +-
arch/x86/kernel/amd_gart_64.c | 10 +-
arch/x86/kernel/apic/apic.c | 12 +-
arch/x86/kernel/apic/io_apic.c | 17 +-
arch/x86/kernel/cpu/aperfmperf.c | 20 +-
arch/x86/kernel/cpu/intel_epb.c | 16 +-
arch/x86/kernel/cpu/mce/core.c | 14 +-
arch/x86/kernel/cpu/microcode/core.c | 15 +-
arch/x86/kernel/cpu/mtrr/legacy.c | 12 +-
arch/x86/kernel/cpu/resctrl/rdtgroup.c | 19 +-
arch/x86/kernel/cpu/umwait.c | 10 +-
arch/x86/kernel/i8237.c | 10 +-
arch/x86/kernel/i8259.c | 14 +-
arch/x86/kernel/kprobes/core.c | 2 +-
arch/x86/kernel/kvm.c | 12 +-
arch/x86/kvm/cpuid.c | 2 +-
arch/x86/kvm/cpuid.h | 16 +-
arch/x86/kvm/lapic.c | 61 +-
arch/x86/kvm/lapic.h | 4 +-
arch/x86/kvm/mmu.h | 2 +-
arch/x86/kvm/mmu/mmu.c | 4 +-
arch/x86/kvm/regs.c | 6 +-
arch/x86/kvm/svm/nested.c | 64 +-
arch/x86/kvm/svm/sev.c | 42 +-
arch/x86/kvm/svm/svm.c | 70 +-
arch/x86/kvm/svm/svm.h | 4 +-
arch/x86/kvm/vmx/nested.c | 11 +-
arch/x86/kvm/vmx/vmx.c | 16 +-
arch/x86/kvm/x86.c | 60 +-
arch/x86/kvm/x86.h | 1 -
arch/x86/purgatory/Makefile | 2 +-
block/bfq-cgroup.c | 9 +-
block/bio-integrity.c | 6 +-
block/blk-cgroup.c | 5 +-
block/blk-cgroup.h | 2 +
block/blk-iocost.c | 21 +-
block/blk-iolatency.c | 19 +-
block/blk-throttle.c | 15 +-
drivers/accel/ivpu/ivpu_drv.c | 2 +-
drivers/accel/ivpu/ivpu_gem.c | 111 +-
drivers/accel/ivpu/ivpu_gem.h | 3 +-
drivers/accel/ivpu/ivpu_job.c | 2 +-
drivers/accel/qaic/mhi_controller.c | 24 -
drivers/accel/qaic/qaic.h | 13 +-
drivers/accel/qaic/qaic_drv.c | 76 +-
drivers/accel/qaic/qaic_timesync.c | 2 +-
drivers/acpi/acpi_platform.c | 16 +-
drivers/acpi/bus.c | 54 +-
drivers/acpi/device_pm.c | 4 +-
drivers/acpi/pci_link.c | 10 +-
drivers/acpi/sleep.c | 12 +-
drivers/ata/libata-core.c | 7 +
drivers/ata/libata-scsi.c | 10 +-
drivers/base/core.c | 74 +-
drivers/base/firmware_loader/main.c | 12 +-
drivers/base/power/main.c | 67 +-
drivers/base/power/runtime.c | 61 +-
drivers/base/syscore.c | 82 +-
drivers/block/ublk_drv.c | 37 +-
drivers/bus/mhi/host/pci_generic.c | 20 +-
drivers/bus/mvebu-mbus.c | 16 +-
drivers/char/ipmi/ipmi_ssif.c | 20 +
drivers/clk/at91/pmc.c | 12 +-
drivers/clk/imx/clk-vf610.c | 12 +-
drivers/clk/ingenic/jz4725b-cgu.c | 2 +-
drivers/clk/ingenic/jz4740-cgu.c | 2 +-
drivers/clk/ingenic/jz4755-cgu.c | 2 +-
drivers/clk/ingenic/jz4760-cgu.c | 2 +-
drivers/clk/ingenic/jz4770-cgu.c | 2 +-
drivers/clk/ingenic/jz4780-cgu.c | 2 +-
drivers/clk/ingenic/pm.c | 14 +-
drivers/clk/ingenic/pm.h | 2 +-
drivers/clk/ingenic/tcu.c | 12 +-
drivers/clk/ingenic/x1000-cgu.c | 2 +-
drivers/clk/ingenic/x1830-cgu.c | 2 +-
drivers/clk/mediatek/clk-pllfh.c | 98 +-
drivers/clk/mvebu/common.c | 12 +-
drivers/clk/rockchip/clk-rk3288.c | 12 +-
drivers/clk/samsung/clk-s5pv210-audss.c | 12 +-
drivers/clk/samsung/clk.c | 12 +-
drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 64 +-
drivers/clk/tegra/clk-tegra210.c | 12 +-
drivers/clk/thead/clk-th1520-ap.c | 30 +-
drivers/clocksource/samsung_pwm_timer.c | 22 +-
drivers/clocksource/timer-armada-370-xp.c | 12 +-
drivers/cpuidle/cpuidle-psci.c | 12 +-
drivers/crypto/hisilicon/hpre/hpre_main.c | 36 +-
drivers/crypto/hisilicon/qm.c | 38 +-
drivers/cxl/core/core.h | 2 +
drivers/cxl/core/mbox.c | 11 +-
drivers/cxl/core/port.c | 7 +-
drivers/cxl/core/ras.c | 10 +-
drivers/cxl/core/region.c | 81 +-
drivers/cxl/core/trace.h | 12 +-
drivers/cxl/cxl.h | 22 +-
drivers/dma/idxd/init.c | 36 +-
drivers/dma/ti/k3-udma-glue.c | 15 +-
drivers/dma/xilinx/xilinx_dma.c | 14 +-
drivers/dpll/dpll_core.c | 12 +-
drivers/dpll/dpll_netlink.c | 68 +-
drivers/edac/igen6_edac.c | 148 ++-
drivers/firewire/ohci.c | 4 +-
drivers/firmware/arm_ffa/driver.c | 56 +-
drivers/firmware/arm_scmi/bus.c | 36 +-
drivers/gpio/gpio-latch.c | 2 +-
drivers/gpio/gpio-mxc.c | 12 +-
drivers/gpio/gpio-pca953x.c | 18 +-
drivers/gpio/gpio-pxa.c | 12 +-
drivers/gpio/gpio-sa1100.c | 12 +-
drivers/gpio/gpiolib.c | 136 ++-
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 +
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 4 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c | 25 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 63 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 52 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 23 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h | 3 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c | 16 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c | 25 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h | 3 -
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 32 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h | 1 +
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 25 +-
drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h | 131 ++-
drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 13 +-
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 -
drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h | 3 +
drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 4 +-
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 1 +
drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 17 +
drivers/gpu/drm/amd/amdkfd/kfd_device.c | 13 +-
.../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 20 +-
.../gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | 2 +
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 199 ++--
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 11 +-
drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 5 +-
drivers/gpu/drm/amd/amdkfd/kfd_process.c | 4 +
.../gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 24 +-
drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c | 6 +-
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 3 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 25 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 8 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 10 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h | 8 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 3 +-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 12 +-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c | 7 +
drivers/gpu/drm/amd/display/dc/core/dc.c | 6 +-
drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 2 +-
.../drm/amd/display/dc/dml2/dml21/dml21_utils.c | 15 +-
.../dml21/src/dml2_core/dml2_core_dcn4_calcs.c | 31 +-
.../drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 52 +
.../drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h | 4 +
.../gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c | 2 +-
.../drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 13 +-
.../amd/display/dc/resource/dcn32/dcn32_resource.c | 8 +-
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/etnaviv/etnaviv_sched.c | 20 +-
drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 +
drivers/gpu/drm/exynos/exynos_drm_vidi.c | 14 +-
drivers/gpu/drm/gud/gud_drv.c | 2 +
drivers/gpu/drm/i915/display/g4x_dp.c | 15 +-
drivers/gpu/drm/i915/display/i9xx_wm.c | 15 +-
drivers/gpu/drm/i915/display/intel_atomic_plane.c | 4 +-
drivers/gpu/drm/i915/display/intel_bios.c | 6 +-
drivers/gpu/drm/i915/display/intel_cdclk.c | 6 +-
drivers/gpu/drm/i915/display/intel_crt.c | 216 ++--
drivers/gpu/drm/i915/display/intel_crt.h | 10 +-
drivers/gpu/drm/i915/display/intel_crtc.c | 15 +-
drivers/gpu/drm/i915/display/intel_crtc.h | 3 +-
drivers/gpu/drm/i915/display/intel_cx0_phy.c | 76 +-
drivers/gpu/drm/i915/display/intel_display.c | 48 +-
drivers/gpu/drm/i915/display/intel_display.h | 17 +-
.../gpu/drm/i915/display/intel_display_driver.c | 18 +-
drivers/gpu/drm/i915/display/intel_display_irq.c | 20 +-
drivers/gpu/drm/i915/display/intel_display_power.c | 71 +-
.../drm/i915/display/intel_display_power_well.c | 6 +-
drivers/gpu/drm/i915/display/intel_display_trace.h | 15 +-
drivers/gpu/drm/i915/display/intel_dp.c | 8 +-
drivers/gpu/drm/i915/display/intel_dpll.c | 12 +-
drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 90 +-
drivers/gpu/drm/i915/display/intel_dsb.c | 2 +-
drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 5 +-
drivers/gpu/drm/i915/display/intel_dvo.c | 8 +-
drivers/gpu/drm/i915/display/intel_fbc.c | 7 +-
drivers/gpu/drm/i915/display/intel_fdi.c | 52 +-
drivers/gpu/drm/i915/display/intel_fifo_underrun.c | 15 +-
drivers/gpu/drm/i915/display/intel_gmbus.c | 290 ++---
drivers/gpu/drm/i915/display/intel_gmbus.h | 15 +-
drivers/gpu/drm/i915/display/intel_gmbus_regs.h | 16 +-
drivers/gpu/drm/i915/display/intel_hdmi.c | 8 +-
drivers/gpu/drm/i915/display/intel_hotplug_irq.c | 6 +-
drivers/gpu/drm/i915/display/intel_link_bw.c | 3 +-
drivers/gpu/drm/i915/display/intel_lvds.c | 2 +-
drivers/gpu/drm/i915/display/intel_modeset_setup.c | 12 +-
.../gpu/drm/i915/display/intel_modeset_verify.c | 89 +-
drivers/gpu/drm/i915/display/intel_pch_display.c | 56 +-
drivers/gpu/drm/i915/display/intel_pps.c | 26 +-
drivers/gpu/drm/i915/display/intel_sdvo.c | 9 +-
drivers/gpu/drm/i915/display/intel_snps_phy.c | 11 +-
drivers/gpu/drm/i915/display/intel_sprite_uapi.c | 3 +-
drivers/gpu/drm/i915/display/intel_vga.c | 45 +-
drivers/gpu/drm/i915/display/intel_vga.h | 14 +-
drivers/gpu/drm/i915/display/skl_watermark.c | 7 +-
drivers/gpu/drm/i915/display/vlv_dsi_pll.c | 7 +-
.../gpu/drm/i915/gt/intel_execlists_submission.c | 19 +-
drivers/gpu/drm/i915/gt/intel_rc6.c | 2 +-
drivers/gpu/drm/i915/i915_suspend.c | 5 +-
drivers/gpu/drm/i915/i915_utils.h | 24 -
drivers/gpu/drm/imagination/pvr_queue.c | 18 +-
drivers/gpu/drm/lima/lima_sched.c | 16 +-
drivers/gpu/drm/mediatek/mtk_dsi.c | 11 +-
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 5 +-
drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c | 24 +-
drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 11 +-
drivers/gpu/drm/msm/msm_gpu.c | 30 +-
drivers/gpu/drm/msm/msm_ringbuffer.c | 24 +-
drivers/gpu/drm/msm/msm_ringbuffer.h | 1 +
drivers/gpu/drm/nouveau/nouveau_sched.c | 16 +-
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c | 29 +-
drivers/gpu/drm/panfrost/panfrost_job.c | 20 +-
drivers/gpu/drm/panthor/panthor_mmu.c | 25 +-
drivers/gpu/drm/panthor/panthor_sched.c | 77 +-
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 8 +
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 182 ++--
drivers/gpu/drm/scheduler/sched_main.c | 50 +-
drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 2 +-
drivers/gpu/drm/tilcdc/tilcdc_drv.c | 53 +-
drivers/gpu/drm/tilcdc/tilcdc_drv.h | 2 +-
drivers/gpu/drm/v3d/v3d_sched.c | 65 +-
drivers/gpu/drm/vc4/vc4_bo.c | 2 +-
drivers/gpu/drm/vc4/vc4_drv.c | 9 +-
drivers/gpu/drm/virtio/virtgpu_drv.h | 25 +
drivers/gpu/drm/virtio/virtgpu_object.c | 2 +-
drivers/gpu/drm/virtio/virtgpu_plane.c | 4 +
drivers/gpu/drm/virtio/virtgpu_prime.c | 42 +
drivers/gpu/drm/virtio/virtgpu_vq.c | 4 +-
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 -
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 +-
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 30 +-
drivers/gpu/drm/xe/xe_execlist.c | 15 +-
drivers/gpu/drm/xe/xe_gpu_scheduler.c | 17 +-
drivers/gpu/drm/xe/xe_guc.c | 8 +-
drivers/gpu/drm/xe/xe_guc_ct.c | 41 +-
drivers/gpu/drm/xe/xe_guc_ct.h | 1 +
drivers/gpu/drm/xe/xe_guc_exec_queue_types.h | 5 +
drivers/gpu/drm/xe/xe_guc_submit.c | 4 +-
drivers/gpu/drm/xe/xe_vm.c | 31 +-
drivers/gpu/drm/xe/xe_vm_types.h | 3 +
drivers/hid/hid-core.c | 12 +-
drivers/hid/hid-logitech-hidpp.c | 23 +-
drivers/hid/hid-steam.c | 33 +-
drivers/hv/vmbus_drv.c | 29 +-
drivers/hwmon/asus_rog_ryujin.c | 137 +--
drivers/hwmon/lm90.c | 26 +-
drivers/hwmon/pmbus/pmbus_core.c | 82 +-
drivers/hwtracing/coresight/coresight-etm4x-core.c | 90 +-
drivers/hwtracing/coresight/coresight-syscfg.c | 2 +
drivers/hwtracing/coresight/coresight-tmc-core.c | 6 +-
drivers/hwtracing/coresight/coresight-tmc-etf.c | 48 +-
drivers/hwtracing/coresight/coresight-tmc-etr.c | 60 +-
drivers/hwtracing/coresight/coresight-tmc.h | 2 +-
drivers/i3c/master.c | 39 +-
drivers/i3c/master/mipi-i3c-hci/core.c | 1 +
drivers/i3c/master/mipi-i3c-hci/dma.c | 27 +-
drivers/i3c/master/mipi-i3c-hci/hci.h | 1 +
drivers/i3c/master/svc-i3c-master.c | 108 +-
drivers/infiniband/core/counters.c | 9 +-
drivers/infiniband/hw/bnxt_re/ib_verbs.c | 61 +-
drivers/infiniband/hw/bnxt_re/ib_verbs.h | 1 +
drivers/infiniband/hw/bnxt_re/qplib_sp.h | 1 +
drivers/infiniband/hw/cxgb4/mem.c | 46 +-
drivers/infiniband/hw/efa/efa_com.c | 28 +-
drivers/infiniband/hw/irdma/hw.c | 7 +-
drivers/infiniband/hw/irdma/main.h | 3 +-
drivers/infiniband/hw/irdma/utils.c | 12 +-
drivers/infiniband/hw/irdma/verbs.c | 22 +-
drivers/infiniband/hw/mlx5/cq.c | 15 +-
drivers/infiniband/hw/mlx5/main.c | 17 -
drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 -
drivers/infiniband/sw/rdmavt/vt.c | 4 +-
drivers/infiniband/sw/rxe/rxe.h | 37 -
drivers/infiniband/sw/rxe/rxe_loc.h | 1 +
drivers/infiniband/sw/rxe/rxe_mr.c | 287 +++--
drivers/infiniband/sw/rxe/rxe_verbs.h | 47 +-
drivers/iommu/amd/init.c | 45 +-
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 60 +-
drivers/iommu/intel/iommu.c | 20 +-
drivers/iommu/intel/iommu.h | 2 +-
drivers/iommu/intel/pasid.c | 9 +-
drivers/iommu/io-pgfault.c | 24 +-
drivers/iommu/iommufd/fault.c | 2 +
drivers/iommu/s390-iommu.c | 63 +-
drivers/irqchip/exynos-combiner.c | 14 +-
drivers/irqchip/irq-armada-370-xp.c | 12 +-
drivers/irqchip/irq-bcm7038-l1.c | 12 +-
drivers/irqchip/irq-gic-v3-its.c | 12 +-
drivers/irqchip/irq-i8259.c | 12 +-
drivers/irqchip/irq-imx-gpcv2.c | 16 +-
drivers/irqchip/irq-loongson-eiointc.c | 12 +-
drivers/irqchip/irq-loongson-htpic.c | 10 +-
drivers/irqchip/irq-loongson-htvec.c | 12 +-
drivers/irqchip/irq-loongson-pch-lpc.c | 12 +-
drivers/irqchip/irq-loongson-pch-pic.c | 12 +-
drivers/irqchip/irq-mchp-eic.c | 12 +-
drivers/irqchip/irq-mst-intc.c | 12 +-
drivers/irqchip/irq-mtk-cirq.c | 12 +-
drivers/irqchip/irq-renesas-rzg2l.c | 12 +-
drivers/irqchip/irq-sa11x0.c | 12 +-
drivers/irqchip/irq-sifive-plic.c | 12 +-
drivers/irqchip/irq-sun6i-r.c | 18 +-
drivers/irqchip/irq-tegra.c | 12 +-
drivers/irqchip/irq-vic.c | 12 +-
drivers/leds/leds-aw200xx.c | 2 +-
drivers/leds/trigger/ledtrig-cpu.c | 14 +-
drivers/macintosh/via-pmu.c | 12 +-
drivers/md/dm-integrity.c | 156 ++-
drivers/md/dm-table.c | 41 +-
drivers/md/dm-verity-fec.c | 102 +-
drivers/md/dm-zone.c | 34 +-
drivers/md/dm.c | 6 +
drivers/md/dm.h | 5 +
drivers/md/md.c | 111 +-
drivers/md/md.h | 5 +
drivers/md/raid1.c | 32 +-
drivers/md/raid10.c | 51 +-
.../platform/chips-media/wave5/wave5-helper.c | 30 +-
.../platform/chips-media/wave5/wave5-helper.h | 1 +
.../platform/chips-media/wave5/wave5-vpu-dec.c | 5 +
.../platform/chips-media/wave5/wave5-vpu-enc.c | 5 +
.../media/platform/chips-media/wave5/wave5-vpu.c | 99 +-
.../platform/chips-media/wave5/wave5-vpuapi.h | 6 +
.../st/stm32/stm32-dcmipp/dcmipp-bytecap.c | 51 +-
.../st/stm32/stm32-dcmipp/dcmipp-byteproc.c | 100 +-
.../st/stm32/stm32-dcmipp/dcmipp-parallel.c | 108 +-
drivers/media/platform/verisilicon/hantro.h | 2 +
drivers/media/platform/verisilicon/hantro_drv.c | 42 +-
drivers/media/platform/verisilicon/imx8m_vpu_hw.c | 8 +
drivers/media/v4l2-core/v4l2-mem2mem.c | 23 +
drivers/mfd/intel-lpss.c | 2 +-
drivers/misc/lkdtm/cfi.c | 2 +-
drivers/mmc/host/vub300.c | 39 +-
drivers/net/amt.c | 5 +-
drivers/net/bonding/bond_main.c | 2 +-
drivers/net/ethernet/adi/adin1110.c | 2 +-
drivers/net/ethernet/airoha/airoha_eth.c | 32 +-
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 76 +-
drivers/net/ethernet/broadcom/bnxt/bnxt.h | 20 +-
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 8 +-
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +-
drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h | 173 ++-
drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 345 +++---
drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h | 25 +-
drivers/net/ethernet/cavium/liquidio/lio_main.c | 27 -
.../net/ethernet/cavium/liquidio/octeon_device.h | 3 -
.../net/ethernet/cavium/liquidio/octeon_mailbox.c | 33 +-
.../chelsio/inline_crypto/chtls/chtls_cm.c | 4 +-
.../chelsio/inline_crypto/chtls/chtls_cm.h | 1 -
drivers/net/ethernet/ibm/emac/core.c | 18 +-
.../net/ethernet/intel/ice/devlink/devlink_port.c | 2 +-
drivers/net/ethernet/intel/ice/ice_base.c | 9 +-
drivers/net/ethernet/intel/ice/ice_ptp.c | 8 +-
drivers/net/ethernet/intel/ice/ice_txrx.c | 6 +-
drivers/net/ethernet/intel/idpf/idpf_dev.c | 2 +-
drivers/net/ethernet/intel/idpf/idpf_lib.c | 15 +-
drivers/net/ethernet/intel/idpf/idpf_vf_dev.c | 2 +-
drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 12 +-
drivers/net/ethernet/intel/idpf/idpf_virtchnl.h | 2 +-
drivers/net/ethernet/intel/igc/igc_main.c | 3 +-
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 3 +-
drivers/net/ethernet/marvell/octeontx2/af/cgx.c | 12 +
drivers/net/ethernet/marvell/octeontx2/af/cgx.h | 1 +
drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 2 +
.../net/ethernet/marvell/octeontx2/af/rvu_cgx.c | 79 ++
.../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 22 +-
.../net/ethernet/marvell/octeontx2/af/rvu_npc.c | 29 +-
.../net/ethernet/marvell/octeontx2/nic/otx2_vf.c | 20 +-
.../net/ethernet/marvell/prestera/prestera_main.c | 2 +-
drivers/net/ethernet/mellanox/mlx4/srq.c | 13 +-
drivers/net/ethernet/mellanox/mlx5/core/cq.c | 24 +-
drivers/net/ethernet/mellanox/mlx5/core/en.h | 13 +
.../ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c | 10 +-
.../net/ethernet/mellanox/mlx5/core/en/params.c | 2 +-
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c | 2 +-
drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h | 5 +-
.../net/ethernet/mellanox/mlx5/core/en/xsk/tx.c | 4 +-
.../net/ethernet/mellanox/mlx5/core/en_common.c | 11 +-
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 37 +-
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 54 +-
drivers/net/ethernet/mellanox/mlx5/core/en_rep.h | 1 -
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 23 +-
drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 9 +-
drivers/net/ethernet/mellanox/mlx5/core/eq.c | 8 +-
.../ethernet/mellanox/mlx5/core/esw/devlink_port.c | 36 +
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 1 +
.../net/ethernet/mellanox/mlx5/core/fpga/conn.c | 16 +-
.../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 3 +-
drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c | 8 +-
drivers/net/ethernet/mellanox/mlx5/core/main.c | 11 +-
.../ethernet/mellanox/mlx5/core/steering/dr_send.c | 29 +-
.../mlx5/core/steering/hws/mlx5hws_action.c | 135 ++-
.../mlx5/core/steering/hws/mlx5hws_action.h | 6 +-
.../mellanox/mlx5/core/steering/hws/mlx5hws_cmd.c | 2 +-
.../mellanox/mlx5/core/steering/hws/mlx5hws_cmd.h | 2 +-
.../mlx5/core/steering/hws/mlx5hws_context.c | 30 +-
.../mlx5/core/steering/hws/mlx5hws_context.h | 4 +-
.../mlx5/core/steering/hws/mlx5hws_debug.c | 56 +-
.../mlx5/core/steering/hws/mlx5hws_definer.h | 2 +-
.../mlx5/core/steering/hws/mlx5hws_internal.h | 1 -
.../mlx5/core/steering/hws/mlx5hws_matcher.c | 237 ++---
.../mlx5/core/steering/hws/mlx5hws_matcher.h | 8 +-
.../mlx5/core/steering/hws/mlx5hws_pat_arg.h | 2 +-
.../mellanox/mlx5/core/steering/hws/mlx5hws_pool.c | 513 +++------
.../mellanox/mlx5/core/steering/hws/mlx5hws_pool.h | 77 +-
.../mellanox/mlx5/core/steering/hws/mlx5hws_rule.c | 75 +-
.../mellanox/mlx5/core/steering/hws/mlx5hws_rule.h | 3 +-
.../mellanox/mlx5/core/steering/hws/mlx5hws_send.c | 16 +-
.../mlx5/core/steering/hws/mlx5hws_table.c | 16 +-
drivers/net/ethernet/mellanox/mlx5/core/wc.c | 4 +-
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 +-
drivers/net/ethernet/microsoft/mana/mana_en.c | 7 +-
drivers/net/ethernet/rocker/rocker_main.c | 2 +-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 91 +-
drivers/net/ethernet/ti/am65-cpsw-nuss.c | 253 +++--
drivers/net/ethernet/ti/cpsw_new.c | 2 +-
drivers/net/ethernet/ti/icssg/icssg_common.c | 2 +-
drivers/net/ethernet/xilinx/xilinx_axienet.h | 7 +-
drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 53 +-
drivers/net/loopback.c | 2 +-
drivers/net/net_failover.c | 2 +-
drivers/net/netconsole.c | 2 +
drivers/net/tap.c | 33 +-
drivers/net/team/team_core.c | 95 +-
drivers/net/team/team_mode_loadbalance.c | 4 +-
drivers/net/virtio_net.c | 26 +-
drivers/net/vrf.c | 2 +-
drivers/net/vxlan/vxlan_core.c | 36 +-
drivers/net/wireguard/device.c | 8 +-
drivers/net/wireless/ath/ath11k/mhi.c | 8 +-
drivers/net/wireless/ath/ath11k/pci.c | 7 +
drivers/net/wireless/ath/ath12k/core.h | 2 +-
drivers/net/wireless/ath/ath12k/dp_mon.c | 217 ++--
drivers/net/wireless/ath/ath12k/dp_rx.c | 62 +-
drivers/net/wireless/ath/ath12k/dp_tx.c | 5 +-
drivers/net/wireless/ath/ath12k/hal_rx.c | 10 +-
drivers/net/wireless/ath/ath12k/hal_rx.h | 12 +-
drivers/net/wireless/ath/ath12k/mac.c | 25 +-
drivers/net/wireless/ath/ath12k/mhi.c | 4 -
drivers/net/wireless/ath/ath12k/wmi.c | 19 +-
drivers/net/wireless/ath/ath9k/wmi.c | 16 +-
drivers/net/wireless/ath/ath9k/wmi.h | 1 -
.../net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 4 +
drivers/net/wireless/intel/iwlwifi/dvm/main.c | 47 +-
drivers/net/wireless/intel/iwlwifi/fw/smem.c | 5 +-
drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/binding.c | 10 +-
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 +-
drivers/net/wireless/intel/iwlwifi/mvm/link.c | 5 +-
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 12 +-
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 +
drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 24 +-
.../net/wireless/intel/iwlwifi/mvm/time-event.c | 3 +-
.../net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 6 +-
drivers/net/wireless/mediatek/mt76/dma.c | 10 +-
drivers/net/wireless/mediatek/mt76/mac80211.c | 59 +-
drivers/net/wireless/mediatek/mt76/mt76.h | 10 +
.../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 9 +-
.../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 23 +
drivers/net/wireless/mediatek/mt76/mt7915/init.c | 2 +
drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 12 +-
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 14 +-
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 6 +-
drivers/net/wireless/mediatek/mt76/mt7996/init.c | 2 +
drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +-
drivers/net/wireless/mediatek/mt76/mt7996/mmio.c | 4 +
drivers/net/wireless/mediatek/mt76/wed.c | 10 +-
drivers/net/wireless/realtek/rtw89/pci.c | 41 +-
drivers/ntb/ntb_transport.c | 18 +-
drivers/nvme/target/admin-cmd.c | 8 +-
drivers/nvme/target/core.c | 41 +-
drivers/nvme/target/fabrics-cmd.c | 2 +-
drivers/nvme/target/nvmet.h | 6 +
drivers/nvme/target/tcp.c | 6 +-
drivers/opp/core.c | 5 +-
drivers/pci/bus.c | 23 +-
drivers/pci/endpoint/functions/pci-epf-ntb.c | 5 +
drivers/pci/endpoint/functions/pci-epf-vntb.c | 5 +
drivers/pci/of.c | 27 +
drivers/pci/pci-driver.c | 198 ++--
drivers/pci/pci.h | 46 +-
drivers/pci/pwrctl/core.c | 2 +
drivers/pci/search.c | 8 +-
drivers/perf/dwc_pcie_pmu.c | 81 +-
drivers/pinctrl/mediatek/pinctrl-moore.c | 6 +-
drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 14 +-
drivers/pinctrl/mediatek/pinctrl-paris.c | 33 +-
drivers/platform/x86/amd/pmf/Kconfig | 1 +
drivers/platform/x86/amd/pmf/acpi.c | 48 +-
drivers/platform/x86/amd/pmf/core.c | 5 +-
drivers/platform/x86/amd/pmf/pmf.h | 7 +-
drivers/platform/x86/amd/pmf/tee-if.c | 64 +-
drivers/platform/x86/asus-wmi.c | 6 +-
drivers/platform/x86/dell/dell-wmi-base.c | 2 +-
drivers/pmdomain/imx/imx93-blk-ctrl.c | 60 +-
drivers/power/reset/sc27xx-poweroff.c | 10 +-
drivers/ptp/ptp_ocp.c | 3 +-
drivers/pwm/pwm-samsung.c | 22 +-
drivers/remoteproc/Kconfig | 11 +-
drivers/remoteproc/da8xx_remoteproc.c | 2 +-
drivers/remoteproc/imx_dsp_rproc.c | 2 +-
drivers/remoteproc/imx_rproc.c | 2 +-
drivers/remoteproc/keystone_remoteproc.c | 2 +-
drivers/remoteproc/meson_mx_ao_arc.c | 2 +-
drivers/remoteproc/mtk_scp.c | 2 +-
drivers/remoteproc/pru_rproc.c | 2 +-
drivers/remoteproc/qcom_q6v5_adsp.c | 2 +-
drivers/remoteproc/qcom_q6v5_mss.c | 2 +-
drivers/remoteproc/qcom_q6v5_pas.c | 639 ++++++-----
drivers/remoteproc/qcom_q6v5_wcss.c | 2 +-
drivers/remoteproc/qcom_wcnss.c | 25 +-
drivers/remoteproc/rcar_rproc.c | 2 +-
drivers/remoteproc/remoteproc_virtio.c | 2 +-
drivers/remoteproc/st_remoteproc.c | 2 +-
drivers/remoteproc/stm32_rproc.c | 2 +-
drivers/remoteproc/ti_k3_dsp_remoteproc.c | 2 +-
drivers/remoteproc/wkup_m3_rproc.c | 2 +-
drivers/s390/crypto/ap_bus.c | 74 ++
drivers/s390/crypto/ap_bus.h | 30 +-
drivers/s390/crypto/pkey_cca.c | 11 +-
drivers/s390/crypto/zcrypt_api.c | 122 ++-
drivers/s390/crypto/zcrypt_api.h | 11 +-
drivers/s390/crypto/zcrypt_ccamisc.c | 80 +-
drivers/s390/crypto/zcrypt_ccamisc.h | 6 +-
drivers/s390/crypto/zcrypt_ep11misc.c | 10 +-
drivers/s390/crypto/zcrypt_msgtype50.c | 36 +-
drivers/s390/crypto/zcrypt_msgtype6.c | 210 ++--
drivers/s390/crypto/zcrypt_msgtype6.h | 51 +-
drivers/s390/net/ism_drv.c | 20 +-
drivers/scsi/ch.c | 30 +-
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 12 +-
drivers/scsi/qla2xxx/qla_iocb.c | 2 -
drivers/scsi/qla2xxx/qla_os.c | 20 +-
drivers/scsi/qla2xxx/qla_target.c | 5 +-
drivers/scsi/qla2xxx/qla_target.h | 1 +
drivers/scsi/scsi_error.c | 6 +-
drivers/scsi/sd.c | 141 +--
drivers/sh/clk/core.c | 10 +-
drivers/sh/intc/core.c | 12 +-
drivers/soc/aspeed/aspeed-lpc-snoop.c | 31 +-
drivers/soc/bcm/brcmstb/biuctrl.c | 12 +-
drivers/soc/tegra/pmc.c | 124 ++-
drivers/soc/xilinx/zynqmp_power.c | 43 +-
drivers/soundwire/generic_bandwidth_allocation.c | 35 +-
drivers/soundwire/intel_auxdevice.c | 36 +-
drivers/spi/spi-ch341.c | 7 +-
drivers/spi/spi-microchip-core-qspi.c | 100 +-
drivers/spi/spi-mpc52xx.c | 26 +-
drivers/staging/greybus/raw.c | 90 +-
drivers/staging/most/Kconfig | 2 -
drivers/staging/most/Makefile | 1 -
drivers/staging/most/i2c/Kconfig | 13 -
drivers/staging/most/i2c/Makefile | 4 -
drivers/staging/most/i2c/i2c.c | 374 -------
drivers/staging/rtl8723bs/core/rtw_mlme.c | 14 +-
drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 22 +-
drivers/thermal/intel/intel_hfi.c | 12 +-
drivers/thermal/thermal_hwmon.c | 89 +-
drivers/tty/serial/8250/8250_core.c | 253 ++---
drivers/tty/serial/serial_core.c | 117 +-
drivers/tty/tty_io.c | 2 +-
drivers/ufs/core/ufs-mcq.c | 35 +-
drivers/ufs/core/ufs-sysfs.c | 2 +
drivers/ufs/core/ufshcd-priv.h | 14 +-
drivers/ufs/core/ufshcd.c | 82 +-
drivers/ufs/host/ufs-qcom.c | 71 +-
drivers/usb/gadget/function/f_fs.c | 55 +-
drivers/usb/gadget/function/f_hid.c | 4 +-
drivers/usb/gadget/function/f_uac1.c | 13 +-
drivers/usb/gadget/function/f_uac2.c | 13 +-
drivers/vdpa/mlx5/core/mlx5_vdpa.h | 2 +
drivers/vdpa/mlx5/core/mr.c | 5 +-
drivers/vdpa/mlx5/core/resources.c | 11 +-
drivers/vdpa/mlx5/net/mlx5_vnet.c | 6 +-
drivers/vdpa/vdpa.c | 48 +-
drivers/vdpa/vdpa_sim/vdpa_sim.c | 10 +-
drivers/vdpa/vdpa_user/iova_domain.c | 11 +-
drivers/vdpa/vdpa_user/vduse_dev.c | 4 +-
drivers/vhost/iotlb.c | 47 +-
drivers/vhost/net.c | 2 +
drivers/vhost/vdpa.c | 9 +-
drivers/vhost/vhost.c | 65 +-
drivers/vhost/vhost.h | 1 +
drivers/vhost/vsock.c | 2 +
drivers/video/fbdev/core/fb_chrdev.c | 6 +-
drivers/video/fbdev/core/fbcon.c | 2 -
drivers/video/fbdev/core/fbmem.c | 13 +
drivers/video/fbdev/core/fbsysfs.c | 4 +-
drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 11 +-
drivers/video/fbdev/ps3fb.c | 5 +-
drivers/video/fbdev/sh_mobile_lcdcfb.c | 5 +-
drivers/virt/acrn/irqfd.c | 75 +-
drivers/virtio/virtio.c | 29 +
drivers/virtio/virtio_ring.c | 19 +-
drivers/watchdog/at91sam9_wdt.c | 4 +-
drivers/xen/pvcalls-front.c | 88 +-
drivers/xen/xen-acpi-processor.c | 12 +-
fs/9p/vfs_addr.c | 2 +-
fs/afs/addr_list.c | 8 +-
fs/afs/file.c | 6 +-
fs/afs/fsclient.c | 2 +-
fs/afs/inode.c | 1 +
fs/afs/internal.h | 4 +-
fs/afs/rxrpc.c | 4 +-
fs/afs/super.c | 2 +-
fs/afs/yfsclient.c | 2 +-
fs/btrfs/acl.c | 4 +
fs/btrfs/bio.c | 8 +-
fs/btrfs/block-rsv.c | 19 +-
fs/btrfs/defrag.c | 50 +-
fs/btrfs/delayed-ref.c | 35 +-
fs/btrfs/disk-io.c | 25 +-
fs/btrfs/extent-tree.c | 35 +-
fs/btrfs/extent-tree.h | 3 +-
fs/btrfs/extent_io.c | 58 +-
fs/btrfs/file.c | 103 +-
fs/btrfs/fs.h | 9 +
fs/btrfs/inode.c | 3 +-
fs/btrfs/lzo.c | 13 +-
fs/btrfs/qgroup.c | 18 +-
fs/btrfs/transaction.c | 9 +-
fs/btrfs/tree-log.c | 142 +--
fs/btrfs/volumes.c | 241 +++--
fs/btrfs/zstd.c | 11 +-
fs/ceph/addr.c | 1115 +++++++++++++-------
fs/ceph/mds_client.c | 65 +-
fs/ceph/mds_client.h | 1 +
fs/ceph/super.h | 9 +
fs/erofs/decompressor.c | 61 +-
fs/erofs/internal.h | 6 +-
fs/erofs/xattr.c | 6 +-
fs/erofs/zdata.c | 18 +-
fs/erofs/zmap.c | 8 +-
fs/ext2/inode.c | 3 +-
fs/ext2/xattr.c | 4 +-
fs/ext4/ext4.h | 3 +-
fs/ext4/inode.c | 35 +-
fs/ext4/xattr.c | 2 +-
fs/f2fs/checkpoint.c | 15 +-
fs/f2fs/data.c | 27 +-
fs/f2fs/f2fs.h | 3 +-
fs/f2fs/gc.c | 5 +-
fs/f2fs/node.c | 50 +-
fs/f2fs/super.c | 65 +-
fs/fcntl.c | 3 +
fs/gfs2/ops_fstype.c | 2 +-
fs/gfs2/super.c | 4 +-
fs/iomap/buffered-io.c | 8 +-
fs/lockd/svc.c | 4 +-
fs/lockd/svc4proc.c | 4 +-
fs/lockd/svcproc.c | 4 +-
fs/lockd/svcsubs.c | 45 +-
fs/namespace.c | 40 +-
fs/netfs/Makefile | 1 +
fs/netfs/buffered_read.c | 129 +--
fs/netfs/direct_read.c | 16 +-
fs/netfs/direct_write.c | 10 +-
fs/netfs/internal.h | 11 +-
fs/netfs/main.c | 7 +
fs/netfs/misc.c | 110 +-
fs/netfs/objects.c | 35 +-
fs/netfs/read_collect.c | 61 +-
fs/netfs/read_pgpriv2.c | 32 +-
fs/netfs/read_retry.c | 4 +-
fs/netfs/rolling_buffer.c | 230 ++++
fs/netfs/write_collect.c | 25 +-
fs/netfs/write_issue.c | 32 +-
fs/nfs/callback_xdr.c | 6 +-
fs/nfs/delegation.c | 18 +-
fs/nfs/flexfilelayout/flexfilelayout.c | 3 +-
fs/nfs/fscache.c | 2 +-
fs/nfs/fscache.h | 2 +-
fs/nfs/localio.c | 15 +
fs/nfs/nfs4session.c | 16 +-
fs/nfsd/filecache.c | 75 +-
fs/nfsd/lockd.c | 6 +-
fs/nfsd/netns.h | 22 +-
fs/nfsd/nfs4proc.c | 2 +-
fs/nfsd/nfs4recover.c | 12 +-
fs/nfsd/nfs4state.c | 41 +-
fs/nfsd/nfsctl.c | 4 +-
fs/nfsd/nfssvc.c | 45 +-
fs/ntfs3/bitmap.c | 62 +-
fs/ntfs3/frecord.c | 1 -
fs/ntfs3/fsntfs.c | 2 +-
fs/ntfs3/run.c | 19 +-
fs/ocfs2/cluster/heartbeat.c | 139 ++-
fs/ocfs2/cluster/tcp.c | 105 +-
fs/ocfs2/cluster/tcp.h | 1 +
fs/ocfs2/inode.c | 133 +++
fs/ocfs2/xattr.c | 215 ++++
fs/ocfs2/xattr.h | 2 +
fs/overlayfs/file.c | 17 +-
fs/smb/client/cifsacl.c | 28 +-
fs/smb/client/cifsfs.c | 1 +
fs/smb/client/cifsglob.h | 5 +-
fs/smb/client/connect.c | 5 +
fs/smb/client/file.c | 72 +-
fs/smb/client/inode.c | 22 +-
fs/smb/client/misc.c | 72 +-
fs/smb/client/readdir.c | 17 +-
fs/smb/client/smb2ops.c | 46 +-
fs/smb/client/smb2pdu.c | 9 -
fs/smb/client/smbdirect.c | 20 +-
fs/smb/client/transport.c | 40 +-
fs/smb/server/auth.c | 14 +-
fs/smb/server/connection.c | 37 +-
fs/smb/server/connection.h | 7 +-
fs/smb/server/mgmt/tree_connect.c | 26 +-
fs/smb/server/mgmt/user_config.c | 11 +
fs/smb/server/mgmt/user_session.c | 8 +-
fs/smb/server/oplock.c | 81 +-
fs/smb/server/oplock.h | 1 +
fs/smb/server/smb2pdu.c | 115 +-
fs/smb/server/smbacl.c | 88 +-
fs/smb/server/smbacl.h | 2 +-
fs/smb/server/transport_rdma.c | 4 +-
fs/smb/server/vfs.c | 2 +
fs/smb/server/vfs_cache.c | 8 +-
fs/sysfs/group.c | 26 +-
fs/tracefs/event_inode.c | 24 +
fs/tracefs/internal.h | 4 +-
fs/xfs/libxfs/xfs_alloc.c | 41 +-
fs/xfs/libxfs/xfs_da_btree.c | 53 +-
fs/xfs/libxfs/xfs_da_btree.h | 2 +
fs/xfs/libxfs/xfs_exchmaps.c | 103 +-
fs/xfs/libxfs/xfs_ialloc.c | 31 +-
fs/xfs/libxfs/xfs_log_format.h | 4 +-
fs/xfs/xfs_attr_inactive.c | 104 +-
fs/xfs/xfs_bmap_util.c | 15 +-
fs/xfs/xfs_buf.c | 65 +-
fs/xfs/xfs_buf.h | 1 -
fs/xfs/xfs_buf_item.c | 297 ++++--
fs/xfs/xfs_buf_item.h | 3 +-
fs/xfs/xfs_dquot.c | 4 +-
fs/xfs/xfs_exchrange.c | 51 +-
fs/xfs/xfs_icache.c | 8 +
fs/xfs/xfs_inode.c | 2 +-
fs/xfs/xfs_qm.c | 87 +-
fs/xfs/xfs_trace.h | 2 -
include/acpi/acpi_bus.h | 6 +
include/asm-generic/vmlinux.lds.h | 2 +-
include/clocksource/samsung_pwm.h | 2 +-
include/drm/gpu_scheduler.h | 36 +-
include/linux/arm_ffa.h | 24 +-
include/linux/bpf.h | 10 +-
include/linux/bpf_mprog.h | 10 +
include/linux/bpf_verifier.h | 2 +
include/linux/cfi.h | 4 +-
include/linux/cfi_types.h | 6 +-
include/linux/cgroup.h | 1 +
include/linux/device.h | 14 +
include/linux/dma/k3-udma-glue.h | 3 +-
include/linux/fb.h | 2 +
include/linux/folio_queue.h | 12 +-
include/linux/gpio.h | 4 +-
include/linux/gpio/consumer.h | 22 +-
include/linux/gpio/driver.h | 10 +
include/linux/gpu_buddy.h | 9 -
include/linux/hid.h | 4 +
include/linux/hugetlb.h | 6 +
include/linux/i3c/master.h | 3 +
include/linux/ieee80211.h | 12 +-
include/linux/if_team.h | 3 +-
include/linux/io_uring_types.h | 8 +
include/linux/iommu.h | 5 +
include/linux/irq_work.h | 9 +-
include/linux/irq_work_types.h | 14 +
include/linux/kasan.h | 6 +-
include/linux/kvm_host.h | 8 +
include/linux/lockd/bind.h | 12 +-
include/linux/mlx5/cq.h | 2 +-
include/linux/mlx5/driver.h | 3 +-
include/linux/mm_inline.h | 15 +-
include/linux/mmzone.h | 2 +
include/linux/mount.h | 3 +-
include/linux/net.h | 23 +
include/linux/netdevice.h | 13 +-
include/linux/netfilter.h | 2 +
include/linux/netfilter/x_tables.h | 1 +
include/linux/netfs.h | 22 +-
include/linux/ntb.h | 24 +
include/linux/overflow.h | 70 ++
include/linux/page-flags.h | 2 +-
include/linux/pci.h | 1 +
include/linux/pm.h | 2 +
include/linux/pm_runtime.h | 21 +-
include/linux/psi.h | 4 +-
include/linux/rcupdate.h | 14 +
include/linux/rcuwait.h | 13 +-
include/linux/refcount.h | 106 ++
include/linux/ring_buffer.h | 5 +-
include/linux/rolling_buffer.h | 61 ++
include/linux/skmsg.h | 14 -
include/linux/slab.h | 9 +
include/linux/soc/mediatek/mtk_wed.h | 1 +
include/linux/srcutiny.h | 4 +
include/linux/stddef.h | 20 +
include/linux/sunrpc/svc_rdma.h | 14 +-
include/linux/syscore_ops.h | 17 +-
include/linux/types.h | 12 +
include/linux/vdpa.h | 4 -
include/media/v4l2-mem2mem.h | 21 +
include/net/act_api.h | 2 +-
include/net/ax25.h | 1 -
include/net/bluetooth/hci_core.h | 2 +
include/net/bluetooth/rfcomm.h | 1 +
include/net/cfg80211.h | 103 +-
include/net/dropreason-core.h | 21 +
include/net/ip_vs.h | 2 +-
include/net/net_namespace.h | 2 +
include/net/netfilter/nf_conntrack_expect.h | 16 +-
include/net/netfilter/nf_tables.h | 32 +-
include/net/netns/mpls.h | 2 +
include/net/pkt_cls.h | 14 +-
include/net/sch_generic.h | 28 +-
include/net/sctp/auth.h | 3 +
include/net/tcp.h | 15 +-
include/net/xdp_sock.h | 1 +
include/net/xdp_sock_drv.h | 6 +-
include/net/xsk_buff_pool.h | 9 +-
include/scsi/scsi_host.h | 7 +-
include/trace/events/netfs.h | 173 +--
include/trace/events/rv.h | 84 +-
include/uapi/linux/netfilter/nf_conntrack_common.h | 1 +
include/ufs/ufshcd.h | 7 +-
init/Kconfig | 4 +-
io_uring/eventfd.c | 6 +-
io_uring/eventfd.h | 2 +-
io_uring/futex.c | 4 +-
io_uring/io_uring.c | 2 +-
io_uring/napi.c | 72 +-
io_uring/napi.h | 6 +-
io_uring/poll.c | 23 +-
io_uring/rw.c | 16 +-
io_uring/waitid.c | 2 +-
kernel/Makefile | 2 +-
kernel/bpf/bpf_struct_ops.c | 12 +
kernel/bpf/btf.c | 30 +-
kernel/bpf/helpers.c | 15 +-
kernel/bpf/mmap_unlock_work.h | 51 +-
kernel/bpf/queue_stack_maps.c | 8 +-
kernel/bpf/stackmap.c | 153 ++-
kernel/bpf/syscall.c | 11 +-
kernel/bpf/task_iter.c | 14 +-
kernel/bpf/trampoline.c | 7 +
kernel/bpf/verifier.c | 481 ++++++---
kernel/cgroup/cgroup.c | 47 +-
kernel/cgroup/rstat.c | 19 +-
kernel/configs/hardening.config | 4 +-
kernel/cpu_pm.c | 12 +-
kernel/irq/debugfs.c | 2 +-
kernel/irq/generic-chip.c | 14 +-
kernel/irq/pm.c | 11 +-
kernel/irq/proc.c | 72 +-
kernel/module/Kconfig | 2 +-
kernel/printk/nbcon.c | 2 +-
kernel/printk/printk.c | 13 +-
kernel/rcu/srcutiny.c | 19 +-
kernel/sched/ext.c | 40 +-
kernel/sched/psi.c | 69 +-
kernel/sched/syscalls.c | 17 +
kernel/time/namespace.c | 5 +
kernel/time/sched_clock.c | 22 +-
kernel/time/timekeeping.c | 22 +-
kernel/trace/ring_buffer.c | 139 ++-
kernel/trace/ring_buffer_benchmark.c | 6 +-
kernel/trace/trace.c | 110 +-
kernel/trace/trace_probe.c | 2 +-
lib/kunit_iov_iter.c | 4 +-
lib/longest_symbol_kunit.c | 2 +-
mm/huge_memory.c | 3 +
mm/hugetlb.c | 9 +-
mm/hugetlb_vmemmap.c | 232 ++--
mm/kasan/shadow.c | 111 +-
mm/memcontrol.c | 2 +-
mm/mm_init.c | 2 +
mm/mremap.c | 68 +-
mm/page_owner.c | 10 +-
mm/page_table_check.c | 20 +-
mm/vma.c | 39 +-
mm/vma.h | 14 +-
mm/vmalloc.c | 8 +-
mm/vmscan.c | 47 +-
net/ax25/af_ax25.c | 30 +-
net/ax25/ax25_route.c | 74 --
net/batman-adv/soft-interface.c | 2 +-
net/bluetooth/6lowpan.c | 27 +-
net/bluetooth/hci_conn.c | 2 +
net/bluetooth/hci_core.c | 4 +
net/bluetooth/hci_event.c | 93 +-
net/bluetooth/hci_sync.c | 145 ++-
net/bluetooth/hci_sysfs.c | 17 +-
net/bluetooth/iso.c | 46 +-
net/bluetooth/l2cap_core.c | 23 +-
net/bluetooth/l2cap_sock.c | 116 +-
net/bluetooth/rfcomm/core.c | 134 ++-
net/bridge/br_arp_nd_proxy.c | 24 +-
net/bridge/br_device.c | 2 +-
net/bridge/netfilter/ebtable_broute.c | 2 +-
net/bridge/netfilter/ebtable_filter.c | 2 +-
net/bridge/netfilter/ebtable_nat.c | 2 +-
net/bridge/netfilter/ebtables.c | 71 +-
net/ceph/auth_x.c | 5 +
net/core/bpf_sk_storage.c | 17 +-
net/core/dev.c | 190 +++-
net/core/filter.c | 4 +-
net/core/net_namespace.c | 175 +--
net/core/rtnetlink.c | 2 +-
net/core/sock.c | 3 +
net/ethtool/module.c | 3 +-
net/ethtool/rss.c | 4 +-
net/handshake/handshake-test.c | 8 +
net/handshake/netlink.c | 6 +-
net/handshake/request.c | 18 +
net/hsr/hsr_device.c | 2 +-
net/ieee802154/6lowpan/core.c | 2 +-
net/ieee802154/core.c | 14 +-
net/ife/ife.c | 14 +-
net/ipv4/igmp.c | 14 +-
net/ipv4/ip_tunnel.c | 2 +-
net/ipv4/ipmr.c | 2 +-
net/ipv4/netfilter/arp_tables.c | 35 +-
net/ipv4/netfilter/ip_tables.c | 41 +-
net/ipv4/netfilter/iptable_nat.c | 4 +-
net/ipv4/tcp.c | 5 +-
net/ipv4/tcp_bpf.c | 17 +-
net/ipv4/tcp_input.c | 15 +-
net/ipv4/tcp_ipv4.c | 3 +-
net/ipv4/udp_bpf.c | 9 +
net/ipv6/ioam6.c | 33 +-
net/ipv6/ip6_gre.c | 9 +-
net/ipv6/ip6_tunnel.c | 2 +-
net/ipv6/ip6_vti.c | 2 +-
net/ipv6/ip6mr.c | 5 +-
net/ipv6/mcast.c | 20 +-
net/ipv6/netfilter/ip6_tables.c | 38 +-
net/ipv6/netfilter/ip6table_nat.c | 4 +-
net/ipv6/sit.c | 2 +-
net/ipv6/tcp_ipv6.c | 3 +-
net/mac80211/debug.h | 10 +-
net/mac80211/mlme.c | 35 +-
net/mac80211/rx.c | 50 +-
net/mac80211/sta_info.c | 79 +-
net/mac80211/util.c | 3 +
net/mpls/af_mpls.c | 232 ++--
net/mpls/internal.h | 16 +-
net/mpls/mpls_iptunnel.c | 2 +-
net/mptcp/fastopen.c | 3 +-
net/mptcp/protocol.c | 256 ++---
net/mptcp/protocol.h | 6 +-
net/netfilter/ipvs/ip_vs_core.c | 11 +-
net/netfilter/ipvs/ip_vs_xmit.c | 3 +-
net/netfilter/nf_conntrack_bpf.c | 111 +-
net/netfilter/nf_conntrack_core.c | 33 +-
net/netfilter/nf_conntrack_expect.c | 148 ++-
net/netfilter/nf_conntrack_h323_main.c | 4 +-
net/netfilter/nf_conntrack_helper.c | 10 +-
net/netfilter/nf_conntrack_netlink.c | 24 +-
net/netfilter/nf_conntrack_sip.c | 13 +-
net/netfilter/nf_flow_table_ip.c | 3 +
net/netfilter/nf_nat_core.c | 10 +-
net/netfilter/nf_tables_api.c | 317 ++++--
net/netfilter/nft_bitwise.c | 15 +-
net/netfilter/nft_byteorder.c | 13 +-
net/netfilter/nft_ct.c | 3 +-
net/netfilter/nft_dynset.c | 25 +-
net/netfilter/nft_flow_offload.c | 3 +-
net/netfilter/nft_set_pipapo.c | 11 +-
net/netfilter/x_tables.c | 77 +-
net/openvswitch/vport-internal_dev.c | 2 +-
net/phonet/socket.c | 10 +-
net/qrtr/mhi.c | 69 +-
net/rxrpc/af_rxrpc.c | 25 +-
net/rxrpc/key.c | 2 +
net/rxrpc/peer_object.c | 22 +-
net/rxrpc/proc.c | 32 +-
net/rxrpc/recvmsg.c | 12 +-
net/rxrpc/sendmsg.c | 7 +-
net/rxrpc/server_key.c | 2 +
net/sched/act_api.c | 2 +-
net/sched/act_bpf.c | 2 +-
net/sched/act_ife.c | 40 +-
net/sched/act_mpls.c | 2 +-
net/sched/act_police.c | 2 +-
net/sched/act_skbedit.c | 2 +-
net/sched/cls_api.c | 6 +-
net/sched/cls_basic.c | 6 +-
net/sched/cls_bpf.c | 6 +-
net/sched/cls_cgroup.c | 2 +-
net/sched/cls_flow.c | 2 +-
net/sched/cls_flower.c | 4 +-
net/sched/cls_fw.c | 4 +-
net/sched/cls_matchall.c | 4 +-
net/sched/cls_route.c | 4 +-
net/sched/cls_u32.c | 18 +-
net/sched/sch_cake.c | 4 +-
net/sched/sch_codel.c | 12 +-
net/sched/sch_drr.c | 2 +-
net/sched/sch_ets.c | 2 +-
net/sched/sch_fq.c | 26 +-
net/sched/sch_fq_codel.c | 16 +-
net/sched/sch_fq_pie.c | 14 +-
net/sched/sch_generic.c | 45 +-
net/sched/sch_gred.c | 2 +-
net/sched/sch_hfsc.c | 2 +-
net/sched/sch_hhf.c | 12 +-
net/sched/sch_htb.c | 2 +-
net/sched/sch_multiq.c | 2 +-
net/sched/sch_pie.c | 12 +-
net/sched/sch_prio.c | 2 +-
net/sched/sch_qfq.c | 2 +-
net/sched/sch_sfb.c | 2 +-
net/sched/sch_sfq.c | 2 +-
net/sctp/auth.c | 76 ++
net/sctp/bind_addr.c | 11 +-
net/sctp/protocol.c | 3 +-
net/sctp/sm_make_chunk.c | 20 +-
net/sctp/sm_statefuns.c | 36 +-
net/smc/af_smc.c | 90 +-
net/smc/smc_loopback.c | 45 +-
net/sunrpc/auth_gss/gss_krb5_unseal.c | 3 +
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 17 +-
net/sunrpc/xprtrdma/svc_rdma_rw.c | 100 +-
net/sunrpc/xprtrdma/svc_rdma_sendto.c | 16 +-
net/sunrpc/xprtrdma/svc_rdma_transport.c | 30 +-
net/tipc/core.c | 4 +-
net/tipc/udp_media.c | 75 +-
net/tls/tls_sw.c | 2 +
net/wireless/core.c | 20 +-
net/wireless/core.h | 2 +-
net/wireless/nl80211.c | 16 +-
net/wireless/scan.c | 15 +-
net/wireless/sme.c | 6 +-
net/xdp/xsk.c | 253 ++++-
net/xdp/xsk_buff_pool.c | 14 +-
net/xdp/xsk_queue.h | 65 +-
net/xfrm/xfrm_device.c | 8 +
security/apparmor/domain.c | 105 +-
security/apparmor/include/policy.h | 3 +
security/apparmor/policy.c | 22 +-
security/selinux/selinuxfs.c | 27 +-
sound/core/seq/oss/seq_oss_event.c | 6 +-
sound/core/seq/oss/seq_oss_event.h | 3 +-
sound/core/seq/oss/seq_oss_ioctl.c | 5 +-
sound/core/seq/oss/seq_oss_midi.c | 6 +-
sound/core/seq/oss/seq_oss_midi.h | 2 +-
sound/core/seq/oss/seq_oss_readq.c | 85 +-
sound/core/seq/oss/seq_oss_rw.c | 5 +-
sound/core/seq/seq_clientmgr.c | 3 +-
sound/core/seq/seq_fifo.c | 67 +-
sound/core/seq/seq_fifo.h | 1 +
sound/drivers/mtpav.c | 6 +-
sound/pci/ctxfi/ctatc.c | 63 +-
sound/pci/ctxfi/ctatc.h | 4 -
sound/pci/ctxfi/ctdaio.c | 91 +-
sound/pci/ctxfi/ctdaio.h | 2 +
sound/pci/ctxfi/cthardware.h | 2 +-
sound/pci/ctxfi/cthw20k1.c | 2 +-
sound/pci/ctxfi/cthw20k2.c | 2 +-
sound/soc/amd/acp/acp-mach-common.c | 18 +-
sound/soc/intel/avs/avs.h | 2 +-
sound/soc/intel/avs/path.c | 11 +-
sound/soc/intel/avs/pcm.c | 23 +-
sound/soc/intel/avs/probes.c | 2 +-
sound/soc/intel/avs/topology.c | 47 +-
sound/soc/intel/avs/topology.h | 4 +-
sound/soc/qcom/qdsp6/q6asm.c | 5 +
sound/soc/sof/ipc3-pcm.c | 13 +-
sound/soc/sof/ipc3-topology.c | 20 +-
sound/soc/sof/ipc4-pcm.c | 41 +-
sound/soc/sof/ipc4-topology.c | 18 +-
sound/soc/sof/pcm.c | 169 ++-
sound/soc/sof/sof-audio.c | 49 -
sound/soc/sof/sof-audio.h | 17 +-
sound/usb/pcm.c | 2 +-
tools/perf/util/event.c | 15 +-
tools/perf/util/include/linux/linkage.h | 2 +-
.../testing/selftests/bpf/progs/exceptions_fail.c | 9 +-
.../bpf/progs/verifier_subprog_precision.c | 12 +-
tools/testing/selftests/net/forwarding/README | 2 +-
tools/testing/selftests/net/tls.c | 515 +++++++++
tools/testing/vma/vma.c | 4 +-
virt/kvm/guest_memfd.c | 8 +-
virt/kvm/kvm_main.c | 36 +-
virt/kvm/kvm_mm.h | 7 +-
1236 files changed, 21709 insertions(+), 13348 deletions(-)
^ permalink raw reply [flat|nested] 872+ messages in thread
* [PATCH 6.12 001/869] spi: mpc52xx: clean up interrupt handling
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 002/869] usb: gadget: f_hid: Add missing error code Greg Kroah-Hartman
` (868 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Johan Hovold, Mark Brown,
Sasha Levin
6.12-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 a4991f3bc9b63..a067e73d9d4db 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] 872+ messages in thread
* [PATCH 6.12 002/869] usb: gadget: f_hid: Add missing error code
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 001/869] spi: mpc52xx: clean up interrupt handling Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 003/869] iommu/amd: Disable AMD IOMMU if CMPXCHG16B feature is not supported Greg Kroah-Hartman
` (867 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ethan Tidmore, Peter Korsgaard,
Michael Zimmermann, Sasha Levin
6.12-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 2f4a5d22aca4c..b5702ccb7b2f2 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -1272,8 +1272,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] 872+ messages in thread
* [PATCH 6.12 003/869] iommu/amd: Disable AMD IOMMU if CMPXCHG16B feature is not supported
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 001/869] spi: mpc52xx: clean up interrupt handling Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 002/869] usb: gadget: f_hid: Add missing error code Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 004/869] iommu/amd: Fix ivrs_base memleak in early_amd_iommu_init() Greg Kroah-Hartman
` (866 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jason Gunthorpe,
Suravee Suthikulpanit, Joerg Roedel, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
[ Upstream commit 82582f85ed22ba6cd27fea76b4248745f3b9fdf7 ]
According to the AMD IOMMU spec, IOMMU hardware reads the entire DTE
in a single 256-bit transaction. It is recommended to update DTE using
128-bit operation followed by an INVALIDATE_DEVTAB_ENTYRY command when
the IV=1b or V=1b before the change.
According to the AMD BIOS and Kernel Developer's Guide (BDKG) dated back
to family 10h Processor [1], which is the first introduction of AMD IOMMU,
AMD processor always has CPUID Fn0000_0001_ECX[CMPXCHG16B]=1.
Therefore, it is safe to assume cmpxchg128 is available with all AMD
processor w/ IOMMU.
In addition, the CMPXCHG16B feature has already been checked separately
before enabling the GA, XT, and GAM modes. Consolidate the detection logic,
and fail the IOMMU initialization if the feature is not supported.
[1] https://www.amd.com/content/dam/amd/en/documents/archived-tech-docs/programmer-references/31116.pdf
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Link: https://lore.kernel.org/r/20241118054937.5203-3-suravee.suthikulpanit@amd.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/iommu/amd/init.c | 23 +++++++++--------------
1 file changed, 9 insertions(+), 14 deletions(-)
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index b9a14c3ef4402..faa46571f6c68 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1787,13 +1787,8 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h,
else
iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
- /*
- * Note: GA (128-bit IRTE) mode requires cmpxchg16b supports.
- * GAM also requires GA mode. Therefore, we need to
- * check cmpxchg16b support before enabling it.
- */
- if (!boot_cpu_has(X86_FEATURE_CX16) ||
- ((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0))
+ /* GAM requires GA mode. */
+ if ((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0)
amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
break;
case 0x11:
@@ -1803,13 +1798,8 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h,
else
iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
- /*
- * Note: GA (128-bit IRTE) mode requires cmpxchg16b supports.
- * XT, GAM also requires GA mode. Therefore, we need to
- * check cmpxchg16b support before enabling them.
- */
- if (!boot_cpu_has(X86_FEATURE_CX16) ||
- ((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0)) {
+ /* XT and GAM require GA mode. */
+ if ((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0) {
amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY;
break;
}
@@ -3106,6 +3096,11 @@ static int __init early_amd_iommu_init(void)
return -EINVAL;
}
+ if (!boot_cpu_has(X86_FEATURE_CX16)) {
+ pr_err("Failed to initialize. The CMPXCHG16B feature is required.\n");
+ return -EINVAL;
+ }
+
/*
* Validate checksum here so we don't need to do it when
* we actually parse the table
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 004/869] iommu/amd: Fix ivrs_base memleak in early_amd_iommu_init()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (2 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 003/869] iommu/amd: Disable AMD IOMMU if CMPXCHG16B feature is not supported Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 005/869] ice: fix use-after-free in dynamic port cleanup Greg Kroah-Hartman
` (865 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Zhen Ni, Suravee Suthikulpanit,
Joerg Roedel, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhen Ni <zhen.ni@easystack.cn>
[ Upstream commit 923b70581cb6acede90f8aaf4afe5d1c58c67b71 ]
Fix a permanent ACPI table memory leak in early_amd_iommu_init() when
CMPXCHG16B feature is not supported
Fixes: 82582f85ed22 ("iommu/amd: Disable AMD IOMMU if CMPXCHG16B feature is not supported")
Cc: stable@vger.kernel.org
Signed-off-by: Zhen Ni <zhen.ni@easystack.cn>
Reviewed-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Link: https://lore.kernel.org/r/20250822024915.673427-1-zhen.ni@easystack.cn
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/iommu/amd/init.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index faa46571f6c68..804b731957db2 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -3098,7 +3098,8 @@ static int __init early_amd_iommu_init(void)
if (!boot_cpu_has(X86_FEATURE_CX16)) {
pr_err("Failed to initialize. The CMPXCHG16B feature is required.\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 005/869] ice: fix use-after-free in dynamic port cleanup
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (3 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 004/869] iommu/amd: Fix ivrs_base memleak in early_amd_iommu_init() Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 006/869] xfs: stop exchanging reflink flags when exchanging mappings Greg Kroah-Hartman
` (864 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Xuanqiang Luo, Marcin Szycik,
Aleksandr Loktionov, Patryk Holda, Tony Nguyen, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
[ Upstream commit 1402fc67d2f4e2e1fc7bf8ee0825b8ad994557ff ]
ice_dealloc_dynamic_port() uses dyn_port->vsi->idx to erase the dynamic
port from pf->dyn_ports. However, it frees the VSI before reading the
index for the erase, resulting in a use-after-free.
Follow the reverse of the allocation order in ice_alloc_dynamic_port()
by erasing the xarray entry before freeing the VSI.
Fixes: eda69d654c7e ("ice: add basic devlink subfunctions support")
Cc: stable@vger.kernel.org
Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
Reviewed-by: Marcin Szycik <marcin.szycik@linux.intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Patryk Holda <patryk.holda@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Link: https://patch.msgid.link/20260928230429.495442-3-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/ice/devlink/devlink_port.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink_port.c b/drivers/net/ethernet/intel/ice/devlink/devlink_port.c
index c6779d9dffffd..a5859fcc10e68 100644
--- a/drivers/net/ethernet/intel/ice/devlink/devlink_port.c
+++ b/drivers/net/ethernet/intel/ice/devlink/devlink_port.c
@@ -588,8 +588,8 @@ static void ice_dealloc_dynamic_port(struct ice_dynamic_port *dyn_port)
xa_erase(&pf->sf_nums, devlink_port->attrs.pci_sf.sf);
ice_eswitch_detach_sf(pf, dyn_port);
- ice_vsi_free(dyn_port->vsi);
xa_erase(&pf->dyn_ports, dyn_port->vsi->idx);
+ ice_vsi_free(dyn_port->vsi);
kfree(dyn_port);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 006/869] xfs: stop exchanging reflink flags when exchanging mappings
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (4 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 005/869] ice: fix use-after-free in dynamic port cleanup Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 007/869] xfs: fix exchange-range-to-eof file size exchange Greg Kroah-Hartman
` (863 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Norbert Szetei, Dave Chinner,
Darrick J. Wong, Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <norbert@doyensec.com>
[ Upstream commit d84d6c1a7f1e2de9e601703a326a4c1b7b421943 ]
When an exchange covers both files from offset 0 to i_disk_size,
xmi_can_exchange_reflink_flags() assumes every mapping moved and hands
the reflink flag over to the other file.
That assumption is wrong. A file can still own shared blocks past
i_disk_size, e.g. after EXCHANGE_RANGE_TO_EOF sets a smaller size
without unmapping anything. The flag is cleared anyway, and the next
write to such a block happens in place instead of CoW, corrupting the
other file that shares it.
Commit a23eca88448e ("xfs: fix exchange-range reflink flag clearing
issue with INO1_WRITTEN") fixed one instance of this. Rather than add
another special case, stop moving the flags.
xfs_exchmaps_ensure_reflink() already sets the flag on both inodes
before the exchange, so both just keep it.
Nothing sets CLEAR_INO{1,2}_REFLINK anymore. Intents logged by older
kernels may still carry them; recovery already masks them off, so they
stay in the log format mask and are ignored.
XFS_IOC_SWAPEXT has the same problem: it moves the reflink flag from
one inode to the other along with the extents. Just removing that is
not enough here: the exchange path flags both inodes up front in
xfs_exchmaps_ensure_reflink(), but swapext has no such step, so the
inode receiving the shared extents would be left without the flag.
Set it on both inodes instead, and make sure both have a CoW fork,
since an inode with the reflink flag is expected to have one.
The flag now stays until FALLOC_FL_UNSHARE_RANGE, xfs_scrub, or a
truncate to zero removes it.
Fixes: 966ceafc7a43 ("xfs: create deferred log items for file mapping exchanges")
Fixes: f0bc4d134b46 ("xfs: swap inode reflink flags when swapping inode extents")
Cc: stable@vger.kernel.org # v6.10
Assisted-by: LLM
Signed-off-by: Norbert Szetei <norbert@doyensec.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
The reflink-exchange eligibility helper contains a duplicate
INO1_WRITTEN guard in the code being updated. Remove both copies
with the helper, as neither is needed once reflink flag clearing
is removed.
Stable-dep-of: 7dfb218c829c ("xfs: fix exchange-range-to-eof file size exchange")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/libxfs/xfs_exchmaps.c | 90 ++--------------------------------
fs/xfs/libxfs/xfs_log_format.h | 4 +-
fs/xfs/xfs_bmap_util.c | 15 +++---
3 files changed, 10 insertions(+), 99 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_exchmaps.c b/fs/xfs/libxfs/xfs_exchmaps.c
index 68b9ddf075019..6a9a73fc5fd90 100644
--- a/fs/xfs/libxfs/xfs_exchmaps.c
+++ b/fs/xfs/libxfs/xfs_exchmaps.c
@@ -49,7 +49,7 @@ struct xfs_exchmaps_adjacent {
.right2 = { .br_startblock = HOLESTARTBLOCK }, \
}
-/* Information to reset reflink flag / CoW fork state after an exchange. */
+/* Information to reset CoW fork state after an exchange. */
/*
* If the reflink flag is set on either inode, make sure it has an incore CoW
@@ -127,9 +127,7 @@ xmi_has_more_exchange_work(const struct xfs_exchmaps_intent *xmi)
static inline bool
xmi_has_postop_work(const struct xfs_exchmaps_intent *xmi)
{
- return xmi->xmi_flags & (XFS_EXCHMAPS_CLEAR_INO1_REFLINK |
- XFS_EXCHMAPS_CLEAR_INO2_REFLINK |
- __XFS_EXCHMAPS_INO2_SHORTFORM);
+ return xmi->xmi_flags & __XFS_EXCHMAPS_INO2_SHORTFORM;
}
/* Check all mappings to make sure we can actually exchange them. */
@@ -525,18 +523,6 @@ xfs_exchmaps_link_to_sf(
return error;
}
-/* Clear the reflink flag after an exchange. */
-static inline void
-xfs_exchmaps_clear_reflink(
- struct xfs_trans *tp,
- struct xfs_inode *ip)
-{
- trace_xfs_reflink_unset_inode_flag(ip);
-
- ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK;
- xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-}
-
/* Finish whatever work might come after an exchange operation. */
static int
xfs_exchmaps_do_postop_work(
@@ -557,16 +543,6 @@ xfs_exchmaps_do_postop_work(
return error;
}
- if (xmi->xmi_flags & XFS_EXCHMAPS_CLEAR_INO1_REFLINK) {
- xfs_exchmaps_clear_reflink(tp, xmi->xmi_ip1);
- xmi->xmi_flags &= ~XFS_EXCHMAPS_CLEAR_INO1_REFLINK;
- }
-
- if (xmi->xmi_flags & XFS_EXCHMAPS_CLEAR_INO2_REFLINK) {
- xfs_exchmaps_clear_reflink(tp, xmi->xmi_ip2);
- xmi->xmi_flags &= ~XFS_EXCHMAPS_CLEAR_INO2_REFLINK;
- }
-
return 0;
}
@@ -946,56 +922,13 @@ xfs_exchmaps_intent_destroy_cache(void)
}
/*
- * Decide if we will exchange the reflink flags between the two files after the
- * exchange. The only time we want to do this is if we're exchanging all
- * mappings under EOF and the inode reflink flags have different states.
+ * Allocate and initialize a new incore intent item from a request.
*/
-static inline bool
-xmi_can_exchange_reflink_flags(
- const struct xfs_exchmaps_req *req,
- unsigned int reflink_state)
-{
- struct xfs_mount *mp = req->ip1->i_mount;
-
- /*
- * The INO1_WRITTEN optimization can skip exchanging hole and
- * unwritten mappings, which means we cannot guarantee that all
- * shared extents actually moved to the other file. Clearing the
- * reflink flag of an inode that still holds shared extents breaks
- * the CoW write path, so refuse to exchange the flags in that case.
- */
- if (req->flags & XFS_EXCHMAPS_INO1_WRITTEN)
- return false;
-
- /*
- * The INO1_WRITTEN optimization can skip exchanging hole and
- * unwritten mappings, which means we cannot guarantee that all
- * shared extents actually moved to the other file. Clearing the
- * reflink flag of an inode that still holds shared extents breaks
- * the CoW write path, so refuse to exchange the flags in that case.
- */
- if (req->flags & XFS_EXCHMAPS_INO1_WRITTEN)
- return false;
-
- if (hweight32(reflink_state) != 1)
- return false;
- if (req->startoff1 != 0 || req->startoff2 != 0)
- return false;
- if (req->blockcount != XFS_B_TO_FSB(mp, req->ip1->i_disk_size))
- return false;
- if (req->blockcount != XFS_B_TO_FSB(mp, req->ip2->i_disk_size))
- return false;
- return true;
-}
-
-
-/* Allocate and initialize a new incore intent item from a request. */
struct xfs_exchmaps_intent *
xfs_exchmaps_init_intent(
const struct xfs_exchmaps_req *req)
{
struct xfs_exchmaps_intent *xmi;
- unsigned int rs = 0;
xmi = kmem_cache_zalloc(xfs_exchmaps_intent_cache,
GFP_NOFS | __GFP_NOFAIL);
@@ -1019,23 +952,6 @@ xfs_exchmaps_init_intent(
xmi->xmi_isize2 = req->ip1->i_disk_size;
}
- /* Record the state of each inode's reflink flag before the op. */
- if (xfs_is_reflink_inode(req->ip1))
- rs |= 1;
- if (xfs_is_reflink_inode(req->ip2))
- rs |= 2;
-
- /*
- * Figure out if we're clearing the reflink flags (which effectively
- * exchanges them) after the operation.
- */
- if (xmi_can_exchange_reflink_flags(req, rs)) {
- if (rs & 1)
- xmi->xmi_flags |= XFS_EXCHMAPS_CLEAR_INO1_REFLINK;
- if (rs & 2)
- xmi->xmi_flags |= XFS_EXCHMAPS_CLEAR_INO2_REFLINK;
- }
-
if (S_ISDIR(VFS_I(xmi->xmi_ip2)->i_mode) ||
S_ISLNK(VFS_I(xmi->xmi_ip2)->i_mode))
xmi->xmi_flags |= __XFS_EXCHMAPS_INO2_SHORTFORM;
diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index a151ea6c0f721..114286c37c3df 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/libxfs/xfs_log_format.h
@@ -948,10 +948,8 @@ struct xfs_xmi_log_format {
*/
#define XFS_EXCHMAPS_INO1_WRITTEN (1ULL << 2)
-/* Clear the reflink flag from inode1 after the operation. */
+/* No longer set, but older intents may carry them; keep them valid. */
#define XFS_EXCHMAPS_CLEAR_INO1_REFLINK (1ULL << 3)
-
-/* Clear the reflink flag from inode2 after the operation. */
#define XFS_EXCHMAPS_CLEAR_INO2_REFLINK (1ULL << 4)
#define XFS_EXCHMAPS_LOGGED_FLAGS (XFS_EXCHMAPS_ATTR_FORK | \
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 95f8a09f96ae2..97ff767da5989 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -1504,7 +1504,6 @@ xfs_swap_extents(
struct xfs_bstat *sbp = &sxp->sx_stat;
int src_log_flags, target_log_flags;
int error = 0;
- uint64_t f;
int resblks = 0;
unsigned int flags = 0;
struct timespec64 ctime, mtime;
@@ -1648,14 +1647,12 @@ xfs_swap_extents(
if (error)
goto out_trans_cancel;
- /* Do we have to swap reflink flags? */
- if ((ip->i_diflags2 & XFS_DIFLAG2_REFLINK) ^
- (tip->i_diflags2 & XFS_DIFLAG2_REFLINK)) {
- f = ip->i_diflags2 & XFS_DIFLAG2_REFLINK;
- ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK;
- ip->i_diflags2 |= tip->i_diflags2 & XFS_DIFLAG2_REFLINK;
- tip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK;
- tip->i_diflags2 |= f & XFS_DIFLAG2_REFLINK;
+ /* Either inode may now own shared blocks; flag both, with CoW forks. */
+ if ((ip->i_diflags2 | tip->i_diflags2) & XFS_DIFLAG2_REFLINK) {
+ ip->i_diflags2 |= XFS_DIFLAG2_REFLINK;
+ tip->i_diflags2 |= XFS_DIFLAG2_REFLINK;
+ xfs_ifork_init_cow(ip);
+ xfs_ifork_init_cow(tip);
}
/* Swap the cow forks. */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 007/869] xfs: fix exchange-range-to-eof file size exchange
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (5 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 006/869] xfs: stop exchanging reflink flags when exchanging mappings Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 008/869] ip6_gre: remove obsolete ERSPAN PMTU update Greg Kroah-Hartman
` (862 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Norbert Szetei, Darrick J. Wong,
Dave Chinner, Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <djwong@kernel.org>
[ Upstream commit 7dfb218c829c1acb626e0fe92c5fddb9a26a03e9 ]
Norbert Szetei posted a patch containing an incomplete description of a
bug in XFS_IOC_EXCHANGE_RANGE's TO_EOF flag. The bug tricks
exchange-range into modifying a file so that it has shared blocks
starting beyond EOF, which is never allowed because files never have
written data beyond EOF, and you can only share written data blocks.
This is key to all the incorrect behavior that follows.
Eventually I got from Norbert a description of what's going wrong:
> Fair. Here it is with physical block numbers, 4k blocks. peer is the file
> that gets rewritten and file1 is the one that ends up with the flag
> cleared.
>
> Start, nothing shared:
>
> peer size 4096 -> [100]
> file1 size 12288 -> [200] [201] [202]
> donor1 size 4096 -> [300]
> donor2 size 4096 -> [400]
>
> 1. FICLONERANGE peer's block into file1's middle slot:
>
> peer size 4096 -> [100]
> file1 size 12288 -> [200] [100] [202] reflink flag set
> ^^^^^ both files own block 100
>
> 2. XFS_IOC_EXCHANGE_RANGE file1 against donor1, file1_offset 0,
> file2_offset 8192, length 0, TO_EOF. One block is exchanged, and the sizes
> are exchanged with it:
>
> file1 size 4096 -> [200] [100] [300] reflink flag set
> ^^^^^^^^^^^ still owned, now past the size
> donor1 size 12288 -> [202]
>
> file1 says it is one block long while it still owns three. Nothing was
> unmapped. file2_offset is block 2, so this exchange cannot clear a flag.
>
> 3. XFS_IOC_EXCHANGE_RANGE file1 against donor2, both offsets 0, length 4096.
> By i_disk_size this is two one-block files exchanging everything, so
> xmi_can_exchange_reflink_flags() agrees and the flag is cleared:
>
> file1 size 4096 -> [400] [100] [300] reflink flag CLEARED
> donor2 size 4096 -> [200]
>
> Block 100 is still shared with peer.
>
> 4. pwrite(file1, 4096, 4096), which is file1's second slot, block 100.
> xfs_is_cow_inode(file1) is false, so no CoW:
>
> peer size 4096 -> [100] same block, new contents
>
> Block 100 is the only one that matters here. PoC below, it reads a file
> called peer in the current directory. The filesystem needs reflink and
> exchange-range, which mkfs.xfs 7.x turns on by default.
So yes, TO_EOF is screwing up the file size even if it's actually
exchanging the data block correctly. The following is the intended
behavior of XFS_EXCHANGE_RANGE_TO_EOF, as described by its manpage:
"Ignore the length parameter. All bytes in file1_fd from file1_offset
to EOF are moved to file2_fd, and file2's size is set to
(file2_offset+(file1_length-file1_offset)). Meanwhile, all bytes in
file2 from file2_offset to EOF are moved to file1 and file1's size is
set to (file1_offset+(file2_length-file2_offset))."
In other words, if we only exchange a portion of the file data, then we
should only exchange the portion of the file size that relates to the
exchanged data. Unfortunately, the code swaps the ondisk file size and
the incore file sizes, which is incorrect if the caller passes in a
nonzero offset.
Having confused the file sizes, the PoC uses a second exchange-range
call on what looks like a non-reflinked single-block file. Because the
file size is set incorrectly, exchange-range thinks it's exchanging the
full contents of two files and clears the reflink flag on the broken
file. That enables an extending write of the broken file to rewrite the
shared block that's just past EOF. This has become known colloquially
as refluxfs.
Once the file sizes are set correctly, the second exchange-range no
longer thinks that it's doing a full-contents swap, so it won't clear
the reflink flag on either of its file arguments.
Norbert followed up to an earlier version of this patch with a second
complaint about us not handling the i_disk_size state correctly:
> The offsets are bounded against the incore i_size but subtracted from
> the ondisk i_disk_size, so a file that has not been written back gives
> xmi_isize1 = 0 + (0 - 12288).
>
> For instance, you can do:
>
> $ xfs_io -f -c "pwrite -q 0 4096" -c fsync file1
> $ xfs_io -f -c "pwrite -q 0 12288" \
> -c "exchangerange -s 0 -d 12288 file1" dirty
> $ stat -c %s file1
> 0
> $ stat -c %i file1
> 131
> $ sudo xfs_io -r -c "bulkstat_single 131" . | grep bs_size
> bs_size = 18446744073709539328
That's wrong, and the new file size update logic depends on the ondisk
i_disk_size matching the incore i_size, so flush the pagecache as needed
to push it upwards.
Link: https://lore.kernel.org/linux-xfs/1E196589-DEBE-40AC-AFEA-D420DAAB067F@doyensec.com/
Reported-by: Norbert Szetei <norbert@doyensec.com>
Cc: stable@vger.kernel.org # v6.10
Fixes: 966ceafc7a4371 ("xfs: create deferred log items for file mapping exchanges")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/libxfs/xfs_exchmaps.c | 13 +++++++--
fs/xfs/xfs_exchrange.c | 51 ++++++++++++++++++++++++++----------
2 files changed, 48 insertions(+), 16 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_exchmaps.c b/fs/xfs/libxfs/xfs_exchmaps.c
index 6a9a73fc5fd90..d900aff4fbea6 100644
--- a/fs/xfs/libxfs/xfs_exchmaps.c
+++ b/fs/xfs/libxfs/xfs_exchmaps.c
@@ -929,6 +929,7 @@ xfs_exchmaps_init_intent(
const struct xfs_exchmaps_req *req)
{
struct xfs_exchmaps_intent *xmi;
+ struct xfs_mount *mp = req->ip1->i_mount;
xmi = kmem_cache_zalloc(xfs_exchmaps_intent_cache,
GFP_NOFS | __GFP_NOFAIL);
@@ -946,10 +947,18 @@ xfs_exchmaps_init_intent(
return xmi;
}
+ /*
+ * If the caller wanted, set each file's size to that file's exchange
+ * offset + length exchanged from the other file because the ranges in
+ * each file might be different lengths.
+ */
if (req->flags & XFS_EXCHMAPS_SET_SIZES) {
+ loff_t off1 = XFS_FSB_TO_B(mp, xmi->xmi_startoff1);
+ loff_t off2 = XFS_FSB_TO_B(mp, xmi->xmi_startoff2);
+
xmi->xmi_flags |= XFS_EXCHMAPS_SET_SIZES;
- xmi->xmi_isize1 = req->ip2->i_disk_size;
- xmi->xmi_isize2 = req->ip1->i_disk_size;
+ xmi->xmi_isize1 = off1 + (req->ip2->i_disk_size - off2);
+ xmi->xmi_isize2 = off2 + (req->ip1->i_disk_size - off1);
}
if (S_ISDIR(VFS_I(xmi->xmi_ip2)->i_mode) ||
diff --git a/fs/xfs/xfs_exchrange.c b/fs/xfs/xfs_exchrange.c
index f54ed30b76e40..449090cbb1698 100644
--- a/fs/xfs/xfs_exchrange.c
+++ b/fs/xfs/xfs_exchrange.c
@@ -287,17 +287,20 @@ xfs_exchrange_mappings(
goto out_unlock;
/*
- * If the caller wanted us to exchange the contents of two complete
- * files of unequal length, exchange the incore sizes now. This should
- * be safe because we flushed both files' page caches, exchanged all
- * the mappings, and updated the ondisk sizes.
+ * If the caller wanted, set each file's size to that file's exchange
+ * offset + length exchanged from the other file because the ranges in
+ * each file might be different lengths. This should be safe because
+ * we flushed both files' page caches, exchanged all the mappings, and
+ * updated the ondisk sizes.
*/
if (fxr->flags & XFS_EXCHANGE_RANGE_TO_EOF) {
- loff_t temp;
+ loff_t old_ip1_size = i_size_read(VFS_I(ip1));
+ loff_t old_ip2_size = i_size_read(VFS_I(ip2));
- temp = i_size_read(VFS_I(ip2));
- i_size_write(VFS_I(ip2), i_size_read(VFS_I(ip1)));
- i_size_write(VFS_I(ip1), temp);
+ i_size_write(VFS_I(ip2), fxr->file2_offset +
+ (old_ip1_size - fxr->file1_offset));
+ i_size_write(VFS_I(ip1), fxr->file1_offset +
+ (old_ip2_size - fxr->file2_offset));
}
out_unlock:
@@ -442,6 +445,30 @@ xfs_exchange_range_checks(
return blen == fxr->length ? 0 : -EINVAL;
}
+/* Flush all relevant dirty pagecache near the range to be exchanged. */
+static inline int
+xfs_exchange_range_flush(
+ struct xfs_inode *ip,
+ const struct xfs_exchrange *fxr,
+ loff_t offset)
+{
+ /*
+ * If TO_EOF is set, the ondisk file size update logic depends on the
+ * ondisk file size matching the incore file size. Flush everything.
+ */
+ if (fxr->flags & XFS_EXCHANGE_RANGE_TO_EOF)
+ return filemap_write_and_wait(VFS_I(ip)->i_mapping);
+
+ /*
+ * Because we're updating the ondisk mappings, flush all dirty data
+ * between the ondisk size and the exchange offset to reduce the chance
+ * of zeroed file contents in that gap after a crash.
+ */
+ return filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
+ min(offset, ip->i_disk_size),
+ offset + fxr->length - 1);
+}
+
/*
* Check that the two inodes are eligible for range exchanges, the ranges make
* sense, and then flush all dirty data. Caller must ensure that the inodes
@@ -467,15 +494,11 @@ xfs_exchange_range_prep(
if (!same_inode)
inode_dio_wait(inode2);
- error = filemap_write_and_wait_range(inode1->i_mapping,
- fxr->file1_offset,
- fxr->file1_offset + fxr->length - 1);
+ error = xfs_exchange_range_flush(XFS_I(inode1), fxr, fxr->file1_offset);
if (error)
return error;
- error = filemap_write_and_wait_range(inode2->i_mapping,
- fxr->file2_offset,
- fxr->file2_offset + fxr->length - 1);
+ error = xfs_exchange_range_flush(XFS_I(inode2), fxr, fxr->file2_offset);
if (error)
return error;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 008/869] ip6_gre: remove obsolete ERSPAN PMTU update
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (6 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 007/869] xfs: fix exchange-range-to-eof file size exchange Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 009/869] xfs: xfs_ifree_cluster vs xfs_iflush_shutdown_abort deadlock Greg Kroah-Hartman
` (861 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ido Schimmel, Daehyeon Ko,
Jakub Kicinski, Sasha Levin
6.12-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 removal 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 ce1ba9d2af405..0cc0e1113845a 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -951,7 +951,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;
@@ -1087,12 +1086,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] 872+ messages in thread
* [PATCH 6.12 009/869] xfs: xfs_ifree_cluster vs xfs_iflush_shutdown_abort deadlock
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (7 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 008/869] ip6_gre: remove obsolete ERSPAN PMTU update Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 010/869] xfs: catch stale AGF/AGF metadata Greg Kroah-Hartman
` (860 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dave Chinner, Christoph Hellwig,
Carlos Maiolino, Carlos Maiolino, Siddh Raman Pant, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Chinner <dchinner@redhat.com>
[ Upstream commit 09234a632be42573d9743ac5ff6773622d233ad0 ]
Lock order of xfs_ifree_cluster() is cluster buffer -> try ILOCK
-> IFLUSHING, except for the last inode in the cluster that is
triggering the free. In that case, the lock order is ILOCK ->
cluster buffer -> IFLUSHING.
xfs_iflush_cluster() uses cluster buffer -> try ILOCK -> IFLUSHING,
so this can safely run concurrently with xfs_ifree_cluster().
xfs_inode_item_precommit() uses ILOCK -> cluster buffer, but this
cannot race with xfs_ifree_cluster() so being in a different order
will not trigger a deadlock.
xfs_reclaim_inode() during a filesystem shutdown uses ILOCK ->
IFLUSHING -> cluster buffer via xfs_iflush_shutdown_abort(), and
this deadlocks against xfs_ifree_cluster() like so:
sysrq: Show Blocked State
task:kworker/10:37 state:D stack:12560 pid:276182 tgid:276182 ppid:2 flags:0x00004000
Workqueue: xfs-inodegc/dm-3 xfs_inodegc_worker
Call Trace:
<TASK>
__schedule+0x650/0xb10
schedule+0x6d/0xf0
schedule_timeout+0x8b/0x180
schedule_timeout_uninterruptible+0x1e/0x30
xfs_ifree+0x326/0x730
xfs_inactive_ifree+0xcb/0x230
xfs_inactive+0x2c8/0x380
xfs_inodegc_worker+0xaa/0x180
process_scheduled_works+0x1d4/0x400
worker_thread+0x234/0x2e0
kthread+0x147/0x170
ret_from_fork+0x3e/0x50
ret_from_fork_asm+0x1a/0x30
</TASK>
task:fsync-tester state:D stack:12160 pid:2255943 tgid:2255943 ppid:3988702 flags:0x00004006
Call Trace:
<TASK>
__schedule+0x650/0xb10
schedule+0x6d/0xf0
schedule_timeout+0x31/0x180
__down_common+0xbe/0x1f0
__down+0x1d/0x30
down+0x48/0x50
xfs_buf_lock+0x3d/0xe0
xfs_iflush_shutdown_abort+0x51/0x1e0
xfs_icwalk_ag+0x386/0x690
xfs_reclaim_inodes_nr+0x114/0x160
xfs_fs_free_cached_objects+0x19/0x20
super_cache_scan+0x17b/0x1a0
do_shrink_slab+0x180/0x350
shrink_slab+0xf8/0x430
drop_slab+0x97/0xf0
drop_caches_sysctl_handler+0x59/0xc0
proc_sys_call_handler+0x189/0x280
proc_sys_write+0x13/0x20
vfs_write+0x33d/0x3f0
ksys_write+0x7c/0xf0
__x64_sys_write+0x1b/0x30
x64_sys_call+0x271d/0x2ee0
do_syscall_64+0x68/0x130
entry_SYSCALL_64_after_hwframe+0x76/0x7e
We can't change the lock order of xfs_ifree_cluster() - XFS_ISTALE
and XFS_IFLUSHING are serialised through to journal IO completion
by the cluster buffer lock being held.
There's quite a few asserts in the code that check that XFS_ISTALE
does not occur out of sync with buffer locking (e.g. in
xfs_iflush_cluster). There's also a dependency on the inode log item
being removed from the buffer before XFS_IFLUSHING is cleared, also
with asserts that trigger on this.
Further, we don't have a requirement for the inode to be locked when
completing or aborting inode flushing because all the inode state
updates are serialised by holding the cluster buffer lock across the
IO to completion.
We can't check for XFS_IRECLAIM in xfs_ifree_mark_inode_stale() and
skip the inode, because there is no guarantee that the inode will be
reclaimed. Hence it *must* be marked XFS_ISTALE regardless of
whether reclaim is preparing to free that inode. Similarly, we can't
check for IFLUSHING before locking the inode because that would
result in dirty inodes not being marked with ISTALE in the event of
racing with XFS_IRECLAIM.
Hence we have to address this issue from the xfs_reclaim_inode()
side. It is clear that we cannot hold the inode locked here when
calling xfs_iflush_shutdown_abort() because it is the inode->buffer
lock order that causes the deadlock against xfs_ifree_cluster().
Hence we need to drop the ILOCK before aborting the inode in the
shutdown case. Once we've aborted the inode, we can grab the ILOCK
again and then immediately reclaim it as it is now guaranteed to be
clean.
Note that dropping the ILOCK in xfs_reclaim_inode() means that it
can now be locked by xfs_ifree_mark_inode_stale() and seen whilst in
this state. This is safe because we have left the XFS_IFLUSHING flag
on the inode and so xfs_ifree_mark_inode_stale() will simply set
XFS_ISTALE and move to the next inode. An ASSERT check in this path
needs to be tweaked to take into account this new shutdown
interaction.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Siddh Raman Pant <siddh.raman.pant@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/xfs_icache.c | 8 ++++++++
fs/xfs/xfs_inode.c | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 08689839dd77e..e22d103f5f827 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -923,7 +923,15 @@ xfs_reclaim_inode(
*/
if (xlog_is_shutdown(ip->i_mount->m_log)) {
xfs_iunpin_wait(ip);
+ /*
+ * Avoid a ABBA deadlock on the inode cluster buffer vs
+ * concurrent xfs_ifree_cluster() trying to mark the inode
+ * stale. We don't need the inode locked to run the flush abort
+ * code, but the flush abort needs to lock the cluster buffer.
+ */
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
xfs_iflush_shutdown_abort(ip);
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
goto reclaim;
}
if (xfs_ipincount(ip))
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 266fcc7890987..3b487341348a0 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1624,7 +1624,7 @@ xfs_ifree_mark_inode_stale(
iip = ip->i_itemp;
if (__xfs_iflags_test(ip, XFS_IFLUSHING)) {
ASSERT(!list_empty(&iip->ili_item.li_bio_list));
- ASSERT(iip->ili_last_fields);
+ ASSERT(iip->ili_last_fields || xlog_is_shutdown(mp->m_log));
goto out_iunlock;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 010/869] xfs: catch stale AGF/AGF metadata
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (8 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 009/869] xfs: xfs_ifree_cluster vs xfs_iflush_shutdown_abort deadlock Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 011/869] xfs: avoid dquot buffer pin deadlock Greg Kroah-Hartman
` (859 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dave Chinner, Carlos Maiolino,
Carlos Maiolino, Siddh Raman Pant, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Chinner <dchinner@redhat.com>
[ Upstream commit db6a2274162de615ff74b927d38942fe3134d298 ]
There is a race condition that can trigger in dmflakey fstests that
can result in asserts in xfs_ialloc_read_agi() and
xfs_alloc_read_agf() firing. The asserts look like this:
XFS: Assertion failed: pag->pagf_freeblks == be32_to_cpu(agf->agf_freeblks), file: fs/xfs/libxfs/xfs_alloc.c, line: 3440
.....
Call Trace:
<TASK>
xfs_alloc_read_agf+0x2ad/0x3a0
xfs_alloc_fix_freelist+0x280/0x720
xfs_alloc_vextent_prepare_ag+0x42/0x120
xfs_alloc_vextent_iterate_ags+0x67/0x260
xfs_alloc_vextent_start_ag+0xe4/0x1c0
xfs_bmapi_allocate+0x6fe/0xc90
xfs_bmapi_convert_delalloc+0x338/0x560
xfs_map_blocks+0x354/0x580
iomap_writepages+0x52b/0xa70
xfs_vm_writepages+0xd7/0x100
do_writepages+0xe1/0x2c0
__writeback_single_inode+0x44/0x340
writeback_sb_inodes+0x2d0/0x570
__writeback_inodes_wb+0x9c/0xf0
wb_writeback+0x139/0x2d0
wb_workfn+0x23e/0x4c0
process_scheduled_works+0x1d4/0x400
worker_thread+0x234/0x2e0
kthread+0x147/0x170
ret_from_fork+0x3e/0x50
ret_from_fork_asm+0x1a/0x30
I've seen the AGI variant from scrub running on the filesysetm
after unmount failed due to systemd interference:
XFS: Assertion failed: pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) || xfs_is_shutdown(pag->pag_mount), file: fs/xfs/libxfs/xfs_ialloc.c, line: 2804
.....
Call Trace:
<TASK>
xfs_ialloc_read_agi+0xee/0x150
xchk_perag_drain_and_lock+0x7d/0x240
xchk_ag_init+0x34/0x90
xchk_inode_xref+0x7b/0x220
xchk_inode+0x14d/0x180
xfs_scrub_metadata+0x2e2/0x510
xfs_ioc_scrub_metadata+0x62/0xb0
xfs_file_ioctl+0x446/0xbf0
__se_sys_ioctl+0x6f/0xc0
__x64_sys_ioctl+0x1d/0x30
x64_sys_call+0x1879/0x2ee0
do_syscall_64+0x68/0x130
? exc_page_fault+0x62/0xc0
entry_SYSCALL_64_after_hwframe+0x76/0x7e
Essentially, it is the same problem. When _flakey_drop_and_remount()
loads the drop-writes table, it makes all writes silently fail. Writes
are reported to the fs as completed successfully, but they are not
issued to the backing store. The filesystem sees the successful
write completion and marks the metadata buffer clean and removes it
from the AIL.
If this happens at the same time as memory pressure is occuring,
the now-clean AGF and/or AGI buffers can be reclaimed from memory.
Shortly afterwards, but before _flakey_drop_and_remount() runs
unmount, background writeback is kicked and it tries to allocate
blocks for the dirty pages in memory. This then tries to access the
AGF buffer we just turfed out of memory. It's not found, so it gets
read in from disk.
This is all fine, except for the fact that the last writeback of the
AGF did not actually reach disk. The AGF on disk is stale compared
to the in-memory state held by the perag, and so they don't match
and the assert fires.
Then other operations on that inode hang because the task was killed
whilst holding inode locks. e.g:
Workqueue: xfs-conv/dm-12 xfs_end_io
Call Trace:
<TASK>
__schedule+0x650/0xb10
schedule+0x6d/0xf0
schedule_preempt_disabled+0x15/0x30
rwsem_down_write_slowpath+0x31a/0x5f0
down_write+0x43/0x60
xfs_ilock+0x1a8/0x210
xfs_trans_alloc_inode+0x9c/0x240
xfs_iomap_write_unwritten+0xe3/0x300
xfs_end_ioend+0x90/0x130
xfs_end_io+0xce/0x100
process_scheduled_works+0x1d4/0x400
worker_thread+0x234/0x2e0
kthread+0x147/0x170
ret_from_fork+0x3e/0x50
ret_from_fork_asm+0x1a/0x30
</TASK>
and it's all down hill from there.
Memory pressure is one way to trigger this, another is to run "echo
3 > /proc/sys/vm/drop_caches" randomly while tests are running.
Regardless of how it is triggered, this effectively takes down the
system once umount hangs because it's holding a sb->s_umount lock
exclusive and now every sync(1) call gets stuck on it.
Fix this by replacing the asserts with a corruption detection check
and a shutdown.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
6.12:
Fixed conflict due to the following missing commit:
e9c4d8bfb26c ("xfs: factor out a generic xfs_group structure")
Signed-off-by: Siddh Raman Pant <siddh.raman.pant@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/libxfs/xfs_alloc.c | 41 ++++++++++++++++++++++++++++++--------
fs/xfs/libxfs/xfs_ialloc.c | 31 ++++++++++++++++++++++++----
2 files changed, 60 insertions(+), 12 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 3633f4d28c3b7..c9a211b7564ba 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -3435,16 +3435,41 @@ xfs_alloc_read_agf(
set_bit(XFS_AGSTATE_AGF_INIT, &pag->pag_opstate);
}
+
#ifdef DEBUG
- else if (!xfs_is_shutdown(pag->pag_mount)) {
- ASSERT(pag->pagf_freeblks == be32_to_cpu(agf->agf_freeblks));
- ASSERT(pag->pagf_btreeblks == be32_to_cpu(agf->agf_btreeblks));
- ASSERT(pag->pagf_flcount == be32_to_cpu(agf->agf_flcount));
- ASSERT(pag->pagf_longest == be32_to_cpu(agf->agf_longest));
- ASSERT(pag->pagf_bno_level == be32_to_cpu(agf->agf_bno_level));
- ASSERT(pag->pagf_cnt_level == be32_to_cpu(agf->agf_cnt_level));
+ /*
+ * It's possible for the AGF to be out of sync if the block device is
+ * silently dropping writes. This can happen in fstests with dmflakey
+ * enabled, which allows the buffer to be cleaned and reclaimed by
+ * memory pressure and then re-read from disk here. We will get a
+ * stale version of the AGF from disk, and nothing good can happen from
+ * here. Hence if we detect this situation, immediately shut down the
+ * filesystem.
+ *
+ * This can also happen if we are already in the middle of a forced
+ * shutdown, so don't bother checking if we are already shut down.
+ */
+ if (!xfs_is_shutdown(pag->pag_mount)) {
+ bool ok = true;
+
+ ok &= pag->pagf_freeblks == be32_to_cpu(agf->agf_freeblks);
+ ok &= pag->pagf_freeblks == be32_to_cpu(agf->agf_freeblks);
+ ok &= pag->pagf_btreeblks == be32_to_cpu(agf->agf_btreeblks);
+ ok &= pag->pagf_flcount == be32_to_cpu(agf->agf_flcount);
+ ok &= pag->pagf_longest == be32_to_cpu(agf->agf_longest);
+ ok &= pag->pagf_bno_level == be32_to_cpu(agf->agf_bno_level);
+ ok &= pag->pagf_cnt_level == be32_to_cpu(agf->agf_cnt_level);
+
+ if (XFS_IS_CORRUPT(pag->pag_mount, !ok)) {
+ xfs_ag_mark_sick(pag, XFS_SICK_AG_AGF);
+ xfs_trans_brelse(tp, agfbp);
+ xfs_force_shutdown(pag->pag_mount,
+ SHUTDOWN_CORRUPT_ONDISK);
+ return -EFSCORRUPTED;
+ }
}
-#endif
+#endif /* DEBUG */
+
if (agfbpp)
*agfbpp = agfbp;
else
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 0fdb2a30e50d1..482540a7e8e8b 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -2785,12 +2785,35 @@ xfs_ialloc_read_agi(
set_bit(XFS_AGSTATE_AGI_INIT, &pag->pag_opstate);
}
+#ifdef DEBUG
/*
- * It's possible for these to be out of sync if
- * we are in the middle of a forced shutdown.
+ * It's possible for the AGF to be out of sync if the block device is
+ * silently dropping writes. This can happen in fstests with dmflakey
+ * enabled, which allows the buffer to be cleaned and reclaimed by
+ * memory pressure and then re-read from disk here. We will get a
+ * stale version of the AGF from disk, and nothing good can happen from
+ * here. Hence if we detect this situation, immediately shut down the
+ * filesystem.
+ *
+ * This can also happen if we are already in the middle of a forced
+ * shutdown, so don't bother checking if we are already shut down.
*/
- ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) ||
- xfs_is_shutdown(pag->pag_mount));
+ if (!xfs_is_shutdown(pag->pag_mount)) {
+ bool ok = true;
+
+ ok &= pag->pagi_freecount == be32_to_cpu(agi->agi_freecount);
+ ok &= pag->pagi_count == be32_to_cpu(agi->agi_count);
+
+ if (XFS_IS_CORRUPT(pag->pag_mount, !ok)) {
+ xfs_ag_mark_sick(pag, XFS_SICK_AG_AGI);
+ xfs_trans_brelse(tp, agibp);
+ xfs_force_shutdown(pag->pag_mount,
+ SHUTDOWN_CORRUPT_ONDISK);
+ return -EFSCORRUPTED;
+ }
+ }
+#endif /* DEBUG */
+
if (agibpp)
*agibpp = agibp;
else
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 011/869] xfs: avoid dquot buffer pin deadlock
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (9 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 010/869] xfs: catch stale AGF/AGF metadata Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 012/869] xfs: rearrange code in xfs_buf_item.c Greg Kroah-Hartman
` (858 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dave Chinner, Carlos Maiolino,
Carlos Maiolino, Siddh Raman Pant, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Chinner <dchinner@redhat.com>
[ Upstream commit d62016b1a2df24c8608fe83cd3ae8090412881b3 ]
On shutdown when quotas are enabled, the shutdown can deadlock
trying to unpin the dquot buffer buf_log_item like so:
[ 3319.483590] task:kworker/20:0H state:D stack:14360 pid:1962230 tgid:1962230 ppid:2 task_flags:0x4208060 flags:0x00004000
[ 3319.493966] Workqueue: xfs-log/dm-6 xlog_ioend_work
[ 3319.498458] Call Trace:
[ 3319.500800] <TASK>
[ 3319.502809] __schedule+0x699/0xb70
[ 3319.512672] schedule+0x64/0xd0
[ 3319.515573] schedule_timeout+0x30/0xf0
[ 3319.528125] __down_common+0xc3/0x200
[ 3319.531488] __down+0x1d/0x30
[ 3319.534186] down+0x48/0x50
[ 3319.540501] xfs_buf_lock+0x3d/0xe0
[ 3319.543609] xfs_buf_item_unpin+0x85/0x1b0
[ 3319.547248] xlog_cil_committed+0x289/0x570
[ 3319.571411] xlog_cil_process_committed+0x6d/0x90
[ 3319.575590] xlog_state_shutdown_callbacks+0x52/0x110
[ 3319.580017] xlog_force_shutdown+0x169/0x1a0
[ 3319.583780] xlog_ioend_work+0x7c/0xb0
[ 3319.587049] process_scheduled_works+0x1d6/0x400
[ 3319.591127] worker_thread+0x202/0x2e0
[ 3319.594452] kthread+0x20c/0x240
The CIL push has seen the deadlock, so it has aborted the push and
is running CIL checkpoint completion to abort all the items in the
checkpoint. This calls ->iop_unpin(remove = true) to clean up the
log items in the checkpoint.
When a buffer log item is unpined like this, it needs to lock the
buffer to run io completion to correctly fail the buffer and run all
the required completions to fail attached log items as well. In this
case, the attempt to lock the buffer on unpin is hanging because the
buffer is already locked.
I suspected a leaked XFS_BLI_HOLD state because of XFS_BLI_STALE
handling changes I was testing, so I went looking for
pin events on HOLD buffers and unpin events on locked buffer. That
isolated this one buffer with these two events:
xfs_buf_item_pin: dev 251:6 daddr 0xa910 bbcount 0x2 hold 2 pincount 0 lock 0 flags DONE|KMEM recur 0 refcount 1 bliflags HOLD|DIRTY|LOGGED liflags DIRTY
....
xfs_buf_item_unpin: dev 251:6 daddr 0xa910 bbcount 0x2 hold 4 pincount 1 lock 0 flags DONE|KMEM recur 0 refcount 1 bliflags DIRTY liflags ABORTED
Firstly, bbcount = 0x2, which means it is not a single sector
structure. That rules out every xfs_trans_bhold() case except one:
dquot buffers.
Then hung task dumping gave this trace:
[ 3197.312078] task:fsync-tester state:D stack:12080 pid:2051125 tgid:2051125 ppid:1643233 task_flags:0x400000 flags:0x00004002
[ 3197.323007] Call Trace:
[ 3197.325581] <TASK>
[ 3197.327727] __schedule+0x699/0xb70
[ 3197.334582] schedule+0x64/0xd0
[ 3197.337672] schedule_timeout+0x30/0xf0
[ 3197.350139] wait_for_completion+0xbd/0x180
[ 3197.354235] __flush_workqueue+0xef/0x4e0
[ 3197.362229] xlog_cil_force_seq+0xa0/0x300
[ 3197.374447] xfs_log_force+0x77/0x230
[ 3197.378015] xfs_qm_dqunpin_wait+0x49/0xf0
[ 3197.382010] xfs_qm_dqflush+0x55/0x460
[ 3197.385663] xfs_qm_dquot_isolate+0x29e/0x4d0
[ 3197.389977] __list_lru_walk_one+0x141/0x220
[ 3197.398867] list_lru_walk_one+0x10/0x20
[ 3197.402713] xfs_qm_shrink_scan+0x6a/0x100
[ 3197.406699] do_shrink_slab+0x18a/0x350
[ 3197.410512] shrink_slab+0xf7/0x430
[ 3197.413967] drop_slab+0x97/0xf0
[ 3197.417121] drop_caches_sysctl_handler+0x59/0xc0
[ 3197.421654] proc_sys_call_handler+0x18b/0x280
[ 3197.426050] proc_sys_write+0x13/0x20
[ 3197.429750] vfs_write+0x2b8/0x3e0
[ 3197.438532] ksys_write+0x7e/0xf0
[ 3197.441742] __x64_sys_write+0x1b/0x30
[ 3197.445363] x64_sys_call+0x2c72/0x2f60
[ 3197.449044] do_syscall_64+0x6c/0x140
[ 3197.456341] entry_SYSCALL_64_after_hwframe+0x76/0x7e
Yup, another test run by check-parallel is running drop_caches
concurrently and the dquot shrinker for the hung filesystem is
running. That's trying to flush a dirty dquot from reclaim context,
and it waiting on a log force to complete. xfs_qm_dqflush is called
with the dquot buffer held locked, and so we've called
xfs_log_force() with that buffer locked.
Now the log force is waiting for a workqueue flush to complete, and
that workqueue flush is waiting of CIL checkpoint processing to
finish.
The CIL checkpoint processing is aborting all the log items it has,
and that requires locking aborted buffers to cancel them.
Now, normally this isn't a problem if we are issuing a log force
to unpin an object, because the ->iop_unpin() method wakes pin
waiters first. That results in the pin waiter finishing off whatever
it was doing, dropping the lock and then xfs_buf_item_unpin() can
lock the buffer and fail it.
However, xfs_qm_dqflush() is waiting on the -dquot- unpin event, not
the dquot buffer unpin event, and so it never gets woken and so does
not drop the buffer lock.
Inodes do not have this problem, as they can only be written from
one spot (->iop_push) whilst dquots can be written from multiple
places (memory reclaim, ->iop_push, xfs_dq_dqpurge, and quotacheck).
The reason that the dquot buffer has an attached buffer log item is
that it has been recently allocated. Initialisation of the dquot
buffer logs the buffer directly, thereby pinning it in memory. We
then modify the dquot in a separate operation, and have memory
reclaim racing with a shutdown and we trigger this deadlock.
check-parallel reproduces this reliably on 1kB FSB filesystems with
quota enabled because it does all of these things concurrently
without having to explicitly write tests to exercise these corner
case conditions.
xfs_qm_dquot_logitem_push() doesn't have this deadlock because it
checks if the dquot is pinned before locking the dquot buffer and
skipping it if it is pinned. This means the xfs_qm_dqunpin_wait()
log force in xfs_qm_dqflush() never triggers and we unlock the
buffer safely allowing a concurrent shutdown to fail the buffer
appropriately.
xfs_qm_dqpurge() could have this problem as it is called from
quotacheck and we might have allocated dquot buffers when recording
the quota updates. This can be fixed by calling
xfs_qm_dqunpin_wait() before we lock the dquot buffer. Because we
hold the dquot locked, nothing will be able to add to the pin count
between the unpin_wait and the dqflush callout, so this now makes
xfs_qm_dqpurge() safe against this race.
xfs_qm_dquot_isolate() can also be fixed this same way but, quite
frankly, we shouldn't be doing IO in memory reclaim context. If the
dquot is pinned or dirty, simply rotate it and let memory reclaim
come back to it later, same as we do for inodes.
This then gets rid of the nasty issue in xfs_qm_flush_one() where
quotacheck writeback races with memory reclaim flushing the dquots.
We can lift xfs_qm_dqunpin_wait() up into this code, then get rid of
the "can't get the dqflush lock" buffer write to cycle the dqlfush
lock and enable it to be flushed again. checking if the dquot is
pinned and returning -EAGAIN so that the dquot walk will revisit the
dquot again later.
Finally, with xfs_qm_dqunpin_wait() lifted into all the callers,
we can remove it from the xfs_qm_dqflush() code.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
6.12:
Fix conflicts due to following missing commits:
fs/xfs/xfs_buf.c:
eb43b0b5cab8 ("xfs: simplify xfs_buf_delwri_pushbuf")
fs/xfs/xfs_qm.c:
da0c02516c50 ("mm/list_lru: simplify the list_lru walk callback function")
fb56fdf8b9a2 ("mm/list_lru: split the lock to per-cgroup scope")
We delete the code so we don't really need to add them.
Signed-off-by: Siddh Raman Pant <siddh.raman.pant@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/xfs_buf.c | 55 -----------------------------
fs/xfs/xfs_buf.h | 1 -
fs/xfs/xfs_dquot.c | 4 +--
fs/xfs/xfs_qm.c | 87 ++++++++++------------------------------------
fs/xfs/xfs_trace.h | 1 -
5 files changed, 20 insertions(+), 128 deletions(-)
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 1f6b2888bd418..52e3535411b27 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -2389,61 +2389,6 @@ xfs_buf_delwri_submit(
return error;
}
-/*
- * Push a single buffer on a delwri queue.
- *
- * The purpose of this function is to submit a single buffer of a delwri queue
- * and return with the buffer still on the original queue. The waiting delwri
- * buffer submission infrastructure guarantees transfer of the delwri queue
- * buffer reference to a temporary wait list. We reuse this infrastructure to
- * transfer the buffer back to the original queue.
- *
- * Note the buffer transitions from the queued state, to the submitted and wait
- * listed state and back to the queued state during this call. The buffer
- * locking and queue management logic between _delwri_pushbuf() and
- * _delwri_queue() guarantee that the buffer cannot be queued to another list
- * before returning.
- */
-int
-xfs_buf_delwri_pushbuf(
- struct xfs_buf *bp,
- struct list_head *buffer_list)
-{
- LIST_HEAD (submit_list);
- int error;
-
- ASSERT(bp->b_flags & _XBF_DELWRI_Q);
-
- trace_xfs_buf_delwri_pushbuf(bp, _RET_IP_);
-
- /*
- * Isolate the buffer to a new local list so we can submit it for I/O
- * independently from the rest of the original list.
- */
- xfs_buf_lock(bp);
- list_move(&bp->b_list, &submit_list);
- xfs_buf_unlock(bp);
-
- /*
- * Delwri submission clears the DELWRI_Q buffer flag and returns with
- * the buffer on the wait list with the original reference. Rather than
- * bounce the buffer from a local wait list back to the original list
- * after I/O completion, reuse the original list as the wait list.
- */
- xfs_buf_delwri_submit_buffers(&submit_list, buffer_list);
-
- /*
- * The buffer is now locked, under I/O and wait listed on the original
- * delwri queue. Wait for I/O completion, restore the DELWRI_Q flag and
- * return with the buffer unlocked and on the original queue.
- */
- error = xfs_buf_iowait(bp);
- bp->b_flags |= _XBF_DELWRI_Q;
- xfs_buf_unlock(bp);
-
- return error;
-}
-
void xfs_buf_set_ref(struct xfs_buf *bp, int lru_ref)
{
/*
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
index 209a389f2abca..3fd9bc72f8b65 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -334,7 +334,6 @@ extern bool xfs_buf_delwri_queue(struct xfs_buf *, struct list_head *);
void xfs_buf_delwri_queue_here(struct xfs_buf *bp, struct list_head *bl);
extern int xfs_buf_delwri_submit(struct list_head *);
extern int xfs_buf_delwri_submit_nowait(struct list_head *);
-extern int xfs_buf_delwri_pushbuf(struct xfs_buf *, struct list_head *);
static inline xfs_daddr_t xfs_buf_daddr(struct xfs_buf *bp)
{
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 511e7b0d58714..1dd4dde91736b 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -1405,11 +1405,9 @@ xfs_qm_dqflush(
ASSERT(XFS_DQ_IS_LOCKED(dqp));
ASSERT(!completion_done(&dqp->q_flush));
+ ASSERT(atomic_read(&dqp->q_pincount) == 0);
trace_xfs_dqflush(dqp);
-
- xfs_qm_dqunpin_wait(dqp);
-
fa = xfs_qm_dqflush_check(dqp);
if (fa) {
xfs_alert(mp, "corrupt dquot ID 0x%x in memory at %pS",
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 36ed81eb0d6d5..43775ad8ce78c 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -132,6 +132,7 @@ xfs_qm_dqpurge(
dqp->q_flags |= XFS_DQFLAG_FREEING;
+ xfs_qm_dqunpin_wait(dqp);
xfs_dqflock(dqp);
/*
@@ -430,6 +431,7 @@ xfs_qm_dquot_isolate(
struct xfs_dquot *dqp = container_of(item,
struct xfs_dquot, q_lru);
struct xfs_qm_isolate *isol = arg;
+ enum lru_status ret = LRU_SKIP;
if (!xfs_dqlock_nowait(dqp))
goto out_miss_busy;
@@ -442,6 +444,16 @@ xfs_qm_dquot_isolate(
if (dqp->q_flags & XFS_DQFLAG_FREEING)
goto out_miss_unlock;
+ /*
+ * If the dquot is pinned or dirty, rotate it to the end of the LRU to
+ * give some time for it to be cleaned before we try to isolate it
+ * again.
+ */
+ ret = LRU_ROTATE;
+ if (XFS_DQ_IS_DIRTY(dqp) || atomic_read(&dqp->q_pincount) > 0) {
+ goto out_miss_unlock;
+ }
+
/*
* This dquot has acquired a reference in the meantime remove it from
* the freelist and try again.
@@ -457,41 +469,14 @@ xfs_qm_dquot_isolate(
}
/*
- * If the dquot is dirty, flush it. If it's already being flushed, just
- * skip it so there is time for the IO to complete before we try to
- * reclaim it again on the next LRU pass.
+ * The dquot may still be under IO, in which case the flush lock will be
+ * held. If we can't get the flush lock now, just skip over the dquot as
+ * if it was dirty.
*/
if (!xfs_dqflock_nowait(dqp))
goto out_miss_unlock;
- if (XFS_DQ_IS_DIRTY(dqp)) {
- struct xfs_buf *bp = NULL;
- int error;
-
- trace_xfs_dqreclaim_dirty(dqp);
-
- /* we have to drop the LRU lock to flush the dquot */
- spin_unlock(lru_lock);
-
- error = xfs_dquot_use_attached_buf(dqp, &bp);
- if (!bp || error == -EAGAIN) {
- xfs_dqfunlock(dqp);
- goto out_unlock_dirty;
- }
-
- /*
- * dqflush completes dqflock on error, and the delwri ioend
- * does it on success.
- */
- error = xfs_qm_dqflush(dqp, bp);
- if (error)
- goto out_unlock_dirty;
-
- xfs_buf_delwri_queue(bp, &isol->buffers);
- xfs_buf_relse(bp);
- goto out_unlock_dirty;
- }
-
+ ASSERT(!XFS_DQ_IS_DIRTY(dqp));
xfs_dquot_detach_buf(dqp);
xfs_dqfunlock(dqp);
@@ -513,14 +498,7 @@ xfs_qm_dquot_isolate(
out_miss_busy:
trace_xfs_dqreclaim_busy(dqp);
XFS_STATS_INC(dqp->q_mount, xs_qm_dqreclaim_misses);
- return LRU_SKIP;
-
-out_unlock_dirty:
- trace_xfs_dqreclaim_busy(dqp);
- XFS_STATS_INC(dqp->q_mount, xs_qm_dqreclaim_misses);
- xfs_dqunlock(dqp);
- spin_lock(lru_lock);
- return LRU_RETRY;
+ return ret;
}
static unsigned long
@@ -1275,7 +1253,6 @@ xfs_qm_flush_one(
struct xfs_dquot *dqp,
void *data)
{
- struct xfs_mount *mp = dqp->q_mount;
struct list_head *buffer_list = data;
struct xfs_buf *bp = NULL;
int error = 0;
@@ -1286,34 +1263,8 @@ xfs_qm_flush_one(
if (!XFS_DQ_IS_DIRTY(dqp))
goto out_unlock;
- /*
- * The only way the dquot is already flush locked by the time quotacheck
- * gets here is if reclaim flushed it before the dqadjust walk dirtied
- * it for the final time. Quotacheck collects all dquot bufs in the
- * local delwri queue before dquots are dirtied, so reclaim can't have
- * possibly queued it for I/O. The only way out is to push the buffer to
- * cycle the flush lock.
- */
- if (!xfs_dqflock_nowait(dqp)) {
- /* buf is pinned in-core by delwri list */
- error = xfs_buf_incore(mp->m_ddev_targp, dqp->q_blkno,
- mp->m_quotainfo->qi_dqchunklen, 0, &bp);
- if (error)
- goto out_unlock;
-
- if (!(bp->b_flags & _XBF_DELWRI_Q)) {
- error = -EAGAIN;
- xfs_buf_relse(bp);
- goto out_unlock;
- }
- xfs_buf_unlock(bp);
-
- xfs_buf_delwri_pushbuf(bp, buffer_list);
- xfs_buf_rele(bp);
-
- error = -EAGAIN;
- goto out_unlock;
- }
+ xfs_qm_dqunpin_wait(dqp);
+ xfs_dqflock(dqp);
error = xfs_dquot_use_attached_buf(dqp, &bp);
if (error)
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index a53a57b4e365d..526920b41766b 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -493,7 +493,6 @@ DEFINE_BUF_EVENT(xfs_buf_iowait_done);
DEFINE_BUF_EVENT(xfs_buf_delwri_queue);
DEFINE_BUF_EVENT(xfs_buf_delwri_queued);
DEFINE_BUF_EVENT(xfs_buf_delwri_split);
-DEFINE_BUF_EVENT(xfs_buf_delwri_pushbuf);
DEFINE_BUF_EVENT(xfs_buf_get_uncached);
DEFINE_BUF_EVENT(xfs_buf_item_relse);
DEFINE_BUF_EVENT(xfs_buf_iodone_async);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 012/869] xfs: rearrange code in xfs_buf_item.c
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (10 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 011/869] xfs: avoid dquot buffer pin deadlock Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 013/869] xfs: factor out stale buffer item completion Greg Kroah-Hartman
` (857 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dave Chinner, Carlos Maiolino,
Carlos Maiolino, Siddh Raman Pant, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Chinner <dchinner@redhat.com>
[ Upstream commit d2fe5c4c8d25999862d615f616aea7befdd62799 ]
The code to initialise, release and free items is all the way down
the bottom of the file. Upcoming fixes need to these functions
earlier in the file, so move them to the top.
There is one code change in this move - the parameter to
xfs_buf_item_relse() is changed from the xfs_buf to the
xfs_buf_log_item - the thing that the function is releasing.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Siddh Raman Pant <siddh.raman.pant@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/xfs_buf_item.c | 116 +++++++++++++++++++++---------------------
fs/xfs/xfs_buf_item.h | 1 -
2 files changed, 58 insertions(+), 59 deletions(-)
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index b746a1a0f8dd9..042282a082161 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -32,6 +32,61 @@ static inline struct xfs_buf_log_item *BUF_ITEM(struct xfs_log_item *lip)
return container_of(lip, struct xfs_buf_log_item, bli_item);
}
+static void
+xfs_buf_item_get_format(
+ struct xfs_buf_log_item *bip,
+ int count)
+{
+ ASSERT(bip->bli_formats == NULL);
+ bip->bli_format_count = count;
+
+ if (count == 1) {
+ bip->bli_formats = &bip->__bli_format;
+ return;
+ }
+
+ bip->bli_formats = kzalloc(count * sizeof(struct xfs_buf_log_format),
+ GFP_KERNEL | __GFP_NOFAIL);
+}
+
+static void
+xfs_buf_item_free_format(
+ struct xfs_buf_log_item *bip)
+{
+ if (bip->bli_formats != &bip->__bli_format) {
+ kfree(bip->bli_formats);
+ bip->bli_formats = NULL;
+ }
+}
+
+static void
+xfs_buf_item_free(
+ struct xfs_buf_log_item *bip)
+{
+ xfs_buf_item_free_format(bip);
+ kvfree(bip->bli_item.li_lv_shadow);
+ kmem_cache_free(xfs_buf_item_cache, bip);
+}
+
+/*
+ * xfs_buf_item_relse() is called when the buf log item is no longer needed.
+ */
+static void
+xfs_buf_item_relse(
+ struct xfs_buf_log_item *bip)
+{
+ struct xfs_buf *bp = bip->bli_buf;
+
+ trace_xfs_buf_item_relse(bp, _RET_IP_);
+
+ ASSERT(!test_bit(XFS_LI_IN_AIL, &bip->bli_item.li_flags));
+ ASSERT(atomic_read(&bip->bli_refcount) == 0);
+
+ bp->b_log_item = NULL;
+ xfs_buf_rele(bp);
+ xfs_buf_item_free(bip);
+}
+
/* Is this log iovec plausibly large enough to contain the buffer log format? */
bool
xfs_buf_log_check_iovec(
@@ -563,7 +618,7 @@ xfs_buf_item_unpin(
ASSERT(list_empty(&bp->b_li_list));
} else {
xfs_trans_ail_delete(lip, SHUTDOWN_LOG_IO_ERROR);
- xfs_buf_item_relse(bp);
+ xfs_buf_item_relse(bip);
ASSERT(bp->b_log_item == NULL);
}
xfs_buf_relse(bp);
@@ -673,7 +728,7 @@ xfs_buf_item_put(
*/
if (aborted)
xfs_trans_ail_delete(lip, 0);
- xfs_buf_item_relse(bip->bli_buf);
+ xfs_buf_item_relse(bip);
return true;
}
@@ -824,33 +879,6 @@ static const struct xfs_item_ops xfs_buf_item_ops = {
.iop_push = xfs_buf_item_push,
};
-STATIC void
-xfs_buf_item_get_format(
- struct xfs_buf_log_item *bip,
- int count)
-{
- ASSERT(bip->bli_formats == NULL);
- bip->bli_format_count = count;
-
- if (count == 1) {
- bip->bli_formats = &bip->__bli_format;
- return;
- }
-
- bip->bli_formats = kzalloc(count * sizeof(struct xfs_buf_log_format),
- GFP_KERNEL | __GFP_NOFAIL);
-}
-
-STATIC void
-xfs_buf_item_free_format(
- struct xfs_buf_log_item *bip)
-{
- if (bip->bli_formats != &bip->__bli_format) {
- kfree(bip->bli_formats);
- bip->bli_formats = NULL;
- }
-}
-
/*
* Allocate a new buf log item to go with the given buffer.
* Set the buffer's b_log_item field to point to the new
@@ -1072,34 +1100,6 @@ xfs_buf_item_dirty_format(
return false;
}
-STATIC void
-xfs_buf_item_free(
- struct xfs_buf_log_item *bip)
-{
- xfs_buf_item_free_format(bip);
- kvfree(bip->bli_item.li_lv_shadow);
- kmem_cache_free(xfs_buf_item_cache, bip);
-}
-
-/*
- * xfs_buf_item_relse() is called when the buf log item is no longer needed.
- */
-void
-xfs_buf_item_relse(
- struct xfs_buf *bp)
-{
- struct xfs_buf_log_item *bip = bp->b_log_item;
-
- trace_xfs_buf_item_relse(bp, _RET_IP_);
- ASSERT(!test_bit(XFS_LI_IN_AIL, &bip->bli_item.li_flags));
-
- if (atomic_read(&bip->bli_refcount))
- return;
- bp->b_log_item = NULL;
- xfs_buf_rele(bp);
- xfs_buf_item_free(bip);
-}
-
void
xfs_buf_item_done(
struct xfs_buf *bp)
@@ -1119,5 +1119,5 @@ xfs_buf_item_done(
xfs_trans_ail_delete(&bp->b_log_item->bli_item,
(bp->b_flags & _XBF_LOGRECOVERY) ? 0 :
SHUTDOWN_CORRUPT_INCORE);
- xfs_buf_item_relse(bp);
+ xfs_buf_item_relse(bp->b_log_item);
}
diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h
index 7ddda0aa9dac2..8a8a46e698be4 100644
--- a/fs/xfs/xfs_buf_item.h
+++ b/fs/xfs/xfs_buf_item.h
@@ -49,7 +49,6 @@ struct xfs_buf_log_item {
int xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *);
void xfs_buf_item_done(struct xfs_buf *bp);
-void xfs_buf_item_relse(struct xfs_buf *);
bool xfs_buf_item_put(struct xfs_buf_log_item *);
void xfs_buf_item_log(struct xfs_buf_log_item *, uint, uint);
bool xfs_buf_item_dirty_format(struct xfs_buf_log_item *);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 013/869] xfs: factor out stale buffer item completion
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (11 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 012/869] xfs: rearrange code in xfs_buf_item.c Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 014/869] xfs: fix unmount hang with unflushable inodes stuck in the AIL Greg Kroah-Hartman
` (856 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dave Chinner, Carlos Maiolino,
Carlos Maiolino, Siddh Raman Pant, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Chinner <dchinner@redhat.com>
[ Upstream commit 816c330b605c3f4813c0dc0ab5af5cce17ff06b3 ]
The stale buffer item completion handling is currently only done
from BLI unpinning. We need to perform this function from where-ever
the last reference to the BLI is dropped, so first we need to
factor this code out into a helper.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Siddh Raman Pant <siddh.raman.pant@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/xfs_buf_item.c | 60 ++++++++++++++++++++++++++-----------------
1 file changed, 37 insertions(+), 23 deletions(-)
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 042282a082161..9e6a68367ca9c 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -539,6 +539,42 @@ xfs_buf_item_pin(
atomic_inc(&bip->bli_buf->b_pin_count);
}
+/*
+ * For a stale BLI, process all the necessary completions that must be
+ * performed when the final BLI reference goes away. The buffer will be
+ * referenced and locked here - we return to the caller with the buffer still
+ * referenced and locked for them to finalise processing of the buffer.
+ */
+static void
+xfs_buf_item_finish_stale(
+ struct xfs_buf_log_item *bip)
+{
+ struct xfs_buf *bp = bip->bli_buf;
+ struct xfs_log_item *lip = &bip->bli_item;
+
+ ASSERT(bip->bli_flags & XFS_BLI_STALE);
+ ASSERT(xfs_buf_islocked(bp));
+ ASSERT(bp->b_flags & XBF_STALE);
+ ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL);
+ ASSERT(list_empty(&lip->li_trans));
+ ASSERT(!bp->b_transp);
+
+ if (bip->bli_flags & XFS_BLI_STALE_INODE) {
+ xfs_buf_item_done(bp);
+ xfs_buf_inode_iodone(bp);
+ ASSERT(list_empty(&bp->b_li_list));
+ return;
+ }
+
+ /*
+ * We may or may not be on the AIL here, xfs_trans_ail_delete() will do
+ * the right thing regardless of the situation in which we are called.
+ */
+ xfs_trans_ail_delete(lip, SHUTDOWN_LOG_IO_ERROR);
+ xfs_buf_item_relse(bip);
+ ASSERT(bp->b_log_item == NULL);
+}
+
/*
* This is called to unpin the buffer associated with the buf log item which was
* previously pinned with a call to xfs_buf_item_pin(). We enter this function
@@ -588,13 +624,6 @@ xfs_buf_item_unpin(
}
if (stale) {
- ASSERT(bip->bli_flags & XFS_BLI_STALE);
- ASSERT(xfs_buf_islocked(bp));
- ASSERT(bp->b_flags & XBF_STALE);
- ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL);
- ASSERT(list_empty(&lip->li_trans));
- ASSERT(!bp->b_transp);
-
trace_xfs_buf_item_unpin_stale(bip);
/*
@@ -605,22 +634,7 @@ xfs_buf_item_unpin(
* processing is complete.
*/
xfs_buf_rele(bp);
-
- /*
- * If we get called here because of an IO error, we may or may
- * not have the item on the AIL. xfs_trans_ail_delete() will
- * take care of that situation. xfs_trans_ail_delete() drops
- * the AIL lock.
- */
- if (bip->bli_flags & XFS_BLI_STALE_INODE) {
- xfs_buf_item_done(bp);
- xfs_buf_inode_iodone(bp);
- ASSERT(list_empty(&bp->b_li_list));
- } else {
- xfs_trans_ail_delete(lip, SHUTDOWN_LOG_IO_ERROR);
- xfs_buf_item_relse(bip);
- ASSERT(bp->b_log_item == NULL);
- }
+ xfs_buf_item_finish_stale(bip);
xfs_buf_relse(bp);
return;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 014/869] xfs: fix unmount hang with unflushable inodes stuck in the AIL
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (12 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 013/869] xfs: factor out stale buffer item completion Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 015/869] drm/amd: Create a device link between APU display and XHCI devices Greg Kroah-Hartman
` (855 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dave Chinner, Carlos Maiolino,
Carlos Maiolino, Siddh Raman Pant, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Chinner <dchinner@redhat.com>
[ Upstream commit 7b5f775be14ac1532c049022feadcfe44769566d ]
Unmount of a shutdown filesystem can hang with stale inode cluster
buffers in the AIL like so:
[95964.140623] Call Trace:
[95964.144641] __schedule+0x699/0xb70
[95964.154003] schedule+0x64/0xd0
[95964.156851] xfs_ail_push_all_sync+0x9b/0xf0
[95964.164816] xfs_unmount_flush_inodes+0x41/0x70
[95964.168698] xfs_unmountfs+0x7f/0x170
[95964.171846] xfs_fs_put_super+0x3b/0x90
[95964.175216] generic_shutdown_super+0x77/0x160
[95964.178060] kill_block_super+0x1b/0x40
[95964.180553] xfs_kill_sb+0x12/0x30
[95964.182796] deactivate_locked_super+0x38/0x100
[95964.185735] deactivate_super+0x41/0x50
[95964.188245] cleanup_mnt+0x9f/0x160
[95964.190519] __cleanup_mnt+0x12/0x20
[95964.192899] task_work_run+0x89/0xb0
[95964.195221] resume_user_mode_work+0x4f/0x60
[95964.197931] syscall_exit_to_user_mode+0x76/0xb0
[95964.201003] do_syscall_64+0x74/0x130
$ pstree -N mnt |grep umount
|-check-parallel---nsexec---run_test.sh---753---umount
It always seems to be generic/753 that triggers this, and repeating
a quick group test run triggers it every 10-15 iterations. Hence it
generally triggers once up every 30-40 minutes of test time. just
running generic/753 by itself or concurrently with a limited group
of tests doesn't reproduce this issue at all.
Tracing on a hung system shows the AIL repeating every 50ms a log
force followed by an attempt to push pinned, aborted inodes from the
AIL (trimmed for brevity):
xfs_log_force: lsn 0x1c caller xfsaild+0x18e
xfs_log_force: lsn 0x0 caller xlog_cil_flush+0xbd
xfs_log_force: lsn 0x1c caller xfs_log_force+0x77
xfs_ail_pinned: lip 0xffff88826014afa0 lsn 1/37472 type XFS_LI_INODE flags IN_AIL|ABORTED
xfs_ail_pinned: lip 0xffff88814000a708 lsn 1/37472 type XFS_LI_INODE flags IN_AIL|ABORTED
xfs_ail_pinned: lip 0xffff88810b850c80 lsn 1/37472 type XFS_LI_INODE flags IN_AIL|ABORTED
xfs_ail_pinned: lip 0xffff88810b850af0 lsn 1/37472 type XFS_LI_INODE flags IN_AIL|ABORTED
xfs_ail_pinned: lip 0xffff888165cf0a28 lsn 1/37472 type XFS_LI_INODE flags IN_AIL|ABORTED
xfs_ail_pinned: lip 0xffff88810b850bb8 lsn 1/37472 type XFS_LI_INODE flags IN_AIL|ABORTED
....
The inode log items are marked as aborted, which means that either:
a) a transaction commit has occurred, seen an error or shutdown, and
called xfs_trans_free_items() to abort the items. This should happen
before any pinning of log items occurs.
or
b) a dirty transaction has been cancelled. This should also happen
before any pinning of log items occurs.
or
c) AIL insertion at journal IO completion is marked as aborted. In
this case, the log item is pinned by the CIL until journal IO
completes and hence needs to be unpinned. This is then done after
the ->iop_committed() callback is run, so the pin count should be
balanced correctly.
Yet none of these seemed to be occurring. Further tracing indicated
this:
d) Shutdown during CIL pushing resulting in log item completion
being called from checkpoint abort processing. Items are unpinned
and released without serialisation against each other, journal IO
completion or transaction commit completion.
In this case, we may still have a transaction commit in flight that
holds a reference to a xfs_buf_log_item (BLI) after CIL insertion.
e.g. a synchronous transaction will flush the CIL before the
transaction is torn down. The concurrent CIL push then aborts
insertion it and drops the commit/AIL reference to the BLI. This can
leave the transaction commit context with the last reference to the
BLI which is dropped here:
xfs_trans_free_items()
->iop_release
xfs_buf_item_release
xfs_buf_item_put
if (XFS_LI_ABORTED)
xfs_trans_ail_delete
xfs_buf_item_relse()
Unlike the journal completion ->iop_unpin path, this path does not
run stale buffer completion process when it drops the last
reference, hence leaving the stale inodes attached to the buffer
sitting the AIL. There are no other references to those inodes, so
there is no other mechanism to remove them from the AIL. Hence
unmount hangs.
The buffer lock context for stale buffers is passed to the last BLI
reference. This is normally the last BLI unpin on journal IO
completion. The unpin then processes the stale buffer completion and
releases the buffer lock. However, if the final unpin from journal
IO completion (or CIL push abort) does not hold the last reference
to the BLI, there -must- still be a transaction context that
references the BLI, and so that context must perform the stale
buffer completion processing before the buffer is unlocked and the
BLI torn down.
The fix for this is to rework the xfs_buf_item_relse() path to run
stale buffer completion processing if it drops the last reference to
the BLI. We still hold the buffer locked, so the buffer owner and
lock context is the same as if we passed the BLI and buffer to the
->iop_unpin() context to finish stale process on journal commit.
However, we have to be careful here. In a shutdown state, we can be
freeing dirty BLIs from xfs_buf_item_put() via xfs_trans_brelse()
and xfs_trans_bdetach(). The existing code handles this case by
considering shutdown state as "aborted", but in doing so
largely masks the failure to clean up stale BLI state from the
xfs_buf_item_relse() path. i.e regardless of the shutdown state and
whether the item is in the AIL, we must finish the stale buffer
cleanup if we are are dropping the last BLI reference from the
->iop_relse path in transaction commit context.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Siddh Raman Pant <siddh.raman.pant@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/xfs_buf_item.c | 121 +++++++++++++++++++++++++++++-------------
fs/xfs/xfs_buf_item.h | 2 +-
2 files changed, 86 insertions(+), 37 deletions(-)
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 9e6a68367ca9c..aa1108e81c22e 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -707,43 +707,42 @@ xfs_buf_item_push(
* Drop the buffer log item refcount and take appropriate action. This helper
* determines whether the bli must be freed or not, since a decrement to zero
* does not necessarily mean the bli is unused.
- *
- * Return true if the bli is freed, false otherwise.
*/
-bool
+void
xfs_buf_item_put(
struct xfs_buf_log_item *bip)
{
- struct xfs_log_item *lip = &bip->bli_item;
- bool aborted;
- bool dirty;
+
+ ASSERT(xfs_buf_islocked(bip->bli_buf));
/* drop the bli ref and return if it wasn't the last one */
if (!atomic_dec_and_test(&bip->bli_refcount))
- return false;
+ return;
- /*
- * We dropped the last ref and must free the item if clean or aborted.
- * If the bli is dirty and non-aborted, the buffer was clean in the
- * transaction but still awaiting writeback from previous changes. In
- * that case, the bli is freed on buffer writeback completion.
- */
- aborted = test_bit(XFS_LI_ABORTED, &lip->li_flags) ||
- xlog_is_shutdown(lip->li_log);
- dirty = bip->bli_flags & XFS_BLI_DIRTY;
- if (dirty && !aborted)
- return false;
+ /* If the BLI is in the AIL, then it is still dirty and in use */
+ if (test_bit(XFS_LI_IN_AIL, &bip->bli_item.li_flags)) {
+ ASSERT(bip->bli_flags & XFS_BLI_DIRTY);
+ return;
+ }
/*
- * The bli is aborted or clean. An aborted item may be in the AIL
- * regardless of dirty state. For example, consider an aborted
- * transaction that invalidated a dirty bli and cleared the dirty
- * state.
+ * In shutdown conditions, we can be asked to free a dirty BLI that
+ * isn't in the AIL. This can occur due to a checkpoint aborting a BLI
+ * instead of inserting it into the AIL at checkpoint IO completion. If
+ * there's another bli reference (e.g. a btree cursor holds a clean
+ * reference) and it is released via xfs_trans_brelse(), we can get here
+ * with that aborted, dirty BLI. In this case, it is safe to free the
+ * dirty BLI immediately, as it is not in the AIL and there are no
+ * other references to it.
+ *
+ * We should never get here with a stale BLI via that path as
+ * xfs_trans_brelse() specifically holds onto stale buffers rather than
+ * releasing them.
*/
- if (aborted)
- xfs_trans_ail_delete(lip, 0);
+ ASSERT(!(bip->bli_flags & XFS_BLI_DIRTY) ||
+ test_bit(XFS_LI_ABORTED, &bip->bli_item.li_flags));
+ ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
xfs_buf_item_relse(bip);
- return true;
}
/*
@@ -764,6 +763,15 @@ xfs_buf_item_put(
* if necessary but do not unlock the buffer. This is for support of
* xfs_trans_bhold(). Make sure the XFS_BLI_HOLD field is cleared if we don't
* free the item.
+ *
+ * If the XFS_BLI_STALE flag is set, the last reference to the BLI *must*
+ * perform a completion abort of any objects attached to the buffer for IO
+ * tracking purposes. This generally only happens in shutdown situations,
+ * normally xfs_buf_item_unpin() will drop the last BLI reference and perform
+ * completion processing. However, because transaction completion can race with
+ * checkpoint completion during a shutdown, this release context may end up
+ * being the last active reference to the BLI and so needs to perform this
+ * cleanup.
*/
STATIC void
xfs_buf_item_release(
@@ -771,18 +779,19 @@ xfs_buf_item_release(
{
struct xfs_buf_log_item *bip = BUF_ITEM(lip);
struct xfs_buf *bp = bip->bli_buf;
- bool released;
bool hold = bip->bli_flags & XFS_BLI_HOLD;
bool stale = bip->bli_flags & XFS_BLI_STALE;
-#if defined(DEBUG) || defined(XFS_WARN)
- bool ordered = bip->bli_flags & XFS_BLI_ORDERED;
- bool dirty = bip->bli_flags & XFS_BLI_DIRTY;
bool aborted = test_bit(XFS_LI_ABORTED,
&lip->li_flags);
+ bool dirty = bip->bli_flags & XFS_BLI_DIRTY;
+#if defined(DEBUG) || defined(XFS_WARN)
+ bool ordered = bip->bli_flags & XFS_BLI_ORDERED;
#endif
trace_xfs_buf_item_release(bip);
+ ASSERT(xfs_buf_islocked(bp));
+
/*
* The bli dirty state should match whether the blf has logged segments
* except for ordered buffers, where only the bli should be dirty.
@@ -798,16 +807,56 @@ xfs_buf_item_release(
bp->b_transp = NULL;
bip->bli_flags &= ~(XFS_BLI_LOGGED | XFS_BLI_HOLD | XFS_BLI_ORDERED);
+ /* If there are other references, then we have nothing to do. */
+ if (!atomic_dec_and_test(&bip->bli_refcount))
+ goto out_release;
+
+ /*
+ * Stale buffer completion frees the BLI, unlocks and releases the
+ * buffer. Neither the BLI or buffer are safe to reference after this
+ * call, so there's nothing more we need to do here.
+ *
+ * If we get here with a stale buffer and references to the BLI remain,
+ * we must not unlock the buffer as the last BLI reference owns lock
+ * context, not us.
+ */
+ if (stale) {
+ xfs_buf_item_finish_stale(bip);
+ xfs_buf_relse(bp);
+ ASSERT(!hold);
+ return;
+ }
+
+ /*
+ * Dirty or clean, aborted items are done and need to be removed from
+ * the AIL and released. This frees the BLI, but leaves the buffer
+ * locked and referenced.
+ */
+ if (aborted || xlog_is_shutdown(lip->li_log)) {
+ ASSERT(list_empty(&bip->bli_buf->b_li_list));
+ xfs_buf_item_done(bp);
+ goto out_release;
+ }
+
+ /*
+ * Clean, unreferenced BLIs can be immediately freed, leaving the buffer
+ * locked and referenced.
+ *
+ * Dirty, unreferenced BLIs *must* be in the AIL awaiting writeback.
+ */
+ if (!dirty)
+ xfs_buf_item_relse(bip);
+ else
+ ASSERT(test_bit(XFS_LI_IN_AIL, &lip->li_flags));
+
+ /* Not safe to reference the BLI from here */
+out_release:
/*
- * Unref the item and unlock the buffer unless held or stale. Stale
- * buffers remain locked until final unpin unless the bli is freed by
- * the unref call. The latter implies shutdown because buffer
- * invalidation dirties the bli and transaction.
+ * If we get here with a stale buffer, we must not unlock the
+ * buffer as the last BLI reference owns lock context, not us.
*/
- released = xfs_buf_item_put(bip);
- if (hold || (stale && !released))
+ if (stale || hold)
return;
- ASSERT(!stale || aborted);
xfs_buf_relse(bp);
}
diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h
index 8a8a46e698be4..141c3780a36b9 100644
--- a/fs/xfs/xfs_buf_item.h
+++ b/fs/xfs/xfs_buf_item.h
@@ -49,7 +49,7 @@ struct xfs_buf_log_item {
int xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *);
void xfs_buf_item_done(struct xfs_buf *bp);
-bool xfs_buf_item_put(struct xfs_buf_log_item *);
+void xfs_buf_item_put(struct xfs_buf_log_item *bip);
void xfs_buf_item_log(struct xfs_buf_log_item *, uint, uint);
bool xfs_buf_item_dirty_format(struct xfs_buf_log_item *);
void xfs_buf_inode_iodone(struct xfs_buf *);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 015/869] drm/amd: Create a device link between APU display and XHCI devices
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (13 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 014/869] xfs: fix unmount hang with unflushable inodes stuck in the AIL Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 016/869] ata: libata-scsi: do not lose CHECK CONDITION for failed ATAPI commands Greg Kroah-Hartman
` (854 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 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.12-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 bc5d3758fbf67..7fb81496aac70 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -1247,6 +1247,14 @@ static bool smu_is_workload_profile_available(struct smu_context *smu,
return smu->workload_map && smu->workload_map[profile].valid_mapping;
}
+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(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -1312,6 +1320,8 @@ static int smu_sw_init(void *handle)
if (!smu->ppt_funcs->get_fan_control_mode)
smu->adev->pm.no_fan = true;
+ smu_set_power_dep(smu, true);
+
return 0;
}
@@ -1334,6 +1344,8 @@ static int smu_sw_fini(void *handle)
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 2b8a18ce25d94..0145aff45c385 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -566,6 +566,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;
@@ -1445,6 +1448,13 @@ struct pptable_funcs {
*/
int (*set_wbrf_exclusion_ranges)(struct smu_context *smu,
struct freq_band_range *exclusion_ranges);
+ /**
+ * @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 3fdca8a5816bd..a710106d28809 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
@@ -1641,6 +1641,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,
@@ -1673,6 +1717,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] 872+ messages in thread
* [PATCH 6.12 016/869] ata: libata-scsi: do not lose CHECK CONDITION for failed ATAPI commands
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (14 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 015/869] drm/amd: Create a device link between APU display and XHCI devices Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 017/869] mm/mremap: fix locked_vm leak by splitting VMA for MREMAP_DONTUNMAP Greg Kroah-Hartman
` (853 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Niklas Cassel, Hengyu Liang,
Damien Le Moal, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hengyu Liang <hengyul@cs.unc.edu>
[ Upstream commit bc8ce2cea5f77c4bd1a5184705e300e83546c0c4 ]
Since commit 2e1d2e65e773 ("ata: libata-scsi: terminate deferred commands
on time out"), atapi_qc_complete() sets SAM_STAT_CHECK_CONDITION for a
failed command only if cmd->result is zero, so that the DID_TIME_OUT or
DID_REQUEUE host byte of a terminated command is preserved.
However, cmd->result can also be non-zero for a regular failed ATAPI
command completed through libata EH: ata_eh_analyze_tf() calls
ata_eh_decide_disposition(), that is, scsi_check_sense(), on the sense
data obtained with REQUEST SENSE, and scsi_check_sense() sets the SCSI
midlayer internal byte of the result for some sense codes, e.g.
SCSIML_STAT_TGT_FAILURE for ILLEGAL REQUEST with ASC 0x20 (INVALID
COMMAND OPERATION CODE) or 0x24 (INVALID FIELD IN CDB), or
SCSIML_STAT_MED_ERROR for MEDIUM ERROR with ASC 0x11 (UNRECOVERED READ
ERROR). For such commands, atapi_qc_complete() keeps the result as is and
the command completes with a GOOD status byte, even though it failed and
valid sense data is available.
As a result, passthrough users see these failed ATAPI commands as
successful. For example, with the emulated IDE CD-ROM drive of QEMU and
no medium loaded, a PLAY AUDIO MSF command issued with SG_IO completes
with status 0x00 (and no DRIVER_SENSE) instead of 0x02 (CHECK CONDITION)
with sense key ILLEGAL REQUEST, ASC/ASCQ 0x20/0x00, and the CDROM ioctls
CDROMPLAYTRKIND, CDROMSUBCHNL, CDROMPAUSE, CDROMRESUME, CDROMPLAYMSF and
CDROM_GET_MCN return 0 instead of -ENOMEDIUM or -EOPNOTSUPP.
Fix this by setting the status byte to SAM_STAT_CHECK_CONDITION whenever
the host byte is not set. Use set_status_byte() rather than overwriting
the whole result, so that the SCSI midlayer internal byte set by
scsi_check_sense() is preserved, as ata_scsi_qc_complete() already does
for ATA commands.
Fixes: 2e1d2e65e773 ("ata: libata-scsi: terminate deferred commands on time out")
Cc: stable@vger.kernel.org
Suggested-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Hengyu Liang <hengyul@cs.unc.edu>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Link: https://lore.kernel.org/r/20260929164135.266708-1-hengyul@cs.unc.edu
Signed-off-by: Niklas Cassel <cassel@kernel.org>
[ sashal: adapted completion handling to use ata_qc_done() with an immediate return ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ata/libata-scsi.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index d2777255129c5..d4f6d82fd9085 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3030,8 +3030,14 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL && qc->dev->sdev)
qc->dev->sdev->locked = 0;
- if (!cmd->result)
- cmd->result = SAM_STAT_CHECK_CONDITION;
+ /*
+ * Report CHECK CONDITION unless the command was terminated
+ * with a host byte set. Only set the status byte, so that the
+ * SCSI midlayer internal byte, which scsi_check_sense() may
+ * have set from the sense data, is preserved.
+ */
+ if (get_host_byte(cmd) == DID_OK)
+ set_status_byte(cmd, SAM_STAT_CHECK_CONDITION);
ata_qc_done(qc);
return;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 017/869] mm/mremap: fix locked_vm leak by splitting VMA for MREMAP_DONTUNMAP
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (15 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 016/869] ata: libata-scsi: do not lose CHECK CONDITION for failed ATAPI commands Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 018/869] mm/mremap: fix locked_vm leak from MREMAP_DONTUNMAP self-merge Greg Kroah-Hartman
` (852 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 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.12-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: Moved the VMA splitting sequence from prep_move_vma() into the existing move_vma(). ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/mremap.c | 21 +++++++++++++++++++--
mm/vma.c | 4 ++--
mm/vma.h | 5 +++++
3 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/mm/mremap.c b/mm/mremap.c
index 9685ea816fde1..2e717cf938aa6 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -702,6 +702,8 @@ static unsigned long move_vma(struct vm_area_struct *vma,
int err = 0;
bool need_rmap_locks;
struct vma_iterator vmi;
+ 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:
@@ -714,9 +716,9 @@ static unsigned long move_vma(struct vm_area_struct *vma,
to_account = new_len;
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;
@@ -734,6 +736,21 @@ static unsigned long move_vma(struct vm_area_struct *vma,
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 ((flags & MREMAP_DONTUNMAP) && (vma->vm_flags & VM_LOCKED)) {
+ vma_iter_init(&vmi, 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);
+ if (err)
+ return err;
+ }
+
if (vm_flags & VM_ACCOUNT) {
if (security_vm_enough_memory_mm(mm, to_account >> PAGE_SHIFT))
return -ENOMEM;
diff --git a/mm/vma.c b/mm/vma.c
index 3df4cf796c7ff..55321fe0f7912 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -457,8 +457,8 @@ static int __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 729fe3741e897..c953d4ade1f0d 100644
--- a/mm/vma.h
+++ b/mm/vma.h
@@ -343,6 +343,11 @@ bool vma_wants_writenotify(struct vm_area_struct *vma, pgprot_t vm_page_prot);
int mm_take_all_locks(struct mm_struct *mm);
void mm_drop_all_locks(struct mm_struct *mm);
+#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] 872+ messages in thread
* [PATCH 6.12 018/869] mm/mremap: fix locked_vm leak from MREMAP_DONTUNMAP self-merge
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (16 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 017/869] mm/mremap: fix locked_vm leak by splitting VMA for MREMAP_DONTUNMAP Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 019/869] wifi: mt76: connac: tolerate inactive BSS deactivation Greg Kroah-Hartman
` (851 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 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.12-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 2e717cf938aa6..83c37ad39d345 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -759,7 +759,7 @@ static unsigned long move_vma(struct vm_area_struct *vma,
vma_start_write(vma);
new_pgoff = vma->vm_pgoff + ((old_addr - vma->vm_start) >> PAGE_SHIFT);
new_vma = copy_vma(&vma, new_addr, new_len, new_pgoff,
- &need_rmap_locks);
+ &need_rmap_locks, flags & MREMAP_DONTUNMAP);
if (!new_vma) {
if (vm_flags & VM_ACCOUNT)
vm_unacct_memory(to_account >> PAGE_SHIFT);
@@ -820,6 +820,9 @@ static unsigned long move_vma(struct vm_area_struct *vma,
untrack_pfn_clear(vma);
if (unlikely(!err && (flags & MREMAP_DONTUNMAP))) {
+ /* 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);
@@ -827,7 +830,7 @@ static unsigned long move_vma(struct vm_area_struct *vma,
* anon_vma links of the old vma is no longer needed after its page
* table has been moved.
*/
- if (new_vma != vma && vma->vm_start == old_addr &&
+ if (vma->vm_start == old_addr &&
vma->vm_end == (old_addr + old_len)) {
const pgoff_t pgoff_unfaulted = vma->vm_start >> PAGE_SHIFT;
diff --git a/mm/vma.c b/mm/vma.c
index 55321fe0f7912..b58588cac3aab 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -1641,7 +1641,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;
@@ -1667,6 +1667,21 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
vmg.vma = NULL; /* New VMA range. */
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_new_range(&vmg);
if (new_vma) {
diff --git a/mm/vma.h b/mm/vma.h
index c953d4ade1f0d..7c2932ec62356 100644
--- a/mm/vma.h
+++ b/mm/vma.h
@@ -333,7 +333,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 9074aaced9c5a..46edffe9c55ac 100644
--- a/tools/testing/vma/vma.c
+++ b/tools/testing/vma/vma.c
@@ -1501,7 +1501,7 @@ static bool test_copy_vma(void)
/* Move backwards and do not merge. */
vma = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, 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);
@@ -1514,7 +1514,7 @@ static bool test_copy_vma(void)
vma = alloc_and_link_vma(&mm, 0, 0x2000, 0, flags);
vma_next = alloc_and_link_vma(&mm, 0x6000, 0x8000, 6, flags);
- vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks);
+ vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks, false);
ASSERT_EQ(vma_new, vma_next);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 019/869] wifi: mt76: connac: tolerate inactive BSS deactivation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (17 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 018/869] mm/mremap: fix locked_vm leak from MREMAP_DONTUNMAP self-merge Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 020/869] net: team: Remove unused team_mode_op, port_enabled Greg Kroah-Hartman
` (850 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Sean Wang, Felix Fietkau,
Sasha Levin
6.12-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 f60fe27ab3f9d..800d1073df27d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -1220,6 +1220,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;
@@ -1227,7 +1230,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 6901971f5da6b..051523090ea7c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -1876,6 +1876,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 *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 789acc53d8a8b..d6437a0fff6a2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -2788,6 +2788,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);
@@ -2813,8 +2814,9 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
if (enable)
mt7925_mcu_bss_rlm_tlv(skb, phy->mt76, link_conf, ctx);
- 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] 872+ messages in thread
* [PATCH 6.12 020/869] net: team: Remove unused team_mode_op, port_enabled
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (18 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 019/869] wifi: mt76: connac: tolerate inactive BSS deactivation Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 021/869] net: team: Rename port_disabled team mode op to port_tx_disabled Greg Kroah-Hartman
` (849 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jiri Pirko, Marc Harvey,
Kuniyuki Iwashima, Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Harvey <marcharvey@google.com>
[ Upstream commit 014f249121d73909528df320818fba7693d0ec92 ]
This team_mode_op wasn't used by any of the team modes, so remove it.
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Marc Harvey <marcharvey@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260409-teaming-driver-internal-v7-2-f47e7589685d@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: b7454f1940c5 ("net: team: stop reusing skb after queue override")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/team/team_core.c | 2 --
include/linux/if_team.h | 1 -
2 files changed, 3 deletions(-)
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index 3cbaee3ff5fd7..7d14acaadd616 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -944,8 +944,6 @@ static void team_port_enable(struct team *team,
team_port_index_hash(team, port->index));
team_adjust_ops(team);
team_queue_override_port_add(team, port);
- if (team->ops.port_enabled)
- team->ops.port_enabled(team, port);
team_notify_peers(team);
team_mcast_rejoin(team);
team_lower_state_changed(port);
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index cdc684e04a2fb..31a4f13ab2986 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -121,7 +121,6 @@ struct team_mode_ops {
int (*port_enter)(struct team *team, struct team_port *port);
void (*port_leave)(struct team *team, struct team_port *port);
void (*port_change_dev_addr)(struct team *team, struct team_port *port);
- void (*port_enabled)(struct team *team, struct team_port *port);
void (*port_disabled)(struct team *team, struct team_port *port);
};
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 021/869] net: team: Rename port_disabled team mode op to port_tx_disabled
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (19 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 020/869] net: team: Remove unused team_mode_op, port_enabled Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 022/869] net: team: fix NULL pointer dereference in team_xmit during mode change Greg Kroah-Hartman
` (848 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jiri Pirko, Marc Harvey,
Kuniyuki Iwashima, Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Harvey <marcharvey@google.com>
[ Upstream commit cfa477df2cc62ba53cb936669886361152b594a7 ]
This team mode op is only used by the load balance mode, and it only
uses it in the tx path.
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Marc Harvey <marcharvey@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260409-teaming-driver-internal-v7-3-f47e7589685d@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: b7454f1940c5 ("net: team: stop reusing skb after queue override")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/team/team_core.c | 4 ++--
drivers/net/team/team_mode_loadbalance.c | 4 ++--
include/linux/if_team.h | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index 7d14acaadd616..ac0df5754254b 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -968,8 +968,8 @@ static void team_port_disable(struct team *team,
{
if (!team_port_enabled(port))
return;
- if (team->ops.port_disabled)
- team->ops.port_disabled(team, port);
+ if (team->ops.port_tx_disabled)
+ team->ops.port_tx_disabled(team, port);
hlist_del_rcu(&port->hlist);
__reconstruct_port_hlist(team, port->index);
port->index = -1;
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c
index 00f8989c29c0f..3ca419884185b 100644
--- a/drivers/net/team/team_mode_loadbalance.c
+++ b/drivers/net/team/team_mode_loadbalance.c
@@ -658,7 +658,7 @@ static void lb_port_leave(struct team *team, struct team_port *port)
free_percpu(lb_port_priv->pcpu_stats);
}
-static void lb_port_disabled(struct team *team, struct team_port *port)
+static void lb_port_tx_disabled(struct team *team, struct team_port *port)
{
lb_tx_hash_to_port_mapping_null_port(team, port);
}
@@ -668,7 +668,7 @@ static const struct team_mode_ops lb_mode_ops = {
.exit = lb_exit,
.port_enter = lb_port_enter,
.port_leave = lb_port_leave,
- .port_disabled = lb_port_disabled,
+ .port_tx_disabled = lb_port_tx_disabled,
.receive = lb_receive,
.transmit = lb_transmit,
};
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index 31a4f13ab2986..06fec0a78db5a 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -121,7 +121,7 @@ struct team_mode_ops {
int (*port_enter)(struct team *team, struct team_port *port);
void (*port_leave)(struct team *team, struct team_port *port);
void (*port_change_dev_addr)(struct team *team, struct team_port *port);
- void (*port_disabled)(struct team *team, struct team_port *port);
+ void (*port_tx_disabled)(struct team *team, struct team_port *port);
};
extern int team_modeop_port_enter(struct team *team, struct team_port *port);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 022/869] net: team: fix NULL pointer dereference in team_xmit during mode change
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (20 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 021/869] net: team: Rename port_disabled team mode op to port_tx_disabled Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 023/869] net: team: stop reusing skb after queue override Greg Kroah-Hartman
` (847 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Xiang Mei, Weiming Shi, Jiayuan Chen,
Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <bestswngs@gmail.com>
[ Upstream commit 25fe708bbc59289d3d1ea4b126fbc1b460a072a5 ]
__team_change_mode() clears team->ops with memset() before restoring
safe dummy handlers via team_adjust_ops(). A concurrent team_xmit()
running under RCU on another CPU can read team->ops.transmit during
this window and call a NULL function pointer, crashing the kernel.
The race requires a mode change (CAP_NET_ADMIN) concurrent with
transmit on the team device.
BUG: kernel NULL pointer dereference, address: 0000000000000000
Oops: 0010 [#1] SMP KASAN NOPTI
RIP: 0010:0x0
Call Trace:
team_xmit (drivers/net/team/team_core.c:1853)
dev_hard_start_xmit (net/core/dev.c:3904)
__dev_queue_xmit (net/core/dev.c:4871)
packet_sendmsg (net/packet/af_packet.c:3109)
__sys_sendto (net/socket.c:2265)
The original code assumed that no ports means no traffic, so mode
changes could freely memset()/memcpy() the ops. AF_PACKET with
forced carrier breaks that assumption.
Prevent the race instead of making it safe: replace memset()/memcpy()
with per-field updates that never touch transmit or receive. Those
two handlers are managed solely by team_adjust_ops(), which already
installs dummies when tx_en_port_count == 0 (always true during mode
change since no ports are present). WRITE_ONCE/READ_ONCE prevent
store/load tearing on the handler pointers.
synchronize_net() before exit_op() drains in-flight readers that may
still reference old mode state from before port removal switched the
handlers to dummies.
Fixes: 3d249d4ca7d0 ("net: introduce ethernet teaming device")
Reported-by: Xiang Mei <xmei5@asu.edu>
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Link: https://patch.msgid.link/20260521081159.1491563-3-bestswngs@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: b7454f1940c5 ("net: team: stop reusing skb after queue override")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/team/team_core.c | 45 +++++++++++++++++++++++++-----------
1 file changed, 32 insertions(+), 13 deletions(-)
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index ac0df5754254b..29d903de77da0 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -534,21 +534,23 @@ static void team_adjust_ops(struct team *team)
if (!team->en_port_count || !team_is_mode_set(team) ||
!team->mode->ops->transmit)
- team->ops.transmit = team_dummy_transmit;
+ WRITE_ONCE(team->ops.transmit, team_dummy_transmit);
else
- team->ops.transmit = team->mode->ops->transmit;
+ WRITE_ONCE(team->ops.transmit, team->mode->ops->transmit);
if (!team->en_port_count || !team_is_mode_set(team) ||
!team->mode->ops->receive)
- team->ops.receive = team_dummy_receive;
+ WRITE_ONCE(team->ops.receive, team_dummy_receive);
else
- team->ops.receive = team->mode->ops->receive;
+ WRITE_ONCE(team->ops.receive, team->mode->ops->receive);
}
/*
- * We can benefit from the fact that it's ensured no port is present
- * at the time of mode change. Therefore no packets are in fly so there's no
- * need to set mode operations in any special way.
+ * team_change_mode() ensures no ports are present during mode change,
+ * but lockless readers can still reach team_xmit(). Avoid touching
+ * transmit/receive -- they are already set to dummies by
+ * team_adjust_ops() since no ports are enabled. synchronize_net()
+ * drains in-flight readers before destroying old mode state.
*/
static int __team_change_mode(struct team *team,
const struct team_mode *new_mode)
@@ -557,9 +559,21 @@ static int __team_change_mode(struct team *team,
if (team_is_mode_set(team)) {
void (*exit_op)(struct team *team) = team->ops.exit;
- /* Clear ops area so no callback is called any longer */
- memset(&team->ops, 0, sizeof(struct team_mode_ops));
- team_adjust_ops(team);
+ /* Clear cold-path ops used only under RTNL. transmit and
+ * receive are already dummies (no ports) so leave them
+ * alone -- overwriting them is the source of the race.
+ */
+ team->ops.init = NULL;
+ team->ops.exit = NULL;
+ team->ops.port_enter = NULL;
+ team->ops.port_leave = NULL;
+ team->ops.port_change_dev_addr = NULL;
+ team->ops.port_tx_disabled = NULL;
+
+ /* Wait for in-flight readers before tearing down mode
+ * state they may reference.
+ */
+ synchronize_net();
if (exit_op)
exit_op(team);
@@ -582,7 +596,12 @@ static int __team_change_mode(struct team *team,
}
team->mode = new_mode;
- memcpy(&team->ops, new_mode->ops, sizeof(struct team_mode_ops));
+ team->ops.init = new_mode->ops->init;
+ team->ops.exit = new_mode->ops->exit;
+ team->ops.port_enter = new_mode->ops->port_enter;
+ team->ops.port_leave = new_mode->ops->port_leave;
+ team->ops.port_change_dev_addr = new_mode->ops->port_change_dev_addr;
+ team->ops.port_tx_disabled = new_mode->ops->port_tx_disabled;
team_adjust_ops(team);
return 0;
@@ -743,7 +762,7 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
/* allow exact match delivery for disabled ports */
res = RX_HANDLER_EXACT;
} else {
- res = team->ops.receive(team, port, skb);
+ res = READ_ONCE(team->ops.receive)(team, port, skb);
}
if (res == RX_HANDLER_ANOTHER) {
struct team_pcpu_stats *pcpu_stats;
@@ -1736,7 +1755,7 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
tx_success = team_queue_override_transmit(team, skb);
if (!tx_success)
- tx_success = team->ops.transmit(team, skb);
+ tx_success = READ_ONCE(team->ops.transmit)(team, skb);
if (tx_success) {
struct team_pcpu_stats *pcpu_stats;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 023/869] net: team: stop reusing skb after queue override
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (21 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 022/869] net: team: fix NULL pointer dereference in team_xmit during mode change Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 024/869] sched_ext: Fix CPU hotplug hang when a dying CPUs tasks sit in the BPF scheduler Greg Kroah-Hartman
` (846 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, co+2cf741c3005abc20, Weiming Shi,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <bestswngs@gmail.com>
[ Upstream commit b7454f1940c5e6d92e753853c476a769e452f30a ]
A nonzero dev_queue_xmit() result does not return ownership of the skb.
When an override port's qdisc drops it, the queue override helper used to
try another port or the mode transmit op with the freed skb.
Return the handoff decision separately from transmit success. Select only
the first override port under RCU and stop after handing it the skb,
regardless of the lower transmit result. Keep the existing success and
drop accounting.
BUG: KASAN: slab-use-after-free in sk_skb_reason_drop
Write of size 4 by task poc/5040
sk_skb_reason_drop (net/core/skbuff.c:1240)
dev_kfree_skb_any_reason (net/core/dev.c:3470)
ab_transmit (drivers/net/team/team_mode_activebackup.c:49)
team_xmit (drivers/net/team/team_core.c:1849)
__dev_direct_xmit (net/core/dev.c:4934)
Freed by task 5040:
__tcf_kfree_skb_list (net/sched/sch_generic.c:43)
__dev_queue_xmit (net/core/dev.c:4831)
team_xmit (drivers/net/team/team_core.c:1846)
Kernel panic - not syncing: KASAN: panic_on_warn set ...
Cc: stable@vger.kernel.org
Fixes: 8ff5105a2b9d ("team: add support for queue override by setting queue_id for port")
Reported-by: <co+2cf741c3005abc20@bugs.sh>
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
Link: https://patch.msgid.link/20261001182326.572045-2-bestswngs@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/team/team_core.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index 29d903de77da0..0cdcff2537c8f 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -821,7 +821,8 @@ static struct list_head *__team_get_qom_list(struct team *team, u16 queue_id)
/*
* note: already called with rcu_read_lock
*/
-static bool team_queue_override_transmit(struct team *team, struct sk_buff *skb)
+static bool team_queue_override_transmit(struct team *team, struct sk_buff *skb,
+ bool *tx_success)
{
struct list_head *qom_list;
struct team_port *port;
@@ -829,11 +830,11 @@ static bool team_queue_override_transmit(struct team *team, struct sk_buff *skb)
if (!team->queue_override_enabled || !skb->queue_mapping)
return false;
qom_list = __team_get_qom_list(team, skb->queue_mapping);
- list_for_each_entry_rcu(port, qom_list, qom_list) {
- if (!team_dev_queue_xmit(team, port, skb))
- return true;
- }
- return false;
+ port = list_first_or_null_rcu(qom_list, struct team_port, qom_list);
+ if (!port)
+ return false;
+ *tx_success = !team_dev_queue_xmit(team, port, skb);
+ return true;
}
static void __team_queue_override_port_del(struct team *team,
@@ -1753,8 +1754,7 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
bool tx_success;
unsigned int len = skb->len;
- tx_success = team_queue_override_transmit(team, skb);
- if (!tx_success)
+ if (!team_queue_override_transmit(team, skb, &tx_success))
tx_success = READ_ONCE(team->ops.transmit)(team, skb);
if (tx_success) {
struct team_pcpu_stats *pcpu_stats;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 024/869] sched_ext: Fix CPU hotplug hang when a dying CPUs tasks sit in the BPF scheduler
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (22 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 023/869] net: team: stop reusing skb after queue override Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 025/869] Bluetooth: hci_sync: Fix command skb lifetime during scan setup Greg Kroah-Hartman
` (845 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alap Mohan, Joonwoo Park, Tejun Heo,
Andrea Righi, Sasha Levin
6.12-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: Replaced guard(sched_change) with the existing sched_deq_and_put_task() and sched_enq_and_set_task() helper pair. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/sched/ext.c | 33 ++++++++++++++++++++++++++++++---
1 file changed, 30 insertions(+), 3 deletions(-)
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 3a1983ef278fc..39dc9d3cfc079 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -2113,8 +2113,8 @@ static void set_task_runnable(struct rq *rq, struct task_struct *p)
}
/*
- * list_add_tail() must be used. scx_ops_bypass() depends on tasks being
- * appened to the runnable_list.
+ * list_add_tail() must be used. scx_ops_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);
}
@@ -2823,7 +2823,14 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
if (consume_global_dsq(rq))
goto has_tasks;
- if (!SCX_HAS_OP(dispatch) || scx_rq_bypassing(rq) || !scx_rq_online(rq))
+ /*
+ * 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 (!SCX_HAS_OP(dispatch) || scx_rq_bypassing(rq) ||
+ !(rq->scx.flags & SCX_RQ_ONLINE))
goto no_tasks;
dspc->rq = rq;
@@ -3514,7 +3521,27 @@ 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) {
+ struct sched_enq_and_set_ctx ctx;
+
+ if (p->scx.dsq == &rq->scx.local_dsq)
+ continue;
+ sched_deq_and_put_task(p, DEQUEUE_SAVE | DEQUEUE_MOVE | DEQUEUE_NOCLOCK, &ctx);
+ sched_enq_and_set_task(&ctx);
+ }
}
#else /* CONFIG_SMP */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 025/869] Bluetooth: hci_sync: Fix command skb lifetime during scan setup
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (23 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 024/869] sched_ext: Fix CPU hotplug hang when a dying CPUs tasks sit in the BPF scheduler Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 026/869] Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex Greg Kroah-Hartman
` (844 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Chengfeng Ye, Luiz Augusto von Dentz,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <nicoyip.dev@gmail.com>
[ Upstream commit 9af12272061d206af8bc3e40215cb694421ab73a ]
During PA sync scan setup, hci_le_set_ext_scan_param_sync() gets the
address used for the PA_LINK lookup from hci_sent_cmd_data(). The
returned pointer borrows storage from sent_cmd or req_skb, without
holding a reference to either skb.
The scan worker runs on req_workqueue while hci_cmd_work() runs on the
separate device workqueue. After the scan worker loads sent_cmd, the
command worker can free and replace it before hci_sent_cmd_data()
dereferences the skb. The command payload can also be freed between
returning from the helper and comparing the address. The connection
lookup's RCU critical section does not protect the command skb.
KASAN reported:
BUG: KASAN: slab-use-after-free in hci_sent_cmd_data+0x27c/0x2f0
Workqueue: hci0 hci_cmd_sync_work
Call Trace:
hci_sent_cmd_data+0x27c/0x2f0
hci_le_set_scan_param_sync+0x43a/0x850
hci_passive_scan_sync+0xb09/0x1460
hci_update_passive_scan_sync+0x47c/0x6e0
hci_le_pa_create_sync+0x200/0xa70
hci_cmd_sync_work+0x13c/0x290
Allocated by task 95:
skb_clone+0x13f/0x340
hci_cmd_work+0x2a9/0x7e0
Freed by task 95:
kmem_cache_free+0xba/0x3a0
hci_cmd_work+0x29c/0x7e0
Use hdev->lock to serialize the address snapshot with sent_cmd
replacement. Protect req_skb replacement and completion cleanup with
the same lock because the helper falls back to that skb. Copy the
address before releasing the lock and use the copy for the existing
RCU-protected connection lookup. Release the mutex before sending or
waiting for commands, preserving the lookup and completion ordering.
Fixes: 22cbf4f84c00 ("Bluetooth: hci_sync: Use QoS to determine which PHY to scan")
Cc: stable@vger.kernel.org
Assisted-by: GPT-6 Astra
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/hci_core.c | 4 ++++
net/bluetooth/hci_sync.c | 10 +++++++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 95900c2325631..ff3ccb33da0c7 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -4155,9 +4155,11 @@ static int hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
bt_dev_dbg(hdev, "skb %p", skb);
+ hci_dev_lock(hdev);
kfree_skb(hdev->sent_cmd);
hdev->sent_cmd = skb_clone(skb, GFP_KERNEL);
+ hci_dev_unlock(hdev);
if (!hdev->sent_cmd) {
skb_queue_head(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
@@ -4178,8 +4180,10 @@ static int hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND &&
!hci_dev_test_and_set_flag(hdev, HCI_CMD_PENDING)) {
+ hci_dev_lock(hdev);
kfree_skb(hdev->req_skb);
hdev->req_skb = skb_get(hdev->sent_cmd);
+ hci_dev_unlock(hdev);
}
return err;
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index f4dea6fffa727..6d7caf00fc897 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -32,8 +32,10 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
WRITE_ONCE(hdev->req_status, HCI_REQ_DONE);
/* Free the request command so it is not used as response */
+ hci_dev_lock(hdev);
kfree_skb(hdev->req_skb);
hdev->req_skb = NULL;
+ hci_dev_unlock(hdev);
if (skb) {
struct sock *sk = hci_skb_sk(skb);
@@ -3058,13 +3060,19 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
*/
if (hci_dev_test_flag(hdev, HCI_PA_SYNC)) {
struct hci_cp_le_add_to_accept_list *sent;
+ bdaddr_t bdaddr;
+ hci_dev_lock(hdev);
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_ACCEPT_LIST);
+ if (sent)
+ bacpy(&bdaddr, &sent->bdaddr);
+ hci_dev_unlock(hdev);
+
if (sent) {
struct hci_conn *conn;
conn = hci_conn_hash_lookup_ba(hdev, PA_LINK,
- &sent->bdaddr);
+ &bdaddr);
if (conn) {
struct bt_iso_qos *qos = &conn->iso_qos;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 026/869] Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (24 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 025/869] Bluetooth: hci_sync: Fix command skb lifetime during scan setup Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 027/869] drm/vmwgfx: Stop using dev_private to store driver data Greg Kroah-Hartman
` (843 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 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.12-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: Changed kernel_connect()’s address cast from struct sockaddr_unsized * to struct sockaddr *. ]
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 6c57f5a766c17..b2d9bd743ea2e 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] 872+ messages in thread
* [PATCH 6.12 027/869] drm/vmwgfx: Stop using dev_private to store driver data.
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (25 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 026/869] Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 028/869] drm/vmwgfx: validate pitch coming from userspace Greg Kroah-Hartman
` (842 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Maaz Mombasawala, Zack Rusin,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maaz Mombasawala <maaz.mombasawala@broadcom.com>
[ Upstream commit 1b1d5fe66ca591d34c5501aab8f5f09f347e8a3e ]
Currently vmwgfx uses the dev_private opaque pointer in drm_device to store
driver data in vmw_private struct. Using dev_private is deprecated, and the
recommendation is to embed struct drm_device in the larger per-device
structure.
The vmwgfx driver already embeds struct drm_device in its struct
vmw_private, so switch to using that exclusively and stop using
dev_private.
Signed-off-by: Maaz Mombasawala <maaz.mombasawala@broadcom.com>
Reviewed-by: Zack Rusin <zack.rusin@broadcom.com>
Signed-off-by: Zack Rusin <zack.rusin@broadcom.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240502004033.107533-1-maaz.mombasawala@broadcom.com
Stable-dep-of: 21bc51cb89ce ("drm/vmwgfx: validate pitch coming from userspace")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 --
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 +-
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 4 ++--
3 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 2e84e1029732d..1b0b9d2d4e720 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -856,8 +856,6 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
bool refuse_dma = false;
struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
- dev_priv->drm.dev_private = dev_priv;
-
vmw_sw_context_init(dev_priv);
mutex_init(&dev_priv->cmdbuf_mutex);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 4e2807f5f94cf..b21831ef214a6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -639,7 +639,7 @@ static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res)
static inline struct vmw_private *vmw_priv(struct drm_device *dev)
{
- return (struct vmw_private *)dev->dev_private;
+ return container_of(dev, struct vmw_private, drm);
}
static inline struct vmw_private *vmw_priv_from_ttm(struct ttm_device *bdev)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 5f99f7437ae61..800a79e035ed6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -280,7 +280,7 @@ static void vmw_du_put_cursor_mob(struct vmw_cursor_plane *vcp,
static int vmw_du_get_cursor_mob(struct vmw_cursor_plane *vcp,
struct vmw_plane_state *vps)
{
- struct vmw_private *dev_priv = vcp->base.dev->dev_private;
+ struct vmw_private *dev_priv = vmw_priv(vcp->base.dev);
u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h);
u32 i;
u32 cursor_max_dim, mob_max_size;
@@ -519,7 +519,7 @@ void vmw_du_cursor_plane_destroy(struct drm_plane *plane)
struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
u32 i;
- vmw_cursor_update_position(plane->dev->dev_private, false, 0, 0);
+ vmw_cursor_update_position(vmw_priv(plane->dev), false, 0, 0);
for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++)
vmw_du_destroy_cursor_mob(&vcp->cursor_mobs[i]);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 028/869] drm/vmwgfx: validate pitch coming from userspace
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (26 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 027/869] drm/vmwgfx: Stop using dev_private to store driver data Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 029/869] namespace: dont inherit MNT_UMOUNT in clone_mnt() Greg Kroah-Hartman
` (841 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Youness HFA, Zack Rusin,
Maaz Mombasawala, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zack Rusin <zack.rusin@broadcom.com>
[ Upstream commit 21bc51cb89ced74d6645a138cc2f21184bc75094 ]
Validate the pitch, alongside the box dimensions before trying
to copy data from the underlying surface. Fixes possible
out of bounds reads with cursor snooping.
Fixes: 2ac863719e51 ("vmwgfx: Snoop DMA transfers with non-covering sizes")
Cc: stable@vger.kernel.org
Reported-by: Youness HFA <hfa.youness@gmail.com>
Signed-off-by: Zack Rusin <zack.rusin@broadcom.com>
Reviewed-by: Maaz Mombasawala <maaz.mombasawala@broadcom.com>
Link: https://patch.msgid.link/20260809204515.211045-1-zack.rusin@broadcom.com
[ sashal: Applied the changes to vmw_kms_cursor_snoop() in its original location because the cursor refactor is absent. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 800a79e035ed6..985774f22a130 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -382,6 +382,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
unsigned long kmap_num;
SVGA3dCopyBox *box;
unsigned box_count;
+ u64 src_extent;
void *virtual;
bool is_iomem;
struct vmw_dma_cmd {
@@ -393,6 +394,8 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT);
const u32 image_pitch = VMW_CURSOR_SNOOP_WIDTH * desc->pitchBytesPerBlock;
+ BUILD_BUG_ON(sizeof(*srf->snooper.image) != desc->pitchBytesPerBlock);
+
cmd = container_of(header, struct vmw_dma_cmd, header);
/* No snooper installed, nothing to copy */
@@ -430,8 +433,19 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
return;
}
+ if (box->w == 0 || box->h == 0)
+ return;
+
+ src_extent = (u64)(box->h - 1) * cmd->dma.guest.pitch +
+ (u64)box->w * desc->pitchBytesPerBlock;
+ if (src_extent > bo->base.size) {
+ DRM_ERROR("Cursor snoop source of %llu bytes exceeds the %zu byte buffer\n",
+ src_extent, bo->base.size);
+ return;
+ }
+
kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT;
- kmap_num = (VMW_CURSOR_SNOOP_HEIGHT*image_pitch) >> PAGE_SHIFT;
+ kmap_num = PFN_UP(src_extent);
ret = ttm_bo_reserve(bo, true, false, NULL);
if (unlikely(ret != 0)) {
@@ -445,14 +459,16 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
virtual = ttm_kmap_obj_virtual(&map, &is_iomem);
- if (box->w == VMW_CURSOR_SNOOP_WIDTH && cmd->dma.guest.pitch == image_pitch) {
+ if (box->w == VMW_CURSOR_SNOOP_WIDTH &&
+ box->h == VMW_CURSOR_SNOOP_HEIGHT &&
+ cmd->dma.guest.pitch == image_pitch) {
memcpy(srf->snooper.image, virtual,
VMW_CURSOR_SNOOP_HEIGHT*image_pitch);
} else {
- /* Image is unsigned pointer. */
+ /* The destination stride is in pixels. */
for (i = 0; i < box->h; i++)
- memcpy(srf->snooper.image + i * image_pitch,
- virtual + i * cmd->dma.guest.pitch,
+ memcpy(srf->snooper.image + i * VMW_CURSOR_SNOOP_WIDTH,
+ virtual + (size_t)i * cmd->dma.guest.pitch,
box->w * desc->pitchBytesPerBlock);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 029/869] namespace: dont inherit MNT_UMOUNT in clone_mnt()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (27 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 028/869] drm/vmwgfx: validate pitch coming from userspace Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 030/869] namespace: check the mounts before reading their parents in pivot_root() Greg Kroah-Hartman
` (840 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Brauner (Amutable),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <brauner@kernel.org>
[ Upstream commit e2c6d326216642011da318b9edfd5d57ebd5a56f ]
MNT_UMOUNT gets raised on a mount that umount_tree() or umount_one() has
taken out of its namespace. It's never cleared. __detach_mounts()
unhooks a mount that carries it instead of unmounting it.
disconnect_mount() lets an unmounted child stay attached only if its
parent carries it. propagate_umount() takes it as the sign that a mount
is going to be unmounted when it decides what else can be unmounted,
where a chain of locked mounts ends and where a for reparenting an
overmount.
clone_mnt() copies the flags of the source and only masks
MNT_INTERNAL_FLAGS which doesn't include MNT_UMOUNT. A mount that was
lazily unmounted but is kept alive by a file descriptor can still be
copied when its root is an nsfs or pidfs file because may_copy_tree()
accepts those before checking whether the source is mounted at all:
mount --bind /proc/self/ns/net /tmp/x
exec 3< /tmp/x
umount -l /tmp/x
mount --bind /proc/self/fd/3 /tmp/y
The mount on /tmp/y is attached to the caller's namespace with
MNT_UMOUNT already set and every copy of it inherits the flag again.
That causes a number of bugs:
- Unlink its mountpoint from a mount namespace where it isn't one.
__detach_mounts() takes it for a mount that was unmounted earlier,
unhooks it from its parent and drops the reference the namespace
holds on it. It stays in the namespace with one reference too few
and as its own parent, so it can't be unmounted through the file
descriptor anymore and the namespace never finds it again. When the
namespace goes away it's leaked and points to a freed struct
mnt_namespace that may_change_propagation() and anon_ns_root() read
on the next propagation change or mount_setattr() through the file
descriptor.
- Make it shared and unmount a peer. trace_transfers() follows the
flag from the peer into it and strips it from its peer group.
- Let a propagated umount reach it. gather_candidates() marks it with
T_UMOUNT_CANDIDATE but never puts it on the candidate list, so the
mark is never cleared and every later propagated umount skips it. If
it's the parent of a locked mount handle_locked() takes it as the
cutoff and commits the locked child that should have stayed and
disconnect_mount() leaves that child attached to it, unmounted under
a mounted parent, which is what disconnect_mount() exists to
prevent. When the namespace goes away umount_tree() visits the child
a second time. And once __detach_mounts() has made it its own parent
reparent() never finds the end of the chain of unmounted parents.
A clone is a new mount that has never been unmounted. Add MNT_UMOUNT
to MNT_INTERNAL_FLAGS so clone_mnt() never copies it. And warn when
umount_tree() reaches a mount that already has it set.
Fixes: 590ce4bcbfb4 ("mnt: Add MNT_UMOUNT flag")
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260926-work-mount-fixes-2-v1-3-f357abf3d17b@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
[ sashal: adapted mount flags to macro definitions and an explicit clone_mnt() mask while replacing VFS_WARN_ON_ONCE() with WARN_ON_ONCE(). ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/namespace.c | 4 +++-
include/linux/mount.h | 3 ++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index f87bdff661664..11e6ddce877d5 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1311,7 +1311,7 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
}
mnt->mnt.mnt_flags = old->mnt.mnt_flags;
- mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL);
+ mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL|MNT_UMOUNT);
atomic_inc(&sb->s_active);
mnt->mnt.mnt_idmap = mnt_idmap_get(mnt_idmap(&old->mnt));
@@ -1778,6 +1778,8 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
/* Gather the mounts to umount */
for (p = mnt; p; p = next_mnt(p, mnt)) {
+ /* A mount is unmounted once. */
+ WARN_ON_ONCE(p->mnt.mnt_flags & MNT_UMOUNT);
p->mnt.mnt_flags |= MNT_UMOUNT;
if (mnt_ns_attached(p))
move_from_ns(p, &tmp_list);
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 04213d8ef8376..fdc14f5d154d7 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -50,7 +50,8 @@ struct path;
#define MNT_ATIME_MASK (MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME )
#define MNT_INTERNAL_FLAGS (MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | \
- MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED)
+ MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED | \
+ MNT_UMOUNT)
#define MNT_INTERNAL 0x4000
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 030/869] namespace: check the mounts before reading their parents in pivot_root()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (28 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 029/869] namespace: dont inherit MNT_UMOUNT in clone_mnt() Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 031/869] dm-integrity: use internal variable for digestsize Greg Kroah-Hartman
` (839 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Brauner (Amutable),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <brauner@kernel.org>
[ Upstream commit 6b7c001eb5857fa09041f47673666060a2e5fc1c ]
path_pivot_root() reads the parents of new_root and of the caller's root
and checks whether they are shared before it checks that either mount is
in the caller's mount namespace. Only namespace_sem is held. That's fine
for a mount that is in the caller's mount namespace.
But new_root can be a file descriptor to a mount that has been unmounted
and that only the file descriptor keeps alive. If that mount stayed
attached to its parent when it was unmounted nothing pins the parent for
it. The final mntput() of the parent unhooks the children under
mount_lock alone and frees the parent afterwards:
pivot_root() close(fd), last ref on the parent
------------ ---------------------------------
ex_parent = new_mnt->mnt_parent
mntput_no_expire_slowpath()
__umount_mnt(new_mnt)
cleanup_mnt()
call_rcu()
IS_MNT_SHARED(ex_parent)
BUG: KASAN: slab-use-after-free in path_pivot_root+0xf1a/0x1840
Read of size 4 at addr ffff8881047382f8 by task pivot_widen/157
path_pivot_root+0xf1a/0x1840
__x64_sys_pivot_root+0x165/0x190
The same goes for the caller's root via chroot(). Both outcomes of the
check end in EINVAL so nothing but the read itself goes wrong. It's the
same thing commit bb4609405752 ("statmount: read the parent of an
unmounted mount under mount_lock") fixed for statmount().
Check that both mounts are in the caller's namespace before their
parents are read. Every path returns EINVAL either way.
Fixes: e0c9c0afd2fc ("mnt: Update detach_mounts to leave mounts connected")
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260930-work-mount-fixes-3-v1-10-be34c83956ae@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
[ sashal: Replaced `return -EINVAL` with `goto out4` to preserve the syscall’s explicit cleanup path. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/namespace.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index 11e6ddce877d5..2c23537a17d19 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -4469,14 +4469,15 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
new_mnt = real_mount(new.mnt);
root_mnt = real_mount(root.mnt);
old_mnt = real_mount(old.mnt);
+ /* only a mounted mount has a parent that namespace_sem pins */
+ if (!check_mnt(root_mnt) || !check_mnt(new_mnt))
+ goto out4;
ex_parent = new_mnt->mnt_parent;
root_parent = root_mnt->mnt_parent;
if (IS_MNT_SHARED(old_mnt) ||
IS_MNT_SHARED(ex_parent) ||
IS_MNT_SHARED(root_parent))
goto out4;
- if (!check_mnt(root_mnt) || !check_mnt(new_mnt))
- goto out4;
if (new_mnt->mnt.mnt_flags & MNT_LOCKED)
goto out4;
error = -ENOENT;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 031/869] dm-integrity: use internal variable for digestsize
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (29 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 030/869] namespace: check the mounts before reading their parents in pivot_root() Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 032/869] dm-integrity: rename internal_hash Greg Kroah-Hartman
` (838 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Harald Freudenberger,
Mikulas Patocka, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <mpatocka@redhat.com>
[ Upstream commit e4cc9deca3da48986072327ae2eeb18e6fd0165d ]
Instead of calling digestsize() each time the digestsize for
the internal hash is needed, store the digestsize in a new
field internal_hash_digestsize within struct dm_integrity_c
once and use this value when needed.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Stable-dep-of: 764b683a6180 ("dm-integrity: fix buffer overflow in inline mode with large tag size")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/dm-integrity.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index 0a7be46701a9c..76d0c84380a8c 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -223,6 +223,7 @@ struct dm_integrity_c {
int failed;
struct crypto_shash *internal_hash;
+ unsigned int internal_hash_digestsize;
struct dm_target *ti;
@@ -1672,7 +1673,7 @@ static void integrity_sector_checksum(struct dm_integrity_c *ic, sector_t sector
goto failed;
}
- digest_size = crypto_shash_digestsize(ic->internal_hash);
+ digest_size = ic->internal_hash_digestsize;
if (unlikely(digest_size < ic->tag_size))
memset(result + digest_size, 0, ic->tag_size - digest_size);
@@ -1772,7 +1773,7 @@ static void integrity_metadata(struct work_struct *w)
if (ic->internal_hash) {
struct bvec_iter iter;
struct bio_vec bv;
- unsigned int digest_size = crypto_shash_digestsize(ic->internal_hash);
+ unsigned int digest_size = ic->internal_hash_digestsize;
struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
char *checksums;
unsigned int extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0;
@@ -2120,7 +2121,7 @@ static bool __journal_read_write(struct dm_integrity_io *dio, struct bio *bio,
} while (++s < ic->sectors_per_block);
if (ic->internal_hash) {
- unsigned int digest_size = crypto_shash_digestsize(ic->internal_hash);
+ unsigned int digest_size = ic->internal_hash_digestsize;
if (unlikely(digest_size > ic->tag_size)) {
char checksums_onstack[HASH_MAX_DIGESTSIZE];
@@ -2427,7 +2428,7 @@ static int dm_integrity_map_inline(struct dm_integrity_io *dio, bool from_map)
if (!dio->integrity_payload) {
unsigned digest_size, extra_size;
dio->payload_len = ic->tuple_size * (bio_sectors(bio) >> ic->sb->log2_sectors_per_block);
- digest_size = crypto_shash_digestsize(ic->internal_hash);
+ digest_size = ic->internal_hash_digestsize;
extra_size = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0;
dio->payload_len += extra_size;
dio->integrity_payload = kmalloc(dio->payload_len, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
@@ -2590,7 +2591,7 @@ static void dm_integrity_inline_recheck(struct work_struct *w)
bio_put(outgoing_bio);
integrity_sector_checksum(ic, dio->bio_details.bi_iter.bi_sector, outgoing_data, digest);
- if (unlikely(crypto_memneq(digest, dio->integrity_payload, min(crypto_shash_digestsize(ic->internal_hash), ic->tag_size)))) {
+ if (unlikely(crypto_memneq(digest, dio->integrity_payload, min(ic->internal_hash_digestsize, ic->tag_size)))) {
DMERR_LIMIT("%pg: Checksum failed at sector 0x%llx",
ic->dev->bdev, dio->bio_details.bi_iter.bi_sector);
atomic64_inc(&ic->number_of_mismatches);
@@ -2630,7 +2631,7 @@ static int dm_integrity_end_io(struct dm_target *ti, struct bio *bio, blk_status
//memset(mem, 0xff, ic->sectors_per_block << SECTOR_SHIFT);
integrity_sector_checksum(ic, dio->bio_details.bi_iter.bi_sector, mem, digest);
if (unlikely(crypto_memneq(digest, dio->integrity_payload + pos,
- min(crypto_shash_digestsize(ic->internal_hash), ic->tag_size)))) {
+ min(ic->internal_hash_digestsize, ic->tag_size)))) {
kunmap_local(mem);
dm_integrity_free_payload(dio);
INIT_WORK(&dio->work, dm_integrity_inline_recheck);
@@ -3012,8 +3013,8 @@ static void integrity_recalc(struct work_struct *w)
goto free_ret;
}
recalc_tags_size = (recalc_sectors >> ic->sb->log2_sectors_per_block) * ic->tag_size;
- if (crypto_shash_digestsize(ic->internal_hash) > ic->tag_size)
- recalc_tags_size += crypto_shash_digestsize(ic->internal_hash) - ic->tag_size;
+ if (ic->internal_hash_digestsize > ic->tag_size)
+ recalc_tags_size += ic->internal_hash_digestsize - ic->tag_size;
recalc_tags = kvmalloc(recalc_tags_size, GFP_NOIO);
if (!recalc_tags) {
vfree(recalc_buffer);
@@ -3172,8 +3173,8 @@ static void integrity_recalc_inline(struct work_struct *w)
}
recalc_tags_size = (recalc_sectors >> ic->sb->log2_sectors_per_block) * ic->tuple_size;
- if (crypto_shash_digestsize(ic->internal_hash) > ic->tuple_size)
- recalc_tags_size += crypto_shash_digestsize(ic->internal_hash) - ic->tuple_size;
+ if (ic->internal_hash_digestsize > ic->tuple_size)
+ recalc_tags_size += ic->internal_hash_digestsize - ic->tuple_size;
recalc_tags = kmalloc(recalc_tags_size, GFP_NOIO | __GFP_NOWARN);
if (!recalc_tags) {
kfree(recalc_buffer);
@@ -4703,6 +4704,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
"Invalid internal hash", "Error setting internal hash key");
if (r)
goto bad;
+ if (ic->internal_hash)
+ ic->internal_hash_digestsize = crypto_shash_digestsize(ic->internal_hash);
r = get_mac(&ic->journal_mac, &ic->journal_mac_alg, &ti->error,
"Invalid journal mac", "Error setting journal mac key");
@@ -4715,7 +4718,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
r = -EINVAL;
goto bad;
}
- ic->tag_size = crypto_shash_digestsize(ic->internal_hash);
+ ic->tag_size = ic->internal_hash_digestsize;
}
if (ic->tag_size > MAX_TAG_SIZE) {
ti->error = "Too big tag size";
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 032/869] dm-integrity: rename internal_hash
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (30 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 031/869] dm-integrity: use internal variable for digestsize Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 033/869] dm-integrity: fix buffer overflow in inline mode with large tag size Greg Kroah-Hartman
` (837 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Mikulas Patocka, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <mpatocka@redhat.com>
[ Upstream commit e8a052ee1fb570b8e07f05f65752646eaac74355 ]
Rename "internal_hash" to "internal_shash" and introduce a boolean value
"internal_hash".
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Stable-dep-of: 764b683a6180 ("dm-integrity: fix buffer overflow in inline mode with large tag size")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/dm-integrity.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index 76d0c84380a8c..bdc83a5f583b9 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -219,10 +219,11 @@ struct dm_integrity_c {
__u8 log2_blocks_per_bitmap_bit;
unsigned char mode;
+ bool internal_hash;
int failed;
- struct crypto_shash *internal_hash;
+ struct crypto_shash *internal_shash;
unsigned int internal_hash_digestsize;
struct dm_target *ti;
@@ -1635,11 +1636,11 @@ static void integrity_sector_checksum(struct dm_integrity_c *ic, sector_t sector
const char *data, char *result)
{
__le64 sector_le = cpu_to_le64(sector);
- SHASH_DESC_ON_STACK(req, ic->internal_hash);
+ SHASH_DESC_ON_STACK(req, ic->internal_shash);
int r;
unsigned int digest_size;
- req->tfm = ic->internal_hash;
+ req->tfm = ic->internal_shash;
r = crypto_shash_init(req);
if (unlikely(r < 0)) {
@@ -4700,12 +4701,14 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
buffer_sectors = 1;
ic->log2_buffer_sectors = min((int)__fls(buffer_sectors), 31 - SECTOR_SHIFT);
- r = get_mac(&ic->internal_hash, &ic->internal_hash_alg, &ti->error,
+ r = get_mac(&ic->internal_shash, &ic->internal_hash_alg, &ti->error,
"Invalid internal hash", "Error setting internal hash key");
if (r)
goto bad;
- if (ic->internal_hash)
- ic->internal_hash_digestsize = crypto_shash_digestsize(ic->internal_hash);
+ if (ic->internal_shash) {
+ ic->internal_hash = true;
+ ic->internal_hash_digestsize = crypto_shash_digestsize(ic->internal_shash);
+ }
r = get_mac(&ic->journal_mac, &ic->journal_mac_alg, &ti->error,
"Invalid journal mac", "Error setting journal mac key");
@@ -5239,8 +5242,8 @@ static void dm_integrity_dtr(struct dm_target *ti)
if (ic->sb)
free_pages_exact(ic->sb, SB_SECTORS << SECTOR_SHIFT);
- if (ic->internal_hash)
- crypto_free_shash(ic->internal_hash);
+ if (ic->internal_shash)
+ crypto_free_shash(ic->internal_shash);
free_alg(&ic->internal_hash_alg);
if (ic->journal_crypt)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 033/869] dm-integrity: fix buffer overflow in inline mode with large tag size
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (31 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 032/869] dm-integrity: rename internal_hash Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 034/869] net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop Greg Kroah-Hartman
` (836 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ben Cressey, Mikulas Patocka,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ben Cressey <ben@cressey.dev>
[ Upstream commit 764b683a6180fd72c931c13fea98d383506a3475 ]
In inline mode, dm_integrity_check and dm_integrity_inline_recheck
compute the checksum of each block into an on-stack buffer of
HASH_MAX_DIGESTSIZE bytes. integrity_sector_checksum pads its result
with zeroes up to the tag size, so if the tag size is larger than
HASH_MAX_DIGESTSIZE, the padding runs past the end of the buffer. With
CONFIG_STACKPROTECTOR the kernel panics in dm_integrity_check on the
first read.
Enlarge both buffers to hold MAX_TAG_SIZE bytes, as commit b93b6643e9b5
("dm integrity: fix a crash with unusually large tag size") did for
integrity_metadata.
Note that this is not a security bug because the buffer overflow can only
be triggered by root.
Fixes: fb0987682c62 ("dm-integrity: introduce the Inline mode")
Cc: stable@vger.kernel.org
Signed-off-by: Ben Cressey <ben@cressey.dev>
Assisted-by: LLM
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
[ sashal: Adapted the dm_integrity_check() hunk to the existing verification loop in dm_integrity_end_io(). ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/dm-integrity.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index bdc83a5f583b9..e43892d1619db 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -2548,7 +2548,7 @@ static void dm_integrity_inline_recheck(struct work_struct *w)
outgoing_data = dio->integrity_payload + PAGE_SIZE;
while (dio->bio_details.bi_iter.bi_size) {
- char digest[HASH_MAX_DIGESTSIZE];
+ char digest[MAX_T(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
int r;
struct bio_integrity_payload *bip;
struct bio_vec bv;
@@ -2626,7 +2626,7 @@ static int dm_integrity_end_io(struct dm_target *ti, struct bio *bio, blk_status
unlikely(dio->integrity_range_locked))
goto skip_check;
while (dio->bio_details.bi_iter.bi_size) {
- char digest[HASH_MAX_DIGESTSIZE];
+ char digest[MAX_T(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
struct bio_vec bv = bio_iter_iovec(bio, dio->bio_details.bi_iter);
char *mem = bvec_kmap_local(&bv);
//memset(mem, 0xff, ic->sectors_per_block << SECTOR_SHIFT);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 034/869] net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (32 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 033/869] dm-integrity: fix buffer overflow in inline mode with large tag size Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 035/869] riscv: patch: Avoid early phys_to_page() Greg Kroah-Hartman
` (835 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Suraj Gupta, Jakub Kicinski,
Sasha Levin
6.12-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 for existing kcalloc() allocation and missing interrupt-coalescing locks. ]
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 cbdca0fb89454..f9e8e83cfed93 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -516,8 +516,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
@@ -542,6 +543,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;
@@ -620,6 +622,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 3339c5e1a57a9..76970a8065494 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -841,6 +841,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);
@@ -1127,6 +1128,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())
@@ -1149,10 +1151,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);
}
/**
@@ -1475,6 +1484,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) {
@@ -1686,20 +1696,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);
}
axienet_iow(lp, XAE_IE_OFFSET, 0);
@@ -2615,6 +2647,7 @@ static int axienet_probe(struct platform_device *pdev)
u64_stats_init(&lp->rx_stat_sync);
u64_stats_init(&lp->tx_stat_sync);
+ spin_lock_init(&lp->rx_submit_lock);
mutex_init(&lp->stats_lock);
seqcount_mutex_init(&lp->hw_stats_seqcount, &lp->stats_lock);
INIT_DEFERRABLE_WORK(&lp->stats_work, axienet_refresh_stats);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 035/869] riscv: patch: Avoid early phys_to_page()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (33 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 034/869] net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 036/869] riscv: patch: fix handling of bpf-jit execmem addresses Greg Kroah-Hartman
` (834 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Thomas Weißschuh, Mike Rapoport,
Vivian Wang, Paul Walmsley, Sasha Levin
6.12-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 34ef522f07a8c..f8826f1595e16 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] 872+ messages in thread
* [PATCH 6.12 036/869] riscv: patch: fix handling of bpf-jit execmem addresses
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (34 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 035/869] riscv: patch: Avoid early phys_to_page() Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 037/869] scsi: ufs: core: Decouple CQ sweep from request iterator in MCQ Greg Kroah-Hartman
` (833 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Wei-Jie Hung, Pu Lehui,
Paul Walmsley, Sasha Levin
6.12-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 f8826f1595e16..9c9282f8a3a50 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] 872+ messages in thread
* [PATCH 6.12 037/869] scsi: ufs: core: Decouple CQ sweep from request iterator in MCQ
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (35 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 036/869] riscv: patch: fix handling of bpf-jit execmem addresses Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 038/869] scsi: ch: Do not keep references to data transfer element devices Greg Kroah-Hartman
` (832 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bart Van Assche, Stanley Jhu,
Peter Wang, Martin K. Petersen (Oracle), Sasha Levin
6.12-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>
[ sashal: adapted blk_mq_tagset_busy_iter() callback changes to the existing tag-based completion loop ]
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 22f4f5f08e74a..9c2f407da28a1 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -5685,7 +5685,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];
@@ -5698,22 +5708,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] 872+ messages in thread
* [PATCH 6.12 038/869] scsi: ch: Do not keep references to data transfer element devices
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (36 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 037/869] scsi: ufs: core: Decouple CQ sweep from request iterator in MCQ Greg Kroah-Hartman
@ 2026-10-17 15:47 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 039/869] scsi: ufs: core: Move an assignment in ufshcd_mcq_process_cqe() Greg Kroah-Hartman
` (831 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:47 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ahmed Abdelhaleem Ahmed,
Laurence Oberman, Martin K. Petersen (Oracle), Sasha Levin
6.12-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: adjusted allocation-removal context for kcalloc() instead of kzalloc_objs() ]
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] 872+ messages in thread
* [PATCH 6.12 039/869] scsi: ufs: core: Move an assignment in ufshcd_mcq_process_cqe()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (37 preceding siblings ...)
2026-10-17 15:47 ` [PATCH 6.12 038/869] scsi: ch: Do not keep references to data transfer element devices Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 040/869] scsi: ufs: core: Add debug log for MCQ command timeout Greg Kroah-Hartman
` (830 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Avri Altman, Bart Van Assche,
Martin K. Petersen, Sasha Levin
6.12-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 5e6197a6af5e2..7ce9aba6bd7d9 100644
--- a/drivers/ufs/core/ufs-mcq.c
+++ b/drivers/ufs/core/ufs-mcq.c
@@ -303,9 +303,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] 872+ messages in thread
* [PATCH 6.12 040/869] scsi: ufs: core: Add debug log for MCQ command timeout
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (38 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 039/869] scsi: ufs: core: Move an assignment in ufshcd_mcq_process_cqe() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 041/869] scsi: ufs: core: Add a comment block above ufshcd_mcq_compl_all_cqes_lock() Greg Kroah-Hartman
` (829 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Peter Wang, Bart Van Assche,
Martin K. Petersen, Sasha Levin
6.12-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 7ce9aba6bd7d9..d4129ceaede6c 100644
--- a/drivers/ufs/core/ufs-mcq.c
+++ b/drivers/ufs/core/ufs-mcq.c
@@ -310,6 +310,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] 872+ messages in thread
* [PATCH 6.12 041/869] scsi: ufs: core: Add a comment block above ufshcd_mcq_compl_all_cqes_lock()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (39 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 040/869] scsi: ufs: core: Add debug log for MCQ command timeout Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 042/869] scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock() Greg Kroah-Hartman
` (828 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bart Van Assche, Peter Wang,
Martin K. Petersen, Sasha Levin
6.12-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 d4129ceaede6c..09c40308789a6 100644
--- a/drivers/ufs/core/ufs-mcq.c
+++ b/drivers/ufs/core/ufs-mcq.c
@@ -315,6 +315,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] 872+ messages in thread
* [PATCH 6.12 042/869] scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (40 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 041/869] scsi: ufs: core: Add a comment block above ufshcd_mcq_compl_all_cqes_lock() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 043/869] drm/vc4: Use video aperture helpers Greg Kroah-Hartman
` (827 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Peter Wang, Stanley Jhu,
Bart Van Assche, Martin K. Petersen (Oracle), Sasha Levin
6.12-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 09c40308789a6..b6514a8b268fb 100644
--- a/drivers/ufs/core/ufs-mcq.c
+++ b/drivers/ufs/core/ufs-mcq.c
@@ -299,20 +299,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");
- }
}
/*
@@ -320,7 +324,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,
@@ -331,13 +335,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] 872+ messages in thread
* [PATCH 6.12 043/869] drm/vc4: Use video aperture helpers
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (41 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 042/869] scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 044/869] drm/vc4: Fix firmware reference leak in vc4_drm_bind() Greg Kroah-Hartman
` (826 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Thomas Zimmermann, Maxime Ripard,
Dave Stevenson, Raspberry Pi Kernel Maintenance,
Javier Martinez Canillas, Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <tzimmermann@suse.de>
[ Upstream commit 7e89e4365fd36ca006670788ec2c1527bfd0c61c ]
DRM's aperture functions have long been implemented as helpers
under drivers/video/ for use with fbdev. Avoid the DRM wrappers by
calling the video functions directly.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Dave Stevenson <dave.stevenson@raspberrypi.com>
Cc: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
Acked-by: Javier Martinez Canillas <javierm@redhat.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240930130921.689876-25-tzimmermann@suse.de
Stable-dep-of: b816da5d5df1 ("drm/vc4: Fix firmware reference leak in vc4_drm_bind()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/vc4/vc4_drv.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 8c104ace3dc6e..802e716f7dc83 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -20,6 +20,7 @@
* driver.
*/
+#include <linux/aperture.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/device.h>
@@ -30,7 +31,6 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_dma.h>
@@ -356,7 +356,7 @@ static int vc4_drm_bind(struct device *dev)
}
}
- ret = drm_aperture_remove_framebuffers(driver);
+ ret = aperture_remove_all_conflicting_devices(driver->name);
if (ret)
goto err;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 044/869] drm/vc4: Fix firmware reference leak in vc4_drm_bind()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (42 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 043/869] drm/vc4: Use video aperture helpers Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 045/869] namespace: unhash a dentry before detaching the mounts on it Greg Kroah-Hartman
` (825 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Wentao Liang, Maíra Canal,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <vulab@iscas.ac.cn>
[ Upstream commit b816da5d5df1461446a0a5f3fe2b4948a659a790 ]
The firmware reference obtained via rpi_firmware_get() is leaked when
aperture_remove_all_conflicting_devices() fails, as the error label
returns without putting it. This happens before the firmware is
consumed and put further down in the function.
Put the firmware reference before jumping to err.
Fixes: c406ad5e4a85 ("drm/vc4: Notify the firmware when DRM is in charge")
Cc: stable@vger.kernel.org
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
Link: https://patch.msgid.link/20260916154015.2056797-1-vulab@iscas.ac.cn
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/vc4/vc4_drv.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 802e716f7dc83..871d4096b74a0 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -357,8 +357,11 @@ static int vc4_drm_bind(struct device *dev)
}
ret = aperture_remove_all_conflicting_devices(driver->name);
- if (ret)
+ if (ret) {
+ if (firmware)
+ rpi_firmware_put(firmware);
goto err;
+ }
if (firmware) {
ret = rpi_firmware_property(firmware,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 045/869] namespace: unhash a dentry before detaching the mounts on it
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (43 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 044/869] drm/vc4: Fix firmware reference leak in vc4_drm_bind() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 046/869] namespace: check the target before walking it in do_mount_setattr() Greg Kroah-Hartman
` (824 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Brauner (Amutable),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <brauner@kernel.org>
[ Upstream commit 528b383dc35d1e5caf64ddf5d35f983ae543b0d0 ]
unlink(), rmdir() and rename() remove the entry from the filesystem,
call detach_mounts() on the entry with the inode locked and then call
d_delete() once the inode is unlocked.
The thing is that between detach_mounts() and d_delete() the dentry is
still hashed and positive. But after detach_mounts() nothing covers the
dentry anymore. A lookup that finds this dentry in the dcache can
uncover what the mounts hid.
That's a problem when unlinking files or directories that are
mountpoints in other mount namespaces. Everybody who had the underlying
entry covered can race the detach_mount() call until d_delete() has run.
The race window isn't all that small. It encompasses namespace_unlock()
with a full synchronize_rcu_expedited() grace period and the
inode_unlock() of the entry.
In my experiments three walkers that kept trying read an overmounted
file in 11938 of the 16140 unlinks that removed its mountpoint from a
bind mount of the filesystem within a minute.
Fun fact, d_invalidate() has the same ordering problem but gets it
right. It unhashes the dentry first and detaches the mounts afterwards.
Let's do the same in __detach_mounts():
- A lookup that hasn't found the dentry yet misses it in the dcache and
waits for the directory lock that the caller holds until the name is
gone for good.
- A lockless lookup that found it already fails the mount_lock check
while the dentry still counts as a mountpoint and the d_seq check once
it doesn't, and retries.
This fixes the lockless path. We still need to fix the reference count
lookup in a follow-up patch.
So d_drop() the dentry. The dentry stays positive and held but can't be
found anymore. Then proceed with the detach and unlink.
Reproducer:
The reads were counted with the program below, three walkers for 60 s
in a VM with 4 CPUs. The race window is stretched with the debug patch
pasted here. fs.detach_race_walk_us sleeps in lookup_fast() once it
found a mountpoint dentry and before its mounts are crossed.
fs.detach_race_unlink_us sleeps in vfs_unlink() between detach_mounts()
and d_delete().
// SPDX-License-Identifier: GPL-2.0
/*
* unlink_covered: unlink a file that is a mountpoint in a detached copy of
* its mount, against lookups that open it through that copy.
*
* A is a tmpfs with the file f1 (content SECRET_F) and the plain file
* MARK_A. A' is an open_tree(OPEN_TREE_CLONE) copy of A with MARK_A bound
* on A'/f1, held through an O_PATH fd on its root once the tree fd is
* closed. Walkers open f1 through that fd while the driver unlinks A/f1,
* where nothing is mounted on it. A walker may read MARK_A or get ENOENT.
* A read of SECRET_F is a hit: the name was found after its mount was
* gone. The lockless walks use openat2(RESOLVE_CACHED).
*
* usage: unlink_covered [-t seconds] [-w walkers]
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <linux/openat2.h>
#ifndef __NR_open_tree
#define __NR_open_tree 428
#endif
#ifndef __NR_move_mount
#define __NR_move_mount 429
#endif
#ifndef __NR_openat2
#define __NR_openat2 437
#endif
#ifndef OPEN_TREE_CLONE
#define OPEN_TREE_CLONE 1
#endif
#ifndef OPEN_TREE_CLOEXEC
#define OPEN_TREE_CLOEXEC O_CLOEXEC
#endif
#ifndef MOVE_MOUNT_F_EMPTY_PATH
#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004
#endif
#define WORK "/tmp/uc"
#define ADIR WORK "/A"
static int duration = 60, nwalkers = 3;
static atomic_int stop, writer_waiting;
static pthread_rwlock_t cur_lock = PTHREAD_RWLOCK_INITIALIZER;
static int cur_fd = -1; /* the root of A', -1 while there is none */
static atomic_long n_unlink, n_walk, n_mark, n_enoent, n_other, n_secret,
n_secret_cached;
static void die(const char *what)
{
fprintf(stderr, "FATAL %s: %s\n", what, strerror(errno));
exit(2);
}
static void put_file(int dfd, const char *name, const char *content)
{
int fd = openat(dfd, name, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC,
0644);
if (fd < 0 || write(fd, content, strlen(content)) < 0)
die(name);
close(fd);
}
/* "plain/../" @n times, then f1: a longer walk that checks nothing on its way */
static char *longpath(int n)
{
char *p = malloc(n * 9 + 3), *q = p;
for (int i = 0; i < n; i++, q += 9)
memcpy(q, "plain/../", 9);
strcpy(q, "f1");
return p;
}
static void try_read(int dfd, const char *path, int cached)
{
struct open_how how = { .flags = O_RDONLY | O_CLOEXEC,
.resolve = RESOLVE_CACHED };
char buf[32] = "";
long n;
int fd;
if (cached)
fd = syscall(__NR_openat2, dfd, path, &how, sizeof(how));
else
fd = openat(dfd, path, O_RDONLY | O_CLOEXEC);
atomic_fetch_add(&n_walk, 1);
if (fd < 0) {
if (errno == ENOENT)
atomic_fetch_add(&n_enoent, 1);
else if (!cached || errno != EAGAIN)
atomic_fetch_add(&n_other, 1);
return;
}
n = read(fd, buf, sizeof(buf) - 1);
close(fd);
if (n >= 6 && !strncmp(buf, "SECRET", 6)) {
if (cached)
atomic_fetch_add(&n_secret_cached, 1);
if (!atomic_fetch_add(&n_secret, 1))
printf("HIT: read \"%s\" through %s (%s walk)\n", buf,
path, cached ? "lockless" : "any");
} else {
atomic_fetch_add(&n_mark, 1);
}
}
static void *walker(void *arg)
{
unsigned int r = (long)arg * 2654435761u;
while (!atomic_load(&stop)) {
char *p_long, *p_short;
int dfd;
while (atomic_load(&writer_waiting) && !atomic_load(&stop))
usleep(20);
pthread_rwlock_rdlock(&cur_lock);
dfd = cur_fd;
if (dfd < 0) {
pthread_rwlock_unlock(&cur_lock);
usleep(100);
continue;
}
r = r * 1103515245u + 12345u;
p_long = longpath(1 + (r >> 8) % 400);
p_short = longpath(0);
try_read(dfd, p_long, 0);
try_read(dfd, p_short, 0);
try_read(dfd, p_long, 1);
pthread_rwlock_unlock(&cur_lock);
free(p_long);
free(p_short);
}
return NULL;
}
/* hand the walkers a new A' (or none), close the old one */
static void publish(int fd)
{
int old;
atomic_fetch_add(&writer_waiting, 1);
pthread_rwlock_wrlock(&cur_lock);
old = cur_fd;
cur_fd = fd;
pthread_rwlock_unlock(&cur_lock);
atomic_fetch_sub(&writer_waiting, 1);
if (old >= 0)
close(old);
}
static void *driver(void *arg __attribute__((unused)))
{
int a;
if (mkdir(ADIR, 0755) && errno != EEXIST)
die("mkdir A");
if (mount("A", ADIR, "tmpfs", 0, "size=4M"))
die("mount A");
a = open(ADIR, O_PATH | O_DIRECTORY | O_CLOEXEC);
if (a < 0 || mkdirat(a, "plain", 0755))
die("A/plain");
put_file(a, "MARK_A", "MARK_A");
while (!atomic_load(&stop)) {
int t, m, fd_a;
put_file(a, "f1", "SECRET_F");
t = syscall(__NR_open_tree, a, "",
OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC | AT_EMPTY_PATH);
if (t < 0)
die("open_tree A");
m = syscall(__NR_open_tree, a, "MARK_A",
OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
if (m < 0)
die("open_tree MARK_A");
if (syscall(__NR_move_mount, m, "", t, "f1",
MOVE_MOUNT_F_EMPTY_PATH))
die("move_mount");
close(m);
fd_a = openat(t, ".", O_PATH | O_DIRECTORY | O_CLOEXEC);
if (fd_a < 0)
die("open A'");
publish(fd_a);
usleep(200 + rand() % 1000);
close(t); /* A' is unmounted, fd_a holds it */
usleep(200 + rand() % 1000);
if (unlinkat(a, "f1", 0)) /* through A, a plain file there */
die("unlink f1");
atomic_fetch_add(&n_unlink, 1);
usleep(rand() % 300);
publish(-1);
}
close(a);
umount2(ADIR, MNT_DETACH);
return NULL;
}
int main(int argc, char **argv)
{
pthread_t d, *w;
int c, i;
setvbuf(stdout, NULL, _IOLBF, 0);
while ((c = getopt(argc, argv, "t:w:")) != -1) {
switch (c) {
case 't':
duration = atoi(optarg);
break;
case 'w':
nwalkers = atoi(optarg);
break;
default:
fprintf(stderr, "usage: unlink_covered [-t seconds] [-w walkers]\n");
return 2;
}
}
if (unshare(CLONE_NEWNS) ||
mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL))
die("unshare");
if (mkdir(WORK, 0755) && errno != EEXIST)
die("mkdir");
w = calloc(nwalkers, sizeof(*w));
for (i = 0; i < nwalkers; i++)
if (pthread_create(&w[i], NULL, walker, (void *)(long)i))
die("pthread_create");
if (pthread_create(&d, NULL, driver, NULL))
die("pthread_create");
sleep(duration);
atomic_store(&stop, 1);
pthread_join(d, NULL);
for (i = 0; i < nwalkers; i++)
pthread_join(w[i], NULL);
printf("unlink_covered: %d s, %d walkers: unlinks %ld walks %ld mark %ld enoent %ld other %ld SECRET %ld (lockless %ld)\n",
duration, nwalkers, atomic_load(&n_unlink), atomic_load(&n_walk),
atomic_load(&n_mark), atomic_load(&n_enoent),
atomic_load(&n_other), atomic_load(&n_secret),
atomic_load(&n_secret_cached));
return atomic_load(&n_secret) ? 1 : 0;
}
# diff --git a/fs/namei.c b/fs/namei.c
# --- a/fs/namei.c
# +++ b/fs/namei.c
# @@ -35,6 +35,7 @@
# #include <linux/fcntl.h>
# #include <linux/device_cgroup.h>
# #include <linux/fs_struct.h>
# +#include <linux/delay.h>
# #include <linux/posix_acl.h>
# #include <linux/hash.h>
# #include <linux/bitops.h>
# @@ -1205,9 +1206,26 @@ static int sysctl_protected_symlinks __read_mostly;
# static int sysctl_protected_hardlinks __read_mostly;
# static int sysctl_protected_fifos __read_mostly;
# static int sysctl_protected_regular __read_mostly;
# +/* debug: widen the two windows of the detach_mounts() race */
# +static int sysctl_detach_race_walk_us __read_mostly;
# +static int sysctl_detach_race_unlink_us __read_mostly;
#
# #ifdef CONFIG_SYSCTL
# static const struct ctl_table namei_sysctls[] = {
# + {
# + .procname = "detach_race_walk_us",
# + .data = &sysctl_detach_race_walk_us,
# + .maxlen = sizeof(int),
# + .mode = 0644,
# + .proc_handler = proc_dointvec,
# + },
# + {
# + .procname = "detach_race_unlink_us",
# + .data = &sysctl_detach_race_unlink_us,
# + .maxlen = sizeof(int),
# + .mode = 0644,
# + .proc_handler = proc_dointvec,
# + },
# {
# .procname = "protected_symlinks",
# .data = &sysctl_protected_symlinks,
# @@ -1878,6 +1896,10 @@ static struct dentry *lookup_fast(struct nameidata *nd)
# dentry = __d_lookup(parent, &nd->last);
# if (unlikely(!dentry))
# return NULL;
# + /* debug: between finding a mountpoint and crossing its mounts */
# + if (unlikely(sysctl_detach_race_walk_us) && d_mountpoint(dentry))
# + usleep_range(sysctl_detach_race_walk_us,
# + sysctl_detach_race_walk_us + 10);
# status = d_revalidate(nd->inode, &nd->last, dentry, nd->flags);
# }
# if (unlikely(status <= 0)) {
# @@ -5693,6 +5715,10 @@ int vfs_unlink(struct mnt_idmap *idmap, struct inode *dir,
# if (!error) {
# dont_mount(dentry);
# detach_mounts(dentry);
# + /* debug: the mounts are gone, d_delete() is still to come */
# + if (unlikely(sysctl_detach_race_unlink_us))
# + usleep_range(sysctl_detach_race_unlink_us,
# + sysctl_detach_race_unlink_us + 10);
# }
# }
# }
Fixes: 8ed936b5671b ("vfs: Lazily remove mounts on unlinked files and directories.")
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20261002-work-mount-fixes-4-v1-1-dd44b89d44ce@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
[ sashal: Adjusted comment context to retain i_mutex wording instead of upstream's i_rwsem. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/namespace.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/fs/namespace.c b/fs/namespace.c
index 2c23537a17d19..5cfceae507098 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1957,6 +1957,9 @@ static int do_umount(struct mount *mnt, int flags)
* detach_mounts allows lazily unmounting those mounts instead of
* leaking them.
*
+ * The dentry is unhashed before the mounts go so that no lookup finds
+ * what they covered. The caller removes it for good afterwards.
+ *
* The caller may hold dentry->d_inode->i_mutex.
*/
void __detach_mounts(struct dentry *dentry)
@@ -1970,6 +1973,8 @@ void __detach_mounts(struct dentry *dentry)
if (!mp)
goto out_unlock;
+ /* the name goes first, what covered it goes second */
+ d_drop(dentry);
event++;
while (!hlist_empty(&mp->m_list)) {
mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 046/869] namespace: check the target before walking it in do_mount_setattr()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (44 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 045/869] namespace: unhash a dentry before detaching the mounts on it Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 047/869] fcntl: refuse F_SET_RW_HINT on an immutable inode Greg Kroah-Hartman
` (823 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Brauner (Amutable),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <brauner@kernel.org>
[ Upstream commit 08f4288a37ef4b3d19b4a9599ec3048219cac828 ]
When mount_setattr() changes the propagation type to MS_SHARED
do_mount_setattr() takes namespace_sem and calls invent_group_ids()
which walks the whole target tree with next_mnt() and allocates a peer
group id for every mount that doesn't have one.
Whether the caller may touch the target at all is only checked
afterwards under mount_lock. If it may not, cleanup_group_ids() walks
the tree a second time on the way out to free the ids again.
A detached tree that a file descriptor keeps alive, a mount in another
mount namespace or a mount below the root of an anonymous mount
namespace does a bunch of allocation work that is completely useless
because it will fail and revert right after.
Do the right thing and check the target right after taking namespace_sem
instead. A mount leaves its namespace only under namespace_sem so the
mount stays stable. The check under mount_lock stays for the case where
no propagation change is requested and namespace_sem isn't taken.
Callers get the same EINVAL as before.
Fixes: 2a1867219c7b ("fs: add mount_setattr()")
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260926-work-mount-fixes-2-v1-5-f357abf3d17b@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
[ sashal: Replaced unavailable anon_ns_root() with equivalent checks using existing mount and namespace helpers. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/namespace.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/fs/namespace.c b/fs/namespace.c
index 5cfceae507098..808a8e79a4863 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -4721,6 +4721,13 @@ static int do_mount_setattr(struct path *path, struct mount_kattr *kattr)
* propagation.
*/
namespace_lock();
+ /* invent_group_ids() walks the tree, only walk a mounted one */
+ if (!is_mounted(&mnt->mnt) ||
+ ((mnt_has_parent(mnt) || !is_anon_ns(mnt->mnt_ns)) &&
+ !check_mnt(mnt))) {
+ namespace_unlock();
+ return -EINVAL;
+ }
if (kattr->propagation == MS_SHARED) {
err = invent_group_ids(mnt, kattr->recurse);
if (err) {
@@ -4733,6 +4740,7 @@ static int do_mount_setattr(struct path *path, struct mount_kattr *kattr)
err = -EINVAL;
lock_mount_hash();
+ /* Checked under namespace_sem already if the propagation changes. */
/* Ensure that this isn't anything purely vfs internal. */
if (!is_mounted(&mnt->mnt))
goto out;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 047/869] fcntl: refuse F_SET_RW_HINT on an immutable inode
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (45 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 046/869] namespace: check the target before walking it in do_mount_setattr() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 048/869] namespace: handle mount locking for automounts correctly Greg Kroah-Hartman
` (822 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Brauner (Amutable),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <brauner@kernel.org>
[ Upstream commit b0d1022b9bdb1e98aa7fb3244fdd50a58c61766c ]
An immutable inode is never written to so write hints are pointless.
Refuse the hint on an immutable inode the way setattr(), fallocate() and
etxattr() refuse their changes.
Fixes: c75b1d9421f8 ("fs: add fcntl() interface for setting/getting write life time hints")
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20261002-work-mount-fixes-4-v1-3-dd44b89d44ce@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
[ sashal: Adjusted context due to the missing inode_owner_or_capable() check. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/fcntl.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/fs/fcntl.c b/fs/fcntl.c
index c4cdee6a78005..cb40e1f661eb2 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -374,6 +374,9 @@ static long fcntl_set_rw_hint(struct file *file, unsigned int cmd,
u64 __user *argp = (u64 __user *)arg;
u64 hint;
+ /* nothing is ever written to it */
+ if (IS_IMMUTABLE(inode))
+ return -EPERM;
if (copy_from_user(&hint, argp, sizeof(hint)))
return -EFAULT;
if (!rw_hint_valid(hint))
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 048/869] namespace: handle mount locking for automounts correctly
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (46 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 047/869] fcntl: refuse F_SET_RW_HINT on an immutable inode Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 049/869] smb: client: improve compound padding in encryption Greg Kroah-Hartman
` (821 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Brauner (Amutable),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <brauner@kernel.org>
[ Upstream commit 33aadc7c72055fca93cb5a3691d836ebf8b31c9b ]
If mounts are propagated across user namespaces, attach_recursive_mnt()
locks every copy of the source mount to protect overmounts from
vanishing and revealing the underlying files or directories.
The user namespace is taken from the caller's mount namespaces since
this is where the mounts end up. Except, that's not always true.
Automounts may legitimately get popped in by tasks located in a
different mount and user namespace during path lookup.
Then check doesn't make sense at that point. The copy in the namespace
of the parent - which may be the host's - is now locked and the host
cannot change the flags of its own mounts anymore.
Here's the reproducer:
- host has debugfs mounted nosuid,nodev,noexec and shared
- tracefs automount below it is not yet active
- hand a child process a directory descriptor on that mount
- child process enters auser and mount namespace
- child process' namespace now holds a locked copy of the host's debugfs
mount that receives propagation from it
- child process stats "tracing/." through the descriptor
- lookup runs on the host's mount so the automount lands below the host's mount
- propagation puts a copy below the child's copy
- both try to clear the flags on the mount they got, with a bind remount:
host, on its own automount: MS_REMOUNT|MS_BIND = EPERM
child, on the copy in its namespace: MS_REMOUNT|MS_BIND = 0
So the lock landed on the host's mount instead of the child's copy.
Congrats. So we need to compare with the owner of the namespace the
mount actually gets mounted on. For all regular cases that is the
caller's mount namespace and so nothing changes.
Detached trees in anonymous mount namespaces by be handed over via
SCM_RIGHTS or inherited in other ways on purpose so the attaching task's
mount namespace is authoritative, not the creator of the detached tree.
Fixes: 132c94e31b8b ("vfs: Carefully propogate mounts across user namespaces")
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20261002-work-mount-fixes-4-v1-6-dd44b89d44ce@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
[ sashal: adapted destination namespace access from dest->parent->mnt_ns to the existing top_mnt->mnt_ns. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/namespace.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index 808a8e79a4863..036d56df28289 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2494,15 +2494,31 @@ static int attach_recursive_mnt(struct mount *source_mnt,
struct mountpoint *dest_mp,
enum mnt_tree_flags_t flags)
{
- struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;
HLIST_HEAD(tree_list);
struct mnt_namespace *ns = top_mnt->mnt_ns;
+ struct user_namespace *user_ns = ns->user_ns;
struct mountpoint *smp;
struct mount *child, *dest_mnt, *p;
struct hlist_node *n;
int err = 0;
bool moving = flags & MNT_TREE_MOVE, beneath = flags & MNT_TREE_BENEATH;
+ /*
+ * A caller in an unprivileged mount namespaces may trigger an
+ * automount and propagate locked mounts into privileged mount
+ * namespaces. Take ownership from the target mount namespace.
+ * It's equivalent for everything but the automount case.
+ *
+ * Detached trees in anonymous mount namespaces by be handed
+ * over via SCM_RIGHTS or inherited in other ways on purpose
+ * the attaching task's mount namespace is authoritative, not
+ * the creator of the detached tree.
+ */
+ if (is_anon_ns(ns))
+ user_ns = current->nsproxy->mnt_ns->user_ns;
+ else
+ user_ns = ns->user_ns;
+
/*
* Preallocate a mountpoint in case the new mounts need to be
* mounted beneath mounts on the same mountpoint.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 049/869] smb: client: improve compound padding in encryption
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (47 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 048/869] namespace: handle mount locking for automounts correctly Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 050/869] smb: client: get rid of bounds check in SMB2_ioctl_init() Greg Kroah-Hartman
` (820 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells,
Paulo Alcantara (Red Hat), Steve French
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <pc@manguebit.com>
commit bc925c1216f0848da96ac642fba3cb92ae1f4e06 upstream.
After commit f7f291e14dde ("cifs: fix oops during encryption"), the
encryption layer can handle vmalloc'd buffers as well as kmalloc'd
buffers, so there is no need to inefficiently squash request iovs
into a single one to handle padding in compound requests.
Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/smb/client/cifsglob.h | 4 ++--
fs/smb/client/smb2ops.c | 37 +++----------------------------------
fs/smb/client/transport.c | 40 +++++++++++++---------------------------
3 files changed, 18 insertions(+), 63 deletions(-)
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -2195,7 +2195,7 @@ static inline int cifs_get_num_sgs(const
struct kvec *iov = &rqst[i].rq_iov[j];
addr = (unsigned long)iov->iov_base + skip;
- if (unlikely(is_vmalloc_addr((void *)addr))) {
+ if (is_vmalloc_or_module_addr((void *)addr)) {
len = iov->iov_len - skip;
nents += DIV_ROUND_UP(offset_in_page(addr) + len,
PAGE_SIZE);
@@ -2222,7 +2222,7 @@ static inline void cifs_sg_set_buf(struc
unsigned int off = offset_in_page(addr);
addr &= PAGE_MASK;
- if (unlikely(is_vmalloc_addr((void *)addr))) {
+ if (is_vmalloc_or_module_addr((void *)addr)) {
do {
unsigned int len = min_t(unsigned int, buflen, PAGE_SIZE - off);
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -2842,7 +2842,7 @@ smb2_set_next_command(struct cifs_tcon *
struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = ses->server;
unsigned long len = smb_rqst_len(server, rqst);
- int i, num_padding;
+ int num_padding;
shdr = (struct smb2_hdr *)(rqst->rq_iov[0].iov_base);
if (shdr == NULL) {
@@ -2851,44 +2851,13 @@ smb2_set_next_command(struct cifs_tcon *
}
/* SMB headers in a compound are 8 byte aligned. */
-
- /* No padding needed */
- if (!(len & 7))
- goto finished;
-
- num_padding = 8 - (len & 7);
- if (!smb3_encryption_required(tcon)) {
- /*
- * If we do not have encryption then we can just add an extra
- * iov for the padding.
- */
+ if (!IS_ALIGNED(len, 8)) {
+ num_padding = 8 - (len & 7);
rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding;
rqst->rq_nvec++;
len += num_padding;
- } else {
- /*
- * We can not add a small padding iov for the encryption case
- * because the encryption framework can not handle the padding
- * iovs.
- * We have to flatten this into a single buffer and add
- * the padding to it.
- */
- for (i = 1; i < rqst->rq_nvec; i++) {
- memcpy(rqst->rq_iov[0].iov_base +
- rqst->rq_iov[0].iov_len,
- rqst->rq_iov[i].iov_base,
- rqst->rq_iov[i].iov_len);
- rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len;
- }
- memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len,
- 0, num_padding);
- rqst->rq_iov[0].iov_len += num_padding;
- len += num_padding;
- rqst->rq_nvec = 1;
}
-
- finished:
shdr->NextCommand = cpu_to_le32(len);
}
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -425,19 +425,16 @@ out:
return rc;
}
-struct send_req_vars {
- struct smb2_transform_hdr tr_hdr;
- struct smb_rqst rqst[MAX_COMPOUND];
- struct kvec iov;
-};
-
static int
smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
struct smb_rqst *rqst, int flags)
{
- struct send_req_vars *vars;
- struct smb_rqst *cur_rqst;
- struct kvec *iov;
+ struct smb2_transform_hdr tr_hdr;
+ struct smb_rqst new_rqst[MAX_COMPOUND] = {};
+ struct kvec iov = {
+ .iov_base = &tr_hdr,
+ .iov_len = sizeof(tr_hdr),
+ };
int rc;
if (flags & CIFS_COMPRESS_REQ)
@@ -454,26 +451,15 @@ smb_send_rqst(struct TCP_Server_Info *se
return -EIO;
}
- vars = kzalloc(sizeof(*vars), GFP_NOFS);
- if (!vars)
- return -ENOMEM;
- cur_rqst = vars->rqst;
- iov = &vars->iov;
-
- iov->iov_base = &vars->tr_hdr;
- iov->iov_len = sizeof(vars->tr_hdr);
- cur_rqst[0].rq_iov = iov;
- cur_rqst[0].rq_nvec = 1;
+ new_rqst[0].rq_iov = &iov;
+ new_rqst[0].rq_nvec = 1;
rc = server->ops->init_transform_rq(server, num_rqst + 1,
- &cur_rqst[0], rqst);
- if (rc)
- goto out;
-
- rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]);
- smb3_free_compound_rqst(num_rqst, &cur_rqst[1]);
-out:
- kfree(vars);
+ new_rqst, rqst);
+ if (!rc) {
+ rc = __smb_send_rqst(server, num_rqst + 1, new_rqst);
+ smb3_free_compound_rqst(num_rqst, &new_rqst[1]);
+ }
return rc;
}
^ permalink raw reply [flat|nested] 872+ messages in thread
* [PATCH 6.12 050/869] smb: client: get rid of bounds check in SMB2_ioctl_init()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (48 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 049/869] smb: client: improve compound padding in encryption Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 051/869] smb: client: fix compound alignment with encryption Greg Kroah-Hartman
` (819 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells,
Paulo Alcantara (Red Hat), Steve French
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <pc@manguebit.com>
commit 9f544d26b15bfc52cf3a6e6a655f759e76c1a01a upstream.
smb2_set_next_command() no longer squashes request iovs into a single
iov, so the bounds check can be dropped.
Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/smb/client/smb2pdu.c | 9 ---------
1 file changed, 9 deletions(-)
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -3357,15 +3357,6 @@ SMB2_ioctl_init(struct cifs_tcon *tcon,
return rc;
if (indatalen) {
- unsigned int len;
-
- if (WARN_ON_ONCE(smb3_encryption_required(tcon) &&
- (check_add_overflow(total_len - 1,
- ALIGN(indatalen, 8), &len) ||
- len > MAX_CIFS_SMALL_BUFFER_SIZE))) {
- cifs_small_buf_release(req);
- return -EIO;
- }
/*
* indatalen is usually small at a couple of bytes max, so
* just allocate through generic pool
^ permalink raw reply [flat|nested] 872+ messages in thread
* [PATCH 6.12 051/869] smb: client: fix compound alignment with encryption
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (49 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 050/869] smb: client: get rid of bounds check in SMB2_ioctl_init() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 052/869] um: work around sched_yield not yielding in time-travel mode Greg Kroah-Hartman
` (818 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Paulo Alcantara (Red Hat),
David Howells, linux-cifs, Steve French
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <pc@manguebit.org>
commit 90f7c100d2dd99d5cd5be950d553edd2647e6cc8 upstream.
The encryption layer can't handle the padding iovs, so flatten the
compound request into a single buffer with required padding to prevent
the server from dropping the connection when finding unaligned
compound requests.
Fixes: bc925c1216f0 ("smb: client: improve compound padding in encryption")
Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Reviewed-by: David Howells <dhowells@redhat.com>
Cc: linux-cifs@vger.kernel.org
Cc: stable@vger.kernel.org
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/smb/client/smb2ops.c | 28 +++++++++++++++++++++++++---
1 file changed, 25 insertions(+), 3 deletions(-)
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -2851,13 +2851,35 @@ smb2_set_next_command(struct cifs_tcon *
}
/* SMB headers in a compound are 8 byte aligned. */
- if (!IS_ALIGNED(len, 8)) {
- num_padding = 8 - (len & 7);
+ if (IS_ALIGNED(len, 8))
+ goto out;
+
+ num_padding = 8 - (len & 7);
+ if (smb3_encryption_required(tcon)) {
+ int i;
+
+ /*
+ * Flatten request into a single buffer with required padding as
+ * the encryption layer can't handle the padding iovs.
+ */
+ for (i = 1; i < rqst->rq_nvec; i++) {
+ memcpy(rqst->rq_iov[0].iov_base +
+ rqst->rq_iov[0].iov_len,
+ rqst->rq_iov[i].iov_base,
+ rqst->rq_iov[i].iov_len);
+ rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len;
+ }
+ memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len,
+ 0, num_padding);
+ rqst->rq_iov[0].iov_len += num_padding;
+ rqst->rq_nvec = 1;
+ } else {
rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding;
rqst->rq_nvec++;
- len += num_padding;
}
+ len += num_padding;
+out:
shdr->NextCommand = cpu_to_le32(len);
}
^ permalink raw reply [flat|nested] 872+ messages in thread
* [PATCH 6.12 052/869] um: work around sched_yield not yielding in time-travel mode
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (50 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 051/869] smb: client: fix compound alignment with encryption Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 053/869] drm/i915/display: pass display to intel_crtc_for_pipe() Greg Kroah-Hartman
` (817 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Benjamin Berg, Johannes Berg,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Berg <benjamin.berg@intel.com>
[ Upstream commit 887c5c12e80c8424bd471122d2e8b6b462e12874 ]
sched_yield by a userspace may not actually cause scheduling in
time-travel mode as no time has passed. In the case seen it appears to
be a badly implemented userspace spinlock in ASAN. Unfortunately, with
time-travel it causes an extreme slowdown or even deadlock depending on
the kernel configuration (CONFIG_UML_MAX_USERSPACE_ITERATIONS).
Work around it by accounting time to the process whenever it executes a
sched_yield syscall.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Link: https://patch.msgid.link/20250314130815.226872-1-benjamin@sipsolutions.net
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/um/include/linux/time-internal.h | 2 ++
arch/um/kernel/skas/syscall.c | 11 +++++++++++
2 files changed, 13 insertions(+)
diff --git a/arch/um/include/linux/time-internal.h b/arch/um/include/linux/time-internal.h
index b22226634ff60..138908b999d76 100644
--- a/arch/um/include/linux/time-internal.h
+++ b/arch/um/include/linux/time-internal.h
@@ -83,6 +83,8 @@ extern void time_travel_not_configured(void);
#define time_travel_del_event(...) time_travel_not_configured()
#endif /* CONFIG_UML_TIME_TRAVEL_SUPPORT */
+extern unsigned long tt_extra_sched_jiffies;
+
/*
* Without CONFIG_UML_TIME_TRAVEL_SUPPORT this is a linker error if used,
* which is intentional since we really shouldn't link it in that case.
diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c
index b09e85279d2b8..a5beaea2967ec 100644
--- a/arch/um/kernel/skas/syscall.c
+++ b/arch/um/kernel/skas/syscall.c
@@ -31,6 +31,17 @@ void handle_syscall(struct uml_pt_regs *r)
goto out;
syscall = UPT_SYSCALL_NR(r);
+
+ /*
+ * If no time passes, then sched_yield may not actually yield, causing
+ * broken spinlock implementations in userspace (ASAN) to hang for long
+ * periods of time.
+ */
+ if ((time_travel_mode == TT_MODE_INFCPU ||
+ time_travel_mode == TT_MODE_EXTERNAL) &&
+ syscall == __NR_sched_yield)
+ tt_extra_sched_jiffies += 1;
+
if (syscall >= 0 && syscall < __NR_syscalls) {
unsigned long ret = EXECUTE_SYSCALL(syscall, regs);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 053/869] drm/i915/display: pass display to intel_crtc_for_pipe()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (51 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 052/869] um: work around sched_yield not yielding in time-travel mode Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 054/869] drm/i915/vga: Convert VGA code to intel_display Greg Kroah-Hartman
` (816 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ville Syrjälä, Jani Nikula,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <jani.nikula@intel.com>
[ Upstream commit 138d2bda4eafc40066d913222e90a443764dc535 ]
Convert the intel_crtc_for_pipe() struct drm_i915_private parameter to
struct intel_display.
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240904130633.3831492-1-jani.nikula@intel.com
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Stable-dep-of: dc3806d9eb66 ("drm/i915: Grab intel_display from the encoder to avoid potential oopsies")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/i915/display/i9xx_wm.c | 15 ++++++++++-----
.../gpu/drm/i915/display/intel_atomic_plane.c | 4 ++--
drivers/gpu/drm/i915/display/intel_cdclk.c | 6 ++++--
drivers/gpu/drm/i915/display/intel_crt.c | 3 ++-
drivers/gpu/drm/i915/display/intel_crtc.c | 7 ++++---
drivers/gpu/drm/i915/display/intel_crtc.h | 3 ++-
drivers/gpu/drm/i915/display/intel_display.c | 17 ++++++++++-------
.../gpu/drm/i915/display/intel_display_driver.c | 3 ++-
.../gpu/drm/i915/display/intel_display_irq.c | 9 ++++++---
.../gpu/drm/i915/display/intel_display_trace.h | 15 ++++++++++-----
drivers/gpu/drm/i915/display/intel_dpll.c | 3 ++-
drivers/gpu/drm/i915/display/intel_dsb.c | 2 +-
drivers/gpu/drm/i915/display/intel_fbc.c | 3 +--
drivers/gpu/drm/i915/display/intel_fdi.c | 10 ++++++----
.../gpu/drm/i915/display/intel_fifo_underrun.c | 15 ++++++++++-----
drivers/gpu/drm/i915/display/intel_link_bw.c | 3 +--
.../gpu/drm/i915/display/intel_modeset_setup.c | 12 ++++++++----
.../gpu/drm/i915/display/intel_sprite_uapi.c | 3 ++-
drivers/gpu/drm/i915/display/skl_watermark.c | 7 ++++---
19 files changed, 87 insertions(+), 53 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.c b/drivers/gpu/drm/i915/display/i9xx_wm.c
index 15cda57fbc912..9535e92dcbf48 100644
--- a/drivers/gpu/drm/i915/display/i9xx_wm.c
+++ b/drivers/gpu/drm/i915/display/i9xx_wm.c
@@ -715,10 +715,11 @@ static unsigned int g4x_tlb_miss_wa(int fifo_size, int width, int cpp)
static void g4x_write_wm_values(struct drm_i915_private *dev_priv,
const struct g4x_wm_values *wm)
{
+ struct intel_display *display = &dev_priv->display;
enum pipe pipe;
for_each_pipe(dev_priv, pipe)
- trace_g4x_wm(intel_crtc_for_pipe(dev_priv, pipe), wm);
+ trace_g4x_wm(intel_crtc_for_pipe(display, pipe), wm);
intel_uncore_write(&dev_priv->uncore, DSPFW1(dev_priv),
FW_WM(wm->sr.plane, SR) |
@@ -747,10 +748,11 @@ static void g4x_write_wm_values(struct drm_i915_private *dev_priv,
static void vlv_write_wm_values(struct drm_i915_private *dev_priv,
const struct vlv_wm_values *wm)
{
+ struct intel_display *display = &dev_priv->display;
enum pipe pipe;
for_each_pipe(dev_priv, pipe) {
- trace_vlv_wm(intel_crtc_for_pipe(dev_priv, pipe), wm);
+ trace_vlv_wm(intel_crtc_for_pipe(display, pipe), wm);
intel_uncore_write(&dev_priv->uncore, VLV_DDL(pipe),
(wm->ddl[pipe].plane[PLANE_CURSOR] << DDL_CURSOR_SHIFT) |
@@ -2088,12 +2090,13 @@ static void i965_update_wm(struct drm_i915_private *dev_priv)
static struct intel_crtc *intel_crtc_for_plane(struct drm_i915_private *i915,
enum i9xx_plane_id i9xx_plane)
{
+ struct intel_display *display = &i915->display;
struct intel_plane *plane;
for_each_intel_plane(&i915->drm, plane) {
if (plane->id == PLANE_PRIMARY &&
plane->i9xx_plane == i9xx_plane)
- return intel_crtc_for_pipe(i915, plane->pipe);
+ return intel_crtc_for_pipe(display, plane->pipe);
}
return NULL;
@@ -3716,6 +3719,7 @@ static void g4x_wm_get_hw_state(struct drm_i915_private *dev_priv)
static void g4x_wm_sanitize(struct drm_i915_private *dev_priv)
{
+ struct intel_display *display = &dev_priv->display;
struct intel_plane *plane;
struct intel_crtc *crtc;
@@ -3723,7 +3727,7 @@ static void g4x_wm_sanitize(struct drm_i915_private *dev_priv)
for_each_intel_plane(&dev_priv->drm, plane) {
struct intel_crtc *crtc =
- intel_crtc_for_pipe(dev_priv, plane->pipe);
+ intel_crtc_for_pipe(display, plane->pipe);
struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
struct intel_plane_state *plane_state =
@@ -3871,6 +3875,7 @@ static void vlv_wm_get_hw_state(struct drm_i915_private *dev_priv)
static void vlv_wm_sanitize(struct drm_i915_private *dev_priv)
{
+ struct intel_display *display = &dev_priv->display;
struct intel_plane *plane;
struct intel_crtc *crtc;
@@ -3878,7 +3883,7 @@ static void vlv_wm_sanitize(struct drm_i915_private *dev_priv)
for_each_intel_plane(&dev_priv->drm, plane) {
struct intel_crtc *crtc =
- intel_crtc_for_pipe(dev_priv, plane->pipe);
+ intel_crtc_for_pipe(display, plane->pipe);
struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
struct intel_plane_state *plane_state =
diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
index 5c2a7987cccb4..186735b469c5c 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
@@ -710,13 +710,13 @@ intel_crtc_get_plane(struct intel_crtc *crtc, enum plane_id plane_id)
int intel_plane_atomic_check(struct intel_atomic_state *state,
struct intel_plane *plane)
{
- struct drm_i915_private *i915 = to_i915(state->base.dev);
+ struct intel_display *display = to_intel_display(state);
struct intel_plane_state *new_plane_state =
intel_atomic_get_new_plane_state(state, plane);
const struct intel_plane_state *old_plane_state =
intel_atomic_get_old_plane_state(state, plane);
const struct intel_plane_state *new_primary_crtc_plane_state;
- struct intel_crtc *crtc = intel_crtc_for_pipe(i915, plane->pipe);
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, plane->pipe);
const struct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc);
struct intel_crtc_state *new_crtc_state =
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
index aa3ba66c5307f..51cd5375145f1 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -2038,6 +2038,7 @@ static void _bxt_set_cdclk(struct drm_i915_private *dev_priv,
const struct intel_cdclk_config *cdclk_config,
enum pipe pipe)
{
+ struct intel_display *display = &dev_priv->display;
int cdclk = cdclk_config->cdclk;
int vco = cdclk_config->vco;
@@ -2063,7 +2064,7 @@ static void _bxt_set_cdclk(struct drm_i915_private *dev_priv,
intel_de_write(dev_priv, CDCLK_CTL, bxt_cdclk_ctl(dev_priv, cdclk_config, pipe));
if (pipe != INVALID_PIPE)
- intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(dev_priv, pipe));
+ intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(display, pipe));
}
static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
@@ -3262,6 +3263,7 @@ static bool intel_cdclk_need_serialize(struct drm_i915_private *i915,
int intel_modeset_calc_cdclk(struct intel_atomic_state *state)
{
+ struct intel_display *display = to_intel_display(state);
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
const struct intel_cdclk_state *old_cdclk_state;
struct intel_cdclk_state *new_cdclk_state;
@@ -3308,7 +3310,7 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state)
struct intel_crtc_state *crtc_state;
pipe = ilog2(new_cdclk_state->active_pipes);
- crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ crtc = intel_crtc_for_pipe(display, pipe);
crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
if (IS_ERR(crtc_state))
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index 835c8b8444946..fd78adbaadbe8 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -694,6 +694,7 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
static enum drm_connector_status
intel_crt_load_detect(struct intel_crt *crt, enum pipe pipe)
{
+ struct intel_display *display = to_intel_display(&crt->base);
struct drm_device *dev = crt->base.base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
enum transcoder cpu_transcoder = (enum transcoder)pipe;
@@ -734,7 +735,7 @@ intel_crt_load_detect(struct intel_crt *crt, enum pipe pipe)
TRANSCONF(dev_priv, cpu_transcoder));
/* Wait for next Vblank to substitue
* border color for Color info */
- intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(dev_priv, pipe));
+ intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(display, pipe));
st00 = intel_de_read8(dev_priv, _VGA_MSR_WRITE);
status = ((st00 & (1 << 4)) != 0) ?
connector_status_connected :
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
index 1b578cad28134..12842bd37aa7f 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -48,12 +48,12 @@ struct intel_crtc *intel_first_crtc(struct drm_i915_private *i915)
return to_intel_crtc(drm_crtc_from_index(&i915->drm, 0));
}
-struct intel_crtc *intel_crtc_for_pipe(struct drm_i915_private *i915,
+struct intel_crtc *intel_crtc_for_pipe(struct intel_display *display,
enum pipe pipe)
{
struct intel_crtc *crtc;
- for_each_intel_crtc(&i915->drm, crtc) {
+ for_each_intel_crtc(display->drm, crtc) {
if (crtc->pipe == pipe)
return crtc;
}
@@ -69,7 +69,8 @@ void intel_crtc_wait_for_next_vblank(struct intel_crtc *crtc)
void intel_wait_for_vblank_if_active(struct drm_i915_private *i915,
enum pipe pipe)
{
- struct intel_crtc *crtc = intel_crtc_for_pipe(i915, pipe);
+ struct intel_display *display = &i915->display;
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
if (crtc->active)
intel_crtc_wait_for_next_vblank(crtc);
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.h b/drivers/gpu/drm/i915/display/intel_crtc.h
index b615b7ab5ccd7..0de8c772df2ee 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.h
+++ b/drivers/gpu/drm/i915/display/intel_crtc.h
@@ -15,6 +15,7 @@ struct drm_i915_private;
struct intel_atomic_state;
struct intel_crtc;
struct intel_crtc_state;
+struct intel_display;
/*
* FIXME: We should instead only take spinlocks once for the entire update
@@ -43,7 +44,7 @@ void intel_pipe_update_end(struct intel_atomic_state *state,
struct intel_crtc *crtc);
void intel_wait_for_vblank_workers(struct intel_atomic_state *state);
struct intel_crtc *intel_first_crtc(struct drm_i915_private *i915);
-struct intel_crtc *intel_crtc_for_pipe(struct drm_i915_private *i915,
+struct intel_crtc *intel_crtc_for_pipe(struct intel_display *display,
enum pipe pipe);
void intel_wait_for_vblank_if_active(struct drm_i915_private *i915,
enum pipe pipe);
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 2b4552cd1eedf..4a81e4563e924 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -292,10 +292,10 @@ u8 intel_crtc_joined_pipe_mask(const struct intel_crtc_state *crtc_state)
struct intel_crtc *intel_primary_crtc(const struct intel_crtc_state *crtc_state)
{
- struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+ struct intel_display *display = to_intel_display(crtc_state);
if (intel_crtc_is_joiner_secondary(crtc_state))
- return intel_crtc_for_pipe(i915, joiner_primary_pipe(crtc_state));
+ return intel_crtc_for_pipe(display, joiner_primary_pipe(crtc_state));
else
return to_intel_crtc(crtc_state->uapi.crtc);
}
@@ -1668,6 +1668,7 @@ static void hsw_configure_cpu_transcoder(const struct intel_crtc_state *crtc_sta
static void hsw_crtc_enable(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
+ struct intel_display *display = to_intel_display(state);
const struct intel_crtc_state *new_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@@ -1762,7 +1763,7 @@ static void hsw_crtc_enable(struct intel_atomic_state *state,
hsw_workaround_pipe = pipe_crtc_state->hsw_workaround_pipe;
if (IS_HASWELL(dev_priv) && hsw_workaround_pipe != INVALID_PIPE) {
struct intel_crtc *wa_crtc =
- intel_crtc_for_pipe(dev_priv, hsw_workaround_pipe);
+ intel_crtc_for_pipe(display, hsw_workaround_pipe);
intel_crtc_wait_for_next_vblank(wa_crtc);
intel_crtc_wait_for_next_vblank(wa_crtc);
@@ -3966,7 +3967,7 @@ int intel_crtc_dotclock(const struct intel_crtc_state *pipe_config)
struct drm_display_mode *
intel_encoder_current_mode(struct intel_encoder *encoder)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct intel_display *display = to_intel_display(encoder);
struct intel_crtc_state *crtc_state;
struct drm_display_mode *mode;
struct intel_crtc *crtc;
@@ -3975,7 +3976,7 @@ intel_encoder_current_mode(struct intel_encoder *encoder)
if (!encoder->get_hw_state(encoder, &pipe))
return NULL;
- crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ crtc = intel_crtc_for_pipe(display, pipe);
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
if (!mode)
@@ -8260,7 +8261,8 @@ int intel_initial_commit(struct drm_device *dev)
void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
{
- struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ struct intel_display *display = &dev_priv->display;
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
enum transcoder cpu_transcoder = (enum transcoder)pipe;
/* 640x480@60Hz, ~25175 kHz */
struct dpll clock = {
@@ -8341,7 +8343,8 @@ void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
{
- struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ struct intel_display *display = &dev_priv->display;
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
drm_dbg_kms(&dev_priv->drm, "disabling pipe %c due to force quirk\n",
pipe_name(pipe));
diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c
index 069426d9260b1..e7670774ecd08 100644
--- a/drivers/gpu/drm/i915/display/intel_display_driver.c
+++ b/drivers/gpu/drm/i915/display/intel_display_driver.c
@@ -168,10 +168,11 @@ static void intel_mode_config_cleanup(struct drm_i915_private *i915)
static void intel_plane_possible_crtcs_init(struct drm_i915_private *dev_priv)
{
+ struct intel_display *display = &dev_priv->display;
struct intel_plane *plane;
for_each_intel_plane(&dev_priv->drm, plane) {
- struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv,
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display,
plane->pipe);
plane->base.possible_crtcs = drm_crtc_mask(&crtc->base);
diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c
index 73369847ed66f..179ed72037e71 100644
--- a/drivers/gpu/drm/i915/display/intel_display_irq.c
+++ b/drivers/gpu/drm/i915/display/intel_display_irq.c
@@ -27,7 +27,8 @@
static void
intel_handle_vblank(struct drm_i915_private *dev_priv, enum pipe pipe)
{
- struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ struct intel_display *display = &dev_priv->display;
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
drm_crtc_handle_vblank(&crtc->base);
}
@@ -305,7 +306,8 @@ static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
u32 crc2, u32 crc3,
u32 crc4)
{
- struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ struct intel_display *display = &dev_priv->display;
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
struct intel_pipe_crc *pipe_crc = &crtc->pipe_crc;
u32 crcs[5] = { crc0, crc1, crc2, crc3, crc4 };
@@ -344,7 +346,8 @@ display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
static void flip_done_handler(struct drm_i915_private *i915,
enum pipe pipe)
{
- struct intel_crtc *crtc = intel_crtc_for_pipe(i915, pipe);
+ struct intel_display *display = &i915->display;
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
spin_lock(&i915->drm.event_lock);
diff --git a/drivers/gpu/drm/i915/display/intel_display_trace.h b/drivers/gpu/drm/i915/display/intel_display_trace.h
index c734ef1fba3c8..7176eefaf5050 100644
--- a/drivers/gpu/drm/i915/display/intel_display_trace.h
+++ b/drivers/gpu/drm/i915/display/intel_display_trace.h
@@ -141,7 +141,8 @@ TRACE_EVENT(intel_cpu_fifo_underrun,
),
TP_fast_assign(
- struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ struct intel_display *display = &dev_priv->display;
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
__assign_str(dev);
__entry->pipe = pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
@@ -165,8 +166,9 @@ TRACE_EVENT(intel_pch_fifo_underrun,
),
TP_fast_assign(
+ struct intel_display *display = &dev_priv->display;
enum pipe pipe = pch_transcoder;
- struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
__assign_str(dev);
__entry->pipe = pipe;
__entry->frame = intel_crtc_get_vblank_counter(crtc);
@@ -458,7 +460,8 @@ TRACE_EVENT(intel_fbc_activate,
),
TP_fast_assign(
- struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev),
+ struct intel_display *display = to_intel_display(plane->base.dev);
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display,
plane->pipe);
__assign_str(dev);
__assign_str(name);
@@ -485,7 +488,8 @@ TRACE_EVENT(intel_fbc_deactivate,
),
TP_fast_assign(
- struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev),
+ struct intel_display *display = to_intel_display(plane->base.dev);
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display,
plane->pipe);
__assign_str(dev);
__assign_str(name);
@@ -512,7 +516,8 @@ TRACE_EVENT(intel_fbc_nuke,
),
TP_fast_assign(
- struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev),
+ struct intel_display *display = to_intel_display(plane->base.dev);
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display,
plane->pipe);
__assign_str(dev);
__assign_str(name);
diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c
index 340dfce480b83..bc72d1c0cb414 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll.c
@@ -2212,7 +2212,8 @@ void chv_enable_pll(const struct intel_crtc_state *crtc_state)
int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe,
const struct dpll *dpll)
{
- struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ struct intel_display *display = &dev_priv->display;
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
struct intel_crtc_state *crtc_state;
crtc_state = intel_crtc_state_alloc(crtc);
diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c
index da24e041d2699..c39bae1be89e3 100644
--- a/drivers/gpu/drm/i915/display/intel_dsb.c
+++ b/drivers/gpu/drm/i915/display/intel_dsb.c
@@ -763,7 +763,7 @@ void intel_dsb_cleanup(struct intel_dsb *dsb)
void intel_dsb_irq_handler(struct intel_display *display,
enum pipe pipe, enum intel_dsb_id dsb_id)
{
- struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(display->drm), pipe);
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
u32 tmp, errors;
tmp = intel_de_read_fw(display, DSB_INTERRUPT(pipe, dsb_id));
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c
index 52b79bacef4d3..7cb1a9cfa20f4 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.c
+++ b/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -1792,7 +1792,6 @@ static void intel_fbc_underrun_work_fn(struct work_struct *work)
{
struct intel_fbc *fbc = container_of(work, typeof(*fbc), underrun_work);
struct intel_display *display = fbc->display;
- struct drm_i915_private *i915 = to_i915(display->drm);
mutex_lock(&fbc->lock);
@@ -1805,7 +1804,7 @@ static void intel_fbc_underrun_work_fn(struct work_struct *work)
intel_fbc_deactivate(fbc, "FIFO underrun");
if (!fbc->flip_pending)
- intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(i915, fbc->state.plane->pipe));
+ intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(display, fbc->state.plane->pipe));
__intel_fbc_disable(fbc);
out:
mutex_unlock(&fbc->lock);
diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c
index 222cd0e1a2bc8..0168894e9cd1b 100644
--- a/drivers/gpu/drm/i915/display/intel_fdi.c
+++ b/drivers/gpu/drm/i915/display/intel_fdi.c
@@ -137,6 +137,7 @@ void intel_fdi_link_train(struct intel_crtc *crtc,
*/
int intel_fdi_add_affected_crtcs(struct intel_atomic_state *state)
{
+ struct intel_display *display = to_intel_display(state);
struct drm_i915_private *i915 = to_i915(state->base.dev);
const struct intel_crtc_state *old_crtc_state;
const struct intel_crtc_state *new_crtc_state;
@@ -145,7 +146,7 @@ int intel_fdi_add_affected_crtcs(struct intel_atomic_state *state)
if (!IS_IVYBRIDGE(i915) || INTEL_NUM_PIPES(i915) != 3)
return 0;
- crtc = intel_crtc_for_pipe(i915, PIPE_C);
+ crtc = intel_crtc_for_pipe(display, PIPE_C);
new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
if (!new_crtc_state)
return 0;
@@ -157,7 +158,7 @@ int intel_fdi_add_affected_crtcs(struct intel_atomic_state *state)
if (!old_crtc_state->fdi_lanes)
return 0;
- crtc = intel_crtc_for_pipe(i915, PIPE_B);
+ crtc = intel_crtc_for_pipe(display, PIPE_B);
new_crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
if (IS_ERR(new_crtc_state))
return PTR_ERR(new_crtc_state);
@@ -184,6 +185,7 @@ static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
struct intel_crtc_state *pipe_config,
enum pipe *pipe_to_reduce)
{
+ struct intel_display *display = to_intel_display(dev);
struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_atomic_state *state = pipe_config->uapi.state;
struct intel_crtc *other_crtc;
@@ -223,7 +225,7 @@ static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
if (pipe_config->fdi_lanes <= 2)
return 0;
- other_crtc = intel_crtc_for_pipe(dev_priv, PIPE_C);
+ other_crtc = intel_crtc_for_pipe(display, PIPE_C);
other_crtc_state =
intel_atomic_get_crtc_state(state, other_crtc);
if (IS_ERR(other_crtc_state))
@@ -244,7 +246,7 @@ static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
return -EINVAL;
}
- other_crtc = intel_crtc_for_pipe(dev_priv, PIPE_B);
+ other_crtc = intel_crtc_for_pipe(display, PIPE_B);
other_crtc_state =
intel_atomic_get_crtc_state(state, other_crtc);
if (IS_ERR(other_crtc_state))
diff --git a/drivers/gpu/drm/i915/display/intel_fifo_underrun.c b/drivers/gpu/drm/i915/display/intel_fifo_underrun.c
index 8949fbb1cc60c..4ffbaf44c21b9 100644
--- a/drivers/gpu/drm/i915/display/intel_fifo_underrun.c
+++ b/drivers/gpu/drm/i915/display/intel_fifo_underrun.c
@@ -57,6 +57,7 @@
static bool ivb_can_enable_err_int(struct drm_device *dev)
{
+ struct intel_display *display = to_intel_display(dev);
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_crtc *crtc;
enum pipe pipe;
@@ -64,7 +65,7 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
lockdep_assert_held(&dev_priv->irq_lock);
for_each_pipe(dev_priv, pipe) {
- crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ crtc = intel_crtc_for_pipe(display, pipe);
if (crtc->cpu_fifo_underrun_disabled)
return false;
@@ -75,6 +76,7 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
static bool cpt_can_enable_serr_int(struct drm_device *dev)
{
+ struct intel_display *display = to_intel_display(dev);
struct drm_i915_private *dev_priv = to_i915(dev);
enum pipe pipe;
struct intel_crtc *crtc;
@@ -82,7 +84,7 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
lockdep_assert_held(&dev_priv->irq_lock);
for_each_pipe(dev_priv, pipe) {
- crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ crtc = intel_crtc_for_pipe(display, pipe);
if (crtc->pch_fifo_underrun_disabled)
return false;
@@ -282,8 +284,9 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
enum pipe pipe, bool enable)
{
+ struct intel_display *display = to_intel_display(dev);
struct drm_i915_private *dev_priv = to_i915(dev);
- struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
bool old;
lockdep_assert_held(&dev_priv->irq_lock);
@@ -351,8 +354,9 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
enum pipe pch_transcoder,
bool enable)
{
+ struct intel_display *display = &dev_priv->display;
struct intel_crtc *crtc =
- intel_crtc_for_pipe(dev_priv, pch_transcoder);
+ intel_crtc_for_pipe(display, pch_transcoder);
unsigned long flags;
bool old;
@@ -395,7 +399,8 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
- struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe);
+ struct intel_display *display = &dev_priv->display;
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
u32 underruns = 0;
/* We may be called too early in init, thanks BIOS! */
diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.c b/drivers/gpu/drm/i915/display/intel_link_bw.c
index e7a9b860fac6e..c87cd1d16d0a2 100644
--- a/drivers/gpu/drm/i915/display/intel_link_bw.c
+++ b/drivers/gpu/drm/i915/display/intel_link_bw.c
@@ -26,7 +26,6 @@ void intel_link_bw_init_limits(struct intel_atomic_state *state,
struct intel_link_bw_limits *limits)
{
struct intel_display *display = to_intel_display(state);
- struct drm_i915_private *i915 = to_i915(state->base.dev);
enum pipe pipe;
limits->force_fec_pipes = 0;
@@ -34,7 +33,7 @@ void intel_link_bw_init_limits(struct intel_atomic_state *state,
for_each_pipe(display, pipe) {
const struct intel_crtc_state *crtc_state =
intel_atomic_get_new_crtc_state(state,
- intel_crtc_for_pipe(i915, pipe));
+ intel_crtc_for_pipe(display, pipe));
if (state->base.duplicated && crtc_state) {
limits->max_bpp_x16[pipe] = crtc_state->max_link_bpp_x16;
diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c
index 72694dde3c225..fe6a90d78e78c 100644
--- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c
+++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c
@@ -221,6 +221,7 @@ static u8 get_transcoder_pipes(struct drm_i915_private *i915,
static void get_portsync_pipes(struct intel_crtc *crtc,
u8 *master_pipe_mask, u8 *slave_pipes_mask)
{
+ struct intel_display *display = to_intel_display(crtc);
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
struct intel_crtc_state *crtc_state =
to_intel_crtc_state(crtc->base.state);
@@ -243,7 +244,7 @@ static void get_portsync_pipes(struct intel_crtc *crtc,
*master_pipe_mask = get_transcoder_pipes(i915, BIT(master_transcoder));
drm_WARN_ON(&i915->drm, !is_power_of_2(*master_pipe_mask));
- master_crtc = intel_crtc_for_pipe(i915, ffs(*master_pipe_mask) - 1);
+ master_crtc = intel_crtc_for_pipe(display, ffs(*master_pipe_mask) - 1);
master_crtc_state = to_intel_crtc_state(master_crtc->base.state);
*slave_pipes_mask = get_transcoder_pipes(i915, master_crtc_state->sync_mode_slaves_mask);
}
@@ -375,6 +376,7 @@ static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state
static void
intel_sanitize_plane_mapping(struct drm_i915_private *i915)
{
+ struct intel_display *display = &i915->display;
struct intel_crtc *crtc;
if (DISPLAY_VER(i915) >= 4)
@@ -396,7 +398,7 @@ intel_sanitize_plane_mapping(struct drm_i915_private *i915)
"[PLANE:%d:%s] attached to the wrong pipe, disabling plane\n",
plane->base.base.id, plane->base.name);
- plane_crtc = intel_crtc_for_pipe(i915, pipe);
+ plane_crtc = intel_crtc_for_pipe(display, pipe);
intel_plane_disable_noatomic(plane_crtc, plane);
}
}
@@ -662,6 +664,7 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
/* FIXME read out full plane state for all planes */
static void readout_plane_state(struct drm_i915_private *i915)
{
+ struct intel_display *display = &i915->display;
struct intel_plane *plane;
struct intel_crtc *crtc;
@@ -674,7 +677,7 @@ static void readout_plane_state(struct drm_i915_private *i915)
visible = plane->get_hw_state(plane, &pipe);
- crtc = intel_crtc_for_pipe(i915, pipe);
+ crtc = intel_crtc_for_pipe(display, pipe);
crtc_state = to_intel_crtc_state(crtc->base.state);
intel_set_plane_visible(crtc_state, plane_state, visible);
@@ -695,6 +698,7 @@ static void readout_plane_state(struct drm_i915_private *i915)
static void intel_modeset_readout_hw_state(struct drm_i915_private *i915)
{
+ struct intel_display *display = &i915->display;
struct intel_cdclk_state *cdclk_state =
to_intel_cdclk_state(i915->display.cdclk.obj.state);
struct intel_dbuf_state *dbuf_state =
@@ -743,7 +747,7 @@ static void intel_modeset_readout_hw_state(struct drm_i915_private *i915)
pipe = 0;
if (encoder->get_hw_state(encoder, &pipe)) {
- crtc = intel_crtc_for_pipe(i915, pipe);
+ crtc = intel_crtc_for_pipe(display, pipe);
crtc_state = to_intel_crtc_state(crtc->base.state);
encoder->base.crtc = &crtc->base;
diff --git a/drivers/gpu/drm/i915/display/intel_sprite_uapi.c b/drivers/gpu/drm/i915/display/intel_sprite_uapi.c
index 4853c48060042..1d0b84b464c14 100644
--- a/drivers/gpu/drm/i915/display/intel_sprite_uapi.c
+++ b/drivers/gpu/drm/i915/display/intel_sprite_uapi.c
@@ -42,6 +42,7 @@ static void intel_plane_set_ckey(struct intel_plane_state *plane_state,
int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
+ struct intel_display *display = to_intel_display(dev);
struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_intel_sprite_colorkey *set = data;
struct drm_plane *plane;
@@ -100,7 +101,7 @@ int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data,
*/
if (!ret && has_dst_key_in_primary_plane(dev_priv)) {
struct intel_crtc *crtc =
- intel_crtc_for_pipe(dev_priv,
+ intel_crtc_for_pipe(display,
to_intel_plane(plane)->pipe);
plane_state = drm_atomic_get_plane_state(state,
diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c
index 0c868be53f2f9..34068a4d915b6 100644
--- a/drivers/gpu/drm/i915/display/skl_watermark.c
+++ b/drivers/gpu/drm/i915/display/skl_watermark.c
@@ -3388,6 +3388,7 @@ static void intel_dbuf_mdclk_min_tracker_update(struct intel_atomic_state *state
static enum pipe intel_mbus_joined_pipe(struct intel_atomic_state *state,
const struct intel_dbuf_state *dbuf_state)
{
+ struct intel_display *display = to_intel_display(state);
struct drm_i915_private *i915 = to_i915(state->base.dev);
enum pipe pipe = ffs(dbuf_state->active_pipes) - 1;
const struct intel_crtc_state *new_crtc_state;
@@ -3396,7 +3397,7 @@ static enum pipe intel_mbus_joined_pipe(struct intel_atomic_state *state,
drm_WARN_ON(&i915->drm, !dbuf_state->joined_mbus);
drm_WARN_ON(&i915->drm, !is_power_of_2(dbuf_state->active_pipes));
- crtc = intel_crtc_for_pipe(i915, pipe);
+ crtc = intel_crtc_for_pipe(display, pipe);
new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
if (new_crtc_state && !intel_crtc_needs_modeset(new_crtc_state))
@@ -3458,7 +3459,7 @@ void intel_dbuf_mbus_pre_ddb_update(struct intel_atomic_state *state)
void intel_dbuf_mbus_post_ddb_update(struct intel_atomic_state *state)
{
- struct drm_i915_private *i915 = to_i915(state->base.dev);
+ struct intel_display *display = to_intel_display(state);
const struct intel_dbuf_state *new_dbuf_state =
intel_atomic_get_new_dbuf_state(state);
const struct intel_dbuf_state *old_dbuf_state =
@@ -3477,7 +3478,7 @@ void intel_dbuf_mbus_post_ddb_update(struct intel_atomic_state *state)
intel_dbuf_mbus_join_update(state, pipe);
if (pipe != INVALID_PIPE) {
- struct intel_crtc *crtc = intel_crtc_for_pipe(i915, pipe);
+ struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
intel_crtc_wait_for_next_vblank(crtc);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 054/869] drm/i915/vga: Convert VGA code to intel_display
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (52 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 053/869] drm/i915/display: pass display to intel_crtc_for_pipe() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 055/869] drm/i915/display: convert I915_STATE_WARN() to struct intel_display Greg Kroah-Hartman
` (815 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ville Syrjälä,
Rodrigo Vivi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
[ Upstream commit 4b6e05c43b7542e9baaf70a0064b9198fe495fd2 ]
struct intel_display will replace struct drm_i915_private as
the main thing for display code. Convert the VGA code to
use it (as much as possible at this stage).
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240906143306.15937-5-ville.syrjala@linux.intel.com
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Stable-dep-of: dc3806d9eb66 ("drm/i915: Grab intel_display from the encoder to avoid potential oopsies")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../drm/i915/display/intel_display_driver.c | 11 ++---
.../i915/display/intel_display_power_well.c | 6 ++-
drivers/gpu/drm/i915/display/intel_vga.c | 45 ++++++++++---------
drivers/gpu/drm/i915/display/intel_vga.h | 14 +++---
drivers/gpu/drm/i915/i915_suspend.c | 3 +-
5 files changed, 43 insertions(+), 36 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c
index e7670774ecd08..c189ce08a950a 100644
--- a/drivers/gpu/drm/i915/display/intel_display_driver.c
+++ b/drivers/gpu/drm/i915/display/intel_display_driver.c
@@ -220,7 +220,7 @@ int intel_display_driver_probe_noirq(struct drm_i915_private *i915)
intel_bios_init(display);
- ret = intel_vga_register(i915);
+ ret = intel_vga_register(display);
if (ret)
goto cleanup_bios;
@@ -274,7 +274,7 @@ int intel_display_driver_probe_noirq(struct drm_i915_private *i915)
intel_dmc_fini(i915);
intel_power_domains_driver_remove(i915);
cleanup_vga:
- intel_vga_unregister(i915);
+ intel_vga_unregister(display);
cleanup_bios:
intel_bios_driver_remove(display);
@@ -457,7 +457,7 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915)
intel_hti_init(display);
/* Just disable it once at startup */
- intel_vga_disable(i915);
+ intel_vga_disable(display);
intel_setup_outputs(i915);
ret = intel_dp_tunnel_mgr_init(display);
@@ -624,7 +624,7 @@ void intel_display_driver_remove_nogem(struct drm_i915_private *i915)
intel_power_domains_driver_remove(i915);
- intel_vga_unregister(i915);
+ intel_vga_unregister(display);
intel_bios_driver_remove(display);
}
@@ -682,12 +682,13 @@ __intel_display_driver_resume(struct drm_i915_private *i915,
struct drm_atomic_state *state,
struct drm_modeset_acquire_ctx *ctx)
{
+ struct intel_display *display = &i915->display;
struct drm_crtc_state *crtc_state;
struct drm_crtc *crtc;
int ret, i;
intel_modeset_setup_hw_state(i915, ctx);
- intel_vga_redisable(i915);
+ intel_vga_redisable(display);
if (!state)
return 0;
diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c
index 46e9eff12c234..3c1a211e7b96d 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power_well.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c
@@ -187,8 +187,10 @@ int intel_power_well_refcount(struct i915_power_well *power_well)
static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv,
u8 irq_pipe_mask, bool has_vga)
{
+ struct intel_display *display = &dev_priv->display;
+
if (has_vga)
- intel_vga_reset_io_mem(dev_priv);
+ intel_vga_reset_io_mem(display);
if (irq_pipe_mask)
gen8_irq_power_well_post_enable(dev_priv, irq_pipe_mask);
@@ -1232,7 +1234,7 @@ static void vlv_display_power_well_init(struct drm_i915_private *dev_priv)
intel_crt_reset(&encoder->base);
}
- intel_vga_redisable_power_on(dev_priv);
+ intel_vga_redisable_power_on(display);
intel_pps_unlock_regs_wa(display);
}
diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c
index 0b5916c15307e..2c76a0176a357 100644
--- a/drivers/gpu/drm/i915/display/intel_vga.c
+++ b/drivers/gpu/drm/i915/display/intel_vga.c
@@ -14,24 +14,26 @@
#include "intel_de.h"
#include "intel_vga.h"
-static i915_reg_t intel_vga_cntrl_reg(struct drm_i915_private *i915)
+static i915_reg_t intel_vga_cntrl_reg(struct intel_display *display)
{
+ struct drm_i915_private *i915 = to_i915(display->drm);
+
if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
return VLV_VGACNTRL;
- else if (DISPLAY_VER(i915) >= 5)
+ else if (DISPLAY_VER(display) >= 5)
return CPU_VGACNTRL;
else
return VGACNTRL;
}
/* Disable the VGA plane that we never use */
-void intel_vga_disable(struct drm_i915_private *dev_priv)
+void intel_vga_disable(struct intel_display *display)
{
- struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
- i915_reg_t vga_reg = intel_vga_cntrl_reg(dev_priv);
+ struct pci_dev *pdev = to_pci_dev(display->drm->dev);
+ i915_reg_t vga_reg = intel_vga_cntrl_reg(display);
u8 sr1;
- if (intel_de_read(dev_priv, vga_reg) & VGA_DISP_DISABLE)
+ if (intel_de_read(display, vga_reg) & VGA_DISP_DISABLE)
return;
/* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */
@@ -42,23 +44,24 @@ void intel_vga_disable(struct drm_i915_private *dev_priv)
vga_put(pdev, VGA_RSRC_LEGACY_IO);
udelay(300);
- intel_de_write(dev_priv, vga_reg, VGA_DISP_DISABLE);
- intel_de_posting_read(dev_priv, vga_reg);
+ intel_de_write(display, vga_reg, VGA_DISP_DISABLE);
+ intel_de_posting_read(display, vga_reg);
}
-void intel_vga_redisable_power_on(struct drm_i915_private *dev_priv)
+void intel_vga_redisable_power_on(struct intel_display *display)
{
- i915_reg_t vga_reg = intel_vga_cntrl_reg(dev_priv);
+ i915_reg_t vga_reg = intel_vga_cntrl_reg(display);
- if (!(intel_de_read(dev_priv, vga_reg) & VGA_DISP_DISABLE)) {
- drm_dbg_kms(&dev_priv->drm,
+ if (!(intel_de_read(display, vga_reg) & VGA_DISP_DISABLE)) {
+ drm_dbg_kms(display->drm,
"Something enabled VGA plane, disabling it\n");
- intel_vga_disable(dev_priv);
+ intel_vga_disable(display);
}
}
-void intel_vga_redisable(struct drm_i915_private *i915)
+void intel_vga_redisable(struct intel_display *display)
{
+ struct drm_i915_private *i915 = to_i915(display->drm);
intel_wakeref_t wakeref;
/*
@@ -74,14 +77,14 @@ void intel_vga_redisable(struct drm_i915_private *i915)
if (!wakeref)
return;
- intel_vga_redisable_power_on(i915);
+ intel_vga_redisable_power_on(display);
intel_display_power_put(i915, POWER_DOMAIN_VGA, wakeref);
}
-void intel_vga_reset_io_mem(struct drm_i915_private *i915)
+void intel_vga_reset_io_mem(struct intel_display *display)
{
- struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
+ struct pci_dev *pdev = to_pci_dev(display->drm->dev);
/*
* After we re-enable the power well, if we touch VGA register 0x3d5
@@ -98,10 +101,10 @@ void intel_vga_reset_io_mem(struct drm_i915_private *i915)
vga_put(pdev, VGA_RSRC_LEGACY_IO);
}
-int intel_vga_register(struct drm_i915_private *i915)
+int intel_vga_register(struct intel_display *display)
{
- struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
+ struct pci_dev *pdev = to_pci_dev(display->drm->dev);
int ret;
/*
@@ -119,9 +122,9 @@ int intel_vga_register(struct drm_i915_private *i915)
return 0;
}
-void intel_vga_unregister(struct drm_i915_private *i915)
+void intel_vga_unregister(struct intel_display *display)
{
- struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
+ struct pci_dev *pdev = to_pci_dev(display->drm->dev);
vga_client_unregister(pdev);
}
diff --git a/drivers/gpu/drm/i915/display/intel_vga.h b/drivers/gpu/drm/i915/display/intel_vga.h
index ba5b55b917f08..824dfc32a1992 100644
--- a/drivers/gpu/drm/i915/display/intel_vga.h
+++ b/drivers/gpu/drm/i915/display/intel_vga.h
@@ -6,13 +6,13 @@
#ifndef __INTEL_VGA_H__
#define __INTEL_VGA_H__
-struct drm_i915_private;
+struct intel_display;
-void intel_vga_reset_io_mem(struct drm_i915_private *i915);
-void intel_vga_disable(struct drm_i915_private *i915);
-void intel_vga_redisable(struct drm_i915_private *i915);
-void intel_vga_redisable_power_on(struct drm_i915_private *i915);
-int intel_vga_register(struct drm_i915_private *i915);
-void intel_vga_unregister(struct drm_i915_private *i915);
+void intel_vga_reset_io_mem(struct intel_display *display);
+void intel_vga_disable(struct intel_display *display);
+void intel_vga_redisable(struct intel_display *display);
+void intel_vga_redisable_power_on(struct intel_display *display);
+int intel_vga_register(struct intel_display *display);
+void intel_vga_unregister(struct intel_display *display);
#endif /* __INTEL_VGA_H__ */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index f8373a461f176..9d3d9b9830320 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -118,6 +118,7 @@ void i915_save_display(struct drm_i915_private *dev_priv)
void i915_restore_display(struct drm_i915_private *dev_priv)
{
+ struct intel_display *display = &dev_priv->display;
struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
if (!HAS_DISPLAY(dev_priv))
@@ -134,7 +135,7 @@ void i915_restore_display(struct drm_i915_private *dev_priv)
intel_de_write(dev_priv, DSPARB(dev_priv),
dev_priv->regfile.saveDSPARB);
- intel_vga_redisable(dev_priv);
+ intel_vga_redisable(display);
intel_gmbus_reset(dev_priv);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 055/869] drm/i915/display: convert I915_STATE_WARN() to struct intel_display
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (53 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 054/869] drm/i915/vga: Convert VGA code to intel_display Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 056/869] drm/i915/gmbus: convert " Greg Kroah-Hartman
` (814 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ville Syrjälä, Jani Nikula,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <jani.nikula@intel.com>
[ Upstream commit 0f4869b1636cddbb14826e148500dfa01f4088e0 ]
Convert I915_STATE_WARN() to struct intel_display *, and rename to
INTEL_DISPLAY_STATE_WARN(). Do some minor opportunistic struct
drm_i915_private to struct intel_display conversions while at it.
v2: crtc_state may be NULL in intel_connector_verify_state()
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241024162510.2410128-1-jani.nikula@intel.com
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Stable-dep-of: dc3806d9eb66 ("drm/i915: Grab intel_display from the encoder to avoid potential oopsies")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/i915/display/g4x_dp.c | 15 ++--
drivers/gpu/drm/i915/display/intel_crtc.c | 8 +-
drivers/gpu/drm/i915/display/intel_cx0_phy.c | 76 ++++++++--------
drivers/gpu/drm/i915/display/intel_display.c | 19 ++--
drivers/gpu/drm/i915/display/intel_display.h | 17 ++--
.../drm/i915/display/intel_display_power.c | 73 +++++++--------
drivers/gpu/drm/i915/display/intel_dpll.c | 9 +-
drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 90 ++++++++++---------
drivers/gpu/drm/i915/display/intel_fdi.c | 42 +++++----
.../drm/i915/display/intel_modeset_verify.c | 89 +++++++++---------
.../gpu/drm/i915/display/intel_pch_display.c | 56 ++++++------
drivers/gpu/drm/i915/display/intel_pps.c | 26 +++---
drivers/gpu/drm/i915/display/intel_snps_phy.c | 11 +--
drivers/gpu/drm/i915/display/vlv_dsi_pll.c | 7 +-
14 files changed, 277 insertions(+), 261 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index 9a5beb91dd4b6..724d24ef1c785 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -169,13 +169,12 @@ static void assert_dp_port(struct intel_dp *intel_dp, bool state)
{
struct intel_display *display = to_intel_display(intel_dp);
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
- struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
bool cur_state = intel_de_read(display, intel_dp->output_reg) & DP_PORT_EN;
- I915_STATE_WARN(dev_priv, cur_state != state,
- "[ENCODER:%d:%s] state assertion failure (expected %s, current %s)\n",
- dig_port->base.base.base.id, dig_port->base.base.name,
- str_on_off(state), str_on_off(cur_state));
+ INTEL_DISPLAY_STATE_WARN(display, cur_state != state,
+ "[ENCODER:%d:%s] state assertion failure (expected %s, current %s)\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ str_on_off(state), str_on_off(cur_state));
}
#define assert_dp_port_disabled(d) assert_dp_port((d), false)
@@ -184,9 +183,9 @@ static void assert_edp_pll(struct drm_i915_private *dev_priv, bool state)
struct intel_display *display = &dev_priv->display;
bool cur_state = intel_de_read(display, DP_A) & DP_PLL_ENABLE;
- I915_STATE_WARN(dev_priv, cur_state != state,
- "eDP PLL state assertion failure (expected %s, current %s)\n",
- str_on_off(state), str_on_off(cur_state));
+ INTEL_DISPLAY_STATE_WARN(display, cur_state != state,
+ "eDP PLL state assertion failure (expected %s, current %s)\n",
+ str_on_off(state), str_on_off(cur_state));
}
#define assert_edp_pll_enabled(d) assert_edp_pll((d), true)
#define assert_edp_pll_disabled(d) assert_edp_pll((d), false)
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
index 12842bd37aa7f..b2faa92a7ecc0 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -35,11 +35,11 @@
static void assert_vblank_disabled(struct drm_crtc *crtc)
{
- struct drm_i915_private *i915 = to_i915(crtc->dev);
+ struct intel_display *display = to_intel_display(crtc->dev);
- if (I915_STATE_WARN(i915, drm_crtc_vblank_get(crtc) == 0,
- "[CRTC:%d:%s] vblank assertion failure (expected off, current on)\n",
- crtc->base.id, crtc->name))
+ if (INTEL_DISPLAY_STATE_WARN(display, drm_crtc_vblank_get(crtc) == 0,
+ "[CRTC:%d:%s] vblank assertion failure (expected off, current on)\n",
+ crtc->base.id, crtc->name))
drm_crtc_vblank_put(crtc);
}
diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
index f11309efff339..c7baf4255c19b 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
@@ -3246,28 +3246,28 @@ static void intel_c10pll_state_verify(const struct intel_crtc_state *state,
struct intel_encoder *encoder,
struct intel_c10pll_state *mpllb_hw_state)
{
- struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ struct intel_display *display = to_intel_display(state);
const struct intel_c10pll_state *mpllb_sw_state = &state->dpll_hw_state.cx0pll.c10;
int i;
for (i = 0; i < ARRAY_SIZE(mpllb_sw_state->pll); i++) {
u8 expected = mpllb_sw_state->pll[i];
- I915_STATE_WARN(i915, mpllb_hw_state->pll[i] != expected,
- "[CRTC:%d:%s] mismatch in C10MPLLB: Register[%d] (expected 0x%02x, found 0x%02x)",
- crtc->base.base.id, crtc->base.name, i,
- expected, mpllb_hw_state->pll[i]);
+ INTEL_DISPLAY_STATE_WARN(display, mpllb_hw_state->pll[i] != expected,
+ "[CRTC:%d:%s] mismatch in C10MPLLB: Register[%d] (expected 0x%02x, found 0x%02x)",
+ crtc->base.base.id, crtc->base.name, i,
+ expected, mpllb_hw_state->pll[i]);
}
- I915_STATE_WARN(i915, mpllb_hw_state->tx != mpllb_sw_state->tx,
- "[CRTC:%d:%s] mismatch in C10MPLLB: Register TX0 (expected 0x%02x, found 0x%02x)",
- crtc->base.base.id, crtc->base.name,
- mpllb_sw_state->tx, mpllb_hw_state->tx);
+ INTEL_DISPLAY_STATE_WARN(display, mpllb_hw_state->tx != mpllb_sw_state->tx,
+ "[CRTC:%d:%s] mismatch in C10MPLLB: Register TX0 (expected 0x%02x, found 0x%02x)",
+ crtc->base.base.id, crtc->base.name,
+ mpllb_sw_state->tx, mpllb_hw_state->tx);
- I915_STATE_WARN(i915, mpllb_hw_state->cmn != mpllb_sw_state->cmn,
- "[CRTC:%d:%s] mismatch in C10MPLLB: Register CMN0 (expected 0x%02x, found 0x%02x)",
- crtc->base.base.id, crtc->base.name,
- mpllb_sw_state->cmn, mpllb_hw_state->cmn);
+ INTEL_DISPLAY_STATE_WARN(display, mpllb_hw_state->cmn != mpllb_sw_state->cmn,
+ "[CRTC:%d:%s] mismatch in C10MPLLB: Register CMN0 (expected 0x%02x, found 0x%02x)",
+ crtc->base.base.id, crtc->base.name,
+ mpllb_sw_state->cmn, mpllb_hw_state->cmn);
}
void intel_cx0pll_readout_hw_state(struct intel_encoder *encoder,
@@ -3353,51 +3353,51 @@ static void intel_c20pll_state_verify(const struct intel_crtc_state *state,
struct intel_encoder *encoder,
struct intel_c20pll_state *mpll_hw_state)
{
- struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ struct intel_display *display = to_intel_display(state);
const struct intel_c20pll_state *mpll_sw_state = &state->dpll_hw_state.cx0pll.c20;
bool sw_use_mpllb = intel_c20phy_use_mpllb(mpll_sw_state);
bool hw_use_mpllb = intel_c20phy_use_mpllb(mpll_hw_state);
int clock = intel_c20pll_calc_port_clock(encoder, mpll_sw_state);
int i;
- I915_STATE_WARN(i915, mpll_hw_state->clock != clock,
- "[CRTC:%d:%s] mismatch in C20: Register CLOCK (expected %d, found %d)",
- crtc->base.base.id, crtc->base.name,
- mpll_sw_state->clock, mpll_hw_state->clock);
+ INTEL_DISPLAY_STATE_WARN(display, mpll_hw_state->clock != clock,
+ "[CRTC:%d:%s] mismatch in C20: Register CLOCK (expected %d, found %d)",
+ crtc->base.base.id, crtc->base.name,
+ mpll_sw_state->clock, mpll_hw_state->clock);
- I915_STATE_WARN(i915, sw_use_mpllb != hw_use_mpllb,
- "[CRTC:%d:%s] mismatch in C20: Register MPLLB selection (expected %d, found %d)",
- crtc->base.base.id, crtc->base.name,
- sw_use_mpllb, hw_use_mpllb);
+ INTEL_DISPLAY_STATE_WARN(display, sw_use_mpllb != hw_use_mpllb,
+ "[CRTC:%d:%s] mismatch in C20: Register MPLLB selection (expected %d, found %d)",
+ crtc->base.base.id, crtc->base.name,
+ sw_use_mpllb, hw_use_mpllb);
if (hw_use_mpllb) {
for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mpllb); i++) {
- I915_STATE_WARN(i915, mpll_hw_state->mpllb[i] != mpll_sw_state->mpllb[i],
- "[CRTC:%d:%s] mismatch in C20MPLLB: Register[%d] (expected 0x%04x, found 0x%04x)",
- crtc->base.base.id, crtc->base.name, i,
- mpll_sw_state->mpllb[i], mpll_hw_state->mpllb[i]);
+ INTEL_DISPLAY_STATE_WARN(display, mpll_hw_state->mpllb[i] != mpll_sw_state->mpllb[i],
+ "[CRTC:%d:%s] mismatch in C20MPLLB: Register[%d] (expected 0x%04x, found 0x%04x)",
+ crtc->base.base.id, crtc->base.name, i,
+ mpll_sw_state->mpllb[i], mpll_hw_state->mpllb[i]);
}
} else {
for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mplla); i++) {
- I915_STATE_WARN(i915, mpll_hw_state->mplla[i] != mpll_sw_state->mplla[i],
- "[CRTC:%d:%s] mismatch in C20MPLLA: Register[%d] (expected 0x%04x, found 0x%04x)",
- crtc->base.base.id, crtc->base.name, i,
- mpll_sw_state->mplla[i], mpll_hw_state->mplla[i]);
+ INTEL_DISPLAY_STATE_WARN(display, mpll_hw_state->mplla[i] != mpll_sw_state->mplla[i],
+ "[CRTC:%d:%s] mismatch in C20MPLLA: Register[%d] (expected 0x%04x, found 0x%04x)",
+ crtc->base.base.id, crtc->base.name, i,
+ mpll_sw_state->mplla[i], mpll_hw_state->mplla[i]);
}
}
for (i = 0; i < ARRAY_SIZE(mpll_sw_state->tx); i++) {
- I915_STATE_WARN(i915, mpll_hw_state->tx[i] != mpll_sw_state->tx[i],
- "[CRTC:%d:%s] mismatch in C20: Register TX[%i] (expected 0x%04x, found 0x%04x)",
- crtc->base.base.id, crtc->base.name, i,
- mpll_sw_state->tx[i], mpll_hw_state->tx[i]);
+ INTEL_DISPLAY_STATE_WARN(display, mpll_hw_state->tx[i] != mpll_sw_state->tx[i],
+ "[CRTC:%d:%s] mismatch in C20: Register TX[%i] (expected 0x%04x, found 0x%04x)",
+ crtc->base.base.id, crtc->base.name, i,
+ mpll_sw_state->tx[i], mpll_hw_state->tx[i]);
}
for (i = 0; i < ARRAY_SIZE(mpll_sw_state->cmn); i++) {
- I915_STATE_WARN(i915, mpll_hw_state->cmn[i] != mpll_sw_state->cmn[i],
- "[CRTC:%d:%s] mismatch in C20: Register CMN[%i] (expected 0x%04x, found 0x%04x)",
- crtc->base.base.id, crtc->base.name, i,
- mpll_sw_state->cmn[i], mpll_hw_state->cmn[i]);
+ INTEL_DISPLAY_STATE_WARN(display, mpll_hw_state->cmn[i] != mpll_sw_state->cmn[i],
+ "[CRTC:%d:%s] mismatch in C20: Register CMN[%i] (expected 0x%04x, found 0x%04x)",
+ crtc->base.base.id, crtc->base.name, i,
+ mpll_sw_state->cmn[i], mpll_hw_state->cmn[i]);
}
}
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 4a81e4563e924..2d4049e6ba785 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -321,6 +321,7 @@ intel_wait_for_pipe_off(const struct intel_crtc_state *old_crtc_state)
void assert_transcoder(struct drm_i915_private *dev_priv,
enum transcoder cpu_transcoder, bool state)
{
+ struct intel_display *display = &dev_priv->display;
bool cur_state;
enum intel_display_power_domain power_domain;
intel_wakeref_t wakeref;
@@ -341,24 +342,24 @@ void assert_transcoder(struct drm_i915_private *dev_priv,
cur_state = false;
}
- I915_STATE_WARN(dev_priv, cur_state != state,
- "transcoder %s assertion failure (expected %s, current %s)\n",
- transcoder_name(cpu_transcoder), str_on_off(state),
- str_on_off(cur_state));
+ INTEL_DISPLAY_STATE_WARN(display, cur_state != state,
+ "transcoder %s assertion failure (expected %s, current %s)\n",
+ transcoder_name(cpu_transcoder), str_on_off(state),
+ str_on_off(cur_state));
}
static void assert_plane(struct intel_plane *plane, bool state)
{
- struct drm_i915_private *i915 = to_i915(plane->base.dev);
+ struct intel_display *display = to_intel_display(plane->base.dev);
enum pipe pipe;
bool cur_state;
cur_state = plane->get_hw_state(plane, &pipe);
- I915_STATE_WARN(i915, cur_state != state,
- "%s assertion failure (expected %s, current %s)\n",
- plane->base.name, str_on_off(state),
- str_on_off(cur_state));
+ INTEL_DISPLAY_STATE_WARN(display, cur_state != state,
+ "%s assertion failure (expected %s, current %s)\n",
+ plane->base.name, str_on_off(state),
+ str_on_off(cur_state));
}
#define assert_plane_enabled(p) assert_plane(p, true)
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index b21d9578d5db4..3c4b48697bb1c 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -570,18 +570,17 @@ void assert_transcoder(struct drm_i915_private *dev_priv,
bool assert_port_valid(struct drm_i915_private *i915, enum port port);
/*
- * Use I915_STATE_WARN(x) (rather than WARN() and WARN_ON()) for hw state sanity
- * checks to check for unexpected conditions which may not necessarily be a user
- * visible problem. This will either WARN() or DRM_ERROR() depending on the
- * verbose_state_checks module param, to enable distros and users to tailor
- * their preferred amount of i915 abrt spam.
+ * Use INTEL_DISPLAY_STATE_WARN(x) (rather than WARN() and WARN_ON()) for hw
+ * state sanity checks to check for unexpected conditions which may not
+ * necessarily be a user visible problem. This will either drm_WARN() or
+ * drm_err() depending on the verbose_state_checks module param, to enable
+ * distros and users to tailor their preferred amount of i915 abrt spam.
*/
-#define I915_STATE_WARN(__i915, condition, format...) ({ \
- struct drm_device *drm = &(__i915)->drm; \
+#define INTEL_DISPLAY_STATE_WARN(__display, condition, format...) ({ \
int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) \
- if (!drm_WARN(drm, __i915->display.params.verbose_state_checks, format)) \
- drm_err(drm, format); \
+ if (!drm_WARN((__display)->drm, (__display)->params.verbose_state_checks, format)) \
+ drm_err((__display)->drm, format); \
unlikely(__ret_warn_on); \
})
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index 85335d8dfec11..be39a0180921b 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -1176,43 +1176,44 @@ static void hsw_assert_cdclk(struct drm_i915_private *dev_priv)
static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
{
+ struct intel_display *display = &dev_priv->display;
struct intel_crtc *crtc;
- for_each_intel_crtc(&dev_priv->drm, crtc)
- I915_STATE_WARN(dev_priv, crtc->active,
- "CRTC for pipe %c enabled\n",
- pipe_name(crtc->pipe));
-
- I915_STATE_WARN(dev_priv, intel_de_read(dev_priv, HSW_PWR_WELL_CTL2),
- "Display power well on\n");
- I915_STATE_WARN(dev_priv,
- intel_de_read(dev_priv, SPLL_CTL) & SPLL_PLL_ENABLE,
- "SPLL enabled\n");
- I915_STATE_WARN(dev_priv,
- intel_de_read(dev_priv, WRPLL_CTL(0)) & WRPLL_PLL_ENABLE,
- "WRPLL1 enabled\n");
- I915_STATE_WARN(dev_priv,
- intel_de_read(dev_priv, WRPLL_CTL(1)) & WRPLL_PLL_ENABLE,
- "WRPLL2 enabled\n");
- I915_STATE_WARN(dev_priv,
- intel_de_read(dev_priv, PP_STATUS(dev_priv, 0)) & PP_ON,
- "Panel power on\n");
- I915_STATE_WARN(dev_priv,
- intel_de_read(dev_priv, BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
- "CPU PWM1 enabled\n");
+ for_each_intel_crtc(display->drm, crtc)
+ INTEL_DISPLAY_STATE_WARN(display, crtc->active,
+ "CRTC for pipe %c enabled\n",
+ pipe_name(crtc->pipe));
+
+ INTEL_DISPLAY_STATE_WARN(display, intel_de_read(display, HSW_PWR_WELL_CTL2),
+ "Display power well on\n");
+ INTEL_DISPLAY_STATE_WARN(display,
+ intel_de_read(display, SPLL_CTL) & SPLL_PLL_ENABLE,
+ "SPLL enabled\n");
+ INTEL_DISPLAY_STATE_WARN(display,
+ intel_de_read(display, WRPLL_CTL(0)) & WRPLL_PLL_ENABLE,
+ "WRPLL1 enabled\n");
+ INTEL_DISPLAY_STATE_WARN(display,
+ intel_de_read(display, WRPLL_CTL(1)) & WRPLL_PLL_ENABLE,
+ "WRPLL2 enabled\n");
+ INTEL_DISPLAY_STATE_WARN(display,
+ intel_de_read(display, PP_STATUS(display, 0)) & PP_ON,
+ "Panel power on\n");
+ INTEL_DISPLAY_STATE_WARN(display,
+ intel_de_read(display, BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
+ "CPU PWM1 enabled\n");
if (IS_HASWELL(dev_priv))
- I915_STATE_WARN(dev_priv,
- intel_de_read(dev_priv, HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
- "CPU PWM2 enabled\n");
- I915_STATE_WARN(dev_priv,
- intel_de_read(dev_priv, BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
- "PCH PWM1 enabled\n");
- I915_STATE_WARN(dev_priv,
- (intel_de_read(dev_priv, UTIL_PIN_CTL) & (UTIL_PIN_ENABLE | UTIL_PIN_MODE_MASK)) == (UTIL_PIN_ENABLE | UTIL_PIN_MODE_PWM),
- "Utility pin enabled in PWM mode\n");
- I915_STATE_WARN(dev_priv,
- intel_de_read(dev_priv, PCH_GTC_CTL) & PCH_GTC_ENABLE,
- "PCH GTC enabled\n");
+ INTEL_DISPLAY_STATE_WARN(display,
+ intel_de_read(display, HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
+ "CPU PWM2 enabled\n");
+ INTEL_DISPLAY_STATE_WARN(display,
+ intel_de_read(display, BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
+ "PCH PWM1 enabled\n");
+ INTEL_DISPLAY_STATE_WARN(display,
+ (intel_de_read(display, UTIL_PIN_CTL) & (UTIL_PIN_ENABLE | UTIL_PIN_MODE_MASK)) == (UTIL_PIN_ENABLE | UTIL_PIN_MODE_PWM),
+ "Utility pin enabled in PWM mode\n");
+ INTEL_DISPLAY_STATE_WARN(display,
+ intel_de_read(display, PCH_GTC_CTL) & PCH_GTC_ENABLE,
+ "PCH GTC enabled\n");
/*
* In theory we can still leave IRQs enabled, as long as only the HPD
@@ -1220,8 +1221,8 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
* gen-specific and since we only disable LCPLL after we fully disable
* the interrupts, the check below should be enough.
*/
- I915_STATE_WARN(dev_priv, intel_irqs_enabled(dev_priv),
- "IRQs enabled\n");
+ INTEL_DISPLAY_STATE_WARN(display, intel_irqs_enabled(dev_priv),
+ "IRQs enabled\n");
}
static u32 hsw_read_dcomp(struct drm_i915_private *dev_priv)
diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c
index bc72d1c0cb414..0e4a21d35be20 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll.c
@@ -2319,12 +2319,13 @@ void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe)
static void assert_pll(struct drm_i915_private *dev_priv,
enum pipe pipe, bool state)
{
+ struct intel_display *display = &dev_priv->display;
bool cur_state;
- cur_state = intel_de_read(dev_priv, DPLL(dev_priv, pipe)) & DPLL_VCO_ENABLE;
- I915_STATE_WARN(dev_priv, cur_state != state,
- "PLL state assertion failure (expected %s, current %s)\n",
- str_on_off(state), str_on_off(cur_state));
+ cur_state = intel_de_read(display, DPLL(display, pipe)) & DPLL_VCO_ENABLE;
+ INTEL_DISPLAY_STATE_WARN(display, cur_state != state,
+ "PLL state assertion failure (expected %s, current %s)\n",
+ str_on_off(state), str_on_off(cur_state));
}
void assert_pll_enabled(struct drm_i915_private *i915, enum pipe pipe)
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
index f490b2157828d..c9eda647919ac 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
@@ -173,18 +173,19 @@ void assert_shared_dpll(struct drm_i915_private *i915,
struct intel_shared_dpll *pll,
bool state)
{
+ struct intel_display *display = &i915->display;
bool cur_state;
struct intel_dpll_hw_state hw_state;
- if (drm_WARN(&i915->drm, !pll,
+ if (drm_WARN(display->drm, !pll,
"asserting DPLL %s with no DPLL\n", str_on_off(state)))
return;
cur_state = intel_dpll_get_hw_state(i915, pll, &hw_state);
- I915_STATE_WARN(i915, cur_state != state,
- "%s assertion failure (expected %s, current %s)\n",
- pll->info->name, str_on_off(state),
- str_on_off(cur_state));
+ INTEL_DISPLAY_STATE_WARN(display, cur_state != state,
+ "%s assertion failure (expected %s, current %s)\n",
+ pll->info->name, str_on_off(state),
+ str_on_off(cur_state));
}
static enum tc_port icl_pll_id_to_tc_port(enum intel_dpll_id id)
@@ -545,14 +546,15 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *i915,
static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *i915)
{
+ struct intel_display *display = &i915->display;
u32 val;
bool enabled;
- val = intel_de_read(i915, PCH_DREF_CONTROL);
+ val = intel_de_read(display, PCH_DREF_CONTROL);
enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
DREF_SUPERSPREAD_SOURCE_MASK));
- I915_STATE_WARN(i915, !enabled,
- "PCH refclk assertion failure, should be active but is disabled\n");
+ INTEL_DISPLAY_STATE_WARN(display, !enabled,
+ "PCH refclk assertion failure, should be active but is disabled\n");
}
static void ibx_pch_dpll_enable(struct drm_i915_private *i915,
@@ -4619,6 +4621,7 @@ verify_single_dpll_state(struct drm_i915_private *i915,
struct intel_crtc *crtc,
const struct intel_crtc_state *new_crtc_state)
{
+ struct intel_display *display = &i915->display;
struct intel_dpll_hw_state dpll_hw_state = {};
u8 pipe_mask;
bool active;
@@ -4626,22 +4629,22 @@ verify_single_dpll_state(struct drm_i915_private *i915,
active = intel_dpll_get_hw_state(i915, pll, &dpll_hw_state);
if (!pll->info->always_on) {
- I915_STATE_WARN(i915, !pll->on && pll->active_mask,
- "%s: pll in active use but not on in sw tracking\n",
- pll->info->name);
- I915_STATE_WARN(i915, pll->on && !pll->active_mask,
- "%s: pll is on but not used by any active pipe\n",
- pll->info->name);
- I915_STATE_WARN(i915, pll->on != active,
- "%s: pll on state mismatch (expected %i, found %i)\n",
- pll->info->name, pll->on, active);
+ INTEL_DISPLAY_STATE_WARN(display, !pll->on && pll->active_mask,
+ "%s: pll in active use but not on in sw tracking\n",
+ pll->info->name);
+ INTEL_DISPLAY_STATE_WARN(display, pll->on && !pll->active_mask,
+ "%s: pll is on but not used by any active pipe\n",
+ pll->info->name);
+ INTEL_DISPLAY_STATE_WARN(display, pll->on != active,
+ "%s: pll on state mismatch (expected %i, found %i)\n",
+ pll->info->name, pll->on, active);
}
if (!crtc) {
- I915_STATE_WARN(i915,
- pll->active_mask & ~pll->state.pipe_mask,
- "%s: more active pll users than references: 0x%x vs 0x%x\n",
- pll->info->name, pll->active_mask, pll->state.pipe_mask);
+ INTEL_DISPLAY_STATE_WARN(display,
+ pll->active_mask & ~pll->state.pipe_mask,
+ "%s: more active pll users than references: 0x%x vs 0x%x\n",
+ pll->info->name, pll->active_mask, pll->state.pipe_mask);
return;
}
@@ -4649,23 +4652,23 @@ verify_single_dpll_state(struct drm_i915_private *i915,
pipe_mask = BIT(crtc->pipe);
if (new_crtc_state->hw.active)
- I915_STATE_WARN(i915, !(pll->active_mask & pipe_mask),
- "%s: pll active mismatch (expected pipe %c in active mask 0x%x)\n",
- pll->info->name, pipe_name(crtc->pipe), pll->active_mask);
+ INTEL_DISPLAY_STATE_WARN(display, !(pll->active_mask & pipe_mask),
+ "%s: pll active mismatch (expected pipe %c in active mask 0x%x)\n",
+ pll->info->name, pipe_name(crtc->pipe), pll->active_mask);
else
- I915_STATE_WARN(i915, pll->active_mask & pipe_mask,
- "%s: pll active mismatch (didn't expect pipe %c in active mask 0x%x)\n",
- pll->info->name, pipe_name(crtc->pipe), pll->active_mask);
+ INTEL_DISPLAY_STATE_WARN(display, pll->active_mask & pipe_mask,
+ "%s: pll active mismatch (didn't expect pipe %c in active mask 0x%x)\n",
+ pll->info->name, pipe_name(crtc->pipe), pll->active_mask);
- I915_STATE_WARN(i915, !(pll->state.pipe_mask & pipe_mask),
- "%s: pll enabled crtcs mismatch (expected 0x%x in 0x%x)\n",
- pll->info->name, pipe_mask, pll->state.pipe_mask);
+ INTEL_DISPLAY_STATE_WARN(display, !(pll->state.pipe_mask & pipe_mask),
+ "%s: pll enabled crtcs mismatch (expected 0x%x in 0x%x)\n",
+ pll->info->name, pipe_mask, pll->state.pipe_mask);
- I915_STATE_WARN(i915,
- pll->on && memcmp(&pll->state.hw_state, &dpll_hw_state,
- sizeof(dpll_hw_state)),
- "%s: pll hw state mismatch\n",
- pll->info->name);
+ INTEL_DISPLAY_STATE_WARN(display,
+ pll->on && memcmp(&pll->state.hw_state, &dpll_hw_state,
+ sizeof(dpll_hw_state)),
+ "%s: pll hw state mismatch\n",
+ pll->info->name);
}
static bool has_alt_port_dpll(const struct intel_shared_dpll *old_pll,
@@ -4678,6 +4681,7 @@ static bool has_alt_port_dpll(const struct intel_shared_dpll *old_pll,
void intel_shared_dpll_state_verify(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
+ struct intel_display *display = to_intel_display(state);
struct drm_i915_private *i915 = to_i915(state->base.dev);
const struct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc);
@@ -4693,16 +4697,16 @@ void intel_shared_dpll_state_verify(struct intel_atomic_state *state,
u8 pipe_mask = BIT(crtc->pipe);
struct intel_shared_dpll *pll = old_crtc_state->shared_dpll;
- I915_STATE_WARN(i915, pll->active_mask & pipe_mask,
- "%s: pll active mismatch (didn't expect pipe %c in active mask (0x%x))\n",
- pll->info->name, pipe_name(crtc->pipe), pll->active_mask);
+ INTEL_DISPLAY_STATE_WARN(display, pll->active_mask & pipe_mask,
+ "%s: pll active mismatch (didn't expect pipe %c in active mask (0x%x))\n",
+ pll->info->name, pipe_name(crtc->pipe), pll->active_mask);
/* TC ports have both MG/TC and TBT PLL referenced simultaneously */
- I915_STATE_WARN(i915, !has_alt_port_dpll(old_crtc_state->shared_dpll,
- new_crtc_state->shared_dpll) &&
- pll->state.pipe_mask & pipe_mask,
- "%s: pll enabled crtcs mismatch (found pipe %c in enabled mask (0x%x))\n",
- pll->info->name, pipe_name(crtc->pipe), pll->state.pipe_mask);
+ INTEL_DISPLAY_STATE_WARN(display, !has_alt_port_dpll(old_crtc_state->shared_dpll,
+ new_crtc_state->shared_dpll) &&
+ pll->state.pipe_mask & pipe_mask,
+ "%s: pll enabled crtcs mismatch (found pipe %c in enabled mask (0x%x))\n",
+ pll->info->name, pipe_name(crtc->pipe), pll->state.pipe_mask);
}
}
diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c
index 0168894e9cd1b..98e1a36062273 100644
--- a/drivers/gpu/drm/i915/display/intel_fdi.c
+++ b/drivers/gpu/drm/i915/display/intel_fdi.c
@@ -26,9 +26,10 @@ struct intel_fdi_funcs {
static void assert_fdi_tx(struct drm_i915_private *dev_priv,
enum pipe pipe, bool state)
{
+ struct intel_display *display = &dev_priv->display;
bool cur_state;
- if (HAS_DDI(dev_priv)) {
+ if (HAS_DDI(display)) {
/*
* DDI does not have a specific FDI_TX register.
*
@@ -36,14 +37,14 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv,
* so pipe->transcoder cast is fine here.
*/
enum transcoder cpu_transcoder = (enum transcoder)pipe;
- cur_state = intel_de_read(dev_priv,
- TRANS_DDI_FUNC_CTL(dev_priv, cpu_transcoder)) & TRANS_DDI_FUNC_ENABLE;
+ cur_state = intel_de_read(display,
+ TRANS_DDI_FUNC_CTL(display, cpu_transcoder)) & TRANS_DDI_FUNC_ENABLE;
} else {
- cur_state = intel_de_read(dev_priv, FDI_TX_CTL(pipe)) & FDI_TX_ENABLE;
+ cur_state = intel_de_read(display, FDI_TX_CTL(pipe)) & FDI_TX_ENABLE;
}
- I915_STATE_WARN(dev_priv, cur_state != state,
- "FDI TX state assertion failure (expected %s, current %s)\n",
- str_on_off(state), str_on_off(cur_state));
+ INTEL_DISPLAY_STATE_WARN(display, cur_state != state,
+ "FDI TX state assertion failure (expected %s, current %s)\n",
+ str_on_off(state), str_on_off(cur_state));
}
void assert_fdi_tx_enabled(struct drm_i915_private *i915, enum pipe pipe)
@@ -59,12 +60,13 @@ void assert_fdi_tx_disabled(struct drm_i915_private *i915, enum pipe pipe)
static void assert_fdi_rx(struct drm_i915_private *dev_priv,
enum pipe pipe, bool state)
{
+ struct intel_display *display = &dev_priv->display;
bool cur_state;
- cur_state = intel_de_read(dev_priv, FDI_RX_CTL(pipe)) & FDI_RX_ENABLE;
- I915_STATE_WARN(dev_priv, cur_state != state,
- "FDI RX state assertion failure (expected %s, current %s)\n",
- str_on_off(state), str_on_off(cur_state));
+ cur_state = intel_de_read(display, FDI_RX_CTL(pipe)) & FDI_RX_ENABLE;
+ INTEL_DISPLAY_STATE_WARN(display, cur_state != state,
+ "FDI RX state assertion failure (expected %s, current %s)\n",
+ str_on_off(state), str_on_off(cur_state));
}
void assert_fdi_rx_enabled(struct drm_i915_private *i915, enum pipe pipe)
@@ -80,6 +82,7 @@ void assert_fdi_rx_disabled(struct drm_i915_private *i915, enum pipe pipe)
void assert_fdi_tx_pll_enabled(struct drm_i915_private *i915,
enum pipe pipe)
{
+ struct intel_display *display = &i915->display;
bool cur_state;
/* ILK FDI PLL is always enabled */
@@ -87,23 +90,24 @@ void assert_fdi_tx_pll_enabled(struct drm_i915_private *i915,
return;
/* On Haswell, DDI ports are responsible for the FDI PLL setup */
- if (HAS_DDI(i915))
+ if (HAS_DDI(display))
return;
- cur_state = intel_de_read(i915, FDI_TX_CTL(pipe)) & FDI_TX_PLL_ENABLE;
- I915_STATE_WARN(i915, !cur_state,
- "FDI TX PLL assertion failure, should be active but is disabled\n");
+ cur_state = intel_de_read(display, FDI_TX_CTL(pipe)) & FDI_TX_PLL_ENABLE;
+ INTEL_DISPLAY_STATE_WARN(display, !cur_state,
+ "FDI TX PLL assertion failure, should be active but is disabled\n");
}
static void assert_fdi_rx_pll(struct drm_i915_private *i915,
enum pipe pipe, bool state)
{
+ struct intel_display *display = &i915->display;
bool cur_state;
- cur_state = intel_de_read(i915, FDI_RX_CTL(pipe)) & FDI_RX_PLL_ENABLE;
- I915_STATE_WARN(i915, cur_state != state,
- "FDI RX PLL assertion failure (expected %s, current %s)\n",
- str_on_off(state), str_on_off(cur_state));
+ cur_state = intel_de_read(display, FDI_RX_CTL(pipe)) & FDI_RX_PLL_ENABLE;
+ INTEL_DISPLAY_STATE_WARN(display, cur_state != state,
+ "FDI RX PLL assertion failure (expected %s, current %s)\n",
+ str_on_off(state), str_on_off(cur_state));
}
void assert_fdi_rx_pll_enabled(struct drm_i915_private *i915, enum pipe pipe)
diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c
index 3491db5cad316..bc70e72ccc2e9 100644
--- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c
+++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c
@@ -27,6 +27,7 @@ static void intel_connector_verify_state(const struct intel_crtc_state *crtc_sta
const struct drm_connector_state *conn_state)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
+ struct intel_display *display = to_intel_display(connector);
struct drm_i915_private *i915 = to_i915(connector->base.dev);
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s]\n",
@@ -35,29 +36,29 @@ static void intel_connector_verify_state(const struct intel_crtc_state *crtc_sta
if (connector->get_hw_state(connector)) {
struct intel_encoder *encoder = intel_attached_encoder(connector);
- I915_STATE_WARN(i915, !crtc_state,
- "connector enabled without attached crtc\n");
+ INTEL_DISPLAY_STATE_WARN(display, !crtc_state,
+ "connector enabled without attached crtc\n");
if (!crtc_state)
return;
- I915_STATE_WARN(i915, !crtc_state->hw.active,
- "connector is active, but attached crtc isn't\n");
+ INTEL_DISPLAY_STATE_WARN(display, !crtc_state->hw.active,
+ "connector is active, but attached crtc isn't\n");
if (!encoder || encoder->type == INTEL_OUTPUT_DP_MST)
return;
- I915_STATE_WARN(i915,
- conn_state->best_encoder != &encoder->base,
- "atomic encoder doesn't match attached encoder\n");
+ INTEL_DISPLAY_STATE_WARN(display,
+ conn_state->best_encoder != &encoder->base,
+ "atomic encoder doesn't match attached encoder\n");
- I915_STATE_WARN(i915, conn_state->crtc != encoder->base.crtc,
- "attached encoder crtc differs from connector crtc\n");
+ INTEL_DISPLAY_STATE_WARN(display, conn_state->crtc != encoder->base.crtc,
+ "attached encoder crtc differs from connector crtc\n");
} else {
- I915_STATE_WARN(i915, crtc_state && crtc_state->hw.active,
- "attached crtc is active, but connector isn't\n");
- I915_STATE_WARN(i915, !crtc_state && conn_state->best_encoder,
- "best encoder set without crtc!\n");
+ INTEL_DISPLAY_STATE_WARN(display, crtc_state && crtc_state->hw.active,
+ "attached crtc is active, but connector isn't\n");
+ INTEL_DISPLAY_STATE_WARN(display, !crtc_state && conn_state->best_encoder,
+ "best encoder set without crtc!\n");
}
}
@@ -65,6 +66,7 @@ static void
verify_connector_state(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
+ struct intel_display *display = to_intel_display(state);
struct drm_connector *connector;
const struct drm_connector_state *new_conn_state;
int i;
@@ -81,8 +83,8 @@ verify_connector_state(struct intel_atomic_state *state,
intel_connector_verify_state(crtc_state, new_conn_state);
- I915_STATE_WARN(to_i915(connector->dev), new_conn_state->best_encoder != encoder,
- "connector's atomic encoder doesn't match legacy encoder\n");
+ INTEL_DISPLAY_STATE_WARN(display, new_conn_state->best_encoder != encoder,
+ "connector's atomic encoder doesn't match legacy encoder\n");
}
}
@@ -109,6 +111,7 @@ static void intel_pipe_config_sanity_check(const struct intel_crtc_state *crtc_s
static void
verify_encoder_state(struct intel_atomic_state *state)
{
+ struct intel_display *display = to_intel_display(state);
struct drm_i915_private *i915 = to_i915(state->base.dev);
struct intel_encoder *encoder;
struct drm_connector *connector;
@@ -134,25 +137,25 @@ verify_encoder_state(struct intel_atomic_state *state)
found = true;
enabled = true;
- I915_STATE_WARN(i915,
- new_conn_state->crtc != encoder->base.crtc,
- "connector's crtc doesn't match encoder crtc\n");
+ INTEL_DISPLAY_STATE_WARN(display,
+ new_conn_state->crtc != encoder->base.crtc,
+ "connector's crtc doesn't match encoder crtc\n");
}
if (!found)
continue;
- I915_STATE_WARN(i915, !!encoder->base.crtc != enabled,
- "encoder's enabled state mismatch (expected %i, found %i)\n",
- !!encoder->base.crtc, enabled);
+ INTEL_DISPLAY_STATE_WARN(display, !!encoder->base.crtc != enabled,
+ "encoder's enabled state mismatch (expected %i, found %i)\n",
+ !!encoder->base.crtc, enabled);
if (!encoder->base.crtc) {
bool active;
active = encoder->get_hw_state(encoder, &pipe);
- I915_STATE_WARN(i915, active,
- "encoder detached but still enabled on pipe %c.\n",
- pipe_name(pipe));
+ INTEL_DISPLAY_STATE_WARN(display, active,
+ "encoder detached but still enabled on pipe %c.\n",
+ pipe_name(pipe));
}
}
}
@@ -161,8 +164,8 @@ static void
verify_crtc_state(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
- struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *i915 = to_i915(dev);
+ struct intel_display *display = to_intel_display(state);
+ struct drm_i915_private *i915 = to_i915(display->drm);
const struct intel_crtc_state *sw_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
struct intel_crtc_state *hw_crtc_state;
@@ -173,7 +176,7 @@ verify_crtc_state(struct intel_atomic_state *state,
if (!hw_crtc_state)
return;
- drm_dbg_kms(&i915->drm, "[CRTC:%d:%s]\n", crtc->base.base.id,
+ drm_dbg_kms(display->drm, "[CRTC:%d:%s]\n", crtc->base.base.id,
crtc->base.name);
hw_crtc_state->hw.enable = sw_crtc_state->hw.enable;
@@ -184,30 +187,30 @@ verify_crtc_state(struct intel_atomic_state *state,
if (IS_I830(i915) && hw_crtc_state->hw.active)
hw_crtc_state->hw.active = sw_crtc_state->hw.active;
- I915_STATE_WARN(i915,
- sw_crtc_state->hw.active != hw_crtc_state->hw.active,
- "crtc active state doesn't match with hw state (expected %i, found %i)\n",
- sw_crtc_state->hw.active, hw_crtc_state->hw.active);
+ INTEL_DISPLAY_STATE_WARN(display,
+ sw_crtc_state->hw.active != hw_crtc_state->hw.active,
+ "crtc active state doesn't match with hw state (expected %i, found %i)\n",
+ sw_crtc_state->hw.active, hw_crtc_state->hw.active);
- I915_STATE_WARN(i915, crtc->active != sw_crtc_state->hw.active,
- "transitional active state does not match atomic hw state (expected %i, found %i)\n",
- sw_crtc_state->hw.active, crtc->active);
+ INTEL_DISPLAY_STATE_WARN(display, crtc->active != sw_crtc_state->hw.active,
+ "transitional active state does not match atomic hw state (expected %i, found %i)\n",
+ sw_crtc_state->hw.active, crtc->active);
primary_crtc = intel_primary_crtc(sw_crtc_state);
- for_each_encoder_on_crtc(dev, &primary_crtc->base, encoder) {
+ for_each_encoder_on_crtc(display->drm, &primary_crtc->base, encoder) {
enum pipe pipe;
bool active;
active = encoder->get_hw_state(encoder, &pipe);
- I915_STATE_WARN(i915, active != sw_crtc_state->hw.active,
- "[ENCODER:%i] active %i with crtc active %i\n",
- encoder->base.base.id, active,
- sw_crtc_state->hw.active);
+ INTEL_DISPLAY_STATE_WARN(display, active != sw_crtc_state->hw.active,
+ "[ENCODER:%i] active %i with crtc active %i\n",
+ encoder->base.base.id, active,
+ sw_crtc_state->hw.active);
- I915_STATE_WARN(i915, active && primary_crtc->pipe != pipe,
- "Encoder connected to wrong pipe %c\n",
- pipe_name(pipe));
+ INTEL_DISPLAY_STATE_WARN(display, active && primary_crtc->pipe != pipe,
+ "Encoder connected to wrong pipe %c\n",
+ pipe_name(pipe));
if (active)
intel_encoder_get_config(encoder, hw_crtc_state);
@@ -220,7 +223,7 @@ verify_crtc_state(struct intel_atomic_state *state,
if (!intel_pipe_config_compare(sw_crtc_state,
hw_crtc_state, false)) {
- I915_STATE_WARN(i915, 1, "pipe state doesn't match!\n");
+ INTEL_DISPLAY_STATE_WARN(display, 1, "pipe state doesn't match!\n");
intel_crtc_state_dump(hw_crtc_state, NULL, "hw state");
intel_crtc_state_dump(sw_crtc_state, NULL, "sw state");
}
diff --git a/drivers/gpu/drm/i915/display/intel_pch_display.c b/drivers/gpu/drm/i915/display/intel_pch_display.c
index f13ab680c2cf4..5fbcb74aeac11 100644
--- a/drivers/gpu/drm/i915/display/intel_pch_display.c
+++ b/drivers/gpu/drm/i915/display/intel_pch_display.c
@@ -39,58 +39,61 @@ static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe, enum port port,
i915_reg_t dp_reg)
{
+ struct intel_display *display = &dev_priv->display;
enum pipe port_pipe;
bool state;
state = g4x_dp_port_enabled(dev_priv, dp_reg, port, &port_pipe);
- I915_STATE_WARN(dev_priv, state && port_pipe == pipe,
- "PCH DP %c enabled on transcoder %c, should be disabled\n",
- port_name(port), pipe_name(pipe));
+ INTEL_DISPLAY_STATE_WARN(display, state && port_pipe == pipe,
+ "PCH DP %c enabled on transcoder %c, should be disabled\n",
+ port_name(port), pipe_name(pipe));
- I915_STATE_WARN(dev_priv,
- HAS_PCH_IBX(dev_priv) && !state && port_pipe == PIPE_B,
- "IBX PCH DP %c still using transcoder B\n",
- port_name(port));
+ INTEL_DISPLAY_STATE_WARN(display,
+ HAS_PCH_IBX(dev_priv) && !state && port_pipe == PIPE_B,
+ "IBX PCH DP %c still using transcoder B\n",
+ port_name(port));
}
static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe, enum port port,
i915_reg_t hdmi_reg)
{
+ struct intel_display *display = &dev_priv->display;
enum pipe port_pipe;
bool state;
state = intel_sdvo_port_enabled(dev_priv, hdmi_reg, &port_pipe);
- I915_STATE_WARN(dev_priv, state && port_pipe == pipe,
- "PCH HDMI %c enabled on transcoder %c, should be disabled\n",
- port_name(port), pipe_name(pipe));
+ INTEL_DISPLAY_STATE_WARN(display, state && port_pipe == pipe,
+ "PCH HDMI %c enabled on transcoder %c, should be disabled\n",
+ port_name(port), pipe_name(pipe));
- I915_STATE_WARN(dev_priv,
- HAS_PCH_IBX(dev_priv) && !state && port_pipe == PIPE_B,
- "IBX PCH HDMI %c still using transcoder B\n",
- port_name(port));
+ INTEL_DISPLAY_STATE_WARN(display,
+ HAS_PCH_IBX(dev_priv) && !state && port_pipe == PIPE_B,
+ "IBX PCH HDMI %c still using transcoder B\n",
+ port_name(port));
}
static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
+ struct intel_display *display = &dev_priv->display;
enum pipe port_pipe;
assert_pch_dp_disabled(dev_priv, pipe, PORT_B, PCH_DP_B);
assert_pch_dp_disabled(dev_priv, pipe, PORT_C, PCH_DP_C);
assert_pch_dp_disabled(dev_priv, pipe, PORT_D, PCH_DP_D);
- I915_STATE_WARN(dev_priv,
- intel_crt_port_enabled(dev_priv, PCH_ADPA, &port_pipe) && port_pipe == pipe,
- "PCH VGA enabled on transcoder %c, should be disabled\n",
- pipe_name(pipe));
+ INTEL_DISPLAY_STATE_WARN(display,
+ intel_crt_port_enabled(dev_priv, PCH_ADPA, &port_pipe) && port_pipe == pipe,
+ "PCH VGA enabled on transcoder %c, should be disabled\n",
+ pipe_name(pipe));
- I915_STATE_WARN(dev_priv,
- intel_lvds_port_enabled(dev_priv, PCH_LVDS, &port_pipe) && port_pipe == pipe,
- "PCH LVDS enabled on transcoder %c, should be disabled\n",
- pipe_name(pipe));
+ INTEL_DISPLAY_STATE_WARN(display,
+ intel_lvds_port_enabled(dev_priv, PCH_LVDS, &port_pipe) && port_pipe == pipe,
+ "PCH LVDS enabled on transcoder %c, should be disabled\n",
+ pipe_name(pipe));
/* PCH SDVOB multiplex with HDMIB */
assert_pch_hdmi_disabled(dev_priv, pipe, PORT_B, PCH_HDMIB);
@@ -101,14 +104,15 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
+ struct intel_display *display = &dev_priv->display;
u32 val;
bool enabled;
- val = intel_de_read(dev_priv, PCH_TRANSCONF(pipe));
+ val = intel_de_read(display, PCH_TRANSCONF(pipe));
enabled = !!(val & TRANS_ENABLE);
- I915_STATE_WARN(dev_priv, enabled,
- "transcoder assertion failed, should be off on pipe %c but is still active\n",
- pipe_name(pipe));
+ INTEL_DISPLAY_STATE_WARN(display, enabled,
+ "transcoder assertion failed, should be off on pipe %c but is still active\n",
+ pipe_name(pipe));
}
static void ibx_sanitize_pch_hdmi_port(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c
index feddc30e3375e..22616a6f75092 100644
--- a/drivers/gpu/drm/i915/display/intel_pps.c
+++ b/drivers/gpu/drm/i915/display/intel_pps.c
@@ -800,7 +800,6 @@ bool intel_pps_vdd_on_unlocked(struct intel_dp *intel_dp)
void intel_pps_vdd_on(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
- struct drm_i915_private *i915 = to_i915(display->drm);
intel_wakeref_t wakeref;
bool vdd;
@@ -810,10 +809,10 @@ void intel_pps_vdd_on(struct intel_dp *intel_dp)
vdd = false;
with_intel_pps_lock(intel_dp, wakeref)
vdd = intel_pps_vdd_on_unlocked(intel_dp);
- I915_STATE_WARN(i915, !vdd, "[ENCODER:%d:%s] %s VDD already requested on\n",
- dp_to_dig_port(intel_dp)->base.base.base.id,
- dp_to_dig_port(intel_dp)->base.base.name,
- pps_name(intel_dp));
+ INTEL_DISPLAY_STATE_WARN(display, !vdd, "[ENCODER:%d:%s] %s VDD already requested on\n",
+ dp_to_dig_port(intel_dp)->base.base.base.id,
+ dp_to_dig_port(intel_dp)->base.base.name,
+ pps_name(intel_dp));
}
static void intel_pps_vdd_off_sync_unlocked(struct intel_dp *intel_dp)
@@ -920,18 +919,17 @@ static void edp_panel_vdd_schedule_off(struct intel_dp *intel_dp)
void intel_pps_vdd_off_unlocked(struct intel_dp *intel_dp, bool sync)
{
struct intel_display *display = to_intel_display(intel_dp);
- struct drm_i915_private *dev_priv = to_i915(display->drm);
lockdep_assert_held(&display->pps.mutex);
if (!intel_dp_is_edp(intel_dp))
return;
- I915_STATE_WARN(dev_priv, !intel_dp->pps.want_panel_vdd,
- "[ENCODER:%d:%s] %s VDD not forced on",
- dp_to_dig_port(intel_dp)->base.base.base.id,
- dp_to_dig_port(intel_dp)->base.base.name,
- pps_name(intel_dp));
+ INTEL_DISPLAY_STATE_WARN(display, !intel_dp->pps.want_panel_vdd,
+ "[ENCODER:%d:%s] %s VDD not forced on",
+ dp_to_dig_port(intel_dp)->base.base.base.id,
+ dp_to_dig_port(intel_dp)->base.base.name,
+ pps_name(intel_dp));
intel_dp->pps.want_panel_vdd = false;
@@ -1806,7 +1804,7 @@ void assert_pps_unlocked(struct intel_display *display, enum pipe pipe)
((val & PANEL_UNLOCK_MASK) == PANEL_UNLOCK_REGS))
locked = false;
- I915_STATE_WARN(dev_priv, panel_pipe == pipe && locked,
- "panel assertion failure, pipe %c regs locked\n",
- pipe_name(pipe));
+ INTEL_DISPLAY_STATE_WARN(display, panel_pipe == pipe && locked,
+ "panel assertion failure, pipe %c regs locked\n",
+ pipe_name(pipe));
}
diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c
index e6df1f92def5f..4b3a32736fd69 100644
--- a/drivers/gpu/drm/i915/display/intel_snps_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c
@@ -1997,6 +1997,7 @@ int intel_snps_phy_check_hdmi_link_rate(int clock)
void intel_mpllb_state_verify(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
+ struct intel_display *display = to_intel_display(state);
struct drm_i915_private *i915 = to_i915(state->base.dev);
const struct intel_crtc_state *new_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
@@ -2019,11 +2020,11 @@ void intel_mpllb_state_verify(struct intel_atomic_state *state,
intel_mpllb_readout_hw_state(encoder, &mpllb_hw_state);
#define MPLLB_CHECK(__name) \
- I915_STATE_WARN(i915, mpllb_sw_state->__name != mpllb_hw_state.__name, \
- "[CRTC:%d:%s] mismatch in MPLLB: %s (expected 0x%08x, found 0x%08x)", \
- crtc->base.base.id, crtc->base.name, \
- __stringify(__name), \
- mpllb_sw_state->__name, mpllb_hw_state.__name)
+ INTEL_DISPLAY_STATE_WARN(display, mpllb_sw_state->__name != mpllb_hw_state.__name, \
+ "[CRTC:%d:%s] mismatch in MPLLB: %s (expected 0x%08x, found 0x%08x)", \
+ crtc->base.base.id, crtc->base.name, \
+ __stringify(__name), \
+ mpllb_sw_state->__name, mpllb_hw_state.__name)
MPLLB_CHECK(mpllb_cp);
MPLLB_CHECK(mpllb_div);
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c
index 70c5a13a3c75b..59a50647f2c3c 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c
@@ -592,15 +592,16 @@ void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
static void assert_dsi_pll(struct drm_i915_private *i915, bool state)
{
+ struct intel_display *display = &i915->display;
bool cur_state;
vlv_cck_get(i915);
cur_state = vlv_cck_read(i915, CCK_REG_DSI_PLL_CONTROL) & DSI_PLL_VCO_EN;
vlv_cck_put(i915);
- I915_STATE_WARN(i915, cur_state != state,
- "DSI PLL state assertion failure (expected %s, current %s)\n",
- str_on_off(state), str_on_off(cur_state));
+ INTEL_DISPLAY_STATE_WARN(display, cur_state != state,
+ "DSI PLL state assertion failure (expected %s, current %s)\n",
+ str_on_off(state), str_on_off(cur_state));
}
void assert_dsi_pll_enabled(struct drm_i915_private *i915)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 056/869] drm/i915/gmbus: convert to struct intel_display
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (54 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 055/869] drm/i915/display: convert I915_STATE_WARN() to struct intel_display Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 057/869] drm/i915/crt: " Greg Kroah-Hartman
` (813 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Rodrigo Vivi, Jani Nikula,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <jani.nikula@intel.com>
[ Upstream commit fdc387383ebd0d88dda9c40bcb81023a70b4408e ]
struct intel_display will replace struct drm_i915_private as the main
device pointer for display code. Switch gmbus code over to it.
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/d784e4799ab5095baa5c8fd840920066878c6273.1730146000.git.jani.nikula@intel.com
Stable-dep-of: dc3806d9eb66 ("drm/i915: Grab intel_display from the encoder to avoid potential oopsies")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/i915/display/intel_bios.c | 6 +-
drivers/gpu/drm/i915/display/intel_crt.c | 6 +-
.../drm/i915/display/intel_display_driver.c | 4 +-
.../gpu/drm/i915/display/intel_display_irq.c | 11 +-
drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 5 +-
drivers/gpu/drm/i915/display/intel_dvo.c | 8 +-
drivers/gpu/drm/i915/display/intel_gmbus.c | 290 +++++++++---------
drivers/gpu/drm/i915/display/intel_gmbus.h | 15 +-
.../gpu/drm/i915/display/intel_gmbus_regs.h | 16 +-
drivers/gpu/drm/i915/display/intel_hdmi.c | 8 +-
.../gpu/drm/i915/display/intel_hotplug_irq.c | 6 +-
drivers/gpu/drm/i915/display/intel_lvds.c | 2 +-
drivers/gpu/drm/i915/display/intel_sdvo.c | 9 +-
drivers/gpu/drm/i915/i915_suspend.c | 2 +-
14 files changed, 202 insertions(+), 186 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 4793d460892b6..18e8453a339c5 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -2815,7 +2815,6 @@ static bool child_device_size_valid(struct intel_display *display, int size)
static void
parse_general_definitions(struct intel_display *display)
{
- struct drm_i915_private *i915 = to_i915(display->drm);
const struct bdb_general_definitions *defs;
struct intel_bios_encoder_data *devdata;
const struct child_device_config *child;
@@ -2840,7 +2839,7 @@ parse_general_definitions(struct intel_display *display)
bus_pin = defs->crt_ddc_gmbus_pin;
drm_dbg_kms(display->drm, "crt_ddc_bus_pin: %d\n", bus_pin);
- if (intel_gmbus_is_valid_pin(i915, bus_pin))
+ if (intel_gmbus_is_valid_pin(display, bus_pin))
display->vbt.crt_ddc_pin = bus_pin;
if (!child_device_size_valid(display, defs->child_dev_size))
@@ -3426,7 +3425,6 @@ bool intel_bios_is_tv_present(struct intel_display *display)
*/
bool intel_bios_is_lvds_present(struct intel_display *display, u8 *i2c_pin)
{
- struct drm_i915_private *i915 = to_i915(display->drm);
const struct intel_bios_encoder_data *devdata;
if (list_empty(&display->vbt.display_devices))
@@ -3443,7 +3441,7 @@ bool intel_bios_is_lvds_present(struct intel_display *display, u8 *i2c_pin)
child->device_type != DEVICE_TYPE_LFP)
continue;
- if (intel_gmbus_is_valid_pin(i915, child->i2c_pin))
+ if (intel_gmbus_is_valid_pin(display, child->i2c_pin))
*i2c_pin = child->i2c_pin;
/* However, we cannot trust the BIOS writers to populate
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index fd78adbaadbe8..8222b1c251db1 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -935,6 +935,7 @@ intel_crt_detect(struct drm_connector *connector,
static int intel_crt_get_modes(struct drm_connector *connector)
{
+ struct intel_display *display = to_intel_display(connector->dev);
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_crt *crt = intel_attached_crt(to_intel_connector(connector));
@@ -954,7 +955,7 @@ static int intel_crt_get_modes(struct drm_connector *connector)
goto out;
/* Try to probe digital port for output in DVI-I -> VGA mode. */
- ddc = intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPB);
+ ddc = intel_gmbus_get_adapter(display, GMBUS_PIN_DPB);
ret = intel_crt_ddc_get_modes(connector, ddc);
out:
@@ -1009,6 +1010,7 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = {
void intel_crt_init(struct drm_i915_private *dev_priv)
{
+ struct intel_display *display = &dev_priv->display;
struct drm_connector *connector;
struct intel_crt *crt;
struct intel_connector *intel_connector;
@@ -1057,7 +1059,7 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
drm_connector_init_with_ddc(&dev_priv->drm, connector,
&intel_crt_connector_funcs,
DRM_MODE_CONNECTOR_VGA,
- intel_gmbus_get_adapter(dev_priv, ddc_pin));
+ intel_gmbus_get_adapter(display, ddc_pin));
drm_encoder_init(&dev_priv->drm, &crt->base.base, &intel_crt_enc_funcs,
DRM_MODE_ENCODER_DAC, "CRT");
diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c
index c189ce08a950a..8d65a26c9a403 100644
--- a/drivers/gpu/drm/i915/display/intel_display_driver.c
+++ b/drivers/gpu/drm/i915/display/intel_display_driver.c
@@ -431,7 +431,7 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915)
intel_pps_setup(display);
- intel_gmbus_setup(i915);
+ intel_gmbus_setup(display);
drm_dbg_kms(&i915->drm, "%d display pipe%s available.\n",
INTEL_NUM_PIPES(i915),
@@ -607,7 +607,7 @@ void intel_display_driver_remove_noirq(struct drm_i915_private *i915)
intel_overlay_cleanup(i915);
- intel_gmbus_teardown(i915);
+ intel_gmbus_teardown(display);
destroy_workqueue(i915->display.wq.flip);
destroy_workqueue(i915->display.wq.modeset);
diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c
index 179ed72037e71..e2a98395e921f 100644
--- a/drivers/gpu/drm/i915/display/intel_display_irq.c
+++ b/drivers/gpu/drm/i915/display/intel_display_irq.c
@@ -551,12 +551,13 @@ void i965_pipestat_irq_handler(struct drm_i915_private *dev_priv,
intel_opregion_asle_intr(display);
if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
- intel_gmbus_irq_handler(dev_priv);
+ intel_gmbus_irq_handler(display);
}
void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
u32 pipe_stats[I915_MAX_PIPES])
{
+ struct intel_display *display = &dev_priv->display;
enum pipe pipe;
for_each_pipe(dev_priv, pipe) {
@@ -574,7 +575,7 @@ void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
}
if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
- intel_gmbus_irq_handler(dev_priv);
+ intel_gmbus_irq_handler(display);
}
static void ibx_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
@@ -596,7 +597,7 @@ static void ibx_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
intel_dp_aux_irq_handler(display);
if (pch_iir & SDE_GMBUS)
- intel_gmbus_irq_handler(dev_priv);
+ intel_gmbus_irq_handler(display);
if (pch_iir & SDE_AUDIO_HDCP_MASK)
drm_dbg(&dev_priv->drm, "PCH HDCP audio interrupt\n");
@@ -685,7 +686,7 @@ static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
intel_dp_aux_irq_handler(display);
if (pch_iir & SDE_GMBUS_CPT)
- intel_gmbus_irq_handler(dev_priv);
+ intel_gmbus_irq_handler(display);
if (pch_iir & SDE_AUDIO_CP_REQ_CPT)
drm_dbg(&dev_priv->drm, "Audio CP request interrupt\n");
@@ -1128,7 +1129,7 @@ void gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) &&
(iir & BXT_DE_PORT_GMBUS)) {
- intel_gmbus_irq_handler(dev_priv);
+ intel_gmbus_irq_handler(display);
found = true;
}
diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c
index f0e3be0fe4208..e8129a7202103 100644
--- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c
+++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c
@@ -323,6 +323,7 @@ enum {
static void icl_native_gpio_set_value(struct drm_i915_private *dev_priv,
int gpio, bool value)
{
+ struct intel_display *display = &dev_priv->display;
int index;
if (drm_WARN_ON(&dev_priv->drm, DISPLAY_VER(dev_priv) == 11 && gpio >= MIPI_RESET_2))
@@ -367,7 +368,7 @@ static void icl_native_gpio_set_value(struct drm_i915_private *dev_priv,
case MIPI_AVEE_EN_2:
index = gpio == MIPI_AVEE_EN_1 ? 1 : 2;
- intel_de_rmw(dev_priv, GPIO(dev_priv, index),
+ intel_de_rmw(display, GPIO(display, index),
GPIO_CLOCK_VAL_OUT,
GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_DIR_OUT |
GPIO_CLOCK_VAL_MASK | (value ? GPIO_CLOCK_VAL_OUT : 0));
@@ -376,7 +377,7 @@ static void icl_native_gpio_set_value(struct drm_i915_private *dev_priv,
case MIPI_VIO_EN_2:
index = gpio == MIPI_VIO_EN_1 ? 1 : 2;
- intel_de_rmw(dev_priv, GPIO(dev_priv, index),
+ intel_de_rmw(display, GPIO(display, index),
GPIO_DATA_VAL_OUT,
GPIO_DATA_DIR_MASK | GPIO_DATA_DIR_OUT |
GPIO_DATA_VAL_MASK | (value ? GPIO_DATA_VAL_OUT : 0));
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c
index 12e7628cbecfb..2bb4d829ca3c4 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo.c
+++ b/drivers/gpu/drm/i915/display/intel_dvo.c
@@ -416,6 +416,7 @@ static bool intel_dvo_init_dev(struct drm_i915_private *dev_priv,
struct intel_dvo *intel_dvo,
const struct intel_dvo_device *dvo)
{
+ struct intel_display *display = &dev_priv->display;
struct i2c_adapter *i2c;
u32 dpll[I915_MAX_PIPES];
enum pipe pipe;
@@ -427,7 +428,7 @@ static bool intel_dvo_init_dev(struct drm_i915_private *dev_priv,
* special cases, but otherwise default to what's defined
* in the spec.
*/
- if (intel_gmbus_is_valid_pin(dev_priv, dvo->gpio))
+ if (intel_gmbus_is_valid_pin(display, dvo->gpio))
gpio = dvo->gpio;
else if (dvo->type == INTEL_DVO_CHIP_LVDS)
gpio = GMBUS_PIN_SSC;
@@ -439,7 +440,7 @@ static bool intel_dvo_init_dev(struct drm_i915_private *dev_priv,
* It appears that everything is on GPIOE except for panels
* on i830 laptops, which are on GPIOB (DVOA).
*/
- i2c = intel_gmbus_get_adapter(dev_priv, gpio);
+ i2c = intel_gmbus_get_adapter(display, gpio);
intel_dvo->dev = *dvo;
@@ -488,6 +489,7 @@ static bool intel_dvo_probe(struct drm_i915_private *i915,
void intel_dvo_init(struct drm_i915_private *i915)
{
+ struct intel_display *display = &i915->display;
struct intel_connector *connector;
struct intel_encoder *encoder;
struct intel_dvo *intel_dvo;
@@ -548,7 +550,7 @@ void intel_dvo_init(struct drm_i915_private *i915)
drm_connector_init_with_ddc(&i915->drm, &connector->base,
&intel_dvo_connector_funcs,
intel_dvo_connector_type(&intel_dvo->dev),
- intel_gmbus_get_adapter(i915, GMBUS_PIN_DPC));
+ intel_gmbus_get_adapter(display, GMBUS_PIN_DPC));
drm_connector_helper_add(&connector->base,
&intel_dvo_connector_helper_funcs);
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c
index 88b37deb5c82a..3a268e70e3080 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus.c
+++ b/drivers/gpu/drm/i915/display/intel_gmbus.c
@@ -48,7 +48,7 @@ struct intel_gmbus {
u32 reg0;
i915_reg_t gpio_reg;
struct i2c_algo_bit_data bit_algo;
- struct drm_i915_private *i915;
+ struct intel_display *display;
};
enum gmbus_gpio {
@@ -149,9 +149,10 @@ static const struct gmbus_pin gmbus_pins_mtp[] = {
[GMBUS_PIN_12_TC4_ICP] = { "tc4", GPIOM },
};
-static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915,
+static const struct gmbus_pin *get_gmbus_pin(struct intel_display *display,
unsigned int pin)
{
+ struct drm_i915_private *i915 = to_i915(display->drm);
const struct gmbus_pin *pins;
size_t size;
@@ -173,7 +174,7 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915,
} else if (IS_GEMINILAKE(i915) || IS_BROXTON(i915)) {
pins = gmbus_pins_bxt;
size = ARRAY_SIZE(gmbus_pins_bxt);
- } else if (DISPLAY_VER(i915) == 9) {
+ } else if (DISPLAY_VER(display) == 9) {
pins = gmbus_pins_skl;
size = ARRAY_SIZE(gmbus_pins_skl);
} else if (IS_BROADWELL(i915)) {
@@ -190,9 +191,9 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915,
return &pins[pin];
}
-bool intel_gmbus_is_valid_pin(struct drm_i915_private *i915, unsigned int pin)
+bool intel_gmbus_is_valid_pin(struct intel_display *display, unsigned int pin)
{
- return get_gmbus_pin(i915, pin);
+ return get_gmbus_pin(display, pin);
}
/* Intel GPIO access functions */
@@ -206,42 +207,45 @@ to_intel_gmbus(struct i2c_adapter *i2c)
}
void
-intel_gmbus_reset(struct drm_i915_private *i915)
+intel_gmbus_reset(struct intel_display *display)
{
- intel_de_write(i915, GMBUS0(i915), 0);
- intel_de_write(i915, GMBUS4(i915), 0);
+ intel_de_write(display, GMBUS0(display), 0);
+ intel_de_write(display, GMBUS4(display), 0);
}
-static void pnv_gmbus_clock_gating(struct drm_i915_private *i915,
+static void pnv_gmbus_clock_gating(struct intel_display *display,
bool enable)
{
/* When using bit bashing for I2C, this bit needs to be set to 1 */
- intel_de_rmw(i915, DSPCLK_GATE_D(i915), PNV_GMBUSUNIT_CLOCK_GATE_DISABLE,
+ intel_de_rmw(display, DSPCLK_GATE_D(display),
+ PNV_GMBUSUNIT_CLOCK_GATE_DISABLE,
!enable ? PNV_GMBUSUNIT_CLOCK_GATE_DISABLE : 0);
}
-static void pch_gmbus_clock_gating(struct drm_i915_private *i915,
+static void pch_gmbus_clock_gating(struct intel_display *display,
bool enable)
{
- intel_de_rmw(i915, SOUTH_DSPCLK_GATE_D, PCH_GMBUSUNIT_CLOCK_GATE_DISABLE,
+ intel_de_rmw(display, SOUTH_DSPCLK_GATE_D,
+ PCH_GMBUSUNIT_CLOCK_GATE_DISABLE,
!enable ? PCH_GMBUSUNIT_CLOCK_GATE_DISABLE : 0);
}
-static void bxt_gmbus_clock_gating(struct drm_i915_private *i915,
+static void bxt_gmbus_clock_gating(struct intel_display *display,
bool enable)
{
- intel_de_rmw(i915, GEN9_CLKGATE_DIS_4, BXT_GMBUS_GATING_DIS,
+ intel_de_rmw(display, GEN9_CLKGATE_DIS_4, BXT_GMBUS_GATING_DIS,
!enable ? BXT_GMBUS_GATING_DIS : 0);
}
static u32 get_reserved(struct intel_gmbus *bus)
{
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
+ struct drm_i915_private *i915 = to_i915(display->drm);
u32 reserved = 0;
/* On most chips, these bits must be preserved in software. */
if (!IS_I830(i915) && !IS_I845G(i915))
- reserved = intel_de_read_notrace(i915, bus->gpio_reg) &
+ reserved = intel_de_read_notrace(display, bus->gpio_reg) &
(GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE);
return reserved;
@@ -250,31 +254,31 @@ static u32 get_reserved(struct intel_gmbus *bus)
static int get_clock(void *data)
{
struct intel_gmbus *bus = data;
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
u32 reserved = get_reserved(bus);
- intel_de_write_notrace(i915, bus->gpio_reg, reserved | GPIO_CLOCK_DIR_MASK);
- intel_de_write_notrace(i915, bus->gpio_reg, reserved);
+ intel_de_write_notrace(display, bus->gpio_reg, reserved | GPIO_CLOCK_DIR_MASK);
+ intel_de_write_notrace(display, bus->gpio_reg, reserved);
- return (intel_de_read_notrace(i915, bus->gpio_reg) & GPIO_CLOCK_VAL_IN) != 0;
+ return (intel_de_read_notrace(display, bus->gpio_reg) & GPIO_CLOCK_VAL_IN) != 0;
}
static int get_data(void *data)
{
struct intel_gmbus *bus = data;
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
u32 reserved = get_reserved(bus);
- intel_de_write_notrace(i915, bus->gpio_reg, reserved | GPIO_DATA_DIR_MASK);
- intel_de_write_notrace(i915, bus->gpio_reg, reserved);
+ intel_de_write_notrace(display, bus->gpio_reg, reserved | GPIO_DATA_DIR_MASK);
+ intel_de_write_notrace(display, bus->gpio_reg, reserved);
- return (intel_de_read_notrace(i915, bus->gpio_reg) & GPIO_DATA_VAL_IN) != 0;
+ return (intel_de_read_notrace(display, bus->gpio_reg) & GPIO_DATA_VAL_IN) != 0;
}
static void set_clock(void *data, int state_high)
{
struct intel_gmbus *bus = data;
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
u32 reserved = get_reserved(bus);
u32 clock_bits;
@@ -284,14 +288,14 @@ static void set_clock(void *data, int state_high)
clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
GPIO_CLOCK_VAL_MASK;
- intel_de_write_notrace(i915, bus->gpio_reg, reserved | clock_bits);
- intel_de_posting_read(i915, bus->gpio_reg);
+ intel_de_write_notrace(display, bus->gpio_reg, reserved | clock_bits);
+ intel_de_posting_read(display, bus->gpio_reg);
}
static void set_data(void *data, int state_high)
{
struct intel_gmbus *bus = data;
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
u32 reserved = get_reserved(bus);
u32 data_bits;
@@ -301,20 +305,21 @@ static void set_data(void *data, int state_high)
data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
GPIO_DATA_VAL_MASK;
- intel_de_write_notrace(i915, bus->gpio_reg, reserved | data_bits);
- intel_de_posting_read(i915, bus->gpio_reg);
+ intel_de_write_notrace(display, bus->gpio_reg, reserved | data_bits);
+ intel_de_posting_read(display, bus->gpio_reg);
}
static int
intel_gpio_pre_xfer(struct i2c_adapter *adapter)
{
struct intel_gmbus *bus = to_intel_gmbus(adapter);
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
+ struct drm_i915_private *i915 = to_i915(display->drm);
- intel_gmbus_reset(i915);
+ intel_gmbus_reset(display);
if (IS_PINEVIEW(i915))
- pnv_gmbus_clock_gating(i915, false);
+ pnv_gmbus_clock_gating(display, false);
set_data(bus, 1);
set_clock(bus, 1);
@@ -326,13 +331,14 @@ static void
intel_gpio_post_xfer(struct i2c_adapter *adapter)
{
struct intel_gmbus *bus = to_intel_gmbus(adapter);
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
+ struct drm_i915_private *i915 = to_i915(display->drm);
set_data(bus, 1);
set_clock(bus, 1);
if (IS_PINEVIEW(i915))
- pnv_gmbus_clock_gating(i915, true);
+ pnv_gmbus_clock_gating(display, true);
}
static void
@@ -355,16 +361,17 @@ intel_gpio_setup(struct intel_gmbus *bus, i915_reg_t gpio_reg)
algo->data = bus;
}
-static bool has_gmbus_irq(struct drm_i915_private *i915)
+static bool has_gmbus_irq(struct intel_display *display)
{
+ struct drm_i915_private *i915 = to_i915(display->drm);
/*
* encoder->shutdown() may want to use GMBUS
* after irqs have already been disabled.
*/
- return HAS_GMBUS_IRQ(i915) && intel_irqs_enabled(i915);
+ return HAS_GMBUS_IRQ(display) && intel_irqs_enabled(i915);
}
-static int gmbus_wait(struct drm_i915_private *i915, u32 status, u32 irq_en)
+static int gmbus_wait(struct intel_display *display, u32 status, u32 irq_en)
{
DEFINE_WAIT(wait);
u32 gmbus2;
@@ -374,21 +381,21 @@ static int gmbus_wait(struct drm_i915_private *i915, u32 status, u32 irq_en)
* we also need to check for NAKs besides the hw ready/idle signal, we
* need to wake up periodically and check that ourselves.
*/
- if (!has_gmbus_irq(i915))
+ if (!has_gmbus_irq(display))
irq_en = 0;
- add_wait_queue(&i915->display.gmbus.wait_queue, &wait);
- intel_de_write_fw(i915, GMBUS4(i915), irq_en);
+ add_wait_queue(&display->gmbus.wait_queue, &wait);
+ intel_de_write_fw(display, GMBUS4(display), irq_en);
status |= GMBUS_SATOER;
- ret = wait_for_us((gmbus2 = intel_de_read_fw(i915, GMBUS2(i915))) & status,
+ ret = wait_for_us((gmbus2 = intel_de_read_fw(display, GMBUS2(display))) & status,
2);
if (ret)
- ret = wait_for((gmbus2 = intel_de_read_fw(i915, GMBUS2(i915))) & status,
+ ret = wait_for((gmbus2 = intel_de_read_fw(display, GMBUS2(display))) & status,
50);
- intel_de_write_fw(i915, GMBUS4(i915), 0);
- remove_wait_queue(&i915->display.gmbus.wait_queue, &wait);
+ intel_de_write_fw(display, GMBUS4(display), 0);
+ remove_wait_queue(&display->gmbus.wait_queue, &wait);
if (gmbus2 & GMBUS_SATOER)
return -ENXIO;
@@ -397,7 +404,7 @@ static int gmbus_wait(struct drm_i915_private *i915, u32 status, u32 irq_en)
}
static int
-gmbus_wait_idle(struct drm_i915_private *i915)
+gmbus_wait_idle(struct intel_display *display)
{
DEFINE_WAIT(wait);
u32 irq_enable;
@@ -405,33 +412,33 @@ gmbus_wait_idle(struct drm_i915_private *i915)
/* Important: The hw handles only the first bit, so set only one! */
irq_enable = 0;
- if (has_gmbus_irq(i915))
+ if (has_gmbus_irq(display))
irq_enable = GMBUS_IDLE_EN;
- add_wait_queue(&i915->display.gmbus.wait_queue, &wait);
- intel_de_write_fw(i915, GMBUS4(i915), irq_enable);
+ add_wait_queue(&display->gmbus.wait_queue, &wait);
+ intel_de_write_fw(display, GMBUS4(display), irq_enable);
- ret = intel_de_wait_fw(i915, GMBUS2(i915), GMBUS_ACTIVE, 0, 10);
+ ret = intel_de_wait_fw(display, GMBUS2(display), GMBUS_ACTIVE, 0, 10);
- intel_de_write_fw(i915, GMBUS4(i915), 0);
- remove_wait_queue(&i915->display.gmbus.wait_queue, &wait);
+ intel_de_write_fw(display, GMBUS4(display), 0);
+ remove_wait_queue(&display->gmbus.wait_queue, &wait);
return ret;
}
-static unsigned int gmbus_max_xfer_size(struct drm_i915_private *i915)
+static unsigned int gmbus_max_xfer_size(struct intel_display *display)
{
- return DISPLAY_VER(i915) >= 9 ? GEN9_GMBUS_BYTE_COUNT_MAX :
+ return DISPLAY_VER(display) >= 9 ? GEN9_GMBUS_BYTE_COUNT_MAX :
GMBUS_BYTE_COUNT_MAX;
}
static int
-gmbus_xfer_read_chunk(struct drm_i915_private *i915,
+gmbus_xfer_read_chunk(struct intel_display *display,
unsigned short addr, u8 *buf, unsigned int len,
u32 gmbus0_reg, u32 gmbus1_index)
{
unsigned int size = len;
- bool burst_read = len > gmbus_max_xfer_size(i915);
+ bool burst_read = len > gmbus_max_xfer_size(display);
bool extra_byte_added = false;
if (burst_read) {
@@ -444,21 +451,21 @@ gmbus_xfer_read_chunk(struct drm_i915_private *i915,
len++;
}
size = len % 256 + 256;
- intel_de_write_fw(i915, GMBUS0(i915),
+ intel_de_write_fw(display, GMBUS0(display),
gmbus0_reg | GMBUS_BYTE_CNT_OVERRIDE);
}
- intel_de_write_fw(i915, GMBUS1(i915),
+ intel_de_write_fw(display, GMBUS1(display),
gmbus1_index | GMBUS_CYCLE_WAIT | (size << GMBUS_BYTE_COUNT_SHIFT) | (addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_READ | GMBUS_SW_RDY);
while (len) {
int ret;
u32 val, loop = 0;
- ret = gmbus_wait(i915, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
+ ret = gmbus_wait(display, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
if (ret)
return ret;
- val = intel_de_read_fw(i915, GMBUS3(i915));
+ val = intel_de_read_fw(display, GMBUS3(display));
do {
if (extra_byte_added && len == 1) {
len--;
@@ -471,7 +478,7 @@ gmbus_xfer_read_chunk(struct drm_i915_private *i915,
if (burst_read && len == size - 4)
/* Reset the override bit */
- intel_de_write_fw(i915, GMBUS0(i915), gmbus0_reg);
+ intel_de_write_fw(display, GMBUS0(display), gmbus0_reg);
}
return 0;
@@ -488,9 +495,10 @@ gmbus_xfer_read_chunk(struct drm_i915_private *i915,
#define INTEL_GMBUS_BURST_READ_MAX_LEN 767U
static int
-gmbus_xfer_read(struct drm_i915_private *i915, struct i2c_msg *msg,
+gmbus_xfer_read(struct intel_display *display, struct i2c_msg *msg,
u32 gmbus0_reg, u32 gmbus1_index)
{
+ struct drm_i915_private *i915 = to_i915(display->drm);
u8 *buf = msg->buf;
unsigned int rx_size = msg->len;
unsigned int len;
@@ -500,9 +508,9 @@ gmbus_xfer_read(struct drm_i915_private *i915, struct i2c_msg *msg,
if (HAS_GMBUS_BURST_READ(i915))
len = min(rx_size, INTEL_GMBUS_BURST_READ_MAX_LEN);
else
- len = min(rx_size, gmbus_max_xfer_size(i915));
+ len = min(rx_size, gmbus_max_xfer_size(display));
- ret = gmbus_xfer_read_chunk(i915, msg->addr, buf, len,
+ ret = gmbus_xfer_read_chunk(display, msg->addr, buf, len,
gmbus0_reg, gmbus1_index);
if (ret)
return ret;
@@ -515,7 +523,7 @@ gmbus_xfer_read(struct drm_i915_private *i915, struct i2c_msg *msg,
}
static int
-gmbus_xfer_write_chunk(struct drm_i915_private *i915,
+gmbus_xfer_write_chunk(struct intel_display *display,
unsigned short addr, u8 *buf, unsigned int len,
u32 gmbus1_index)
{
@@ -528,8 +536,8 @@ gmbus_xfer_write_chunk(struct drm_i915_private *i915,
len -= 1;
}
- intel_de_write_fw(i915, GMBUS3(i915), val);
- intel_de_write_fw(i915, GMBUS1(i915),
+ intel_de_write_fw(display, GMBUS3(display), val);
+ intel_de_write_fw(display, GMBUS1(display),
gmbus1_index | GMBUS_CYCLE_WAIT | (chunk_size << GMBUS_BYTE_COUNT_SHIFT) | (addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
while (len) {
int ret;
@@ -539,9 +547,9 @@ gmbus_xfer_write_chunk(struct drm_i915_private *i915,
val |= *buf++ << (8 * loop);
} while (--len && ++loop < 4);
- intel_de_write_fw(i915, GMBUS3(i915), val);
+ intel_de_write_fw(display, GMBUS3(display), val);
- ret = gmbus_wait(i915, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
+ ret = gmbus_wait(display, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
if (ret)
return ret;
}
@@ -550,7 +558,7 @@ gmbus_xfer_write_chunk(struct drm_i915_private *i915,
}
static int
-gmbus_xfer_write(struct drm_i915_private *i915, struct i2c_msg *msg,
+gmbus_xfer_write(struct intel_display *display, struct i2c_msg *msg,
u32 gmbus1_index)
{
u8 *buf = msg->buf;
@@ -559,9 +567,9 @@ gmbus_xfer_write(struct drm_i915_private *i915, struct i2c_msg *msg,
int ret;
do {
- len = min(tx_size, gmbus_max_xfer_size(i915));
+ len = min(tx_size, gmbus_max_xfer_size(display));
- ret = gmbus_xfer_write_chunk(i915, msg->addr, buf, len,
+ ret = gmbus_xfer_write_chunk(display, msg->addr, buf, len,
gmbus1_index);
if (ret)
return ret;
@@ -588,7 +596,7 @@ gmbus_is_index_xfer(struct i2c_msg *msgs, int i, int num)
}
static int
-gmbus_index_xfer(struct drm_i915_private *i915, struct i2c_msg *msgs,
+gmbus_index_xfer(struct intel_display *display, struct i2c_msg *msgs,
u32 gmbus0_reg)
{
u32 gmbus1_index = 0;
@@ -604,17 +612,17 @@ gmbus_index_xfer(struct drm_i915_private *i915, struct i2c_msg *msgs,
/* GMBUS5 holds 16-bit index */
if (gmbus5)
- intel_de_write_fw(i915, GMBUS5(i915), gmbus5);
+ intel_de_write_fw(display, GMBUS5(display), gmbus5);
if (msgs[1].flags & I2C_M_RD)
- ret = gmbus_xfer_read(i915, &msgs[1], gmbus0_reg,
+ ret = gmbus_xfer_read(display, &msgs[1], gmbus0_reg,
gmbus1_index);
else
- ret = gmbus_xfer_write(i915, &msgs[1], gmbus1_index);
+ ret = gmbus_xfer_write(display, &msgs[1], gmbus1_index);
/* Clear GMBUS5 after each index transfer */
if (gmbus5)
- intel_de_write_fw(i915, GMBUS5(i915), 0);
+ intel_de_write_fw(display, GMBUS5(display), 0);
return ret;
}
@@ -624,34 +632,35 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
u32 gmbus0_source)
{
struct intel_gmbus *bus = to_intel_gmbus(adapter);
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
+ struct drm_i915_private *i915 = to_i915(display->drm);
int i = 0, inc, try = 0;
int ret = 0;
/* Display WA #0868: skl,bxt,kbl,cfl,glk */
if (IS_GEMINILAKE(i915) || IS_BROXTON(i915))
- bxt_gmbus_clock_gating(i915, false);
+ bxt_gmbus_clock_gating(display, false);
else if (HAS_PCH_SPT(i915) || HAS_PCH_CNP(i915))
- pch_gmbus_clock_gating(i915, false);
+ pch_gmbus_clock_gating(display, false);
retry:
- intel_de_write_fw(i915, GMBUS0(i915), gmbus0_source | bus->reg0);
+ intel_de_write_fw(display, GMBUS0(display), gmbus0_source | bus->reg0);
for (; i < num; i += inc) {
inc = 1;
if (gmbus_is_index_xfer(msgs, i, num)) {
- ret = gmbus_index_xfer(i915, &msgs[i],
+ ret = gmbus_index_xfer(display, &msgs[i],
gmbus0_source | bus->reg0);
inc = 2; /* an index transmission is two msgs */
} else if (msgs[i].flags & I2C_M_RD) {
- ret = gmbus_xfer_read(i915, &msgs[i],
+ ret = gmbus_xfer_read(display, &msgs[i],
gmbus0_source | bus->reg0, 0);
} else {
- ret = gmbus_xfer_write(i915, &msgs[i], 0);
+ ret = gmbus_xfer_write(display, &msgs[i], 0);
}
if (!ret)
- ret = gmbus_wait(i915,
+ ret = gmbus_wait(display,
GMBUS_HW_WAIT_PHASE, GMBUS_HW_WAIT_EN);
if (ret == -ETIMEDOUT)
goto timeout;
@@ -663,19 +672,19 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
* a STOP on the very first cycle. To simplify the code we
* unconditionally generate the STOP condition with an additional gmbus
* cycle. */
- intel_de_write_fw(i915, GMBUS1(i915), GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
+ intel_de_write_fw(display, GMBUS1(display), GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
/* Mark the GMBUS interface as disabled after waiting for idle.
* We will re-enable it at the start of the next xfer,
* till then let it sleep.
*/
- if (gmbus_wait_idle(i915)) {
- drm_dbg_kms(&i915->drm,
+ if (gmbus_wait_idle(display)) {
+ drm_dbg_kms(display->drm,
"GMBUS [%s] timed out waiting for idle\n",
adapter->name);
ret = -ETIMEDOUT;
}
- intel_de_write_fw(i915, GMBUS0(i915), 0);
+ intel_de_write_fw(display, GMBUS0(display), 0);
ret = ret ?: i;
goto out;
@@ -694,8 +703,8 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
* it's slow responding and only answers on the 2nd retry.
*/
ret = -ENXIO;
- if (gmbus_wait_idle(i915)) {
- drm_dbg_kms(&i915->drm,
+ if (gmbus_wait_idle(display)) {
+ drm_dbg_kms(display->drm,
"GMBUS [%s] timed out after NAK\n",
adapter->name);
ret = -ETIMEDOUT;
@@ -705,11 +714,11 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
* of resetting the GMBUS controller and so clearing the
* BUS_ERROR raised by the target's NAK.
*/
- intel_de_write_fw(i915, GMBUS1(i915), GMBUS_SW_CLR_INT);
- intel_de_write_fw(i915, GMBUS1(i915), 0);
- intel_de_write_fw(i915, GMBUS0(i915), 0);
+ intel_de_write_fw(display, GMBUS1(display), GMBUS_SW_CLR_INT);
+ intel_de_write_fw(display, GMBUS1(display), 0);
+ intel_de_write_fw(display, GMBUS0(display), 0);
- drm_dbg_kms(&i915->drm, "GMBUS [%s] NAK for addr: %04x %c(%d)\n",
+ drm_dbg_kms(display->drm, "GMBUS [%s] NAK for addr: %04x %c(%d)\n",
adapter->name, msgs[i].addr,
(msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len);
@@ -720,7 +729,7 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
* drm_do_probe_ddc_edid, which bails out on the first -ENXIO.
*/
if (ret == -ENXIO && i == 0 && try++ == 0) {
- drm_dbg_kms(&i915->drm,
+ drm_dbg_kms(display->drm,
"GMBUS [%s] NAK on first message, retry\n",
adapter->name);
goto retry;
@@ -729,10 +738,10 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
goto out;
timeout:
- drm_dbg_kms(&i915->drm,
+ drm_dbg_kms(display->drm,
"GMBUS [%s] timed out, falling back to bit banging on pin %d\n",
bus->adapter.name, bus->reg0 & 0xff);
- intel_de_write_fw(i915, GMBUS0(i915), 0);
+ intel_de_write_fw(display, GMBUS0(display), 0);
/*
* Hardware may not support GMBUS over these pins? Try GPIO bitbanging
@@ -743,9 +752,9 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
out:
/* Display WA #0868: skl,bxt,kbl,cfl,glk */
if (IS_GEMINILAKE(i915) || IS_BROXTON(i915))
- bxt_gmbus_clock_gating(i915, true);
+ bxt_gmbus_clock_gating(display, true);
else if (HAS_PCH_SPT(i915) || HAS_PCH_CNP(i915))
- pch_gmbus_clock_gating(i915, true);
+ pch_gmbus_clock_gating(display, true);
return ret;
}
@@ -754,7 +763,8 @@ static int
gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{
struct intel_gmbus *bus = to_intel_gmbus(adapter);
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
+ struct drm_i915_private *i915 = to_i915(display->drm);
intel_wakeref_t wakeref;
int ret;
@@ -778,7 +788,8 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
{
struct intel_gmbus *bus = to_intel_gmbus(adapter);
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
+ struct drm_i915_private *i915 = to_i915(display->drm);
u8 cmd = DRM_HDCP_DDC_AKSV;
u8 buf[DRM_HDCP_KSV_LEN] = {};
struct i2c_msg msgs[] = {
@@ -799,7 +810,7 @@ int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
int ret;
wakeref = intel_display_power_get(i915, POWER_DOMAIN_GMBUS);
- mutex_lock(&i915->display.gmbus.mutex);
+ mutex_lock(&display->gmbus.mutex);
/*
* In order to output Aksv to the receiver, use an indexed write to
@@ -808,7 +819,7 @@ int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
*/
ret = do_gmbus_xfer(adapter, msgs, ARRAY_SIZE(msgs), GMBUS_AKSV_SELECT);
- mutex_unlock(&i915->display.gmbus.mutex);
+ mutex_unlock(&display->gmbus.mutex);
intel_display_power_put(i915, POWER_DOMAIN_GMBUS, wakeref);
return ret;
@@ -832,27 +843,27 @@ static void gmbus_lock_bus(struct i2c_adapter *adapter,
unsigned int flags)
{
struct intel_gmbus *bus = to_intel_gmbus(adapter);
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
- mutex_lock(&i915->display.gmbus.mutex);
+ mutex_lock(&display->gmbus.mutex);
}
static int gmbus_trylock_bus(struct i2c_adapter *adapter,
unsigned int flags)
{
struct intel_gmbus *bus = to_intel_gmbus(adapter);
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
- return mutex_trylock(&i915->display.gmbus.mutex);
+ return mutex_trylock(&display->gmbus.mutex);
}
static void gmbus_unlock_bus(struct i2c_adapter *adapter,
unsigned int flags)
{
struct intel_gmbus *bus = to_intel_gmbus(adapter);
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
- mutex_unlock(&i915->display.gmbus.mutex);
+ mutex_unlock(&display->gmbus.mutex);
}
static const struct i2c_lock_operations gmbus_lock_ops = {
@@ -863,31 +874,32 @@ static const struct i2c_lock_operations gmbus_lock_ops = {
/**
* intel_gmbus_setup - instantiate all Intel i2c GMBuses
- * @i915: i915 device private
+ * @display: display device
*/
-int intel_gmbus_setup(struct drm_i915_private *i915)
+int intel_gmbus_setup(struct intel_display *display)
{
- struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
+ struct drm_i915_private *i915 = to_i915(display->drm);
+ struct pci_dev *pdev = to_pci_dev(display->drm->dev);
unsigned int pin;
int ret;
if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
- i915->display.gmbus.mmio_base = VLV_DISPLAY_BASE;
- else if (!HAS_GMCH(i915))
+ display->gmbus.mmio_base = VLV_DISPLAY_BASE;
+ else if (!HAS_GMCH(display))
/*
* Broxton uses the same PCH offsets for South Display Engine,
* even though it doesn't have a PCH.
*/
- i915->display.gmbus.mmio_base = PCH_DISPLAY_BASE;
+ display->gmbus.mmio_base = PCH_DISPLAY_BASE;
- mutex_init(&i915->display.gmbus.mutex);
- init_waitqueue_head(&i915->display.gmbus.wait_queue);
+ mutex_init(&display->gmbus.mutex);
+ init_waitqueue_head(&display->gmbus.wait_queue);
- for (pin = 0; pin < ARRAY_SIZE(i915->display.gmbus.bus); pin++) {
+ for (pin = 0; pin < ARRAY_SIZE(display->gmbus.bus); pin++) {
const struct gmbus_pin *gmbus_pin;
struct intel_gmbus *bus;
- gmbus_pin = get_gmbus_pin(i915, pin);
+ gmbus_pin = get_gmbus_pin(display, pin);
if (!gmbus_pin)
continue;
@@ -903,7 +915,7 @@ int intel_gmbus_setup(struct drm_i915_private *i915)
"i915 gmbus %s", gmbus_pin->name);
bus->adapter.dev.parent = &pdev->dev;
- bus->i915 = i915;
+ bus->display = display;
bus->adapter.algo = &gmbus_algorithm;
bus->adapter.lock_ops = &gmbus_lock_ops;
@@ -921,7 +933,7 @@ int intel_gmbus_setup(struct drm_i915_private *i915)
if (IS_I830(i915))
bus->force_bit = 1;
- intel_gpio_setup(bus, GPIO(i915, gmbus_pin->gpio));
+ intel_gpio_setup(bus, GPIO(display, gmbus_pin->gpio));
ret = i2c_add_adapter(&bus->adapter);
if (ret) {
@@ -929,43 +941,43 @@ int intel_gmbus_setup(struct drm_i915_private *i915)
goto err;
}
- i915->display.gmbus.bus[pin] = bus;
+ display->gmbus.bus[pin] = bus;
}
- intel_gmbus_reset(i915);
+ intel_gmbus_reset(display);
return 0;
err:
- intel_gmbus_teardown(i915);
+ intel_gmbus_teardown(display);
return ret;
}
-struct i2c_adapter *intel_gmbus_get_adapter(struct drm_i915_private *i915,
+struct i2c_adapter *intel_gmbus_get_adapter(struct intel_display *display,
unsigned int pin)
{
- if (drm_WARN_ON(&i915->drm, pin >= ARRAY_SIZE(i915->display.gmbus.bus) ||
- !i915->display.gmbus.bus[pin]))
+ if (drm_WARN_ON(display->drm, pin >= ARRAY_SIZE(display->gmbus.bus) ||
+ !display->gmbus.bus[pin]))
return NULL;
- return &i915->display.gmbus.bus[pin]->adapter;
+ return &display->gmbus.bus[pin]->adapter;
}
void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit)
{
struct intel_gmbus *bus = to_intel_gmbus(adapter);
- struct drm_i915_private *i915 = bus->i915;
+ struct intel_display *display = bus->display;
- mutex_lock(&i915->display.gmbus.mutex);
+ mutex_lock(&display->gmbus.mutex);
bus->force_bit += force_bit ? 1 : -1;
- drm_dbg_kms(&i915->drm,
+ drm_dbg_kms(display->drm,
"%sabling bit-banging on %s. force bit now %d\n",
force_bit ? "en" : "dis", adapter->name,
bus->force_bit);
- mutex_unlock(&i915->display.gmbus.mutex);
+ mutex_unlock(&display->gmbus.mutex);
}
bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
@@ -975,25 +987,25 @@ bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
return bus->force_bit;
}
-void intel_gmbus_teardown(struct drm_i915_private *i915)
+void intel_gmbus_teardown(struct intel_display *display)
{
unsigned int pin;
- for (pin = 0; pin < ARRAY_SIZE(i915->display.gmbus.bus); pin++) {
+ for (pin = 0; pin < ARRAY_SIZE(display->gmbus.bus); pin++) {
struct intel_gmbus *bus;
- bus = i915->display.gmbus.bus[pin];
+ bus = display->gmbus.bus[pin];
if (!bus)
continue;
i2c_del_adapter(&bus->adapter);
kfree(bus);
- i915->display.gmbus.bus[pin] = NULL;
+ display->gmbus.bus[pin] = NULL;
}
}
-void intel_gmbus_irq_handler(struct drm_i915_private *i915)
+void intel_gmbus_irq_handler(struct intel_display *display)
{
- wake_up_all(&i915->display.gmbus.wait_queue);
+ wake_up_all(&display->gmbus.wait_queue);
}
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.h b/drivers/gpu/drm/i915/display/intel_gmbus.h
index 8111eb23e2af2..35a200a9efc00 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus.h
+++ b/drivers/gpu/drm/i915/display/intel_gmbus.h
@@ -8,8 +8,8 @@
#include <linux/types.h>
-struct drm_i915_private;
struct i2c_adapter;
+struct intel_display;
#define GMBUS_PIN_DISABLED 0
#define GMBUS_PIN_SSC 1
@@ -34,18 +34,17 @@ struct i2c_adapter;
#define GMBUS_NUM_PINS 15 /* including 0 */
-int intel_gmbus_setup(struct drm_i915_private *dev_priv);
-void intel_gmbus_teardown(struct drm_i915_private *dev_priv);
-bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
- unsigned int pin);
+int intel_gmbus_setup(struct intel_display *display);
+void intel_gmbus_teardown(struct intel_display *display);
+bool intel_gmbus_is_valid_pin(struct intel_display *display, unsigned int pin);
int intel_gmbus_output_aksv(struct i2c_adapter *adapter);
struct i2c_adapter *
-intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, unsigned int pin);
+intel_gmbus_get_adapter(struct intel_display *display, unsigned int pin);
void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter);
-void intel_gmbus_reset(struct drm_i915_private *dev_priv);
+void intel_gmbus_reset(struct intel_display *display);
-void intel_gmbus_irq_handler(struct drm_i915_private *i915);
+void intel_gmbus_irq_handler(struct intel_display *display);
#endif /* __INTEL_GMBUS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus_regs.h b/drivers/gpu/drm/i915/display/intel_gmbus_regs.h
index 53aacbda983c4..59bad1dda6d6a 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_gmbus_regs.h
@@ -8,9 +8,9 @@
#include "i915_reg_defs.h"
-#define GMBUS_MMIO_BASE(__i915) ((__i915)->display.gmbus.mmio_base)
+#define __GMBUS_MMIO_BASE(__display) ((__display)->gmbus.mmio_base)
-#define GPIO(__i915, gpio) _MMIO(GMBUS_MMIO_BASE(__i915) + 0x5010 + 4 * (gpio))
+#define GPIO(__display, gpio) _MMIO(__GMBUS_MMIO_BASE(__display) + 0x5010 + 4 * (gpio))
#define GPIO_CLOCK_DIR_MASK (1 << 0)
#define GPIO_CLOCK_DIR_IN (0 << 1)
#define GPIO_CLOCK_DIR_OUT (1 << 1)
@@ -27,7 +27,7 @@
#define GPIO_DATA_PULLUP_DISABLE (1 << 13)
/* clock/port select */
-#define GMBUS0(__i915) _MMIO(GMBUS_MMIO_BASE(__i915) + 0x5100)
+#define GMBUS0(__display) _MMIO(__GMBUS_MMIO_BASE(__display) + 0x5100)
#define GMBUS_AKSV_SELECT (1 << 11)
#define GMBUS_RATE_100KHZ (0 << 8)
#define GMBUS_RATE_50KHZ (1 << 8)
@@ -37,7 +37,7 @@
#define GMBUS_BYTE_CNT_OVERRIDE (1 << 6)
/* command/status */
-#define GMBUS1(__i915) _MMIO(GMBUS_MMIO_BASE(__i915) + 0x5104)
+#define GMBUS1(__display) _MMIO(__GMBUS_MMIO_BASE(__display) + 0x5104)
#define GMBUS_SW_CLR_INT (1 << 31)
#define GMBUS_SW_RDY (1 << 30)
#define GMBUS_ENT (1 << 29) /* enable timeout */
@@ -54,7 +54,7 @@
#define GMBUS_SLAVE_WRITE (0 << 0)
/* status */
-#define GMBUS2(__i915) _MMIO(GMBUS_MMIO_BASE(__i915) + 0x5108)
+#define GMBUS2(__display) _MMIO(__GMBUS_MMIO_BASE(__display) + 0x5108)
#define GMBUS_INUSE (1 << 15)
#define GMBUS_HW_WAIT_PHASE (1 << 14)
#define GMBUS_STALL_TIMEOUT (1 << 13)
@@ -64,10 +64,10 @@
#define GMBUS_ACTIVE (1 << 9)
/* data buffer bytes 3-0 */
-#define GMBUS3(__i915) _MMIO(GMBUS_MMIO_BASE(__i915) + 0x510c)
+#define GMBUS3(__display) _MMIO(__GMBUS_MMIO_BASE(__display) + 0x510c)
/* interrupt mask (Pineview+) */
-#define GMBUS4(__i915) _MMIO(GMBUS_MMIO_BASE(__i915) + 0x5110)
+#define GMBUS4(__display) _MMIO(__GMBUS_MMIO_BASE(__display) + 0x5110)
#define GMBUS_SLAVE_TIMEOUT_EN (1 << 4)
#define GMBUS_NAK_EN (1 << 3)
#define GMBUS_IDLE_EN (1 << 2)
@@ -75,7 +75,7 @@
#define GMBUS_HW_RDY_EN (1 << 0)
/* byte index */
-#define GMBUS5(__i915) _MMIO(GMBUS_MMIO_BASE(__i915) + 0x5120)
+#define GMBUS5(__display) _MMIO(__GMBUS_MMIO_BASE(__display) + 0x5120)
#define GMBUS_2BYTE_INDEX_EN (1 << 31)
#endif /* __INTEL_GMBUS_REGS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index c5b2fbaeff897..1f3d099a97119 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2913,7 +2913,6 @@ static struct intel_encoder *
get_encoder_by_ddc_pin(struct intel_encoder *encoder, u8 ddc_pin)
{
struct intel_display *display = to_intel_display(encoder);
- struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_encoder *other;
for_each_intel_encoder(display->drm, other) {
@@ -2927,7 +2926,7 @@ get_encoder_by_ddc_pin(struct intel_encoder *encoder, u8 ddc_pin)
connector = enc_to_dig_port(other)->hdmi.attached_connector;
- if (connector && connector->base.ddc == intel_gmbus_get_adapter(i915, ddc_pin))
+ if (connector && connector->base.ddc == intel_gmbus_get_adapter(display, ddc_pin))
return other;
}
@@ -2937,7 +2936,6 @@ get_encoder_by_ddc_pin(struct intel_encoder *encoder, u8 ddc_pin)
static u8 intel_hdmi_ddc_pin(struct intel_encoder *encoder)
{
struct intel_display *display = to_intel_display(encoder);
- struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_encoder *other;
const char *source;
u8 ddc_pin;
@@ -2950,7 +2948,7 @@ static u8 intel_hdmi_ddc_pin(struct intel_encoder *encoder)
source = "platform default";
}
- if (!intel_gmbus_is_valid_pin(i915, ddc_pin)) {
+ if (!intel_gmbus_is_valid_pin(display, ddc_pin)) {
drm_dbg_kms(display->drm,
"[ENCODER:%d:%s] Invalid DDC pin %d\n",
encoder->base.base.id, encoder->base.name, ddc_pin);
@@ -3048,7 +3046,7 @@ bool intel_hdmi_init_connector(struct intel_digital_port *dig_port,
drm_connector_init_with_ddc(dev, connector,
&intel_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- intel_gmbus_get_adapter(dev_priv, ddc_pin));
+ intel_gmbus_get_adapter(display, ddc_pin));
drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c
index 2c4e946d55754..b34e759db4ceb 100644
--- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c
+++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c
@@ -556,6 +556,7 @@ void xelpdp_pica_irq_handler(struct drm_i915_private *i915, u32 iir)
void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
{
+ struct intel_display *display = &dev_priv->display;
u32 ddi_hotplug_trigger = pch_iir & SDE_DDI_HOTPLUG_MASK_ICP;
u32 tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_MASK_ICP;
u32 pin_mask = 0, long_mask = 0;
@@ -589,11 +590,12 @@ void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
if (pch_iir & SDE_GMBUS_ICP)
- intel_gmbus_irq_handler(dev_priv);
+ intel_gmbus_irq_handler(display);
}
void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
{
+ struct intel_display *display = &dev_priv->display;
u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT &
~SDE_PORTE_HOTPLUG_SPT;
u32 hotplug2_trigger = pch_iir & SDE_PORTE_HOTPLUG_SPT;
@@ -625,7 +627,7 @@ void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
if (pch_iir & SDE_GMBUS_CPT)
- intel_gmbus_irq_handler(dev_priv);
+ intel_gmbus_irq_handler(display);
}
void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 hotplug_trigger)
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index fb4ed9f7855b6..a3459f89315fe 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -899,7 +899,7 @@ void intel_lvds_init(struct drm_i915_private *i915)
drm_connector_init_with_ddc(&i915->drm, &connector->base,
&intel_lvds_connector_funcs,
DRM_MODE_CONNECTOR_LVDS,
- intel_gmbus_get_adapter(i915, ddc_pin));
+ intel_gmbus_get_adapter(display, ddc_pin));
drm_encoder_init(&i915->drm, &encoder->base, &intel_lvds_enc_funcs,
DRM_MODE_ENCODER_LVDS, "LVDS");
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index 7cc519b402e90..3af9447714712 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -2081,10 +2081,10 @@ intel_sdvo_get_edid(struct drm_connector *connector)
static const struct drm_edid *
intel_sdvo_get_analog_edid(struct drm_connector *connector)
{
- struct drm_i915_private *i915 = to_i915(connector->dev);
+ struct intel_display *display = to_intel_display(connector->dev);
struct i2c_adapter *ddc;
- ddc = intel_gmbus_get_adapter(i915, i915->display.vbt.crt_ddc_pin);
+ ddc = intel_gmbus_get_adapter(display, display->vbt.crt_ddc_pin);
if (!ddc)
return NULL;
@@ -2637,6 +2637,7 @@ intel_sdvo_select_ddc_bus(struct intel_sdvo *sdvo,
static void
intel_sdvo_select_i2c_bus(struct intel_sdvo *sdvo)
{
+ struct intel_display *display = to_intel_display(&sdvo->base);
struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev);
const struct sdvo_device_mapping *mapping;
u8 pin;
@@ -2647,7 +2648,7 @@ intel_sdvo_select_i2c_bus(struct intel_sdvo *sdvo)
mapping = &dev_priv->display.vbt.sdvo_mappings[1];
if (mapping->initialized &&
- intel_gmbus_is_valid_pin(dev_priv, mapping->i2c_pin))
+ intel_gmbus_is_valid_pin(display, mapping->i2c_pin))
pin = mapping->i2c_pin;
else
pin = GMBUS_PIN_DPB;
@@ -2656,7 +2657,7 @@ intel_sdvo_select_i2c_bus(struct intel_sdvo *sdvo)
sdvo->base.base.base.id, sdvo->base.base.name,
pin, sdvo->target_addr);
- sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin);
+ sdvo->i2c = intel_gmbus_get_adapter(display, pin);
/*
* With gmbus we should be able to drive sdvo i2c at 2MHz, but somehow
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 9d3d9b9830320..f18f1acf21587 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -137,5 +137,5 @@ void i915_restore_display(struct drm_i915_private *dev_priv)
intel_vga_redisable(display);
- intel_gmbus_reset(dev_priv);
+ intel_gmbus_reset(display);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 057/869] drm/i915/crt: convert to struct intel_display
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (55 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 056/869] drm/i915/gmbus: convert " Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 058/869] drm/i915: Grab intel_display from the encoder to avoid potential oopsies Greg Kroah-Hartman
` (812 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Rodrigo Vivi, Jani Nikula,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <jani.nikula@intel.com>
[ Upstream commit 40eb34c3f49170cf79a953ecf8f89ae4659bb527 ]
struct intel_display will replace struct drm_i915_private as the main
device pointer for display code. Switch CRT code over to it.
v2: Rebase
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241029105257.391572-1-jani.nikula@intel.com
Stable-dep-of: dc3806d9eb66 ("drm/i915: Grab intel_display from the encoder to avoid potential oopsies")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/i915/display/intel_crt.c | 209 +++++++++---------
drivers/gpu/drm/i915/display/intel_crt.h | 10 +-
drivers/gpu/drm/i915/display/intel_display.c | 12 +-
.../gpu/drm/i915/display/intel_pch_display.c | 2 +-
4 files changed, 122 insertions(+), 111 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index 8222b1c251db1..74c1983fe07ea 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -81,12 +81,13 @@ static struct intel_crt *intel_attached_crt(struct intel_connector *connector)
return intel_encoder_to_crt(intel_attached_encoder(connector));
}
-bool intel_crt_port_enabled(struct drm_i915_private *dev_priv,
+bool intel_crt_port_enabled(struct intel_display *display,
i915_reg_t adpa_reg, enum pipe *pipe)
{
+ struct drm_i915_private *dev_priv = to_i915(display->drm);
u32 val;
- val = intel_de_read(dev_priv, adpa_reg);
+ val = intel_de_read(display, adpa_reg);
/* asserts want to know the pipe even if the port is disabled */
if (HAS_PCH_CPT(dev_priv))
@@ -100,6 +101,7 @@ bool intel_crt_port_enabled(struct drm_i915_private *dev_priv,
static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{
+ struct intel_display *display = to_intel_display(encoder);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_crt *crt = intel_encoder_to_crt(encoder);
intel_wakeref_t wakeref;
@@ -110,7 +112,7 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
if (!wakeref)
return false;
- ret = intel_crt_port_enabled(dev_priv, crt->adpa_reg, pipe);
+ ret = intel_crt_port_enabled(display, crt->adpa_reg, pipe);
intel_display_power_put(dev_priv, encoder->power_domain, wakeref);
@@ -119,11 +121,11 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
static unsigned int intel_crt_get_flags(struct intel_encoder *encoder)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct intel_display *display = to_intel_display(encoder);
struct intel_crt *crt = intel_encoder_to_crt(encoder);
u32 tmp, flags = 0;
- tmp = intel_de_read(dev_priv, crt->adpa_reg);
+ tmp = intel_de_read(display, crt->adpa_reg);
if (tmp & ADPA_HSYNC_ACTIVE_HIGH)
flags |= DRM_MODE_FLAG_PHSYNC;
@@ -168,13 +170,14 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
int mode)
{
+ struct intel_display *display = to_intel_display(encoder);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_crt *crt = intel_encoder_to_crt(encoder);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
u32 adpa;
- if (DISPLAY_VER(dev_priv) >= 5)
+ if (DISPLAY_VER(display) >= 5)
adpa = ADPA_HOTPLUG_BITS;
else
adpa = 0;
@@ -193,7 +196,7 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder,
adpa |= ADPA_PIPE_SEL(crtc->pipe);
if (!HAS_PCH_SPLIT(dev_priv))
- intel_de_write(dev_priv, BCLRPAT(dev_priv, crtc->pipe), 0);
+ intel_de_write(display, BCLRPAT(display, crtc->pipe), 0);
switch (mode) {
case DRM_MODE_DPMS_ON:
@@ -210,7 +213,7 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder,
break;
}
- intel_de_write(dev_priv, crt->adpa_reg, adpa);
+ intel_de_write(display, crt->adpa_reg, adpa);
}
static void intel_disable_crt(struct intel_atomic_state *state,
@@ -241,9 +244,10 @@ static void hsw_disable_crt(struct intel_atomic_state *state,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
+ struct intel_display *display = to_intel_display(state);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- drm_WARN_ON(&dev_priv->drm, !old_crtc_state->has_pch_encoder);
+ drm_WARN_ON(display->drm, !old_crtc_state->has_pch_encoder);
intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
}
@@ -253,6 +257,7 @@ static void hsw_post_disable_crt(struct intel_atomic_state *state,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
+ struct intel_display *display = to_intel_display(state);
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -272,7 +277,7 @@ static void hsw_post_disable_crt(struct intel_atomic_state *state,
hsw_fdi_disable(encoder);
- drm_WARN_ON(&dev_priv->drm, !old_crtc_state->has_pch_encoder);
+ drm_WARN_ON(display->drm, !old_crtc_state->has_pch_encoder);
intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
}
@@ -282,9 +287,10 @@ static void hsw_pre_pll_enable_crt(struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
+ struct intel_display *display = to_intel_display(state);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- drm_WARN_ON(&dev_priv->drm, !crtc_state->has_pch_encoder);
+ drm_WARN_ON(display->drm, !crtc_state->has_pch_encoder);
intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
}
@@ -294,11 +300,12 @@ static void hsw_pre_enable_crt(struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
+ struct intel_display *display = to_intel_display(state);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum pipe pipe = crtc->pipe;
- drm_WARN_ON(&dev_priv->drm, !crtc_state->has_pch_encoder);
+ drm_WARN_ON(display->drm, !crtc_state->has_pch_encoder);
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
@@ -312,11 +319,12 @@ static void hsw_enable_crt(struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
+ struct intel_display *display = to_intel_display(state);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum pipe pipe = crtc->pipe;
- drm_WARN_ON(&dev_priv->drm, !crtc_state->has_pch_encoder);
+ drm_WARN_ON(display->drm, !crtc_state->has_pch_encoder);
intel_ddi_enable_transcoder_func(encoder, crtc_state);
@@ -346,9 +354,10 @@ static enum drm_mode_status
intel_crt_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
+ struct intel_display *display = to_intel_display(connector->dev);
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
- int max_dotclk = dev_priv->display.cdclk.max_dotclk_freq;
+ int max_dotclk = display->cdclk.max_dotclk_freq;
enum drm_mode_status status;
int max_clock;
@@ -367,7 +376,7 @@ intel_crt_mode_valid(struct drm_connector *connector,
* DAC limit supposedly 355 MHz.
*/
max_clock = 270000;
- else if (IS_DISPLAY_VER(dev_priv, 3, 4))
+ else if (IS_DISPLAY_VER(display, 3, 4))
max_clock = 400000;
else
max_clock = 350000;
@@ -428,6 +437,7 @@ static int hsw_crt_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state)
{
+ struct intel_display *display = to_intel_display(encoder);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct drm_display_mode *adjusted_mode =
&pipe_config->hw.adjusted_mode;
@@ -450,7 +460,7 @@ static int hsw_crt_compute_config(struct intel_encoder *encoder,
if (HAS_PCH_LPT(dev_priv)) {
/* TODO: Check crtc_state->max_link_bpp_x16 instead of bw_constrained */
if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(display->drm,
"LPT only supports 24bpp\n");
return -EINVAL;
}
@@ -470,6 +480,7 @@ static int hsw_crt_compute_config(struct intel_encoder *encoder,
static bool ilk_crt_detect_hotplug(struct drm_connector *connector)
{
+ struct intel_display *display = to_intel_display(connector->dev);
struct drm_device *dev = connector->dev;
struct intel_crt *crt = intel_attached_crt(to_intel_connector(connector));
struct drm_i915_private *dev_priv = to_i915(dev);
@@ -483,36 +494,36 @@ static bool ilk_crt_detect_hotplug(struct drm_connector *connector)
crt->force_hotplug_required = false;
- save_adpa = adpa = intel_de_read(dev_priv, crt->adpa_reg);
- drm_dbg_kms(&dev_priv->drm,
+ save_adpa = adpa = intel_de_read(display, crt->adpa_reg);
+ drm_dbg_kms(display->drm,
"trigger hotplug detect cycle: adpa=0x%x\n", adpa);
adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
if (turn_off_dac)
adpa &= ~ADPA_DAC_ENABLE;
- intel_de_write(dev_priv, crt->adpa_reg, adpa);
+ intel_de_write(display, crt->adpa_reg, adpa);
- if (intel_de_wait_for_clear(dev_priv,
+ if (intel_de_wait_for_clear(display,
crt->adpa_reg,
ADPA_CRT_HOTPLUG_FORCE_TRIGGER,
1000))
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(display->drm,
"timed out waiting for FORCE_TRIGGER");
if (turn_off_dac) {
- intel_de_write(dev_priv, crt->adpa_reg, save_adpa);
- intel_de_posting_read(dev_priv, crt->adpa_reg);
+ intel_de_write(display, crt->adpa_reg, save_adpa);
+ intel_de_posting_read(display, crt->adpa_reg);
}
}
/* Check the status to see if both blue and green are on now */
- adpa = intel_de_read(dev_priv, crt->adpa_reg);
+ adpa = intel_de_read(display, crt->adpa_reg);
if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
ret = true;
else
ret = false;
- drm_dbg_kms(&dev_priv->drm, "ironlake hotplug adpa=0x%x, result %d\n",
+ drm_dbg_kms(display->drm, "ironlake hotplug adpa=0x%x, result %d\n",
adpa, ret);
return ret;
@@ -520,6 +531,7 @@ static bool ilk_crt_detect_hotplug(struct drm_connector *connector)
static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
{
+ struct intel_display *display = to_intel_display(connector->dev);
struct drm_device *dev = connector->dev;
struct intel_crt *crt = intel_attached_crt(to_intel_connector(connector));
struct drm_i915_private *dev_priv = to_i915(dev);
@@ -542,29 +554,29 @@ static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
*/
reenable_hpd = intel_hpd_disable(dev_priv, crt->base.hpd_pin);
- save_adpa = adpa = intel_de_read(dev_priv, crt->adpa_reg);
- drm_dbg_kms(&dev_priv->drm,
+ save_adpa = adpa = intel_de_read(display, crt->adpa_reg);
+ drm_dbg_kms(display->drm,
"trigger hotplug detect cycle: adpa=0x%x\n", adpa);
adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
- intel_de_write(dev_priv, crt->adpa_reg, adpa);
+ intel_de_write(display, crt->adpa_reg, adpa);
- if (intel_de_wait_for_clear(dev_priv, crt->adpa_reg,
+ if (intel_de_wait_for_clear(display, crt->adpa_reg,
ADPA_CRT_HOTPLUG_FORCE_TRIGGER, 1000)) {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(display->drm,
"timed out waiting for FORCE_TRIGGER");
- intel_de_write(dev_priv, crt->adpa_reg, save_adpa);
+ intel_de_write(display, crt->adpa_reg, save_adpa);
}
/* Check the status to see if both blue and green are on now */
- adpa = intel_de_read(dev_priv, crt->adpa_reg);
+ adpa = intel_de_read(display, crt->adpa_reg);
if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
ret = true;
else
ret = false;
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(display->drm,
"valleyview hotplug adpa=0x%x, result %d\n", adpa, ret);
if (reenable_hpd)
@@ -575,6 +587,7 @@ static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
static bool intel_crt_detect_hotplug(struct drm_connector *connector)
{
+ struct intel_display *display = to_intel_display(connector->dev);
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
u32 stat;
@@ -603,18 +616,18 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
CRT_HOTPLUG_FORCE_DETECT,
CRT_HOTPLUG_FORCE_DETECT);
/* wait for FORCE_DETECT to go off */
- if (intel_de_wait_for_clear(dev_priv, PORT_HOTPLUG_EN(dev_priv),
+ if (intel_de_wait_for_clear(display, PORT_HOTPLUG_EN(display),
CRT_HOTPLUG_FORCE_DETECT, 1000))
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(display->drm,
"timed out waiting for FORCE_DETECT to go off");
}
- stat = intel_de_read(dev_priv, PORT_HOTPLUG_STAT(dev_priv));
+ stat = intel_de_read(display, PORT_HOTPLUG_STAT(display));
if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE)
ret = true;
/* clear the interrupt we just generated, if any */
- intel_de_write(dev_priv, PORT_HOTPLUG_STAT(dev_priv),
+ intel_de_write(display, PORT_HOTPLUG_STAT(display),
CRT_HOTPLUG_INT_STATUS);
i915_hotplug_interrupt_update(dev_priv, CRT_HOTPLUG_FORCE_DETECT, 0);
@@ -660,8 +673,7 @@ static int intel_crt_ddc_get_modes(struct drm_connector *connector,
static bool intel_crt_detect_ddc(struct drm_connector *connector)
{
- struct intel_crt *crt = intel_attached_crt(to_intel_connector(connector));
- struct drm_i915_private *dev_priv = to_i915(crt->base.base.dev);
+ struct intel_display *display = to_intel_display(connector->dev);
const struct drm_edid *drm_edid;
bool ret = false;
@@ -674,15 +686,15 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
* have to check the EDID input spec of the attached device.
*/
if (drm_edid_is_digital(drm_edid)) {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(display->drm,
"CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
} else {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(display->drm,
"CRT detected via DDC:0x50 [EDID]\n");
ret = true;
}
} else {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(display->drm,
"CRT not detected via DDC:0x50 [no valid EDID found]\n");
}
@@ -695,8 +707,6 @@ static enum drm_connector_status
intel_crt_load_detect(struct intel_crt *crt, enum pipe pipe)
{
struct intel_display *display = to_intel_display(&crt->base);
- struct drm_device *dev = crt->base.base.dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
enum transcoder cpu_transcoder = (enum transcoder)pipe;
u32 save_bclrpat;
u32 save_vtotal;
@@ -707,14 +717,14 @@ intel_crt_load_detect(struct intel_crt *crt, enum pipe pipe)
u8 st00;
enum drm_connector_status status;
- drm_dbg_kms(&dev_priv->drm, "starting load-detect on CRT\n");
+ drm_dbg_kms(display->drm, "starting load-detect on CRT\n");
- save_bclrpat = intel_de_read(dev_priv,
- BCLRPAT(dev_priv, cpu_transcoder));
- save_vtotal = intel_de_read(dev_priv,
- TRANS_VTOTAL(dev_priv, cpu_transcoder));
- vblank = intel_de_read(dev_priv,
- TRANS_VBLANK(dev_priv, cpu_transcoder));
+ save_bclrpat = intel_de_read(display,
+ BCLRPAT(display, cpu_transcoder));
+ save_vtotal = intel_de_read(display,
+ TRANS_VTOTAL(display, cpu_transcoder));
+ vblank = intel_de_read(display,
+ TRANS_VBLANK(display, cpu_transcoder));
vtotal = REG_FIELD_GET(VTOTAL_MASK, save_vtotal) + 1;
vactive = REG_FIELD_GET(VACTIVE_MASK, save_vtotal) + 1;
@@ -723,25 +733,25 @@ intel_crt_load_detect(struct intel_crt *crt, enum pipe pipe)
vblank_end = REG_FIELD_GET(VBLANK_END_MASK, vblank) + 1;
/* Set the border color to purple. */
- intel_de_write(dev_priv, BCLRPAT(dev_priv, cpu_transcoder), 0x500050);
+ intel_de_write(display, BCLRPAT(display, cpu_transcoder), 0x500050);
- if (DISPLAY_VER(dev_priv) != 2) {
- u32 transconf = intel_de_read(dev_priv,
- TRANSCONF(dev_priv, cpu_transcoder));
+ if (DISPLAY_VER(display) != 2) {
+ u32 transconf = intel_de_read(display,
+ TRANSCONF(display, cpu_transcoder));
- intel_de_write(dev_priv, TRANSCONF(dev_priv, cpu_transcoder),
+ intel_de_write(display, TRANSCONF(display, cpu_transcoder),
transconf | TRANSCONF_FORCE_BORDER);
- intel_de_posting_read(dev_priv,
- TRANSCONF(dev_priv, cpu_transcoder));
+ intel_de_posting_read(display,
+ TRANSCONF(display, cpu_transcoder));
/* Wait for next Vblank to substitue
* border color for Color info */
intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(display, pipe));
- st00 = intel_de_read8(dev_priv, _VGA_MSR_WRITE);
+ st00 = intel_de_read8(display, _VGA_MSR_WRITE);
status = ((st00 & (1 << 4)) != 0) ?
connector_status_connected :
connector_status_disconnected;
- intel_de_write(dev_priv, TRANSCONF(dev_priv, cpu_transcoder),
+ intel_de_write(display, TRANSCONF(display, cpu_transcoder),
transconf);
} else {
bool restore_vblank = false;
@@ -752,13 +762,13 @@ intel_crt_load_detect(struct intel_crt *crt, enum pipe pipe)
* Yes, this will flicker
*/
if (vblank_start <= vactive && vblank_end >= vtotal) {
- u32 vsync = intel_de_read(dev_priv,
- TRANS_VSYNC(dev_priv, cpu_transcoder));
+ u32 vsync = intel_de_read(display,
+ TRANS_VSYNC(display, cpu_transcoder));
u32 vsync_start = REG_FIELD_GET(VSYNC_START_MASK, vsync) + 1;
vblank_start = vsync_start;
- intel_de_write(dev_priv,
- TRANS_VBLANK(dev_priv, cpu_transcoder),
+ intel_de_write(display,
+ TRANS_VBLANK(display, cpu_transcoder),
VBLANK_START(vblank_start - 1) |
VBLANK_END(vblank_end - 1));
restore_vblank = true;
@@ -772,9 +782,9 @@ intel_crt_load_detect(struct intel_crt *crt, enum pipe pipe)
/*
* Wait for the border to be displayed
*/
- while (intel_de_read(dev_priv, PIPEDSL(dev_priv, pipe)) >= vactive)
+ while (intel_de_read(display, PIPEDSL(display, pipe)) >= vactive)
;
- while ((dsl = intel_de_read(dev_priv, PIPEDSL(dev_priv, pipe))) <= vsample)
+ while ((dsl = intel_de_read(display, PIPEDSL(display, pipe))) <= vsample)
;
/*
* Watch ST00 for an entire scanline
@@ -784,15 +794,15 @@ intel_crt_load_detect(struct intel_crt *crt, enum pipe pipe)
do {
count++;
/* Read the ST00 VGA status register */
- st00 = intel_de_read8(dev_priv, _VGA_MSR_WRITE);
+ st00 = intel_de_read8(display, _VGA_MSR_WRITE);
if (st00 & (1 << 4))
detect++;
- } while ((intel_de_read(dev_priv, PIPEDSL(dev_priv, pipe)) == dsl));
+ } while ((intel_de_read(display, PIPEDSL(display, pipe)) == dsl));
/* restore vblank if necessary */
if (restore_vblank)
- intel_de_write(dev_priv,
- TRANS_VBLANK(dev_priv, cpu_transcoder),
+ intel_de_write(display,
+ TRANS_VBLANK(display, cpu_transcoder),
vblank);
/*
* If more than 3/4 of the scanline detected a monitor,
@@ -806,7 +816,7 @@ intel_crt_load_detect(struct intel_crt *crt, enum pipe pipe)
}
/* Restore previous settings */
- intel_de_write(dev_priv, BCLRPAT(dev_priv, cpu_transcoder),
+ intel_de_write(display, BCLRPAT(display, cpu_transcoder),
save_bclrpat);
return status;
@@ -843,6 +853,7 @@ intel_crt_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
{
+ struct intel_display *display = to_intel_display(connector->dev);
struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_crt *crt = intel_attached_crt(to_intel_connector(connector));
struct intel_encoder *intel_encoder = &crt->base;
@@ -850,7 +861,7 @@ intel_crt_detect(struct drm_connector *connector,
intel_wakeref_t wakeref;
int status;
- drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s] force=%d\n",
+ drm_dbg_kms(display->drm, "[CONNECTOR:%d:%s] force=%d\n",
connector->base.id, connector->name,
force);
@@ -860,7 +871,7 @@ intel_crt_detect(struct drm_connector *connector,
if (!intel_display_driver_check_access(dev_priv))
return connector->status;
- if (dev_priv->display.params.load_detect_test) {
+ if (display->params.load_detect_test) {
wakeref = intel_display_power_get(dev_priv,
intel_encoder->power_domain);
goto load_detect;
@@ -873,18 +884,18 @@ intel_crt_detect(struct drm_connector *connector,
wakeref = intel_display_power_get(dev_priv,
intel_encoder->power_domain);
- if (I915_HAS_HOTPLUG(dev_priv)) {
+ if (I915_HAS_HOTPLUG(display)) {
/* We can not rely on the HPD pin always being correctly wired
* up, for example many KVM do not pass it through, and so
* only trust an assertion that the monitor is connected.
*/
if (intel_crt_detect_hotplug(connector)) {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(display->drm,
"CRT detected via hotplug\n");
status = connector_status_connected;
goto out;
} else
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(display->drm,
"CRT not detected via hotplug\n");
}
@@ -897,7 +908,7 @@ intel_crt_detect(struct drm_connector *connector,
* broken monitor (without edid) to work behind a broken kvm (that fails
* to have the right resistors for HP detection) needs to fix this up.
* For now just bail out. */
- if (I915_HAS_HOTPLUG(dev_priv)) {
+ if (I915_HAS_HOTPLUG(display)) {
status = connector_status_disconnected;
goto out;
}
@@ -917,10 +928,10 @@ intel_crt_detect(struct drm_connector *connector,
} else {
if (intel_crt_detect_ddc(connector))
status = connector_status_connected;
- else if (DISPLAY_VER(dev_priv) < 4)
+ else if (DISPLAY_VER(display) < 4)
status = intel_crt_load_detect(crt,
to_intel_crtc(connector->state->crtc)->pipe);
- else if (dev_priv->display.params.load_detect_test)
+ else if (display->params.load_detect_test)
status = connector_status_disconnected;
else
status = connector_status_unknown;
@@ -966,19 +977,19 @@ static int intel_crt_get_modes(struct drm_connector *connector)
void intel_crt_reset(struct drm_encoder *encoder)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+ struct intel_display *display = to_intel_display(encoder->dev);
struct intel_crt *crt = intel_encoder_to_crt(to_intel_encoder(encoder));
- if (DISPLAY_VER(dev_priv) >= 5) {
+ if (DISPLAY_VER(display) >= 5) {
u32 adpa;
- adpa = intel_de_read(dev_priv, crt->adpa_reg);
+ adpa = intel_de_read(display, crt->adpa_reg);
adpa &= ~ADPA_CRT_HOTPLUG_MASK;
adpa |= ADPA_HOTPLUG_BITS;
- intel_de_write(dev_priv, crt->adpa_reg, adpa);
- intel_de_posting_read(dev_priv, crt->adpa_reg);
+ intel_de_write(display, crt->adpa_reg, adpa);
+ intel_de_posting_read(display, crt->adpa_reg);
- drm_dbg_kms(&dev_priv->drm, "crt adpa set to 0x%x\n", adpa);
+ drm_dbg_kms(display->drm, "crt adpa set to 0x%x\n", adpa);
crt->force_hotplug_required = true;
}
@@ -1008,9 +1019,9 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = {
.destroy = intel_encoder_destroy,
};
-void intel_crt_init(struct drm_i915_private *dev_priv)
+void intel_crt_init(struct intel_display *display)
{
- struct intel_display *display = &dev_priv->display;
+ struct drm_i915_private *dev_priv = to_i915(display->drm);
struct drm_connector *connector;
struct intel_crt *crt;
struct intel_connector *intel_connector;
@@ -1025,7 +1036,7 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
else
adpa_reg = ADPA;
- adpa = intel_de_read(dev_priv, adpa_reg);
+ adpa = intel_de_read(display, adpa_reg);
if ((adpa & ADPA_DAC_ENABLE) == 0) {
/*
* On some machines (some IVB at least) CRT can be
@@ -1035,11 +1046,11 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
* take. So the only way to tell is attempt to enable
* it and see what happens.
*/
- intel_de_write(dev_priv, adpa_reg,
+ intel_de_write(display, adpa_reg,
adpa | ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
- if ((intel_de_read(dev_priv, adpa_reg) & ADPA_DAC_ENABLE) == 0)
+ if ((intel_de_read(display, adpa_reg) & ADPA_DAC_ENABLE) == 0)
return;
- intel_de_write(dev_priv, adpa_reg, adpa);
+ intel_de_write(display, adpa_reg, adpa);
}
crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL);
@@ -1052,16 +1063,16 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
return;
}
- ddc_pin = dev_priv->display.vbt.crt_ddc_pin;
+ ddc_pin = display->vbt.crt_ddc_pin;
connector = &intel_connector->base;
crt->connector = intel_connector;
- drm_connector_init_with_ddc(&dev_priv->drm, connector,
+ drm_connector_init_with_ddc(display->drm, connector,
&intel_crt_connector_funcs,
DRM_MODE_CONNECTOR_VGA,
intel_gmbus_get_adapter(display, ddc_pin));
- drm_encoder_init(&dev_priv->drm, &crt->base.base, &intel_crt_enc_funcs,
+ drm_encoder_init(display->drm, &crt->base.base, &intel_crt_enc_funcs,
DRM_MODE_ENCODER_DAC, "CRT");
intel_connector_attach_encoder(intel_connector, &crt->base);
@@ -1073,14 +1084,14 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
else
crt->base.pipe_mask = ~0;
- if (DISPLAY_VER(dev_priv) != 2)
+ if (DISPLAY_VER(display) != 2)
connector->interlace_allowed = true;
crt->adpa_reg = adpa_reg;
crt->base.power_domain = POWER_DOMAIN_PORT_CRT;
- if (I915_HAS_HOTPLUG(dev_priv) &&
+ if (I915_HAS_HOTPLUG(display) &&
!dmi_check_system(intel_spurious_crt_detect)) {
crt->base.hpd_pin = HPD_CRT;
crt->base.hotplug = intel_encoder_hotplug;
@@ -1090,7 +1101,7 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
}
intel_connector->base.polled = intel_connector->polled;
- if (HAS_DDI(dev_priv)) {
+ if (HAS_DDI(display)) {
assert_port_valid(dev_priv, PORT_E);
crt->base.port = PORT_E;
@@ -1134,8 +1145,8 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT |
FDI_RX_LINK_REVERSAL_OVERRIDE;
- dev_priv->display.fdi.rx_config = intel_de_read(dev_priv,
- FDI_RX_CTL(PIPE_A)) & fdi_config;
+ display->fdi.rx_config = intel_de_read(display,
+ FDI_RX_CTL(PIPE_A)) & fdi_config;
}
intel_crt_reset(&crt->base.base);
diff --git a/drivers/gpu/drm/i915/display/intel_crt.h b/drivers/gpu/drm/i915/display/intel_crt.h
index fe7690c2b9487..e0abfe96a3d29 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.h
+++ b/drivers/gpu/drm/i915/display/intel_crt.h
@@ -10,20 +10,20 @@
enum pipe;
struct drm_encoder;
-struct drm_i915_private;
+struct intel_display;
#ifdef I915
-bool intel_crt_port_enabled(struct drm_i915_private *dev_priv,
+bool intel_crt_port_enabled(struct intel_display *display,
i915_reg_t adpa_reg, enum pipe *pipe);
-void intel_crt_init(struct drm_i915_private *dev_priv);
+void intel_crt_init(struct intel_display *display);
void intel_crt_reset(struct drm_encoder *encoder);
#else
-static inline bool intel_crt_port_enabled(struct drm_i915_private *dev_priv,
+static inline bool intel_crt_port_enabled(struct intel_display *display,
i915_reg_t adpa_reg, enum pipe *pipe)
{
return false;
}
-static inline void intel_crt_init(struct drm_i915_private *dev_priv)
+static inline void intel_crt_init(struct intel_display *display)
{
}
static inline void intel_crt_reset(struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 2d4049e6ba785..4a3cc3369180b 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -7805,7 +7805,7 @@ void intel_setup_outputs(struct drm_i915_private *dev_priv)
if (HAS_DDI(dev_priv)) {
if (intel_ddi_crt_present(dev_priv))
- intel_crt_init(dev_priv);
+ intel_crt_init(display);
intel_bios_for_each_encoder(display, intel_ddi_init);
@@ -7820,7 +7820,7 @@ void intel_setup_outputs(struct drm_i915_private *dev_priv)
* incorrect sharing of the PPS.
*/
intel_lvds_init(dev_priv);
- intel_crt_init(dev_priv);
+ intel_crt_init(display);
dpd_is_edp = intel_dp_is_port_edp(dev_priv, PORT_D);
@@ -7851,7 +7851,7 @@ void intel_setup_outputs(struct drm_i915_private *dev_priv)
bool has_edp, has_port;
if (IS_VALLEYVIEW(dev_priv) && dev_priv->display.vbt.int_crt_support)
- intel_crt_init(dev_priv);
+ intel_crt_init(display);
/*
* The DP_DETECTED bit is the latched state of the DDC
@@ -7897,14 +7897,14 @@ void intel_setup_outputs(struct drm_i915_private *dev_priv)
vlv_dsi_init(dev_priv);
} else if (IS_PINEVIEW(dev_priv)) {
intel_lvds_init(dev_priv);
- intel_crt_init(dev_priv);
+ intel_crt_init(display);
} else if (IS_DISPLAY_VER(dev_priv, 3, 4)) {
bool found = false;
if (IS_MOBILE(dev_priv))
intel_lvds_init(dev_priv);
- intel_crt_init(dev_priv);
+ intel_crt_init(display);
if (intel_de_read(dev_priv, GEN3_SDVOB) & SDVO_DETECTED) {
drm_dbg_kms(&dev_priv->drm, "probing SDVOB\n");
@@ -7946,7 +7946,7 @@ void intel_setup_outputs(struct drm_i915_private *dev_priv)
if (IS_I85X(dev_priv))
intel_lvds_init(dev_priv);
- intel_crt_init(dev_priv);
+ intel_crt_init(display);
intel_dvo_init(dev_priv);
}
diff --git a/drivers/gpu/drm/i915/display/intel_pch_display.c b/drivers/gpu/drm/i915/display/intel_pch_display.c
index 5fbcb74aeac11..4210de87a0a22 100644
--- a/drivers/gpu/drm/i915/display/intel_pch_display.c
+++ b/drivers/gpu/drm/i915/display/intel_pch_display.c
@@ -86,7 +86,7 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
assert_pch_dp_disabled(dev_priv, pipe, PORT_D, PCH_DP_D);
INTEL_DISPLAY_STATE_WARN(display,
- intel_crt_port_enabled(dev_priv, PCH_ADPA, &port_pipe) && port_pipe == pipe,
+ intel_crt_port_enabled(display, PCH_ADPA, &port_pipe) && port_pipe == pipe,
"PCH VGA enabled on transcoder %c, should be disabled\n",
pipe_name(pipe));
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 058/869] drm/i915: Grab intel_display from the encoder to avoid potential oopsies
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (56 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 057/869] drm/i915/crt: " Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 059/869] ax25: Remove broken autobind Greg Kroah-Hartman
` (811 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ville Syrjälä, Jani Nikula,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
[ Upstream commit dc3806d9eb66d0105f8d55d462d4ef681d9eac59 ]
Grab the intel_display from 'encoder' rather than 'state'
in the encoder hooks to avoid the massive footgun that is
intel_sanitize_encoder(), which passes NULL as the 'state'
argument to encoder .disable() and .post_disable().
TODO: figure out how to actually fix intel_sanitize_encoder()...
Fixes: 40eb34c3f491 ("drm/i915/crt: convert to struct intel_display")
Fixes: ab0b0eb5c85c ("drm/i915/tv: convert to struct intel_display")
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241107161123.16269-2-ville.syrjala@linux.intel.com
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/i915/display/intel_crt.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index 74c1983fe07ea..1be55bdb48b96 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -244,7 +244,7 @@ static void hsw_disable_crt(struct intel_atomic_state *state,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
- struct intel_display *display = to_intel_display(state);
+ struct intel_display *display = to_intel_display(encoder);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
drm_WARN_ON(display->drm, !old_crtc_state->has_pch_encoder);
@@ -257,7 +257,7 @@ static void hsw_post_disable_crt(struct intel_atomic_state *state,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
- struct intel_display *display = to_intel_display(state);
+ struct intel_display *display = to_intel_display(encoder);
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -287,7 +287,7 @@ static void hsw_pre_pll_enable_crt(struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
- struct intel_display *display = to_intel_display(state);
+ struct intel_display *display = to_intel_display(encoder);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
drm_WARN_ON(display->drm, !crtc_state->has_pch_encoder);
@@ -300,7 +300,7 @@ static void hsw_pre_enable_crt(struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
- struct intel_display *display = to_intel_display(state);
+ struct intel_display *display = to_intel_display(encoder);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum pipe pipe = crtc->pipe;
@@ -319,7 +319,7 @@ static void hsw_enable_crt(struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
- struct intel_display *display = to_intel_display(state);
+ struct intel_display *display = to_intel_display(encoder);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
enum pipe pipe = crtc->pipe;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 059/869] ax25: Remove broken autobind
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (57 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 058/869] drm/i915: Grab intel_display from the encoder to avoid potential oopsies Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 060/869] f2fs: quota: fix to avoid warning in dquot_writeback_dquots() Greg Kroah-Hartman
` (810 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+33841dc6aa3e1d86b78a,
Murad Masimov, David S. Miller, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Murad Masimov <m.masimov@mt-integration.ru>
[ Upstream commit 2f6efbabceb6b2914ee9bafb86d9a51feae9cce8 ]
Binding AX25 socket by using the autobind feature leads to memory leaks
in ax25_connect() and also refcount leaks in ax25_release(). Memory
leak was detected with kmemleak:
================================================================
unreferenced object 0xffff8880253cd680 (size 96):
backtrace:
__kmalloc_node_track_caller_noprof (./include/linux/kmemleak.h:43)
kmemdup_noprof (mm/util.c:136)
ax25_rt_autobind (net/ax25/ax25_route.c:428)
ax25_connect (net/ax25/af_ax25.c:1282)
__sys_connect_file (net/socket.c:2045)
__sys_connect (net/socket.c:2064)
__x64_sys_connect (net/socket.c:2067)
do_syscall_64 (arch/x86/entry/common.c:52 arch/x86/entry/common.c:83)
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
================================================================
When socket is bound, refcounts must be incremented the way it is done
in ax25_bind() and ax25_setsockopt() (SO_BINDTODEVICE). In case of
autobind, the refcounts are not incremented.
This bug leads to the following issue reported by Syzkaller:
================================================================
ax25_connect(): syz-executor318 uses autobind, please contact jreuter@yaina.de
------------[ cut here ]------------
refcount_t: decrement hit 0; leaking memory.
WARNING: CPU: 0 PID: 5317 at lib/refcount.c:31 refcount_warn_saturate+0xfa/0x1d0 lib/refcount.c:31
Modules linked in:
CPU: 0 UID: 0 PID: 5317 Comm: syz-executor318 Not tainted 6.14.0-rc4-syzkaller-00278-gece144f151ac #0
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
RIP: 0010:refcount_warn_saturate+0xfa/0x1d0 lib/refcount.c:31
...
Call Trace:
<TASK>
__refcount_dec include/linux/refcount.h:336 [inline]
refcount_dec include/linux/refcount.h:351 [inline]
ref_tracker_free+0x6af/0x7e0 lib/ref_tracker.c:236
netdev_tracker_free include/linux/netdevice.h:4302 [inline]
netdev_put include/linux/netdevice.h:4319 [inline]
ax25_release+0x368/0x960 net/ax25/af_ax25.c:1080
__sock_release net/socket.c:647 [inline]
sock_close+0xbc/0x240 net/socket.c:1398
__fput+0x3e9/0x9f0 fs/file_table.c:464
__do_sys_close fs/open.c:1580 [inline]
__se_sys_close fs/open.c:1565 [inline]
__x64_sys_close+0x7f/0x110 fs/open.c:1565
do_syscall_x64 arch/x86/entry/common.c:52 [inline]
do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
entry_SYSCALL_64_after_hwframe+0x77/0x7f
...
</TASK>
================================================================
Considering the issues above and the comments left in the code that say:
"check if we can remove this feature. It is broken."; "autobinding in this
may or may not work"; - it is better to completely remove this feature than
to fix it because it is broken and leads to various kinds of memory bugs.
Now calling connect() without first binding socket will result in an
error (-EINVAL). Userspace software that relies on the autobind feature
might get broken. However, this feature does not seem widely used with
this specific driver as it was not reliable at any point of time, and it
is already broken anyway. E.g. ax25-tools and ax25-apps packages for
popular distributions do not use the autobind feature for AF_AX25.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot+33841dc6aa3e1d86b78a@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=33841dc6aa3e1d86b78a
Signed-off-by: Murad Masimov <m.masimov@mt-integration.ru>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/ax25.h | 1 -
net/ax25/af_ax25.c | 30 ++++++------------
net/ax25/ax25_route.c | 74 -------------------------------------------
3 files changed, 10 insertions(+), 95 deletions(-)
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 4ee141aae0a29..a7bba42dde153 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -418,7 +418,6 @@ void ax25_rt_device_down(struct net_device *);
int ax25_rt_ioctl(unsigned int, void __user *);
extern const struct seq_operations ax25_rt_seqops;
ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev);
-int ax25_rt_autobind(ax25_cb *, ax25_address *);
struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *,
ax25_address *, ax25_digi *);
void ax25_rt_free(void);
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 9f3b8b682adb2..3ee7dba343100 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1270,28 +1270,18 @@ static int __must_check ax25_connect(struct socket *sock,
}
}
- /*
- * Must bind first - autobinding in this may or may not work. If
- * the socket is already bound, check to see if the device has
- * been filled in, error if it hasn't.
- */
+ /* Must bind first - autobinding does not work. */
if (sock_flag(sk, SOCK_ZAPPED)) {
- /* check if we can remove this feature. It is broken. */
- printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@yaina.de\n",
- current->comm);
- if ((err = ax25_rt_autobind(ax25, &fsa->fsa_ax25.sax25_call)) < 0) {
- kfree(digi);
- goto out_release;
- }
+ kfree(digi);
+ err = -EINVAL;
+ goto out_release;
+ }
- ax25_fillin_cb(ax25, ax25->ax25_dev);
- ax25_cb_add(ax25);
- } else {
- if (ax25->ax25_dev == NULL) {
- kfree(digi);
- err = -EHOSTUNREACH;
- goto out_release;
- }
+ /* Check to see if the device has been filled in, error if it hasn't. */
+ if (ax25->ax25_dev == NULL) {
+ kfree(digi);
+ err = -EHOSTUNREACH;
+ goto out_release;
}
if (sk->sk_type == SOCK_SEQPACKET &&
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index 69de75db0c9c2..10577434f40bf 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -373,80 +373,6 @@ ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
return ax25_rt;
}
-/*
- * Adjust path: If you specify a default route and want to connect
- * a target on the digipeater path but w/o having a special route
- * set before, the path has to be truncated from your target on.
- */
-static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
-{
- int k;
-
- for (k = 0; k < digipeat->ndigi; k++) {
- if (ax25cmp(addr, &digipeat->calls[k]) == 0)
- break;
- }
-
- digipeat->ndigi = k;
-}
-
-
-/*
- * Find which interface to use.
- */
-int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
-{
- ax25_uid_assoc *user;
- ax25_route *ax25_rt;
- int err = 0;
-
- ax25_route_lock_use();
- ax25_rt = ax25_get_route(addr, NULL);
- if (!ax25_rt) {
- ax25_route_lock_unuse();
- return -EHOSTUNREACH;
- }
- rcu_read_lock();
- if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) {
- err = -EHOSTUNREACH;
- goto put;
- }
-
- user = ax25_findbyuid(current_euid());
- if (user) {
- ax25->source_addr = user->call;
- ax25_uid_put(user);
- } else {
- if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
- err = -EPERM;
- goto put;
- }
- ax25->source_addr = *(ax25_address *)ax25->ax25_dev->dev->dev_addr;
- }
-
- if (ax25_rt->digipeat != NULL) {
- ax25->digipeat = kmemdup(ax25_rt->digipeat, sizeof(ax25_digi),
- GFP_ATOMIC);
- if (ax25->digipeat == NULL) {
- err = -ENOMEM;
- goto put;
- }
- ax25_adjust_path(addr, ax25->digipeat);
- }
-
- if (ax25->sk != NULL) {
- local_bh_disable();
- bh_lock_sock(ax25->sk);
- sock_reset_flag(ax25->sk, SOCK_ZAPPED);
- bh_unlock_sock(ax25->sk);
- local_bh_enable();
- }
-
-put:
- rcu_read_unlock();
- ax25_route_lock_unuse();
- return err;
-}
struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
ax25_address *dest, ax25_digi *digi)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 060/869] f2fs: quota: fix to avoid warning in dquot_writeback_dquots()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (58 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 059/869] ax25: Remove broken autobind Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 061/869] RISC-V: KVM: Teardown riscv specific bits after kvm_exit Greg Kroah-Hartman
` (809 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Chao Yu, Jaegeuk Kim, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <chao@kernel.org>
[ Upstream commit eb85c2410d6f581e957cd03a644ff6ddbe592af9 ]
F2FS-fs (dm-59): checkpoint=enable has some unwritten data.
------------[ cut here ]------------
WARNING: CPU: 6 PID: 8013 at fs/quota/dquot.c:691 dquot_writeback_dquots+0x2fc/0x308
pc : dquot_writeback_dquots+0x2fc/0x308
lr : f2fs_quota_sync+0xcc/0x1c4
Call trace:
dquot_writeback_dquots+0x2fc/0x308
f2fs_quota_sync+0xcc/0x1c4
f2fs_write_checkpoint+0x3d4/0x9b0
f2fs_issue_checkpoint+0x1bc/0x2c0
f2fs_sync_fs+0x54/0x150
f2fs_do_sync_file+0x2f8/0x814
__f2fs_ioctl+0x1960/0x3244
f2fs_ioctl+0x54/0xe0
__arm64_sys_ioctl+0xa8/0xe4
invoke_syscall+0x58/0x114
checkpoint and f2fs_remount may race as below, resulting triggering warning
in dquot_writeback_dquots().
atomic write remount
- do_remount
- down_write(&sb->s_umount);
- f2fs_remount
- ioctl
- f2fs_do_sync_file
- f2fs_sync_fs
- f2fs_write_checkpoint
- block_operations
- locked = down_read_trylock(&sbi->sb->s_umount)
: fail to lock due to the write lock was held by remount
- up_write(&sb->s_umount);
- f2fs_quota_sync
- dquot_writeback_dquots
- WARN_ON_ONCE(!rwsem_is_locked(&sb->s_umount))
: trigger warning because s_umount lock was unlocked by remount
If checkpoint comes from mount/umount/remount/freeze/quotactl, caller of
checkpoint has already held s_umount lock, calling dquot_writeback_dquots()
in the context should be safe.
So let's record task to sbi->umount_lock_holder, so that checkpoint can
know whether the lock has held in the context or not by checking current
w/ it.
In addition, in order to not misrepresent caller of checkpoint, we should
not allow to trigger async checkpoint for those callers: mount/umount/remount/
freeze/quotactl.
Fixes: af033b2aa8a8 ("f2fs: guarantee journalled quota data by checkpoint")
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/checkpoint.c | 15 ++++++----
fs/f2fs/f2fs.h | 3 +-
fs/f2fs/super.c | 65 ++++++++++++++++++++++++++++++++++----------
3 files changed, 61 insertions(+), 22 deletions(-)
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 6322bf2e16228..dc9540400caae 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -1249,7 +1249,7 @@ static int block_operations(struct f2fs_sb_info *sbi)
retry_flush_quotas:
f2fs_lock_all(sbi);
if (__need_flush_quota(sbi)) {
- int locked;
+ bool need_lock = sbi->umount_lock_holder != current;
if (++cnt > DEFAULT_RETRY_QUOTA_FLUSH_COUNT) {
set_sbi_flag(sbi, SBI_QUOTA_SKIP_FLUSH);
@@ -1258,11 +1258,13 @@ static int block_operations(struct f2fs_sb_info *sbi)
}
f2fs_unlock_all(sbi);
- /* only failed during mount/umount/freeze/quotactl */
- locked = down_read_trylock(&sbi->sb->s_umount);
- f2fs_quota_sync(sbi->sb, -1);
- if (locked)
+ /* don't grab s_umount lock during mount/umount/remount/freeze/quotactl */
+ if (!need_lock) {
+ f2fs_do_quota_sync(sbi->sb, -1);
+ } else if (down_read_trylock(&sbi->sb->s_umount)) {
+ f2fs_do_quota_sync(sbi->sb, -1);
up_read(&sbi->sb->s_umount);
+ }
cond_resched();
goto retry_flush_quotas;
}
@@ -1870,7 +1872,8 @@ int f2fs_issue_checkpoint(struct f2fs_sb_info *sbi)
struct cp_control cpc;
cpc.reason = __get_cp_reason(sbi);
- if (!test_opt(sbi, MERGE_CHECKPOINT) || cpc.reason != CP_SYNC) {
+ if (!test_opt(sbi, MERGE_CHECKPOINT) || cpc.reason != CP_SYNC ||
+ sbi->umount_lock_holder == current) {
int ret;
f2fs_down_write(&sbi->gc_lock);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 12ca7ba9d6dc4..81c2a566f1d42 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1708,6 +1708,7 @@ struct f2fs_sb_info {
unsigned int nquota_files; /* # of quota sysfile */
struct f2fs_rwsem quota_sem; /* blocking cp for flags */
+ struct task_struct *umount_lock_holder; /* s_umount lock holder */
/* # of pages, see count_type */
atomic_t nr_pages[NR_COUNT_TYPE];
@@ -3728,7 +3729,7 @@ int f2fs_inode_dirtied(struct inode *inode, bool sync);
void f2fs_inode_synced(struct inode *inode);
int f2fs_dquot_initialize(struct inode *inode);
int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly);
-int f2fs_quota_sync(struct super_block *sb, int type);
+int f2fs_do_quota_sync(struct super_block *sb, int type);
loff_t max_file_blocks(struct inode *inode);
void f2fs_quota_off_umount(struct super_block *sb);
void f2fs_save_errors(struct f2fs_sb_info *sbi, unsigned char flag);
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index f7acb1998b2cd..c278ce7842056 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1736,22 +1736,28 @@ int f2fs_sync_fs(struct super_block *sb, int sync)
static int f2fs_freeze(struct super_block *sb)
{
+ struct f2fs_sb_info *sbi = F2FS_SB(sb);
+
if (f2fs_readonly(sb))
return 0;
/* IO error happened before */
- if (unlikely(f2fs_cp_error(F2FS_SB(sb))))
+ if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
/* must be clean, since sync_filesystem() was already called */
- if (is_sbi_flag_set(F2FS_SB(sb), SBI_IS_DIRTY))
+ if (is_sbi_flag_set(sbi, SBI_IS_DIRTY))
return -EINVAL;
+ sbi->umount_lock_holder = current;
+
/* Let's flush checkpoints and stop the thread. */
- f2fs_flush_ckpt_thread(F2FS_SB(sb));
+ f2fs_flush_ckpt_thread(sbi);
+
+ sbi->umount_lock_holder = NULL;
/* to avoid deadlock on f2fs_evict_inode->SB_FREEZE_FS */
- set_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING);
+ set_sbi_flag(sbi, SBI_IS_FREEZING);
return 0;
}
@@ -2363,6 +2369,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
org_mount_opt = sbi->mount_opt;
old_sb_flags = sb->s_flags;
+ sbi->umount_lock_holder = current;
+
#ifdef CONFIG_QUOTA
org_mount_opt.s_jquota_fmt = F2FS_OPTION(sbi).s_jquota_fmt;
for (i = 0; i < MAXQUOTAS; i++) {
@@ -2593,6 +2601,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
limit_reserve_root(sbi);
adjust_unusable_cap_perc(sbi);
*flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME);
+
+ sbi->umount_lock_holder = NULL;
return 0;
restore_checkpoint:
if (need_enable_checkpoint) {
@@ -2634,6 +2644,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
#endif
sbi->mount_opt = org_mount_opt;
sb->s_flags = old_sb_flags;
+
+ sbi->umount_lock_holder = NULL;
return err;
}
@@ -2950,7 +2962,7 @@ static int f2fs_quota_sync_file(struct f2fs_sb_info *sbi, int type)
return ret;
}
-int f2fs_quota_sync(struct super_block *sb, int type)
+int f2fs_do_quota_sync(struct super_block *sb, int type)
{
struct f2fs_sb_info *sbi = F2FS_SB(sb);
struct quota_info *dqopt = sb_dqopt(sb);
@@ -2998,11 +3010,21 @@ int f2fs_quota_sync(struct super_block *sb, int type)
return ret;
}
+static int f2fs_quota_sync(struct super_block *sb, int type)
+{
+ int ret;
+
+ F2FS_SB(sb)->umount_lock_holder = current;
+ ret = f2fs_do_quota_sync(sb, type);
+ F2FS_SB(sb)->umount_lock_holder = NULL;
+ return ret;
+}
+
static int f2fs_quota_on(struct super_block *sb, int type, int format_id,
const struct path *path)
{
struct inode *inode;
- int err;
+ int err = 0;
/* if quota sysfile exists, deny enabling quota with specific file */
if (f2fs_sb_has_quota_ino(F2FS_SB(sb))) {
@@ -3013,31 +3035,34 @@ static int f2fs_quota_on(struct super_block *sb, int type, int format_id,
if (path->dentry->d_sb != sb)
return -EXDEV;
- err = f2fs_quota_sync(sb, type);
+ F2FS_SB(sb)->umount_lock_holder = current;
+
+ err = f2fs_do_quota_sync(sb, type);
if (err)
- return err;
+ goto out;
inode = d_inode(path->dentry);
err = filemap_fdatawrite(inode->i_mapping);
if (err)
- return err;
+ goto out;
err = filemap_fdatawait(inode->i_mapping);
if (err)
- return err;
+ goto out;
err = dquot_quota_on(sb, type, format_id, path);
if (err)
- return err;
+ goto out;
inode_lock(inode);
F2FS_I(inode)->i_flags |= F2FS_QUOTA_DEFAULT_FL;
f2fs_set_inode_flags(inode);
inode_unlock(inode);
f2fs_mark_inode_dirty_sync(inode, false);
-
- return 0;
+out:
+ F2FS_SB(sb)->umount_lock_holder = NULL;
+ return err;
}
static int __f2fs_quota_off(struct super_block *sb, int type)
@@ -3048,7 +3073,7 @@ static int __f2fs_quota_off(struct super_block *sb, int type)
if (!inode || !igrab(inode))
return dquot_quota_off(sb, type);
- err = f2fs_quota_sync(sb, type);
+ err = f2fs_do_quota_sync(sb, type);
if (err)
goto out_put;
@@ -3071,6 +3096,8 @@ static int f2fs_quota_off(struct super_block *sb, int type)
struct f2fs_sb_info *sbi = F2FS_SB(sb);
int err;
+ F2FS_SB(sb)->umount_lock_holder = current;
+
err = __f2fs_quota_off(sb, type);
/*
@@ -3080,6 +3107,9 @@ static int f2fs_quota_off(struct super_block *sb, int type)
*/
if (is_journalled_quota(sbi))
set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
+
+ F2FS_SB(sb)->umount_lock_holder = NULL;
+
return err;
}
@@ -3212,7 +3242,7 @@ int f2fs_dquot_initialize(struct inode *inode)
return 0;
}
-int f2fs_quota_sync(struct super_block *sb, int type)
+int f2fs_do_quota_sync(struct super_block *sb, int type)
{
return 0;
}
@@ -4760,6 +4790,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
if (err)
goto free_compress_inode;
+ sbi->umount_lock_holder = current;
#ifdef CONFIG_QUOTA
/* Enable quota usage during mount */
if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sb)) {
@@ -4892,6 +4923,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
f2fs_update_time(sbi, CP_TIME);
f2fs_update_time(sbi, REQ_TIME);
clear_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
+
+ sbi->umount_lock_holder = NULL;
return 0;
sync_free_meta:
@@ -4997,6 +5030,8 @@ static void kill_f2fs_super(struct super_block *sb)
struct f2fs_sb_info *sbi = F2FS_SB(sb);
if (sb->s_root) {
+ sbi->umount_lock_holder = current;
+
set_sbi_flag(sbi, SBI_IS_CLOSE);
f2fs_stop_gc_thread(sbi);
f2fs_stop_discard_thread(sbi);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 061/869] RISC-V: KVM: Teardown riscv specific bits after kvm_exit
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (59 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 060/869] f2fs: quota: fix to avoid warning in dquot_writeback_dquots() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 062/869] wifi: ath12k: fix struct hal_rx_phyrx_rssi_legacy_info Greg Kroah-Hartman
` (808 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Atish Patra, Anup Patel,
Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Atish Patra <atishp@rivosinc.com>
[ Upstream commit 2d117e67f318303f6ab699a5511d1fac3f170545 ]
During a module removal, kvm_exit invokes arch specific disable
call which disables AIA. However, we invoke aia_exit before kvm_exit
resulting in the following warning. KVM kernel module can't be inserted
afterwards due to inconsistent state of IRQ.
[25469.031389] percpu IRQ 31 still enabled on CPU0!
[25469.031732] WARNING: CPU: 3 PID: 943 at kernel/irq/manage.c:2476 __free_percpu_irq+0xa2/0x150
[25469.031804] Modules linked in: kvm(-)
[25469.031848] CPU: 3 UID: 0 PID: 943 Comm: rmmod Not tainted 6.14.0-rc5-06947-g91c763118f47-dirty #2
[25469.031905] Hardware name: riscv-virtio,qemu (DT)
[25469.031928] epc : __free_percpu_irq+0xa2/0x150
[25469.031976] ra : __free_percpu_irq+0xa2/0x150
[25469.032197] epc : ffffffff8007db1e ra : ffffffff8007db1e sp : ff2000000088bd50
[25469.032241] gp : ffffffff8131cef8 tp : ff60000080b96400 t0 : ff2000000088baf8
[25469.032285] t1 : fffffffffffffffc t2 : 5249207570637265 s0 : ff2000000088bd90
[25469.032329] s1 : ff60000098b21080 a0 : 037d527a15eb4f00 a1 : 037d527a15eb4f00
[25469.032372] a2 : 0000000000000023 a3 : 0000000000000001 a4 : ffffffff8122dbf8
[25469.032410] a5 : 0000000000000fff a6 : 0000000000000000 a7 : ffffffff8122dc10
[25469.032448] s2 : ff60000080c22eb0 s3 : 0000000200000022 s4 : 000000000000001f
[25469.032488] s5 : ff60000080c22e00 s6 : ffffffff80c351c0 s7 : 0000000000000000
[25469.032582] s8 : 0000000000000003 s9 : 000055556b7fb490 s10: 00007ffff0e12fa0
[25469.032621] s11: 00007ffff0e13e9a t3 : ffffffff81354ac7 t4 : ffffffff81354ac7
[25469.032664] t5 : ffffffff81354ac8 t6 : ffffffff81354ac7
[25469.032698] status: 0000000200000100 badaddr: ffffffff8007db1e cause: 0000000000000003
[25469.032738] [<ffffffff8007db1e>] __free_percpu_irq+0xa2/0x150
[25469.032797] [<ffffffff8007dbfc>] free_percpu_irq+0x30/0x5e
[25469.032856] [<ffffffff013a57dc>] kvm_riscv_aia_exit+0x40/0x42 [kvm]
[25469.033947] [<ffffffff013b4e82>] cleanup_module+0x10/0x32 [kvm]
[25469.035300] [<ffffffff8009b150>] __riscv_sys_delete_module+0x18e/0x1fc
[25469.035374] [<ffffffff8000c1ca>] syscall_handler+0x3a/0x46
[25469.035456] [<ffffffff809ec9a4>] do_trap_ecall_u+0x72/0x134
[25469.035536] [<ffffffff809f5e18>] handle_exception+0x148/0x156
Invoke aia_exit and other arch specific cleanup functions after kvm_exit
so that disable gets a chance to be called first before exit.
Fixes: 54e43320c2ba ("RISC-V: KVM: Initial skeletal support for AIA")
Fixes: eded6754f398 ("riscv: KVM: add basic support for host vs guest profiling")
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Sean Christopherson <seanjc@google.com>
Link: https://lore.kernel.org/r/20250317-kvm_exit_fix-v1-1-aa5240c5dbd2@rivosinc.com
Signed-off-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/riscv/kvm/main.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c
index f3427f6de6080..fed55b469794a 100644
--- a/arch/riscv/kvm/main.c
+++ b/arch/riscv/kvm/main.c
@@ -117,8 +117,8 @@ module_init(riscv_kvm_init);
static void __exit riscv_kvm_exit(void)
{
- kvm_riscv_aia_exit();
-
kvm_exit();
+
+ kvm_riscv_aia_exit();
}
module_exit(riscv_kvm_exit);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 062/869] wifi: ath12k: fix struct hal_rx_phyrx_rssi_legacy_info
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (60 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 061/869] RISC-V: KVM: Teardown riscv specific bits after kvm_exit Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 063/869] wifi: ath12k: fix incorrect TID updation in DP monitor status path Greg Kroah-Hartman
` (807 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Kang Yang, Jeff Johnson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kang Yang <quic_kangyang@quicinc.com>
[ Upstream commit 04f33114af00317dc3c494e60a7c42292e0ffd7e ]
Current struct hal_rx_phyrx_rssi_legacy_info in hal_rx.h is not matched
with hardware descriptor definition. This hardware descriptor definition
is determined by hardware. Host shall follow it.
So update struct hal_rx_phyrx_rssi_legacy_info and related code.
Both QCN9274 and WCN7850 need this modification.
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00210-QCAHKSWPL_SILICONZ-1
Signed-off-by: Kang Yang <quic_kangyang@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Link: https://patch.msgid.link/20241022110831.974-5-quic_kangyang@quicinc.com
Signed-off-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Stable-dep-of: ecfc13138992 ("wifi: ath12k: Avoid memory leak while enabling statistics")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath12k/dp_mon.c | 25 ++++++------------------
drivers/net/wireless/ath/ath12k/hal_rx.h | 9 ++++++---
2 files changed, 12 insertions(+), 22 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
index 7bfd323cdf244..95e9d652c611d 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
@@ -731,33 +731,20 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
case HAL_PHYRX_RSSI_LEGACY: {
struct hal_rx_phyrx_rssi_legacy_info *rssi =
(struct hal_rx_phyrx_rssi_legacy_info *)tlv_data;
- u32 reception_type = 0;
- u32 rssi_legacy_info = __le32_to_cpu(rssi->rsvd[0]);
info[0] = __le32_to_cpu(rssi->info0);
+ info[1] = __le32_to_cpu(rssi->info1);
/* TODO: Please note that the combined rssi will not be accurate
* in MU case. Rssi in MU needs to be retrieved from
* PHYRX_OTHER_RECEIVE_INFO TLV.
*/
ppdu_info->rssi_comb =
- u32_get_bits(info[0],
- HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RSSI_COMB);
- reception_type =
- u32_get_bits(rssi_legacy_info,
- HAL_RX_PHYRX_RSSI_LEGACY_INFO_RSVD1_RECEPTION);
-
- switch (reception_type) {
- case HAL_RECEPTION_TYPE_ULOFMDA:
- ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_OFDMA;
- break;
- case HAL_RECEPTION_TYPE_ULMIMO:
- ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO;
- break;
- default:
- ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
- break;
- }
+ u32_get_bits(info[1],
+ HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB);
+
+ ppdu_info->bw = u32_get_bits(info[0],
+ HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RX_BW);
break;
}
case HAL_RXPCU_PPDU_END_INFO: {
diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h
index 8c37cbc01b1c5..e12734fd56bca 100644
--- a/drivers/net/wireless/ath/ath12k/hal_rx.h
+++ b/drivers/net/wireless/ath/ath12k/hal_rx.h
@@ -437,12 +437,15 @@ enum hal_rx_ul_reception_type {
HAL_RECEPTION_TYPE_FRAMELESS
};
-#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RSSI_COMB GENMASK(15, 8)
-#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_RSVD1_RECEPTION GENMASK(3, 0)
+#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RECEPTION GENMASK(3, 0)
+#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RX_BW GENMASK(7, 5)
+#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB GENMASK(15, 8)
struct hal_rx_phyrx_rssi_legacy_info {
- __le32 rsvd[35];
__le32 info0;
+ __le32 rsvd0[39];
+ __le32 info1;
+ __le32 rsvd1;
} __packed;
#define HAL_RX_MPDU_START_INFO0_PPDU_ID GENMASK(31, 16)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 063/869] wifi: ath12k: fix incorrect TID updation in DP monitor status path
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (61 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 062/869] wifi: ath12k: fix struct hal_rx_phyrx_rssi_legacy_info Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 064/869] wifi: ath12k: Avoid explicit type cast in monitor status parse handler Greg Kroah-Hartman
` (806 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Karthikeyan Periyasamy, Jeff Johnson,
Kalle Valo, Jeff Johnson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
[ Upstream commit ebee84cc961cd3947015efbf4a5dbea63b11c5d3 ]
Currently, an incorrect TID value gets populated in the monitor status Rx
path due to an incorrect bitmap value given to the ffs() built-in helper
function. Therefore, avoid the decrement and directly provide the TID
bitmap to the ffs() built-in helper function for the correct TID update
in the monitor status Rx path.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Acked-by: Kalle Valo <kvalo@kernel.org>
Link: https://patch.msgid.link/20241217084511.2981515-6-quic_periyasa@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Stable-dep-of: ecfc13138992 ("wifi: ath12k: Avoid memory leak while enabling statistics")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath12k/dp_mon.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
index 95e9d652c611d..f1377e186518a 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
@@ -612,6 +612,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
case HAL_RX_PPDU_END_USER_STATS: {
struct hal_rx_ppdu_end_user_stats *eu_stats =
(struct hal_rx_ppdu_end_user_stats *)tlv_data;
+ u32 tid_bitmap;
info[0] = __le32_to_cpu(eu_stats->info0);
info[1] = __le32_to_cpu(eu_stats->info1);
@@ -624,10 +625,9 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
u32_get_bits(info[2], HAL_RX_PPDU_END_USER_STATS_INFO2_AST_INDEX);
ppdu_info->fc_valid =
u32_get_bits(info[1], HAL_RX_PPDU_END_USER_STATS_INFO1_FC_VALID);
- ppdu_info->tid =
- ffs(u32_get_bits(info[6],
- HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP)
- - 1);
+ tid_bitmap = u32_get_bits(info[6],
+ HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP);
+ ppdu_info->tid = ffs(tid_bitmap) - 1;
ppdu_info->tcp_msdu_count =
u32_get_bits(info[4],
HAL_RX_PPDU_END_USER_STATS_INFO4_TCP_MSDU_CNT);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 064/869] wifi: ath12k: Avoid explicit type cast in monitor status parse handler
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (62 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 063/869] wifi: ath12k: fix incorrect TID updation in DP monitor status path Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 065/869] wifi: ath12k: Avoid memory leak while enabling statistics Greg Kroah-Hartman
` (805 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Karthikeyan Periyasamy, Jeff Johnson,
Kalle Valo, Jeff Johnson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
[ Upstream commit 8534c42397ed8f05257dbddcd305a351ad40add1 ]
Currently, monitor status parse procedure handles all the supported TLV
tags. Each TLV tag has its own data structure for parsing. Now, this
handler is passed the tlv_data as a u8 pointer, so explicit type cast
conversion happens for every TLV tag parsing. Therefore, avoid the
explicit type conversion by changing the tlv_data type from a u8 pointer
to a const void pointer.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Acked-by: Kalle Valo <kvalo@kernel.org>
Link: https://patch.msgid.link/20241217084511.2981515-9-quic_periyasa@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Stable-dep-of: ecfc13138992 ("wifi: ath12k: Avoid memory leak while enabling statistics")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath12k/dp_mon.c | 126 +++++++++--------------
1 file changed, 47 insertions(+), 79 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
index f1377e186518a..bc24b8edfaea3 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
@@ -10,11 +10,10 @@
#include "dp_tx.h"
#include "peer.h"
-static void ath12k_dp_mon_rx_handle_ofdma_info(void *rx_tlv,
- struct hal_rx_user_status *rx_user_status)
+static void
+ath12k_dp_mon_rx_handle_ofdma_info(const struct hal_rx_ppdu_end_user_stats *ppdu_end_user,
+ struct hal_rx_user_status *rx_user_status)
{
- struct hal_rx_ppdu_end_user_stats *ppdu_end_user = rx_tlv;
-
rx_user_status->ul_ofdma_user_v0_word0 =
__le32_to_cpu(ppdu_end_user->usr_resp_ref);
rx_user_status->ul_ofdma_user_v0_word1 =
@@ -38,7 +37,7 @@ ath12k_dp_mon_rx_populate_byte_count(const struct hal_rx_ppdu_end_user_stats *st
}
static void
-ath12k_dp_mon_rx_populate_mu_user_info(void *rx_tlv,
+ath12k_dp_mon_rx_populate_mu_user_info(const struct hal_rx_ppdu_end_user_stats *rx_tlv,
struct hal_rx_mon_ppdu_info *ppdu_info,
struct hal_rx_user_status *rx_user_status)
{
@@ -76,11 +75,9 @@ ath12k_dp_mon_rx_populate_mu_user_info(void *rx_tlv,
ath12k_dp_mon_rx_populate_byte_count(rx_tlv, ppdu_info, rx_user_status);
}
-static void ath12k_dp_mon_parse_vht_sig_a(u8 *tlv_data,
+static void ath12k_dp_mon_parse_vht_sig_a(const struct hal_rx_vht_sig_a_info *vht_sig,
struct hal_rx_mon_ppdu_info *ppdu_info)
{
- struct hal_rx_vht_sig_a_info *vht_sig =
- (struct hal_rx_vht_sig_a_info *)tlv_data;
u32 nsts, group_id, info0, info1;
u8 gi_setting;
@@ -122,11 +119,9 @@ static void ath12k_dp_mon_parse_vht_sig_a(u8 *tlv_data,
u32_get_bits(info1, HAL_RX_VHT_SIG_A_INFO_INFO1_SU_MU_CODING);
}
-static void ath12k_dp_mon_parse_ht_sig(u8 *tlv_data,
+static void ath12k_dp_mon_parse_ht_sig(const struct hal_rx_ht_sig_info *ht_sig,
struct hal_rx_mon_ppdu_info *ppdu_info)
{
- struct hal_rx_ht_sig_info *ht_sig =
- (struct hal_rx_ht_sig_info *)tlv_data;
u32 info0 = __le32_to_cpu(ht_sig->info0);
u32 info1 = __le32_to_cpu(ht_sig->info1);
@@ -139,11 +134,9 @@ static void ath12k_dp_mon_parse_ht_sig(u8 *tlv_data,
ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
}
-static void ath12k_dp_mon_parse_l_sig_b(u8 *tlv_data,
+static void ath12k_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb,
struct hal_rx_mon_ppdu_info *ppdu_info)
{
- struct hal_rx_lsig_b_info *lsigb =
- (struct hal_rx_lsig_b_info *)tlv_data;
u32 info0 = __le32_to_cpu(lsigb->info0);
u8 rate;
@@ -173,11 +166,9 @@ static void ath12k_dp_mon_parse_l_sig_b(u8 *tlv_data,
ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
}
-static void ath12k_dp_mon_parse_l_sig_a(u8 *tlv_data,
+static void ath12k_dp_mon_parse_l_sig_a(const struct hal_rx_lsig_a_info *lsiga,
struct hal_rx_mon_ppdu_info *ppdu_info)
{
- struct hal_rx_lsig_a_info *lsiga =
- (struct hal_rx_lsig_a_info *)tlv_data;
u32 info0 = __le32_to_cpu(lsiga->info0);
u8 rate;
@@ -215,14 +206,13 @@ static void ath12k_dp_mon_parse_l_sig_a(u8 *tlv_data,
ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
}
-static void ath12k_dp_mon_parse_he_sig_b2_ofdma(u8 *tlv_data,
- struct hal_rx_mon_ppdu_info *ppdu_info)
+static void
+ath12k_dp_mon_parse_he_sig_b2_ofdma(const struct hal_rx_he_sig_b2_ofdma_info *ofdma,
+ struct hal_rx_mon_ppdu_info *ppdu_info)
{
- struct hal_rx_he_sig_b2_ofdma_info *he_sig_b2_ofdma =
- (struct hal_rx_he_sig_b2_ofdma_info *)tlv_data;
u32 info0, value;
- info0 = __le32_to_cpu(he_sig_b2_ofdma->info0);
+ info0 = __le32_to_cpu(ofdma->info0);
ppdu_info->he_data1 |= HE_MCS_KNOWN | HE_DCM_KNOWN | HE_CODING_KNOWN;
@@ -253,11 +243,10 @@ static void ath12k_dp_mon_parse_he_sig_b2_ofdma(u8 *tlv_data,
ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_OFDMA;
}
-static void ath12k_dp_mon_parse_he_sig_b2_mu(u8 *tlv_data,
- struct hal_rx_mon_ppdu_info *ppdu_info)
+static void
+ath12k_dp_mon_parse_he_sig_b2_mu(const struct hal_rx_he_sig_b2_mu_info *he_sig_b2_mu,
+ struct hal_rx_mon_ppdu_info *ppdu_info)
{
- struct hal_rx_he_sig_b2_mu_info *he_sig_b2_mu =
- (struct hal_rx_he_sig_b2_mu_info *)tlv_data;
u32 info0, value;
info0 = __le32_to_cpu(he_sig_b2_mu->info0);
@@ -280,11 +269,10 @@ static void ath12k_dp_mon_parse_he_sig_b2_mu(u8 *tlv_data,
ppdu_info->nss = u32_get_bits(info0, HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_NSTS);
}
-static void ath12k_dp_mon_parse_he_sig_b1_mu(u8 *tlv_data,
- struct hal_rx_mon_ppdu_info *ppdu_info)
+static void
+ath12k_dp_mon_parse_he_sig_b1_mu(const struct hal_rx_he_sig_b1_mu_info *he_sig_b1_mu,
+ struct hal_rx_mon_ppdu_info *ppdu_info)
{
- struct hal_rx_he_sig_b1_mu_info *he_sig_b1_mu =
- (struct hal_rx_he_sig_b1_mu_info *)tlv_data;
u32 info0 = __le32_to_cpu(he_sig_b1_mu->info0);
u16 ru_tones;
@@ -295,11 +283,10 @@ static void ath12k_dp_mon_parse_he_sig_b1_mu(u8 *tlv_data,
ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO;
}
-static void ath12k_dp_mon_parse_he_sig_mu(u8 *tlv_data,
- struct hal_rx_mon_ppdu_info *ppdu_info)
+static void
+ath12k_dp_mon_parse_he_sig_mu(const struct hal_rx_he_sig_a_mu_dl_info *he_sig_a_mu_dl,
+ struct hal_rx_mon_ppdu_info *ppdu_info)
{
- struct hal_rx_he_sig_a_mu_dl_info *he_sig_a_mu_dl =
- (struct hal_rx_he_sig_a_mu_dl_info *)tlv_data;
u32 info0, info1, value;
u16 he_gi = 0, he_ltf = 0;
@@ -430,11 +417,9 @@ static void ath12k_dp_mon_parse_he_sig_mu(u8 *tlv_data,
ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO;
}
-static void ath12k_dp_mon_parse_he_sig_su(u8 *tlv_data,
+static void ath12k_dp_mon_parse_he_sig_su(const struct hal_rx_he_sig_a_su_info *he_sig_a,
struct hal_rx_mon_ppdu_info *ppdu_info)
{
- struct hal_rx_he_sig_a_su_info *he_sig_a =
- (struct hal_rx_he_sig_a_su_info *)tlv_data;
u32 info0, info1, value;
u32 dcm;
u8 he_dcm = 0, he_stbc = 0;
@@ -583,15 +568,15 @@ static void ath12k_dp_mon_parse_he_sig_su(u8 *tlv_data,
static enum hal_rx_mon_status
ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
struct ath12k_mon_data *pmon,
- u32 tlv_tag, u8 *tlv_data, u32 userid)
+ u32 tlv_tag, const void *tlv_data,
+ u32 userid)
{
struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info;
u32 info[7];
switch (tlv_tag) {
case HAL_RX_PPDU_START: {
- struct hal_rx_ppdu_start *ppdu_start =
- (struct hal_rx_ppdu_start *)tlv_data;
+ const struct hal_rx_ppdu_start *ppdu_start = tlv_data;
info[0] = __le32_to_cpu(ppdu_start->info0);
@@ -610,8 +595,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
break;
}
case HAL_RX_PPDU_END_USER_STATS: {
- struct hal_rx_ppdu_end_user_stats *eu_stats =
- (struct hal_rx_ppdu_end_user_stats *)tlv_data;
+ const struct hal_rx_ppdu_end_user_stats *eu_stats = tlv_data;
u32 tid_bitmap;
info[0] = __le32_to_cpu(eu_stats->info0);
@@ -673,8 +657,8 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
ppdu_info->num_users += 1;
- ath12k_dp_mon_rx_handle_ofdma_info(tlv_data, rxuser_stats);
- ath12k_dp_mon_rx_populate_mu_user_info(tlv_data, ppdu_info,
+ ath12k_dp_mon_rx_handle_ofdma_info(eu_stats, rxuser_stats);
+ ath12k_dp_mon_rx_populate_mu_user_info(eu_stats, ppdu_info,
rxuser_stats);
}
ppdu_info->mpdu_fcs_ok_bitmap[0] = __le32_to_cpu(eu_stats->rsvd1[0]);
@@ -682,8 +666,8 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
break;
}
case HAL_RX_PPDU_END_USER_STATS_EXT: {
- struct hal_rx_ppdu_end_user_stats_ext *eu_stats =
- (struct hal_rx_ppdu_end_user_stats_ext *)tlv_data;
+ const struct hal_rx_ppdu_end_user_stats_ext *eu_stats = tlv_data;
+
ppdu_info->mpdu_fcs_ok_bitmap[2] = __le32_to_cpu(eu_stats->info1);
ppdu_info->mpdu_fcs_ok_bitmap[3] = __le32_to_cpu(eu_stats->info2);
ppdu_info->mpdu_fcs_ok_bitmap[4] = __le32_to_cpu(eu_stats->info3);
@@ -729,8 +713,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
break;
case HAL_PHYRX_RSSI_LEGACY: {
- struct hal_rx_phyrx_rssi_legacy_info *rssi =
- (struct hal_rx_phyrx_rssi_legacy_info *)tlv_data;
+ const struct hal_rx_phyrx_rssi_legacy_info *rssi = tlv_data;
info[0] = __le32_to_cpu(rssi->info0);
info[1] = __le32_to_cpu(rssi->info1);
@@ -748,8 +731,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
break;
}
case HAL_RXPCU_PPDU_END_INFO: {
- struct hal_rx_ppdu_end_duration *ppdu_rx_duration =
- (struct hal_rx_ppdu_end_duration *)tlv_data;
+ const struct hal_rx_ppdu_end_duration *ppdu_rx_duration = tlv_data;
info[0] = __le32_to_cpu(ppdu_rx_duration->info0);
ppdu_info->rx_duration =
@@ -760,8 +742,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
break;
}
case HAL_RX_MPDU_START: {
- struct hal_rx_mpdu_start *mpdu_start =
- (struct hal_rx_mpdu_start *)tlv_data;
+ const struct hal_rx_mpdu_start *mpdu_start = tlv_data;
struct dp_mon_mpdu *mon_mpdu = pmon->mon_mpdu;
u16 peer_id;
@@ -790,8 +771,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
break;
case HAL_MON_BUF_ADDR: {
struct dp_rxdma_mon_ring *buf_ring = &ab->dp.rxdma_mon_buf_ring;
- struct dp_mon_packet_info *packet_info =
- (struct dp_mon_packet_info *)tlv_data;
+ const struct dp_mon_packet_info *packet_info = tlv_data;
int buf_id = u32_get_bits(packet_info->cookie,
DP_RXDMA_BUF_COOKIE_BUF_ID);
struct sk_buff *msdu;
@@ -823,8 +803,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
break;
}
case HAL_RX_MSDU_END: {
- struct rx_msdu_end_qcn9274 *msdu_end =
- (struct rx_msdu_end_qcn9274 *)tlv_data;
+ const struct rx_msdu_end_qcn9274 *msdu_end = tlv_data;
bool is_first_msdu_in_mpdu;
u16 msdu_end_info;
@@ -1589,7 +1568,7 @@ ath12k_dp_mon_tx_gen_prot_frame(struct dp_mon_tx_ppdu_info *tx_ppdu_info)
static enum dp_mon_tx_tlv_status
ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
struct ath12k_mon_data *pmon,
- u16 tlv_tag, u8 *tlv_data, u32 userid)
+ u16 tlv_tag, const void *tlv_data, u32 userid)
{
struct dp_mon_tx_ppdu_info *tx_ppdu_info;
enum dp_mon_tx_tlv_status status = DP_MON_TX_STATUS_PPDU_NOT_DONE;
@@ -1599,8 +1578,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
switch (tlv_tag) {
case HAL_TX_FES_SETUP: {
- struct hal_tx_fes_setup *tx_fes_setup =
- (struct hal_tx_fes_setup *)tlv_data;
+ const struct hal_tx_fes_setup *tx_fes_setup = tlv_data;
info[0] = __le32_to_cpu(tx_fes_setup->info0);
tx_ppdu_info->ppdu_id = __le32_to_cpu(tx_fes_setup->schedule_id);
@@ -1611,8 +1589,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
}
case HAL_TX_FES_STATUS_END: {
- struct hal_tx_fes_status_end *tx_fes_status_end =
- (struct hal_tx_fes_status_end *)tlv_data;
+ const struct hal_tx_fes_status_end *tx_fes_status_end = tlv_data;
u32 tst_15_0, tst_31_16;
info[0] = __le32_to_cpu(tx_fes_status_end->info0);
@@ -1629,8 +1606,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
}
case HAL_RX_RESPONSE_REQUIRED_INFO: {
- struct hal_rx_resp_req_info *rx_resp_req_info =
- (struct hal_rx_resp_req_info *)tlv_data;
+ const struct hal_rx_resp_req_info *rx_resp_req_info = tlv_data;
u32 addr_32;
u16 addr_16;
@@ -1675,8 +1651,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
}
case HAL_PCU_PPDU_SETUP_INIT: {
- struct hal_tx_pcu_ppdu_setup_init *ppdu_setup =
- (struct hal_tx_pcu_ppdu_setup_init *)tlv_data;
+ const struct hal_tx_pcu_ppdu_setup_init *ppdu_setup = tlv_data;
u32 addr_32;
u16 addr_16;
@@ -1722,8 +1697,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
}
case HAL_TX_QUEUE_EXTENSION: {
- struct hal_tx_queue_exten *tx_q_exten =
- (struct hal_tx_queue_exten *)tlv_data;
+ const struct hal_tx_queue_exten *tx_q_exten = tlv_data;
info[0] = __le32_to_cpu(tx_q_exten->info0);
@@ -1735,8 +1709,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
}
case HAL_TX_FES_STATUS_START: {
- struct hal_tx_fes_status_start *tx_fes_start =
- (struct hal_tx_fes_status_start *)tlv_data;
+ const struct hal_tx_fes_status_start *tx_fes_start = tlv_data;
info[0] = __le32_to_cpu(tx_fes_start->info0);
@@ -1747,8 +1720,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
}
case HAL_TX_FES_STATUS_PROT: {
- struct hal_tx_fes_status_prot *tx_fes_status =
- (struct hal_tx_fes_status_prot *)tlv_data;
+ const struct hal_tx_fes_status_prot *tx_fes_status = tlv_data;
u32 start_timestamp;
u32 end_timestamp;
@@ -1775,8 +1747,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
case HAL_TX_FES_STATUS_START_PPDU:
case HAL_TX_FES_STATUS_START_PROT: {
- struct hal_tx_fes_status_start_prot *tx_fes_stat_start =
- (struct hal_tx_fes_status_start_prot *)tlv_data;
+ const struct hal_tx_fes_status_start_prot *tx_fes_stat_start = tlv_data;
u64 ppdu_ts;
info[0] = __le32_to_cpu(tx_fes_stat_start->info0);
@@ -1791,8 +1762,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
}
case HAL_TX_FES_STATUS_USER_PPDU: {
- struct hal_tx_fes_status_user_ppdu *tx_fes_usr_ppdu =
- (struct hal_tx_fes_status_user_ppdu *)tlv_data;
+ const struct hal_tx_fes_status_user_ppdu *tx_fes_usr_ppdu = tlv_data;
info[0] = __le32_to_cpu(tx_fes_usr_ppdu->info0);
@@ -1835,8 +1805,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
break;
case HAL_RX_FRAME_BITMAP_ACK: {
- struct hal_rx_frame_bitmap_ack *fbm_ack =
- (struct hal_rx_frame_bitmap_ack *)tlv_data;
+ const struct hal_rx_frame_bitmap_ack *fbm_ack = tlv_data;
u32 addr_32;
u16 addr_16;
@@ -1854,8 +1823,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
}
case HAL_MACTX_PHY_DESC: {
- struct hal_tx_phy_desc *tx_phy_desc =
- (struct hal_tx_phy_desc *)tlv_data;
+ const struct hal_tx_phy_desc *tx_phy_desc = tlv_data;
info[0] = __le32_to_cpu(tx_phy_desc->info0);
info[1] = __le32_to_cpu(tx_phy_desc->info1);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 065/869] wifi: ath12k: Avoid memory leak while enabling statistics
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (63 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 064/869] wifi: ath12k: Avoid explicit type cast in monitor status parse handler Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 066/869] perf/dwc_pcie: Qualify RAS DES VSEC Capability by Vendor, Revision Greg Kroah-Hartman
` (804 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, P Praneesh, Jeff Johnson,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: P Praneesh <quic_ppranees@quicinc.com>
[ Upstream commit ecfc131389923405be8e7a6f4408fd9321e4d19b ]
Driver uses monitor destination rings for extended statistics mode and
standalone monitor mode. In extended statistics mode, TLVs are parsed from
the buffer received from the monitor destination ring and assigned to the
ppdu_info structure to update per-packet statistics. In standalone monitor
mode, along with per-packet statistics, the packet data (payload) is
captured, and the driver updates per MSDU to mac80211.
When the AP interface is enabled, only extended statistics mode is
activated. As part of enabling monitor rings for collecting statistics,
the driver subscribes to HAL_RX_MPDU_START TLV in the filter
configuration. This TLV is received from the monitor destination ring, and
kzalloc for the mon_mpdu object occurs, which is not freed, leading to a
memory leak. The kzalloc for the mon_mpdu object is only required while
enabling the standalone monitor interface. This causes a memory leak while
enabling extended statistics mode in the driver.
Fix this memory leak by removing the kzalloc for the mon_mpdu object in
the HAL_RX_MPDU_START TLV handling. Additionally, remove the standalone
monitor mode handlings in the HAL_MON_BUF_ADDR and HAL_RX_MSDU_END TLVs.
These TLV tags will be handled properly when enabling standalone monitor
mode in the future.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Signed-off-by: P Praneesh <quic_ppranees@quicinc.com>
Link: https://patch.msgid.link/20241223060132.3506372-13-quic_ppranees@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath12k/dp_mon.c | 64 ++++--------------------
drivers/net/wireless/ath/ath12k/hal_rx.h | 3 ++
2 files changed, 12 insertions(+), 55 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
index bc24b8edfaea3..ad276f8605054 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
@@ -743,7 +743,6 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
}
case HAL_RX_MPDU_START: {
const struct hal_rx_mpdu_start *mpdu_start = tlv_data;
- struct dp_mon_mpdu *mon_mpdu = pmon->mon_mpdu;
u16 peer_id;
info[1] = __le32_to_cpu(mpdu_start->info1);
@@ -760,65 +759,17 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
u32_get_bits(info[0], HAL_RX_MPDU_START_INFO0_PPDU_ID);
}
- mon_mpdu = kzalloc(sizeof(*mon_mpdu), GFP_ATOMIC);
- if (!mon_mpdu)
- return HAL_RX_MON_STATUS_PPDU_NOT_DONE;
-
break;
}
case HAL_RX_MSDU_START:
/* TODO: add msdu start parsing logic */
break;
- case HAL_MON_BUF_ADDR: {
- struct dp_rxdma_mon_ring *buf_ring = &ab->dp.rxdma_mon_buf_ring;
- const struct dp_mon_packet_info *packet_info = tlv_data;
- int buf_id = u32_get_bits(packet_info->cookie,
- DP_RXDMA_BUF_COOKIE_BUF_ID);
- struct sk_buff *msdu;
- struct dp_mon_mpdu *mon_mpdu = pmon->mon_mpdu;
- struct ath12k_skb_rxcb *rxcb;
-
- spin_lock_bh(&buf_ring->idr_lock);
- msdu = idr_remove(&buf_ring->bufs_idr, buf_id);
- spin_unlock_bh(&buf_ring->idr_lock);
-
- if (unlikely(!msdu)) {
- ath12k_warn(ab, "monitor destination with invalid buf_id %d\n",
- buf_id);
- return HAL_RX_MON_STATUS_PPDU_NOT_DONE;
- }
-
- rxcb = ATH12K_SKB_RXCB(msdu);
- dma_unmap_single(ab->dev, rxcb->paddr,
- msdu->len + skb_tailroom(msdu),
- DMA_FROM_DEVICE);
-
- if (mon_mpdu->tail)
- mon_mpdu->tail->next = msdu;
- else
- mon_mpdu->tail = msdu;
-
- ath12k_dp_mon_buf_replenish(ab, buf_ring, 1);
-
- break;
- }
- case HAL_RX_MSDU_END: {
- const struct rx_msdu_end_qcn9274 *msdu_end = tlv_data;
- bool is_first_msdu_in_mpdu;
- u16 msdu_end_info;
-
- msdu_end_info = __le16_to_cpu(msdu_end->info5);
- is_first_msdu_in_mpdu = u32_get_bits(msdu_end_info,
- RX_MSDU_END_INFO5_FIRST_MSDU);
- if (is_first_msdu_in_mpdu) {
- pmon->mon_mpdu->head = pmon->mon_mpdu->tail;
- pmon->mon_mpdu->tail = NULL;
- }
- break;
- }
+ case HAL_MON_BUF_ADDR:
+ return HAL_RX_MON_STATUS_BUF_ADDR;
+ case HAL_RX_MSDU_END:
+ return HAL_RX_MON_STATUS_MSDU_END;
case HAL_RX_MPDU_END:
- list_add_tail(&pmon->mon_mpdu->list, &pmon->dp_rx_mon_mpdu_list);
- break;
+ return HAL_RX_MON_STATUS_MPDU_END;
case HAL_DUMMY:
return HAL_RX_MON_STATUS_BUF_DONE;
case HAL_RX_PPDU_END_STATUS_DONE:
@@ -1196,7 +1147,10 @@ ath12k_dp_mon_parse_rx_dest(struct ath12k_base *ab, struct ath12k_mon_data *pmon
if ((ptr - skb->data) >= DP_RX_BUFFER_SIZE)
break;
- } while (hal_status == HAL_RX_MON_STATUS_PPDU_NOT_DONE);
+ } while ((hal_status == HAL_RX_MON_STATUS_PPDU_NOT_DONE) ||
+ (hal_status == HAL_RX_MON_STATUS_BUF_ADDR) ||
+ (hal_status == HAL_RX_MON_STATUS_MPDU_END) ||
+ (hal_status == HAL_RX_MON_STATUS_MSDU_END));
return hal_status;
}
diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h
index e12734fd56bca..33fb765628c55 100644
--- a/drivers/net/wireless/ath/ath12k/hal_rx.h
+++ b/drivers/net/wireless/ath/ath12k/hal_rx.h
@@ -108,6 +108,9 @@ enum hal_rx_mon_status {
HAL_RX_MON_STATUS_PPDU_NOT_DONE,
HAL_RX_MON_STATUS_PPDU_DONE,
HAL_RX_MON_STATUS_BUF_DONE,
+ HAL_RX_MON_STATUS_BUF_ADDR,
+ HAL_RX_MON_STATUS_MPDU_END,
+ HAL_RX_MON_STATUS_MSDU_END,
};
#define HAL_RX_MAX_MPDU 256
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 066/869] perf/dwc_pcie: Qualify RAS DES VSEC Capability by Vendor, Revision
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (64 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 065/869] wifi: ath12k: Avoid memory leak while enabling statistics Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 067/869] perf/dwc_pcie: fix duplicate pci_dev devices Greg Kroah-Hartman
` (803 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bjorn Helgaas, Will Deacon,
Sasha Levin, Ilkka Koskinen, Shuai Xue
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bjorn Helgaas <bhelgaas@google.com>
[ Upstream commit b34d605d120f09303cf8d9e25ad3e17a4997c3a1 ]
PCI Vendor-Specific (VSEC) Capabilities are defined by each vendor.
Devices from different vendors may advertise a VSEC Capability with the DWC
RAS DES functionality, but the vendors may assign different VSEC IDs.
Search for the DWC RAS DES Capability using the VSEC ID and VSEC Rev
chosen by the vendor.
This does not fix a current problem because Alibaba, Ampere, and Qualcomm
all assigned the same VSEC ID and VSEC Rev for the DWC RAS DES Capability.
The potential issue is that we may add support for a device from another
vendor, where the vendor has already assigned DWC_PCIE_VSEC_RAS_DES_ID
(0x02) for an unrelated VSEC. In that event, dwc_pcie_des_cap() would find
the unrelated VSEC and mistakenly assume it was a DWC RAS DES Capability.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-and-tested-by: Ilkka Koskinen <ilkka@os.amperecomputing.com>
Reviewed-and-tested-by: Shuai Xue <xueshuai@linux.alibaba.com>
Link: https://lore.kernel.org/r/20241209222938.3219364-1-helgaas@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
Keep the vendor table limited to the existing Alibaba and Qualcomm
devices. Omit the Ampere entry because its separate support change
is absent. Retain the capability lookup conversion and probe checks
needed by the device-registration fix.
Stable-dep-of: 7f35b429802a ("perf/dwc_pcie: fix duplicate pci_dev devices")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/perf/dwc_pcie_pmu.c | 65 ++++++++++++++++++++-----------------
1 file changed, 35 insertions(+), 30 deletions(-)
diff --git a/drivers/perf/dwc_pcie_pmu.c b/drivers/perf/dwc_pcie_pmu.c
index 7dbda36884c8d..9687083c42fbc 100644
--- a/drivers/perf/dwc_pcie_pmu.c
+++ b/drivers/perf/dwc_pcie_pmu.c
@@ -20,7 +20,6 @@
#include <linux/sysfs.h>
#include <linux/types.h>
-#define DWC_PCIE_VSEC_RAS_DES_ID 0x02
#define DWC_PCIE_EVENT_CNT_CTL 0x8
/*
@@ -101,13 +100,21 @@ struct dwc_pcie_dev_info {
struct list_head dev_node;
};
-struct dwc_pcie_vendor_id {
- int vendor_id;
+struct dwc_pcie_pmu_vsec_id {
+ u16 vendor_id;
+ u16 vsec_id;
+ u8 vsec_rev;
};
-static const struct dwc_pcie_vendor_id dwc_pcie_vendor_ids[] = {
- {.vendor_id = PCI_VENDOR_ID_ALIBABA },
- {.vendor_id = PCI_VENDOR_ID_QCOM },
+/*
+ * VSEC IDs are allocated by the vendor, so a given ID may mean different
+ * things to different vendors. See PCIe r6.0, sec 7.9.5.2.
+ */
+static const struct dwc_pcie_pmu_vsec_id dwc_pcie_pmu_vsec_ids[] = {
+ { .vendor_id = PCI_VENDOR_ID_ALIBABA,
+ .vsec_id = 0x02, .vsec_rev = 0x4 },
+ { .vendor_id = PCI_VENDOR_ID_QCOM,
+ .vsec_id = 0x02, .vsec_rev = 0x4 },
{} /* terminator */
};
@@ -519,31 +526,28 @@ static void dwc_pcie_unregister_pmu(void *data)
perf_pmu_unregister(&pcie_pmu->pmu);
}
-static bool dwc_pcie_match_des_cap(struct pci_dev *pdev)
+static u16 dwc_pcie_des_cap(struct pci_dev *pdev)
{
- const struct dwc_pcie_vendor_id *vid;
- u16 vsec = 0;
+ const struct dwc_pcie_pmu_vsec_id *vid;
+ u16 vsec;
u32 val;
if (!pci_is_pcie(pdev) || !(pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT))
- return false;
+ return 0;
- for (vid = dwc_pcie_vendor_ids; vid->vendor_id; vid++) {
+ for (vid = dwc_pcie_pmu_vsec_ids; vid->vendor_id; vid++) {
vsec = pci_find_vsec_capability(pdev, vid->vendor_id,
- DWC_PCIE_VSEC_RAS_DES_ID);
- if (vsec)
- break;
+ vid->vsec_id);
+ if (vsec) {
+ pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER,
+ &val);
+ if (PCI_VNDR_HEADER_REV(val) == vid->vsec_rev) {
+ pci_dbg(pdev, "Detected PCIe Vendor-Specific Extended Capability RAS DES\n");
+ return vsec;
+ }
+ }
}
- if (!vsec)
- return false;
-
- pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER, &val);
- if (PCI_VNDR_HEADER_REV(val) != 0x04)
- return false;
-
- pci_dbg(pdev,
- "Detected PCIe Vendor-Specific Extended Capability RAS DES\n");
- return true;
+ return 0;
}
static void dwc_pcie_unregister_dev(struct dwc_pcie_dev_info *dev_info)
@@ -589,7 +593,7 @@ static int dwc_pcie_pmu_notifier(struct notifier_block *nb,
switch (action) {
case BUS_NOTIFY_ADD_DEVICE:
- if (!dwc_pcie_match_des_cap(pdev))
+ if (!dwc_pcie_des_cap(pdev))
return NOTIFY_DONE;
if (dwc_pcie_register_dev(pdev))
return NOTIFY_BAD;
@@ -614,13 +618,14 @@ static int dwc_pcie_pmu_probe(struct platform_device *plat_dev)
struct pci_dev *pdev = plat_dev->dev.platform_data;
struct dwc_pcie_pmu *pcie_pmu;
char *name;
- u32 sbdf, val;
+ u32 sbdf;
u16 vsec;
int ret;
- vsec = pci_find_vsec_capability(pdev, pdev->vendor,
- DWC_PCIE_VSEC_RAS_DES_ID);
- pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER, &val);
+ vsec = dwc_pcie_des_cap(pdev);
+ if (!vsec)
+ return -ENODEV;
+
sbdf = plat_dev->id;
name = devm_kasprintf(&plat_dev->dev, GFP_KERNEL, "dwc_rootport_%x", sbdf);
if (!name)
@@ -741,7 +746,7 @@ static int __init dwc_pcie_pmu_init(void)
int ret;
for_each_pci_dev(pdev) {
- if (!dwc_pcie_match_des_cap(pdev))
+ if (!dwc_pcie_des_cap(pdev))
continue;
ret = dwc_pcie_register_dev(pdev);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 067/869] perf/dwc_pcie: fix duplicate pci_dev devices
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (65 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 066/869] perf/dwc_pcie: Qualify RAS DES VSEC Capability by Vendor, Revision Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 068/869] ublk: fix race between io_uring_cmd_complete_in_task and ublk_cancel_cmd Greg Kroah-Hartman
` (802 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yunhui Cui, Shuai Xue, Will Deacon,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yunhui Cui <cuiyunhui@bytedance.com>
[ Upstream commit 7f35b429802a8065aa61e2a3f567089649f4d98e ]
During platform_device_register, wrongly using struct device
pci_dev as platform_data caused a kmemdup copy of pci_dev. Worse
still, accessing the duplicated device leads to list corruption as its
mutex content (e.g., list, magic) remains the same as the original.
Signed-off-by: Yunhui Cui <cuiyunhui@bytedance.com>
Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com>
Link: https://lore.kernel.org/r/20250220121716.50324-3-cuiyunhui@bytedance.com
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/perf/dwc_pcie_pmu.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/perf/dwc_pcie_pmu.c b/drivers/perf/dwc_pcie_pmu.c
index 9687083c42fbc..bde0a0a06cff5 100644
--- a/drivers/perf/dwc_pcie_pmu.c
+++ b/drivers/perf/dwc_pcie_pmu.c
@@ -564,9 +564,7 @@ static int dwc_pcie_register_dev(struct pci_dev *pdev)
u32 sbdf;
sbdf = (pci_domain_nr(pdev->bus) << 16) | PCI_DEVID(pdev->bus->number, pdev->devfn);
- plat_dev = platform_device_register_data(NULL, "dwc_pcie_pmu", sbdf,
- pdev, sizeof(*pdev));
-
+ plat_dev = platform_device_register_simple("dwc_pcie_pmu", sbdf, NULL, 0);
if (IS_ERR(plat_dev))
return PTR_ERR(plat_dev);
@@ -615,18 +613,26 @@ static struct notifier_block dwc_pcie_pmu_nb = {
static int dwc_pcie_pmu_probe(struct platform_device *plat_dev)
{
- struct pci_dev *pdev = plat_dev->dev.platform_data;
+ struct pci_dev *pdev;
struct dwc_pcie_pmu *pcie_pmu;
char *name;
u32 sbdf;
u16 vsec;
int ret;
+ sbdf = plat_dev->id;
+ pdev = pci_get_domain_bus_and_slot(sbdf >> 16, PCI_BUS_NUM(sbdf & 0xffff),
+ sbdf & 0xff);
+ if (!pdev) {
+ pr_err("No pdev found for the sbdf 0x%x\n", sbdf);
+ return -ENODEV;
+ }
+
vsec = dwc_pcie_des_cap(pdev);
if (!vsec)
return -ENODEV;
- sbdf = plat_dev->id;
+ pci_dev_put(pdev);
name = devm_kasprintf(&plat_dev->dev, GFP_KERNEL, "dwc_rootport_%x", sbdf);
if (!name)
return -ENOMEM;
@@ -641,7 +647,7 @@ static int dwc_pcie_pmu_probe(struct platform_device *plat_dev)
pcie_pmu->on_cpu = -1;
pcie_pmu->pmu = (struct pmu){
.name = name,
- .parent = &pdev->dev,
+ .parent = &plat_dev->dev,
.module = THIS_MODULE,
.attr_groups = dwc_pcie_attr_groups,
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 068/869] ublk: fix race between io_uring_cmd_complete_in_task and ublk_cancel_cmd
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (66 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 067/869] perf/dwc_pcie: fix duplicate pci_dev devices Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 069/869] kasan: avoid sleepable page allocation from atomic context Greg Kroah-Hartman
` (801 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jared Holzman, Ming Lei, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Lei <ming.lei@redhat.com>
[ Upstream commit f40139fde5278d81af3227444fd6e76a76b9506d ]
ublk_cancel_cmd() calls io_uring_cmd_done() to complete uring_cmd, but
we may have scheduled task work via io_uring_cmd_complete_in_task() for
dispatching request, then kernel crash can be triggered.
Fix it by not trying to canceling the command if ublk block request is
started.
Fixes: 216c8f5ef0f2 ("ublk: replace monitor with cancelable uring_cmd")
Reported-by: Jared Holzman <jholzman@nvidia.com>
Tested-by: Jared Holzman <jholzman@nvidia.com>
Closes: https://lore.kernel.org/linux-block/d2179120-171b-47ba-b664-23242981ef19@nvidia.com/
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250425013742.1079549-3-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/block/ublk_drv.c | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 6d5523058bed8..bd0b2046981e4 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -1552,14 +1552,31 @@ static bool ublk_abort_requests(struct ublk_device *ub, struct ublk_queue *ubq)
return !was_canceled;
}
-static void ublk_cancel_cmd(struct ublk_queue *ubq, struct ublk_io *io,
+static void ublk_cancel_cmd(struct ublk_queue *ubq, unsigned tag,
unsigned int issue_flags)
{
+ struct ublk_io *io = &ubq->ios[tag];
+ struct ublk_device *ub = ubq->dev;
+ struct request *req;
bool done;
if (!(io->flags & UBLK_IO_FLAG_ACTIVE))
return;
+ /*
+ * Don't try to cancel this command if the request is started for
+ * avoiding race between io_uring_cmd_done() and
+ * io_uring_cmd_complete_in_task().
+ *
+ * Either the started request will be aborted via __ublk_abort_rq(),
+ * then this uring_cmd is canceled next time, or it will be done in
+ * task work function ublk_dispatch_req() because io_uring guarantees
+ * that ublk_dispatch_req() is always called
+ */
+ req = blk_mq_tag_to_rq(ub->tag_set.tags[ubq->q_id], tag);
+ if (req && blk_mq_request_started(req))
+ return;
+
spin_lock(&ubq->cancel_lock);
done = !!(io->flags & UBLK_IO_FLAG_CANCELED);
if (!done)
@@ -1582,7 +1599,6 @@ static void ublk_uring_cmd_cancel_fn(struct io_uring_cmd *cmd,
struct task_struct *task;
struct ublk_device *ub;
bool need_schedule;
- struct ublk_io *io;
if (WARN_ON_ONCE(!ubq))
return;
@@ -1597,9 +1613,8 @@ static void ublk_uring_cmd_cancel_fn(struct io_uring_cmd *cmd,
ub = ubq->dev;
need_schedule = ublk_abort_requests(ub, ubq);
- io = &ubq->ios[pdu->tag];
- WARN_ON_ONCE(io->cmd != cmd);
- ublk_cancel_cmd(ubq, io, issue_flags);
+ WARN_ON_ONCE(ubq->ios[pdu->tag].cmd != cmd);
+ ublk_cancel_cmd(ubq, pdu->tag, issue_flags);
if (need_schedule) {
if (ublk_nosrv_should_stop_dev(ub))
@@ -1619,7 +1634,7 @@ static void ublk_cancel_queue(struct ublk_queue *ubq)
int i;
for (i = 0; i < ubq->q_depth; i++)
- ublk_cancel_cmd(ubq, &ubq->ios[i], IO_URING_F_UNLOCKED);
+ ublk_cancel_cmd(ubq, i, IO_URING_F_UNLOCKED);
}
/* Cancel all pending commands, must be called after del_gendisk() returns */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 069/869] kasan: avoid sleepable page allocation from atomic context
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (67 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 068/869] ublk: fix race between io_uring_cmd_complete_in_task and ublk_cancel_cmd Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 070/869] clk: sunxi-ng: h616: Reparent CPU clock during frequency changes Greg Kroah-Hartman
` (800 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alexander Gordeev, Andrey Ryabinin,
Harry Yoo, Daniel Axtens, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Gordeev <agordeev@linux.ibm.com>
[ Upstream commit b6ea95a34cbd014ab6ade4248107b86b0aaf2d6c ]
apply_to_pte_range() enters the lazy MMU mode and then invokes
kasan_populate_vmalloc_pte() callback on each page table walk iteration.
However, the callback can go into sleep when trying to allocate a single
page, e.g. if an architecutre disables preemption on lazy MMU mode enter.
On s390 if make arch_enter_lazy_mmu_mode() -> preempt_enable() and
arch_leave_lazy_mmu_mode() -> preempt_disable(), such crash occurs:
[ 0.663336] BUG: sleeping function called from invalid context at ./include/linux/sched/mm.h:321
[ 0.663348] in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 2, name: kthreadd
[ 0.663358] preempt_count: 1, expected: 0
[ 0.663366] RCU nest depth: 0, expected: 0
[ 0.663375] no locks held by kthreadd/2.
[ 0.663383] Preemption disabled at:
[ 0.663386] [<0002f3284cbb4eda>] apply_to_pte_range+0xfa/0x4a0
[ 0.663405] CPU: 0 UID: 0 PID: 2 Comm: kthreadd Not tainted 6.15.0-rc5-gcc-kasan-00043-gd76bb1ebb558-dirty #162 PREEMPT
[ 0.663408] Hardware name: IBM 3931 A01 701 (KVM/Linux)
[ 0.663409] Call Trace:
[ 0.663410] [<0002f3284c385f58>] dump_stack_lvl+0xe8/0x140
[ 0.663413] [<0002f3284c507b9e>] __might_resched+0x66e/0x700
[ 0.663415] [<0002f3284cc4f6c0>] __alloc_frozen_pages_noprof+0x370/0x4b0
[ 0.663419] [<0002f3284ccc73c0>] alloc_pages_mpol+0x1a0/0x4a0
[ 0.663421] [<0002f3284ccc8518>] alloc_frozen_pages_noprof+0x88/0xc0
[ 0.663424] [<0002f3284ccc8572>] alloc_pages_noprof+0x22/0x120
[ 0.663427] [<0002f3284cc341ac>] get_free_pages_noprof+0x2c/0xc0
[ 0.663429] [<0002f3284cceba70>] kasan_populate_vmalloc_pte+0x50/0x120
[ 0.663433] [<0002f3284cbb4ef8>] apply_to_pte_range+0x118/0x4a0
[ 0.663435] [<0002f3284cbc7c14>] apply_to_pmd_range+0x194/0x3e0
[ 0.663437] [<0002f3284cbc99be>] __apply_to_page_range+0x2fe/0x7a0
[ 0.663440] [<0002f3284cbc9e88>] apply_to_page_range+0x28/0x40
[ 0.663442] [<0002f3284ccebf12>] kasan_populate_vmalloc+0x82/0xa0
[ 0.663445] [<0002f3284cc1578c>] alloc_vmap_area+0x34c/0xc10
[ 0.663448] [<0002f3284cc1c2a6>] __get_vm_area_node+0x186/0x2a0
[ 0.663451] [<0002f3284cc1e696>] __vmalloc_node_range_noprof+0x116/0x310
[ 0.663454] [<0002f3284cc1d950>] __vmalloc_node_noprof+0xd0/0x110
[ 0.663457] [<0002f3284c454b88>] alloc_thread_stack_node+0xf8/0x330
[ 0.663460] [<0002f3284c458d56>] dup_task_struct+0x66/0x4d0
[ 0.663463] [<0002f3284c45be90>] copy_process+0x280/0x4b90
[ 0.663465] [<0002f3284c460940>] kernel_clone+0xd0/0x4b0
[ 0.663467] [<0002f3284c46115e>] kernel_thread+0xbe/0xe0
[ 0.663469] [<0002f3284c4e440e>] kthreadd+0x50e/0x7f0
[ 0.663472] [<0002f3284c38c04a>] __ret_from_fork+0x8a/0xf0
[ 0.663475] [<0002f3284ed57ff2>] ret_from_fork+0xa/0x38
Instead of allocating single pages per-PTE, bulk-allocate the shadow
memory prior to applying kasan_populate_vmalloc_pte() callback on a page
range.
Link: https://lkml.kernel.org/r/c61d3560297c93ed044f0b1af085610353a06a58.1747316918.git.agordeev@linux.ibm.com
Fixes: 3c5c3cfb9ef4 ("kasan: support backing vmalloc space with real shadow memory")
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
Suggested-by: Andrey Ryabinin <ryabinin.a.a@gmail.com>
Reviewed-by: Harry Yoo <harry.yoo@oracle.com>
Cc: Daniel Axtens <dja@axtens.net>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/kasan/shadow.c | 92 +++++++++++++++++++++++++++++++++++++++--------
1 file changed, 78 insertions(+), 14 deletions(-)
diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c
index b18cfa5e2cb79..1cf08821af9d6 100644
--- a/mm/kasan/shadow.c
+++ b/mm/kasan/shadow.c
@@ -292,33 +292,99 @@ void __init __weak kasan_populate_early_vm_area_shadow(void *start,
{
}
+struct vmalloc_populate_data {
+ unsigned long start;
+ struct page **pages;
+};
+
static int kasan_populate_vmalloc_pte(pte_t *ptep, unsigned long addr,
- void *unused)
+ void *_data)
{
- unsigned long page;
+ struct vmalloc_populate_data *data = _data;
+ struct page *page;
pte_t pte;
+ int index;
if (likely(!pte_none(ptep_get(ptep))))
return 0;
- page = __get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
-
- __memset((void *)page, KASAN_VMALLOC_INVALID, PAGE_SIZE);
- pte = pfn_pte(PFN_DOWN(__pa(page)), PAGE_KERNEL);
+ index = PFN_DOWN(addr - data->start);
+ page = data->pages[index];
+ __memset(page_to_virt(page), KASAN_VMALLOC_INVALID, PAGE_SIZE);
+ pte = pfn_pte(page_to_pfn(page), PAGE_KERNEL);
spin_lock(&init_mm.page_table_lock);
if (likely(pte_none(ptep_get(ptep)))) {
set_pte_at(&init_mm, addr, ptep, pte);
- page = 0;
+ data->pages[index] = NULL;
}
spin_unlock(&init_mm.page_table_lock);
- if (page)
- free_page(page);
+
+ return 0;
+}
+
+static void ___free_pages_bulk(struct page **pages, int nr_pages)
+{
+ int i;
+
+ for (i = 0; i < nr_pages; i++) {
+ if (pages[i]) {
+ __free_pages(pages[i], 0);
+ pages[i] = NULL;
+ }
+ }
+}
+
+static int ___alloc_pages_bulk(struct page **pages, int nr_pages)
+{
+ unsigned long nr_populated, nr_total = nr_pages;
+ struct page **page_array = pages;
+
+ while (nr_pages) {
+ nr_populated = alloc_pages_bulk_array(GFP_KERNEL, nr_pages, pages);
+ if (!nr_populated) {
+ ___free_pages_bulk(page_array, nr_total - nr_pages);
+ return -ENOMEM;
+ }
+ pages += nr_populated;
+ nr_pages -= nr_populated;
+ }
+
return 0;
}
+static int __kasan_populate_vmalloc(unsigned long start, unsigned long end)
+{
+ unsigned long nr_pages, nr_total = PFN_UP(end - start);
+ struct vmalloc_populate_data data;
+ int ret = 0;
+
+ data.pages = (struct page **)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+ if (!data.pages)
+ return -ENOMEM;
+
+ while (nr_total) {
+ nr_pages = min(nr_total, PAGE_SIZE / sizeof(data.pages[0]));
+ ret = ___alloc_pages_bulk(data.pages, nr_pages);
+ if (ret)
+ break;
+
+ data.start = start;
+ ret = apply_to_page_range(&init_mm, start, nr_pages * PAGE_SIZE,
+ kasan_populate_vmalloc_pte, &data);
+ ___free_pages_bulk(data.pages, nr_pages);
+ if (ret)
+ break;
+
+ start += nr_pages * PAGE_SIZE;
+ nr_total -= nr_pages;
+ }
+
+ free_page((unsigned long)data.pages);
+
+ return ret;
+}
+
int kasan_populate_vmalloc(unsigned long addr, unsigned long size)
{
unsigned long shadow_start, shadow_end;
@@ -348,9 +414,7 @@ int kasan_populate_vmalloc(unsigned long addr, unsigned long size)
shadow_start = PAGE_ALIGN_DOWN(shadow_start);
shadow_end = PAGE_ALIGN(shadow_end);
- ret = apply_to_page_range(&init_mm, shadow_start,
- shadow_end - shadow_start,
- kasan_populate_vmalloc_pte, NULL);
+ ret = __kasan_populate_vmalloc(shadow_start, shadow_end);
if (ret)
return ret;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 070/869] clk: sunxi-ng: h616: Reparent CPU clock during frequency changes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (68 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 069/869] kasan: avoid sleepable page allocation from atomic context Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 071/869] clk: sunxi-ng: h616: Reparent GPU " Greg Kroah-Hartman
` (799 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Andre Przywara, Evgeny Boger,
Chen-Yu Tsai, Stephen Boyd, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andre Przywara <andre.przywara@arm.com>
[ Upstream commit 087b4083d3f9d202266debc6b684b0662c96f51b ]
The H616 user manual recommends to re-parent the CPU clock during
frequency changes of the PLL, and recommends PLL_PERI0(1X), which runs
at 600 MHz. Also it asks to disable and then re-enable the PLL lock bit,
after the factor changes have been applied.
Add clock notifiers for the PLL and the CPU mux clock, using the existing
notifier callbacks, and tell them to use mux 4 (the PLL_PERI0(1X) source),
and bit 29 (the LOCK_ENABLE) bit. The existing code already follows the
correct algorithms.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Link: https://lore.kernel.org/r/20241025105620.1891596-1-andre.przywara@arm.com
Tested-by: Evgeny Boger <boger@wirenboard.com>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Stable-dep-of: eb963d7948ce ("clk: sunxi-ng: h616: Reparent GPU clock during frequency changes")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 28 ++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
index 84e406ddf9d12..85eea196f25e3 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
@@ -1095,11 +1095,24 @@ static const u32 usb2_clk_regs[] = {
SUN50I_H616_USB3_CLK_REG,
};
+static struct ccu_mux_nb sun50i_h616_cpu_nb = {
+ .common = &cpux_clk.common,
+ .cm = &cpux_clk.mux,
+ .delay_us = 1, /* manual doesn't really say */
+ .bypass_index = 4, /* PLL_PERI0@600MHz, as recommended by manual */
+};
+
+static struct ccu_pll_nb sun50i_h616_pll_cpu_nb = {
+ .common = &pll_cpux_clk.common,
+ .enable = BIT(29), /* LOCK_ENABLE */
+ .lock = BIT(28),
+};
+
static int sun50i_h616_ccu_probe(struct platform_device *pdev)
{
void __iomem *reg;
u32 val;
- int i;
+ int ret, i;
reg = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(reg))
@@ -1152,7 +1165,18 @@ static int sun50i_h616_ccu_probe(struct platform_device *pdev)
val |= BIT(24);
writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG);
- return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_h616_ccu_desc);
+ ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_h616_ccu_desc);
+ if (ret)
+ return ret;
+
+ /* Reparent CPU during CPU PLL rate changes */
+ ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
+ &sun50i_h616_cpu_nb);
+
+ /* Re-lock the CPU PLL after any rate changes */
+ ccu_pll_notifier_register(&sun50i_h616_pll_cpu_nb);
+
+ return 0;
}
static const struct of_device_id sun50i_h616_ccu_ids[] = {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 071/869] clk: sunxi-ng: h616: Reparent GPU clock during frequency changes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (69 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 070/869] clk: sunxi-ng: h616: Reparent CPU clock during frequency changes Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 072/869] net: ethernet: ti: am65-cpsw: streamline RX queue creation and cleanup Greg Kroah-Hartman
` (798 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Philippe Simons, Andre Przywara,
Jernej Skrabec, Chen-Yu Tsai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Philippe Simons <simons.philippe@gmail.com>
[ Upstream commit eb963d7948ce6571939c6875424b557b25f16610 ]
The H616 manual does not state that the GPU PLL supports
dynamic frequency configuration, so we must take extra care when changing
the frequency. Currently any attempt to do device DVFS on the GPU lead
to panfrost various ooops, and GPU hangs.
The manual describes the algorithm for changing the PLL
frequency, which the CPU PLL notifier code already support, so we reuse
that to reparent the GPU clock to GPU1 clock during frequency
changes.
Signed-off-by: Philippe Simons <simons.philippe@gmail.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Link: https://patch.msgid.link/20250220113808.1122414-2-simons.philippe@gmail.com
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 36 +++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
index 85eea196f25e3..d4e3838ed90ba 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c
@@ -318,10 +318,16 @@ static SUNXI_CCU_M_WITH_MUX_GATE(gpu0_clk, "gpu0", gpu0_parents, 0x670,
24, 1, /* mux */
BIT(31), /* gate */
CLK_SET_RATE_PARENT);
+
+/*
+ * This clk is needed as a temporary fall back during GPU PLL freq changes.
+ * Set CLK_IS_CRITICAL flag to prevent from being disabled.
+ */
+#define SUN50I_H616_GPU_CLK1_REG 0x674
static SUNXI_CCU_M_WITH_GATE(gpu1_clk, "gpu1", "pll-periph0-2x", 0x674,
0, 2, /* M */
BIT(31),/* gate */
- 0);
+ CLK_IS_CRITICAL);
static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2",
0x67c, BIT(0), 0);
@@ -1108,6 +1114,19 @@ static struct ccu_pll_nb sun50i_h616_pll_cpu_nb = {
.lock = BIT(28),
};
+static struct ccu_mux_nb sun50i_h616_gpu_nb = {
+ .common = &gpu0_clk.common,
+ .cm = &gpu0_clk.mux,
+ .delay_us = 1, /* manual doesn't really say */
+ .bypass_index = 1, /* GPU_CLK1@400MHz */
+};
+
+static struct ccu_pll_nb sun50i_h616_pll_gpu_nb = {
+ .common = &pll_gpu_clk.common,
+ .enable = BIT(29), /* LOCK_ENABLE */
+ .lock = BIT(28),
+};
+
static int sun50i_h616_ccu_probe(struct platform_device *pdev)
{
void __iomem *reg;
@@ -1156,6 +1175,14 @@ static int sun50i_h616_ccu_probe(struct platform_device *pdev)
val &= ~(GENMASK(21, 16) | BIT(0));
writel(val | (11 << 16) | BIT(0), reg + SUN50I_H616_PLL_AUDIO_REG);
+ /*
+ * Set the input-divider for the gpu1 clock to 3, to reach a safe 400 MHz.
+ */
+ val = readl(reg + SUN50I_H616_GPU_CLK1_REG);
+ val &= ~GENMASK(1, 0);
+ val |= 2;
+ writel(val, reg + SUN50I_H616_GPU_CLK1_REG);
+
/*
* First clock parent (osc32K) is unusable for CEC. But since there
* is no good way to force parent switch (both run with same frequency),
@@ -1176,6 +1203,13 @@ static int sun50i_h616_ccu_probe(struct platform_device *pdev)
/* Re-lock the CPU PLL after any rate changes */
ccu_pll_notifier_register(&sun50i_h616_pll_cpu_nb);
+ /* Reparent GPU during GPU PLL rate changes */
+ ccu_mux_notifier_register(pll_gpu_clk.common.hw.clk,
+ &sun50i_h616_gpu_nb);
+
+ /* Re-lock the GPU PLL after any rate changes */
+ ccu_pll_notifier_register(&sun50i_h616_pll_gpu_nb);
+
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 072/869] net: ethernet: ti: am65-cpsw: streamline RX queue creation and cleanup
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (70 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 071/869] clk: sunxi-ng: h616: Reparent GPU " Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 073/869] dmaengine: ti: k3-udma-glue: Drop skip_fdq argument from k3_udma_glue_reset_rx_chn Greg Kroah-Hartman
` (797 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Roger Quadros, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Roger Quadros <rogerq@kernel.org>
[ Upstream commit 66c1ae68a1e9bde7376a50229b0b33145fcb0a71 ]
Introduce am65_cpsw_create_rxqs() and am65_cpsw_destroy_rxqs()
and use them.
Signed-off-by: Roger Quadros <rogerq@kernel.org>
Link: https://patch.msgid.link/20250117-am65-cpsw-streamline-v2-2-91a29c97e569@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 0da30874729b ("dmaengine: ti: k3-udma-glue: Drop skip_fdq argument from k3_udma_glue_reset_rx_chn")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/ti/am65-cpsw-nuss.c | 243 +++++++++++------------
1 file changed, 119 insertions(+), 124 deletions(-)
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index 45cea845d4aaa..8b47ff7a8b15b 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -398,35 +398,61 @@ static void am65_cpsw_init_host_port_switch(struct am65_cpsw_common *common);
static void am65_cpsw_init_host_port_emac(struct am65_cpsw_common *common);
static void am65_cpsw_init_port_switch_ale(struct am65_cpsw_port *port);
static void am65_cpsw_init_port_emac_ale(struct am65_cpsw_port *port);
+static inline void am65_cpsw_put_page(struct am65_cpsw_rx_flow *flow,
+ struct page *page,
+ bool allow_direct);
+static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma);
-static void am65_cpsw_destroy_xdp_rxqs(struct am65_cpsw_common *common)
+static void am65_cpsw_destroy_rxq(struct am65_cpsw_common *common, int id)
{
struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns;
struct am65_cpsw_rx_flow *flow;
struct xdp_rxq_info *rxq;
- int id, port;
+ int port;
- for (id = 0; id < common->rx_ch_num_flows; id++) {
- flow = &rx_chn->flows[id];
+ flow = &rx_chn->flows[id];
+ napi_disable(&flow->napi_rx);
+ hrtimer_cancel(&flow->rx_hrtimer);
+ k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, id, rx_chn,
+ am65_cpsw_nuss_rx_cleanup, !!id);
- for (port = 0; port < common->port_num; port++) {
- if (!common->ports[port].ndev)
- continue;
+ for (port = 0; port < common->port_num; port++) {
+ if (!common->ports[port].ndev)
+ continue;
- rxq = &common->ports[port].xdp_rxq[id];
+ rxq = &common->ports[port].xdp_rxq[id];
- if (xdp_rxq_info_is_reg(rxq))
- xdp_rxq_info_unreg(rxq);
- }
+ if (xdp_rxq_info_is_reg(rxq))
+ xdp_rxq_info_unreg(rxq);
+ }
- if (flow->page_pool) {
- page_pool_destroy(flow->page_pool);
- flow->page_pool = NULL;
- }
+ if (flow->page_pool) {
+ page_pool_destroy(flow->page_pool);
+ flow->page_pool = NULL;
}
}
-static int am65_cpsw_create_xdp_rxqs(struct am65_cpsw_common *common)
+static void am65_cpsw_destroy_rxqs(struct am65_cpsw_common *common)
+{
+ struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns;
+ int id;
+
+ reinit_completion(&common->tdown_complete);
+ k3_udma_glue_tdown_rx_chn(rx_chn->rx_chn, true);
+
+ if (common->pdata.quirks & AM64_CPSW_QUIRK_DMA_RX_TDOWN_IRQ) {
+ id = wait_for_completion_timeout(&common->tdown_complete, msecs_to_jiffies(1000));
+ if (!id)
+ dev_err(common->dev, "rx teardown timeout\n");
+ }
+
+ for (id = common->rx_ch_num_flows - 1; id >= 0; id--)
+ am65_cpsw_destroy_rxq(common, id);
+
+ k3_udma_glue_disable_rx_chn(common->rx_chns.rx_chn);
+}
+
+static int am65_cpsw_create_rxq(struct am65_cpsw_common *common, int id)
{
struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns;
struct page_pool_params pp_params = {
@@ -441,45 +467,92 @@ static int am65_cpsw_create_xdp_rxqs(struct am65_cpsw_common *common)
struct am65_cpsw_rx_flow *flow;
struct xdp_rxq_info *rxq;
struct page_pool *pool;
- int id, port, ret;
+ struct page *page;
+ int port, ret, i;
- for (id = 0; id < common->rx_ch_num_flows; id++) {
- flow = &rx_chn->flows[id];
- pp_params.napi = &flow->napi_rx;
- pool = page_pool_create(&pp_params);
- if (IS_ERR(pool)) {
- ret = PTR_ERR(pool);
+ flow = &rx_chn->flows[id];
+ pp_params.napi = &flow->napi_rx;
+ pool = page_pool_create(&pp_params);
+ if (IS_ERR(pool)) {
+ ret = PTR_ERR(pool);
+ return ret;
+ }
+
+ flow->page_pool = pool;
+
+ /* using same page pool is allowed as no running rx handlers
+ * simultaneously for both ndevs
+ */
+ for (port = 0; port < common->port_num; port++) {
+ if (!common->ports[port].ndev)
+ /* FIXME should we BUG here? */
+ continue;
+
+ rxq = &common->ports[port].xdp_rxq[id];
+ ret = xdp_rxq_info_reg(rxq, common->ports[port].ndev,
+ id, flow->napi_rx.napi_id);
+ if (ret)
+ goto err;
+
+ ret = xdp_rxq_info_reg_mem_model(rxq,
+ MEM_TYPE_PAGE_POOL,
+ pool);
+ if (ret)
+ goto err;
+ }
+
+ for (i = 0; i < AM65_CPSW_MAX_RX_DESC; i++) {
+ page = page_pool_dev_alloc_pages(flow->page_pool);
+ if (!page) {
+ dev_err(common->dev, "cannot allocate page in flow %d\n",
+ id);
+ ret = -ENOMEM;
goto err;
}
- flow->page_pool = pool;
+ ret = am65_cpsw_nuss_rx_push(common, page, id);
+ if (ret < 0) {
+ dev_err(common->dev,
+ "cannot submit page to rx channel flow %d, error %d\n",
+ id, ret);
+ am65_cpsw_put_page(flow, page, false);
+ goto err;
+ }
+ }
- /* using same page pool is allowed as no running rx handlers
- * simultaneously for both ndevs
- */
- for (port = 0; port < common->port_num; port++) {
- if (!common->ports[port].ndev)
- continue;
+ napi_enable(&flow->napi_rx);
+ return 0;
- rxq = &common->ports[port].xdp_rxq[id];
+err:
+ am65_cpsw_destroy_rxq(common, id);
+ return ret;
+}
- ret = xdp_rxq_info_reg(rxq, common->ports[port].ndev,
- id, flow->napi_rx.napi_id);
- if (ret)
- goto err;
+static int am65_cpsw_create_rxqs(struct am65_cpsw_common *common)
+{
+ int id, ret;
- ret = xdp_rxq_info_reg_mem_model(rxq,
- MEM_TYPE_PAGE_POOL,
- pool);
- if (ret)
- goto err;
+ for (id = 0; id < common->rx_ch_num_flows; id++) {
+ ret = am65_cpsw_create_rxq(common, id);
+ if (ret) {
+ dev_err(common->dev, "couldn't create rxq %d: %d\n",
+ id, ret);
+ goto err;
}
}
+ ret = k3_udma_glue_enable_rx_chn(common->rx_chns.rx_chn);
+ if (ret) {
+ dev_err(common->dev, "couldn't enable rx chn: %d\n", ret);
+ goto err;
+ }
+
return 0;
err:
- am65_cpsw_destroy_xdp_rxqs(common);
+ for (--id; id >= 0; id--)
+ am65_cpsw_destroy_rxq(common, id);
+
return ret;
}
@@ -543,7 +616,6 @@ static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma)
k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);
dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE);
k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
-
am65_cpsw_put_page(&rx_chn->flows[flow_id], page, false);
}
@@ -625,12 +697,9 @@ static struct sk_buff *am65_cpsw_build_skb(void *page_addr,
static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common)
{
struct am65_cpsw_host *host_p = am65_common_get_host(common);
- struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns;
struct am65_cpsw_tx_chn *tx_chn = common->tx_chns;
- int port_idx, i, ret, tx, flow_idx;
- struct am65_cpsw_rx_flow *flow;
+ int port_idx, ret, tx;
u32 val, port_mask;
- struct page *page;
if (common->usage_count)
return 0;
@@ -690,47 +759,9 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common)
am65_cpsw_qos_tx_p0_rate_init(common);
- ret = am65_cpsw_create_xdp_rxqs(common);
- if (ret) {
- dev_err(common->dev, "Failed to create XDP rx queues\n");
+ ret = am65_cpsw_create_rxqs(common);
+ if (ret)
return ret;
- }
-
- for (flow_idx = 0; flow_idx < common->rx_ch_num_flows; flow_idx++) {
- flow = &rx_chn->flows[flow_idx];
- for (i = 0; i < AM65_CPSW_MAX_RX_DESC; i++) {
- page = page_pool_dev_alloc_pages(flow->page_pool);
- if (!page) {
- dev_err(common->dev, "cannot allocate page in flow %d\n",
- flow_idx);
- ret = -ENOMEM;
- goto fail_rx;
- }
-
- ret = am65_cpsw_nuss_rx_push(common, page, flow_idx);
- if (ret < 0) {
- dev_err(common->dev,
- "cannot submit page to rx channel flow %d, error %d\n",
- flow_idx, ret);
- am65_cpsw_put_page(flow, page, false);
- goto fail_rx;
- }
- }
- }
-
- ret = k3_udma_glue_enable_rx_chn(rx_chn->rx_chn);
- if (ret) {
- dev_err(common->dev, "couldn't enable rx chn: %d\n", ret);
- goto fail_rx;
- }
-
- for (i = 0; i < common->rx_ch_num_flows ; i++) {
- napi_enable(&rx_chn->flows[i].napi_rx);
- if (rx_chn->flows[i].irq_disabled) {
- rx_chn->flows[i].irq_disabled = false;
- enable_irq(rx_chn->flows[i].irq);
- }
- }
for (tx = 0; tx < common->tx_ch_num; tx++) {
ret = k3_udma_glue_enable_tx_chn(tx_chn[tx].tx_chn);
@@ -753,30 +784,13 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common)
tx--;
}
- for (flow_idx = 0; i < common->rx_ch_num_flows; flow_idx++) {
- flow = &rx_chn->flows[flow_idx];
- if (!flow->irq_disabled) {
- disable_irq(flow->irq);
- flow->irq_disabled = true;
- }
- napi_disable(&flow->napi_rx);
- }
-
- k3_udma_glue_disable_rx_chn(rx_chn->rx_chn);
-
-fail_rx:
- for (i = 0; i < common->rx_ch_num_flows; i++)
- k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, i, rx_chn,
- am65_cpsw_nuss_rx_cleanup, !!i);
-
- am65_cpsw_destroy_xdp_rxqs(common);
+ am65_cpsw_destroy_rxqs(common);
return ret;
}
static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
{
- struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns;
struct am65_cpsw_tx_chn *tx_chn = common->tx_chns;
int i;
@@ -810,31 +824,12 @@ static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
k3_udma_glue_disable_tx_chn(tx_chn[i].tx_chn);
}
- reinit_completion(&common->tdown_complete);
- k3_udma_glue_tdown_rx_chn(rx_chn->rx_chn, true);
-
- if (common->pdata.quirks & AM64_CPSW_QUIRK_DMA_RX_TDOWN_IRQ) {
- i = wait_for_completion_timeout(&common->tdown_complete, msecs_to_jiffies(1000));
- if (!i)
- dev_err(common->dev, "rx teardown timeout\n");
- }
-
- for (i = common->rx_ch_num_flows - 1; i >= 0; i--) {
- napi_disable(&rx_chn->flows[i].napi_rx);
- hrtimer_cancel(&rx_chn->flows[i].rx_hrtimer);
- k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, i, rx_chn,
- am65_cpsw_nuss_rx_cleanup, !!i);
- }
-
- k3_udma_glue_disable_rx_chn(rx_chn->rx_chn);
-
+ am65_cpsw_destroy_rxqs(common);
cpsw_ale_stop(common->ale);
writel(0, common->cpsw_base + AM65_CPSW_REG_CTL);
writel(0, common->cpsw_base + AM65_CPSW_REG_STAT_PORT_EN);
- am65_cpsw_destroy_xdp_rxqs(common);
-
dev_dbg(common->dev, "cpsw_nuss stopped\n");
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 073/869] dmaengine: ti: k3-udma-glue: Drop skip_fdq argument from k3_udma_glue_reset_rx_chn
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (71 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 072/869] net: ethernet: ti: am65-cpsw: streamline RX queue creation and cleanup Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 074/869] virtio: break and reset virtio devices on device_shutdown() Greg Kroah-Hartman
` (796 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Roger Quadros, Jakub Kicinski,
Peter Ujfalusi, Vinod Koul, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Roger Quadros <rogerq@kernel.org>
[ Upstream commit 0da30874729baeb01889b0eca16cfda122687503 ]
The user of k3_udma_glue_reset_rx_chn() e.g. ti_am65_cpsw_nuss can
run on multiple platforms having different DMA architectures.
On some platforms there can be one FDQ for all flows in the RX channel
while for others there is a separate FDQ for each flow in the RX channel.
So far we have been relying on the skip_fdq argument of
k3_udma_glue_reset_rx_chn().
Instead of relying on the user to provide this information, infer it
based on DMA architecture during k3_udma_glue_request_rx_chn() and save it
in an internal flag 'single_fdq'. Use that flag at
k3_udma_glue_reset_rx_chn() to deicide if the FDQ needs
to be cleared for every flow or just for flow 0.
Fixes the below issue on ti_am65_cpsw_nuss driver on AM62-SK.
> ip link set eth1 down
> ip link set eth0 down
> ethtool -L eth0 rx 8
> ip link set eth0 up
> modprobe -r ti_am65_cpsw_nuss
[ 103.045726] ------------[ cut here ]------------
[ 103.050505] k3_knav_desc_pool size 512000 != avail 64000
[ 103.050703] WARNING: CPU: 1 PID: 450 at drivers/net/ethernet/ti/k3-cppi-desc-pool.c:33 k3_cppi_desc_pool_destroy+0xa0/0xa8 [k3_cppi_desc_pool]
[ 103.068810] Modules linked in: ti_am65_cpsw_nuss(-) k3_cppi_desc_pool snd_soc_hdmi_codec crct10dif_ce snd_soc_simple_card snd_soc_simple_card_utils display_connector rtc_ti_k3 k3_j72xx_bandgap tidss drm_client_lib snd_soc_davinci_mcas
p drm_dma_helper tps6598x phylink snd_soc_ti_udma rti_wdt drm_display_helper snd_soc_tlv320aic3x_i2c typec at24 phy_gmii_sel snd_soc_ti_edma snd_soc_tlv320aic3x sii902x snd_soc_ti_sdma sa2ul omap_mailbox drm_kms_helper authenc cfg80211 r
fkill fuse drm drm_panel_orientation_quirks backlight ip_tables x_tables ipv6 [last unloaded: k3_cppi_desc_pool]
[ 103.119950] CPU: 1 UID: 0 PID: 450 Comm: modprobe Not tainted 6.13.0-rc7-00001-g9c5e3435fa66 #1011
[ 103.119968] Hardware name: Texas Instruments AM625 SK (DT)
[ 103.119974] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 103.119983] pc : k3_cppi_desc_pool_destroy+0xa0/0xa8 [k3_cppi_desc_pool]
[ 103.148007] lr : k3_cppi_desc_pool_destroy+0xa0/0xa8 [k3_cppi_desc_pool]
[ 103.154709] sp : ffff8000826ebbc0
[ 103.158015] x29: ffff8000826ebbc0 x28: ffff0000090b6300 x27: 0000000000000000
[ 103.165145] x26: 0000000000000000 x25: 0000000000000000 x24: ffff0000019df6b0
[ 103.172271] x23: ffff0000019df6b8 x22: ffff0000019df410 x21: ffff8000826ebc88
[ 103.179397] x20: 000000000007d000 x19: ffff00000a3b3000 x18: 0000000000000000
[ 103.186522] x17: 0000000000000000 x16: 0000000000000000 x15: 000001e8c35e1cde
[ 103.193647] x14: 0000000000000396 x13: 000000000000035c x12: 0000000000000000
[ 103.200772] x11: 000000000000003a x10: 00000000000009c0 x9 : ffff8000826eba20
[ 103.207897] x8 : ffff0000090b6d20 x7 : ffff00007728c180 x6 : ffff00007728c100
[ 103.215022] x5 : 0000000000000001 x4 : ffff000000508a50 x3 : ffff7ffff6146000
[ 103.222147] x2 : 0000000000000000 x1 : e300b4173ee6b200 x0 : 0000000000000000
[ 103.229274] Call trace:
[ 103.231714] k3_cppi_desc_pool_destroy+0xa0/0xa8 [k3_cppi_desc_pool] (P)
[ 103.238408] am65_cpsw_nuss_free_rx_chns+0x28/0x4c [ti_am65_cpsw_nuss]
[ 103.244942] devm_action_release+0x14/0x20
[ 103.249040] release_nodes+0x3c/0x68
[ 103.252610] devres_release_all+0x8c/0xdc
[ 103.256614] device_unbind_cleanup+0x18/0x60
[ 103.260876] device_release_driver_internal+0xf8/0x178
[ 103.266004] driver_detach+0x50/0x9c
[ 103.269571] bus_remove_driver+0x6c/0xbc
[ 103.273485] driver_unregister+0x30/0x60
[ 103.277401] platform_driver_unregister+0x14/0x20
[ 103.282096] am65_cpsw_nuss_driver_exit+0x18/0xff4 [ti_am65_cpsw_nuss]
[ 103.288620] __arm64_sys_delete_module+0x17c/0x25c
[ 103.293404] invoke_syscall+0x44/0x100
[ 103.297149] el0_svc_common.constprop.0+0xc0/0xe0
[ 103.301845] do_el0_svc+0x1c/0x28
[ 103.305155] el0_svc+0x28/0x98
[ 103.308207] el0t_64_sync_handler+0xc8/0xcc
[ 103.312384] el0t_64_sync+0x198/0x19c
[ 103.316040] ---[ end trace 0000000000000000 ]---
Signed-off-by: Roger Quadros <rogerq@kernel.org>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Acked-by: Peter Ujfalusi <peter.ujfalusi@gmail.com>
Link: https://lore.kernel.org/r/20250224-k3-udma-glue-single-fdq-v2-1-cbe7621f2507@kernel.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/dma/ti/k3-udma-glue.c | 15 +++++++++++----
drivers/net/ethernet/ti/am65-cpsw-nuss.c | 4 ++--
drivers/net/ethernet/ti/icssg/icssg_common.c | 2 +-
include/linux/dma/k3-udma-glue.h | 3 +--
4 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/dma/ti/k3-udma-glue.c b/drivers/dma/ti/k3-udma-glue.c
index bf177879cc28a..d651983fe3816 100644
--- a/drivers/dma/ti/k3-udma-glue.c
+++ b/drivers/dma/ti/k3-udma-glue.c
@@ -84,6 +84,7 @@ struct k3_udma_glue_rx_channel {
struct k3_udma_glue_rx_flow *flows;
u32 flow_num;
u32 flows_ready;
+ bool single_fdq; /* one FDQ for all flows */
};
static void k3_udma_chan_dev_release(struct device *dev)
@@ -970,10 +971,13 @@ k3_udma_glue_request_rx_chn_priv(struct device *dev, const char *name,
ep_cfg = rx_chn->common.ep_config;
- if (xudma_is_pktdma(rx_chn->common.udmax))
+ if (xudma_is_pktdma(rx_chn->common.udmax)) {
rx_chn->udma_rchan_id = ep_cfg->mapped_channel_id;
- else
+ rx_chn->single_fdq = false;
+ } else {
rx_chn->udma_rchan_id = -1;
+ rx_chn->single_fdq = true;
+ }
/* request and cfg UDMAP RX channel */
rx_chn->udma_rchanx = xudma_rchan_get(rx_chn->common.udmax,
@@ -1103,6 +1107,9 @@ k3_udma_glue_request_remote_rx_chn_common(struct k3_udma_glue_rx_channel *rx_chn
rx_chn->common.chan_dev.dma_coherent = true;
dma_coerce_mask_and_coherent(&rx_chn->common.chan_dev,
DMA_BIT_MASK(48));
+ rx_chn->single_fdq = false;
+ } else {
+ rx_chn->single_fdq = true;
}
ret = k3_udma_glue_allocate_rx_flows(rx_chn, cfg);
@@ -1454,7 +1461,7 @@ EXPORT_SYMBOL_GPL(k3_udma_glue_tdown_rx_chn);
void k3_udma_glue_reset_rx_chn(struct k3_udma_glue_rx_channel *rx_chn,
u32 flow_num, void *data,
- void (*cleanup)(void *data, dma_addr_t desc_dma), bool skip_fdq)
+ void (*cleanup)(void *data, dma_addr_t desc_dma))
{
struct k3_udma_glue_rx_flow *flow = &rx_chn->flows[flow_num];
struct device *dev = rx_chn->common.dev;
@@ -1466,7 +1473,7 @@ void k3_udma_glue_reset_rx_chn(struct k3_udma_glue_rx_channel *rx_chn,
dev_dbg(dev, "RX reset flow %u occ_rx %u\n", flow_num, occ_rx);
/* Skip RX FDQ in case one FDQ is used for the set of flows */
- if (skip_fdq)
+ if (rx_chn->single_fdq && flow_num)
goto do_reset;
/*
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index 8b47ff7a8b15b..e9d9d69e2ba9d 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -414,7 +414,7 @@ static void am65_cpsw_destroy_rxq(struct am65_cpsw_common *common, int id)
napi_disable(&flow->napi_rx);
hrtimer_cancel(&flow->rx_hrtimer);
k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, id, rx_chn,
- am65_cpsw_nuss_rx_cleanup, !!id);
+ am65_cpsw_nuss_rx_cleanup);
for (port = 0; port < common->port_num; port++) {
if (!common->ports[port].ndev)
@@ -3370,7 +3370,7 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
for (i = 0; i < common->rx_ch_num_flows; i++)
k3_udma_glue_reset_rx_chn(rx_chan->rx_chn, i,
rx_chan,
- am65_cpsw_nuss_rx_cleanup, !!i);
+ am65_cpsw_nuss_rx_cleanup);
k3_udma_glue_disable_rx_chn(rx_chan->rx_chn);
diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c
index 74f0f200a89d4..62065416e8861 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
@@ -955,7 +955,7 @@ void prueth_reset_rx_chan(struct prueth_rx_chn *chn,
for (i = 0; i < num_flows; i++)
k3_udma_glue_reset_rx_chn(chn->rx_chn, i, chn,
- prueth_rx_cleanup, !!i);
+ prueth_rx_cleanup);
if (disable)
k3_udma_glue_disable_rx_chn(chn->rx_chn);
}
diff --git a/include/linux/dma/k3-udma-glue.h b/include/linux/dma/k3-udma-glue.h
index 2dea217629d0a..5d43881e6fb77 100644
--- a/include/linux/dma/k3-udma-glue.h
+++ b/include/linux/dma/k3-udma-glue.h
@@ -138,8 +138,7 @@ int k3_udma_glue_rx_get_irq(struct k3_udma_glue_rx_channel *rx_chn,
u32 flow_num);
void k3_udma_glue_reset_rx_chn(struct k3_udma_glue_rx_channel *rx_chn,
u32 flow_num, void *data,
- void (*cleanup)(void *data, dma_addr_t desc_dma),
- bool skip_fdq);
+ void (*cleanup)(void *data, dma_addr_t desc_dma));
int k3_udma_glue_rx_flow_enable(struct k3_udma_glue_rx_channel *rx_chn,
u32 flow_idx);
int k3_udma_glue_rx_flow_disable(struct k3_udma_glue_rx_channel *rx_chn,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 074/869] virtio: break and reset virtio devices on device_shutdown()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (72 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 073/869] dmaengine: ti: k3-udma-glue: Drop skip_fdq argument from k3_udma_glue_reset_rx_chn Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 075/869] coresight: holding cscfg_csdev_lock while removing cscfg from csdev Greg Kroah-Hartman
` (795 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Auger, Hongyu Ning, Eric Auger,
Jason Wang, Michael S. Tsirkin, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael S. Tsirkin <mst@redhat.com>
[ Upstream commit 8bd2fa086a04886798b505f28db4002525895203 ]
Hongyu reported a hang on kexec in a VM. QEMU reported invalid memory
accesses during the hang.
Invalid read at addr 0x102877002, size 2, region '(null)', reason: rejected
Invalid write at addr 0x102877A44, size 2, region '(null)', reason: rejected
...
It was traced down to virtio-console. Kexec works fine if virtio-console
is not in use.
The issue is that virtio-console continues to write to the MMIO even after
underlying virtio-pci device is reset.
Additionally, Eric noticed that IOMMUs are reset before devices, if
devices are not reset on shutdown they continue to poke at guest memory
and get errors from the IOMMU. Some devices get wedged then.
The problem can be solved by breaking all virtio devices on virtio
bus shutdown, then resetting them.
Reported-by: Eric Auger <eauger@redhat.com>
Reported-by: Hongyu Ning <hongyu.ning@linux.intel.com>
Message-ID: <c1dbc7dbad9b445245d3348f19e6742b0be07347.1740094946.git.mst@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/virtio/virtio.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index 1b193d08a6ba8..148ce610ccb83 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -377,6 +377,34 @@ static void virtio_dev_remove(struct device *_d)
of_node_put(dev->dev.of_node);
}
+static void virtio_dev_shutdown(struct device *_d)
+{
+ struct virtio_device *dev = dev_to_virtio(_d);
+ struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
+
+ /*
+ * Stop accesses to or from the device.
+ * We only need to do it if there's a driver - no accesses otherwise.
+ */
+ if (!drv)
+ return;
+
+ /*
+ * Some devices get wedged if you kick them after they are
+ * reset. Mark all vqs as broken to make sure we don't.
+ */
+ virtio_break_device(dev);
+ /*
+ * Guarantee that any callback will see vq->broken as true.
+ */
+ virtio_synchronize_cbs(dev);
+ /*
+ * As IOMMUs are reset on shutdown, this will block device access to memory.
+ * Some devices get wedged if this happens, so reset to make sure it does not.
+ */
+ dev->config->reset(dev);
+}
+
static const struct bus_type virtio_bus = {
.name = "virtio",
.match = virtio_dev_match,
@@ -384,6 +412,7 @@ static const struct bus_type virtio_bus = {
.uevent = virtio_uevent,
.probe = virtio_dev_probe,
.remove = virtio_dev_remove,
+ .shutdown = virtio_dev_shutdown,
};
int __register_virtio_driver(struct virtio_driver *driver, struct module *owner)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 075/869] coresight: holding cscfg_csdev_lock while removing cscfg from csdev
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (73 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 074/869] virtio: break and reset virtio devices on device_shutdown() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 076/869] PCI/pwrctl: Use of_platform_device_create() to create pwrctl devices Greg Kroah-Hartman
` (794 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yeoreum Yun, Leo Yan,
Suzuki K Poulose, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yeoreum Yun <yeoreum.yun@arm.com>
[ Upstream commit 53b9e2659719b04f5ba7593f2af0f2335f75e94a ]
There'll be possible race scenario for coresight config:
CPU0 CPU1
(perf enable) load module
cscfg_load_config_sets()
activate config. // sysfs
(sys_active_cnt == 1)
...
cscfg_csdev_enable_active_config()
lock(csdev->cscfg_csdev_lock)
deactivate config // sysfs
(sys_activec_cnt == 0)
cscfg_unload_config_sets()
<iterating config_csdev_list> cscfg_remove_owned_csdev_configs()
// here load config activate by CPU1
unlock(csdev->cscfg_csdev_lock)
iterating config_csdev_list could be raced with config_csdev_list's
entry delete.
To resolve this race , hold csdev->cscfg_csdev_lock() while
cscfg_remove_owned_csdev_configs()
Fixes: 02bd588e12df ("coresight: configuration: Update API to permit dynamic load/unload")
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20250514161951.3427590-3-yeoreum.yun@arm.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hwtracing/coresight/coresight-syscfg.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
index 30a561d874819..55f36ed1af13c 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg.c
+++ b/drivers/hwtracing/coresight/coresight-syscfg.c
@@ -395,6 +395,8 @@ static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, voi
if (list_empty(&csdev->config_csdev_list))
return;
+ guard(spinlock_irqsave)(&csdev->cscfg_csdev_lock);
+
list_for_each_entry_safe(config_csdev, tmp, &csdev->config_csdev_list, node) {
if (config_csdev->config_desc->load_owner == load_owner)
list_del(&config_csdev->node);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 076/869] PCI/pwrctl: Use of_platform_device_create() to create pwrctl devices
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (74 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 075/869] coresight: holding cscfg_csdev_lock while removing cscfg from csdev Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 077/869] PCI/pwrctl: Create pwrctl device only if at least one power supply is present Greg Kroah-Hartman
` (793 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bartosz Golaszewski,
Krishna chaitanya chundru, Manivannan Sadhasivam, Bjorn Helgaas,
Krzysztof Wilczyński, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
[ Upstream commit 7582fe07f4ca4c560eb47800b640997f06a8baa2 ]
The of_platform_populate() API creates platform devices by descending
through the children of the parent node. But it provides no control over
the child nodes, which makes it difficult to add checks for the child
nodes in the future.
Use of_platform_device_create() and for_each_child_of_node_scoped() to make
it possible to add checks for each node before creating the platform
device.
Link: https://lore.kernel.org/r/20241025-pci-pwrctl-rework-v2-1-568756156cbe@linaro.org
Tested-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Tested-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Stable-dep-of: 8b926f237743 ("PCI/pwrctrl: Cancel outstanding rescan work when unregistering")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pci/bus.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index bdb3e10f947a1..aa11262857166 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -13,6 +13,7 @@
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
@@ -329,6 +330,7 @@ void __weak pcibios_bus_add_device(struct pci_dev *pdev) { }
void pci_bus_add_device(struct pci_dev *dev)
{
struct device_node *dn = dev->dev.of_node;
+ struct platform_device *pdev;
int retval;
/*
@@ -354,11 +356,11 @@ void pci_bus_add_device(struct pci_dev *dev)
pci_dev_assign_added(dev, true);
if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) {
- retval = of_platform_populate(dev_of_node(&dev->dev), NULL, NULL,
- &dev->dev);
- if (retval)
- pci_err(dev, "failed to populate child OF nodes (%d)\n",
- retval);
+ for_each_available_child_of_node_scoped(dn, child) {
+ pdev = of_platform_device_create(child, NULL, &dev->dev);
+ if (!pdev)
+ pci_err(dev, "failed to create OF node: %s\n", child->name);
+ }
}
}
EXPORT_SYMBOL_GPL(pci_bus_add_device);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 077/869] PCI/pwrctl: Create pwrctl device only if at least one power supply is present
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (75 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 076/869] PCI/pwrctl: Use of_platform_device_create() to create pwrctl devices Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 078/869] PCI/pwrctrl: Cancel outstanding rescan work when unregistering Greg Kroah-Hartman
` (792 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dmitry Baryshkov,
Bartosz Golaszewski, Krishna chaitanya chundru,
Manivannan Sadhasivam, Bjorn Helgaas, Krzysztof Wilczyński,
Sasha Levin, stable+noautosel
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
[ Upstream commit 278dd091e95d428eea0a2c3c517d895b052de5ff ]
Currently, pwrctl devices are created if the corresponding PCI nodes are
defined in devicetree. But this is not correct, because not all PCI nodes
require pwrctl support. Pwrctl comes into the picture only when the device
requires kernel to manage its power state. This can be determined using the
power supply properties present in the devicetree node of the device.
Add of_pci_supply_present() to check whether the devicetree contains at
least one power supply property for a device. If one is present, create a
pwrctl device for that PCI node.
Suggested-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Fixes: 8fb18619d910 ("PCI/pwrctl: Create platform devices for child OF nodes of the port node")
Link: https://lore.kernel.org/r/20241025-pci-pwrctl-rework-v2-2-568756156cbe@linaro.org
Tested-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Tested-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
[bhelgaas: rename of_pci_is_supply_present() to of_pci_supply_present() for
readability]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Cc: stable+noautosel@kernel.org # Depends on of_platform_device_create() rework
Stable-dep-of: 8b926f237743 ("PCI/pwrctrl: Cancel outstanding rescan work when unregistering")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pci/bus.c | 11 +++++++++++
drivers/pci/of.c | 27 +++++++++++++++++++++++++++
drivers/pci/pci.h | 5 +++++
3 files changed, 43 insertions(+)
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index aa11262857166..b7f4510c284c0 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -357,6 +357,17 @@ void pci_bus_add_device(struct pci_dev *dev)
if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) {
for_each_available_child_of_node_scoped(dn, child) {
+ /*
+ * First check whether the pwrctl device needs to be
+ * created or not. This is decided based on at least
+ * one of the power supplies being defined in the
+ * devicetree node of the device.
+ */
+ if (!of_pci_supply_present(child)) {
+ pci_dbg(dev, "skipping OF node: %s\n", child->name);
+ continue;
+ }
+
pdev = of_platform_device_create(child, NULL, &dev->dev);
if (!pdev)
pci_err(dev, "failed to create OF node: %s\n", child->name);
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index dacea3fc5128f..52f770bcc4819 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -728,6 +728,33 @@ void of_pci_make_dev_node(struct pci_dev *pdev)
}
#endif
+/**
+ * of_pci_supply_present() - Check if the power supply is present for the PCI
+ * device
+ * @np: Device tree node
+ *
+ * Check if the power supply for the PCI device is present in the device tree
+ * node or not.
+ *
+ * Return: true if at least one power supply exists; false otherwise.
+ */
+bool of_pci_supply_present(struct device_node *np)
+{
+ struct property *prop;
+ char *supply;
+
+ if (!np)
+ return false;
+
+ for_each_property_of_node(np, prop) {
+ supply = strrchr(prop->name, '-');
+ if (supply && !strcmp(supply, "-supply"))
+ return true;
+ }
+
+ return false;
+}
+
#endif /* CONFIG_PCI */
/**
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index cdc0c78b36f56..7b3d45f243264 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -775,6 +775,7 @@ void pci_set_bus_of_node(struct pci_bus *bus);
void pci_release_bus_of_node(struct pci_bus *bus);
int devm_of_pci_bridge_init(struct device *dev, struct pci_host_bridge *bridge);
+bool of_pci_supply_present(struct device_node *np);
#else
static inline int
@@ -822,6 +823,10 @@ static inline int devm_of_pci_bridge_init(struct device *dev, struct pci_host_br
return 0;
}
+static inline bool of_pci_supply_present(struct device_node *np)
+{
+ return false;
+}
#endif /* CONFIG_OF */
struct of_changeset;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 078/869] PCI/pwrctrl: Cancel outstanding rescan work when unregistering
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (76 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 077/869] PCI/pwrctl: Create pwrctl device only if at least one power supply is present Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 079/869] drm/nouveau: fix a use-after-free in r535_gsp_rpc_push() Greg Kroah-Hartman
` (791 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Brian Norris, Brian Norris,
Krzysztof Wilczyński, Bjorn Helgaas, Manivannan Sadhasivam,
Bartosz Golaszewski, Konrad Dybcio, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brian Norris <briannorris@google.com>
[ Upstream commit 8b926f237743f020518162c62b93cb7107a2b5eb ]
It's possible to trigger use-after-free here by:
(a) forcing rescan_work_func() to take a long time and
(b) utilizing a pwrctrl driver that may be unloaded for some reason
Cancel outstanding work to ensure it is finished before we allow our data
structures to be cleaned up.
[bhelgaas: tidy commit log]
Fixes: 8f62819aaace ("PCI/pwrctl: Rescan bus on a separate thread")
Signed-off-by: Brian Norris <briannorris@google.com>
Signed-off-by: Brian Norris <briannorris@chromium.org>
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Cc: Konrad Dybcio <konradybcio@kernel.org>
Link: https://patch.msgid.link/20250409115313.1.Ia319526ed4ef06bec3180378c9a008340cec9658@changeid
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pci/pwrctl/core.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/pci/pwrctl/core.c b/drivers/pci/pwrctl/core.c
index 01d913b603160..316c1bc05d4d9 100644
--- a/drivers/pci/pwrctl/core.c
+++ b/drivers/pci/pwrctl/core.c
@@ -110,6 +110,8 @@ EXPORT_SYMBOL_GPL(pci_pwrctl_device_set_ready);
*/
void pci_pwrctl_device_unset_ready(struct pci_pwrctl *pwrctl)
{
+ cancel_work_sync(&pwrctl->work);
+
/*
* We don't have to delete the link here. Typically, this function
* is only called when the power control device is being detached. If
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 079/869] drm/nouveau: fix a use-after-free in r535_gsp_rpc_push()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (77 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 078/869] PCI/pwrctrl: Cancel outstanding rescan work when unregistering Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 080/869] wifi: ath12k: convert struct ath12k_sta::update_wk to use struct wiphy_work Greg Kroah-Hartman
` (790 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Zhi Wang, Danilo Krummrich,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhi Wang <zhiw@nvidia.com>
[ Upstream commit 9802f0a63b641f4cddb2139c814c2e95cb825099 ]
The RPC container is released after being passed to r535_gsp_rpc_send().
When sending the initial fragment of a large RPC and passing the
caller's RPC container, the container will be freed prematurely. Subsequent
attempts to send remaining fragments will therefore result in a
use-after-free.
Allocate a temporary RPC container for holding the initial fragment of a
large RPC when sending. Free the caller's container when all fragments
are successfully sent.
Fixes: 176fdcbddfd2 ("drm/nouveau/gsp/r535: add support for booting GSP-RM")
Signed-off-by: Zhi Wang <zhiw@nvidia.com>
Link: https://lore.kernel.org/r/20250527163712.3444-1-zhiw@nvidia.com
[ Rebase onto Blackwell changes. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
index 3ad4f6e9a8ac2..801b0bc676ab2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
@@ -734,12 +734,18 @@ r535_gsp_rpc_push(struct nvkm_gsp *gsp, void *argv, bool wait, u32 repc)
mutex_lock(&gsp->cmdq.mutex);
if (rpc_size > max_rpc_size) {
const u32 fn = rpc->function;
+ void *next;
- /* Adjust length, and send initial RPC. */
- rpc->length = sizeof(*rpc) + max_rpc_size;
- cmd->checksum = rpc->length;
+ /* Send initial RPC. */
+ next = r535_gsp_rpc_get(gsp, fn, max_rpc_size);
+ if (IS_ERR(next)) {
+ repv = next;
+ goto done;
+ }
- repv = r535_gsp_rpc_send(gsp, argv, false, 0);
+ memcpy(next, argv, max_rpc_size);
+
+ repv = r535_gsp_rpc_send(gsp, next, false, 0);
if (IS_ERR(repv))
goto done;
@@ -749,7 +755,6 @@ r535_gsp_rpc_push(struct nvkm_gsp *gsp, void *argv, bool wait, u32 repc)
/* Remaining chunks sent as CONTINUATION_RECORD RPCs. */
while (rpc_size) {
u32 size = min(rpc_size, max_rpc_size);
- void *next;
next = r535_gsp_rpc_get(gsp, NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD, size);
if (IS_ERR(next)) {
@@ -777,6 +782,8 @@ r535_gsp_rpc_push(struct nvkm_gsp *gsp, void *argv, bool wait, u32 repc)
} else {
repv = NULL;
}
+ if (!IS_ERR(repv))
+ kvfree(cmd);
} else {
repv = r535_gsp_rpc_send(gsp, argv, wait, repc);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 080/869] wifi: ath12k: convert struct ath12k_sta::update_wk to use struct wiphy_work
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (78 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 079/869] drm/nouveau: fix a use-after-free in r535_gsp_rpc_push() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 081/869] wifi: ath12k: ath12k_mac_op_sta_state(): clean up update_wk cancellation Greg Kroah-Hartman
` (789 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Kalle Valo, Jeff Johnson,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kalle Valo <quic_kvalo@quicinc.com>
[ Upstream commit 58550cdda961dedad8ed08c5abf8367d5c020fb6 ]
For preparation to switch ath12k to use wiphy_lock() we can convert
ath12k_sta_rc_update_wk() to use wiphy_work_queue() for consistency. To avoid
any deadlocks do the struct ath12k_sta::update_wk conversion before switching
to using wiphy_lock() throughout the driver.
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://patch.msgid.link/20241007165932.78081-3-kvalo@kernel.org
Signed-off-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Stable-dep-of: c426497fa205 ("wifi: ath12k: Fix memory leak due to multiple rx_stats allocation")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath12k/core.h | 2 +-
drivers/net/wireless/ath/ath12k/mac.c | 12 +++++++-----
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 3faf3430effb9..3567150b49ffb 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -452,7 +452,7 @@ struct ath12k_sta {
u32 smps;
enum hal_pn_type pn_type;
- struct work_struct update_wk;
+ struct wiphy_work update_wk;
struct rate_info txrate;
struct rate_info last_txrate;
u64 rx_duration;
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 8e8defddc8fa9..e5d3cfade4e1f 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -4271,7 +4271,7 @@ static int ath12k_station_disassoc(struct ath12k *ar,
return 0;
}
-static void ath12k_sta_rc_update_wk(struct work_struct *wk)
+static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk)
{
struct ath12k *ar;
struct ath12k_vif *arvif;
@@ -4287,6 +4287,8 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk)
struct ath12k_wmi_peer_assoc_arg peer_arg;
enum wmi_phy_mode peer_phymode;
+ lockdep_assert_wiphy(wiphy);
+
arsta = container_of(wk, struct ath12k_sta, update_wk);
sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
arvif = arsta->arvif;
@@ -4584,7 +4586,7 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
/* cancel must be done outside the mutex to avoid deadlock */
if ((old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST))
- cancel_work_sync(&arsta->update_wk);
+ wiphy_work_cancel(hw->wiphy, &arsta->update_wk);
ar = ath12k_get_ar_by_vif(hw, vif);
if (!ar) {
@@ -4598,7 +4600,7 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
new_state == IEEE80211_STA_NONE) {
memset(arsta, 0, sizeof(*arsta));
arsta->arvif = arvif;
- INIT_WORK(&arsta->update_wk, ath12k_sta_rc_update_wk);
+ wiphy_work_init(&arsta->update_wk, ath12k_sta_rc_update_wk);
ret = ath12k_mac_station_add(ar, vif, sta);
if (ret)
@@ -4809,7 +4811,7 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
spin_unlock_bh(&ar->data_lock);
- ieee80211_queue_work(hw, &arsta->update_wk);
+ wiphy_work_queue(hw->wiphy, &arsta->update_wk);
}
static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif,
@@ -8119,7 +8121,7 @@ static void ath12k_mac_set_bitrate_mask_iter(void *data,
arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
spin_unlock_bh(&ar->data_lock);
- ieee80211_queue_work(ath12k_ar_to_hw(ar), &arsta->update_wk);
+ wiphy_work_queue(ath12k_ar_to_hw(ar)->wiphy, &arsta->update_wk);
}
static void ath12k_mac_disable_peer_fixed_rate(void *data,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 081/869] wifi: ath12k: ath12k_mac_op_sta_state(): clean up update_wk cancellation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (79 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 080/869] wifi: ath12k: convert struct ath12k_sta::update_wk to use struct wiphy_work Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 082/869] wifi: ath12k: prepare vif data structure for MLO handling Greg Kroah-Hartman
` (788 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Kalle Valo, Jeff Johnson,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kalle Valo <quic_kvalo@quicinc.com>
[ Upstream commit e805272f8c2dee280e2fa1c1a454517df17f1261 ]
Now that we have switched to using wiphy_lock() there's no need to have
update_wk cancel call separately, for consistency move it to the rest of code
handling IEEE80211_STA_NONE state.
No functional changes.
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://patch.msgid.link/20241007165932.78081-7-kvalo@kernel.org
Signed-off-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Stable-dep-of: c426497fa205 ("wifi: ath12k: Fix memory leak due to multiple rx_stats allocation")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath12k/mac.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index e5d3cfade4e1f..f3785bc0f4c8e 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -4583,11 +4583,6 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
struct ath12k_peer *peer;
int ret = 0;
- /* cancel must be done outside the mutex to avoid deadlock */
- if ((old_state == IEEE80211_STA_NONE &&
- new_state == IEEE80211_STA_NOTEXIST))
- wiphy_work_cancel(hw->wiphy, &arsta->update_wk);
-
ar = ath12k_get_ar_by_vif(hw, vif);
if (!ar) {
WARN_ON_ONCE(1);
@@ -4608,6 +4603,8 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
sta->addr, arvif->vdev_id);
} else if ((old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST)) {
+ wiphy_work_cancel(hw->wiphy, &arsta->update_wk);
+
if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
ath12k_bss_disassoc(ar, arvif);
ret = ath12k_mac_vdev_stop(arvif);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 082/869] wifi: ath12k: prepare vif data structure for MLO handling
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (80 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 081/869] wifi: ath12k: ath12k_mac_op_sta_state(): clean up update_wk cancellation Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 083/869] wifi: ath12k: Fix memory leak due to multiple rx_stats allocation Greg Kroah-Hartman
` (787 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sriram R, Rameshkumar Sundaram,
Kalle Valo, Jeff Johnson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sriram R <quic_srirrama@quicinc.com>
[ Upstream commit 3dd2c68f206ef7020d12b9f85cbfe05ca8662cf4 ]
To prepare the driver for MLO support, split the driver vif data structure to
scale for multiple links. This requires changing the use of arvif to per link
and not per hw which can now comprise of multiple links. Also since most
configurations from mac80211 are done per link, do refactoring of the driver
functions to apply these configurations at link level.
Split ath12k_vif which is the driver private of ieee80211_vif to store link
specific information as ath12k_link_vif. For default use cases the ath12k vif
will have a preallocated link vif called deflink which will be used by non ML
and the first link vif of ML vif.
With MLO support to be added, remaining link vifs will be allocated during
channel assignment where vdev create/start happens. These link vifs will be
freed during interface down.
Current ath12k_vif(arvif) structure
+---------------+ +---------------+ +---------------+
| ieee80211_vif | | ieee80211_vif | | ieee80211_vif |
| private data | | private data | | private data |
| | | | | |
| ath12k_vif | | ath12k_vif | | ath12k_vif |
| (arvif) | | (arvif) | | (arvif) |
| | | | | |
| +----------+ | | +----------+ | | +----------+ |
| |*ar (2GHz)| | | |*ar (5GHz)| | | |*ar (2GHz)| |
| +----------+ | | +----------+ | | +----------+ |
| | | | | |
+---------------+ +---------------+ +---------------+
The new ath12k_vif (ahvif) containing ath12k_link_vif(s) (arvif) (deflink is
preallocated member which is always the first link if ieee80211_vif is MLD and
is the only link otherwise):
+---------------------------------+
| ieee80211_vif |
| private data |
| |
| ath12k_vif(ahvif) |
| |
| +-------------------------------+
| |ath12k_link_vif deflink (arvif)|
| | +---------------+ |
| | | *ar(2GHz) | |
| +-------------------------------+
| +-------------------------------+
| | ath12k_link_vif *link (arvif)|
| | +---------------+ |
| | | *ar(5GHz) | |
| +-------------------------------+
| +-------------------------------+
| | ath12k_link_vif *link (arvif)|
| | +---------------+ |
| | | *ar(6GHz) | |
| +-------------------------------+
| |
+---------------------------------+
To refactor existing ath12k_vif to make use of link vifs, following
changes are made:
1. ath12k_vif now called by variable name ahvif storing multiple
arvifs (struct ah12k_link_vif) and also has a back pointer to ieee80211_vif.
2. In this patch set, only deflink is used to be on par with the
existing code. When MLO support is added the link id will be used to fetch
the arvif.
3. For mac80211 ops which doesn't use specific link_id, the config or info
is common for the vif, hence apply the config to all link vifs.
The links_map in the ahvif, will be used to identify all the link vifs that
are setup.
4. Change ath12k_vif_to_arvif() as ath12k_vif_to_ahvif() to fetch the
hw level vif. The link vif can be fetched from ahvif->link[], or the
deflink can be accessed via ahvif->deflink. API to access link
vif (arvif) by passing link_id can be introduced with MLO Support.
5. The ieee80211_vif can be accessed from ahvif using ath12k_ahvif_to_vif().
The locking continues to use wiphy_lock() for protecting access to most data in
struct ath12k&co, there are no changes in that regard. Though struct
ath12k_vif::link[] is protected with RCU.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Co-developed-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://patch.msgid.link/20241015171416.518022-2-kvalo@kernel.org
Signed-off-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Retain only the removal of the blank line immediately before the rx_stats
allocation in ath12k_mac_station_add(). This supplies the exact preimage
needed by the subsequent allocation guard fix. Keeping the separator
causes that fix to conflict, including when using a three-way merge.
Drop the MLO vif split and associated API changes. The allocation guard
does not need them, and they assume locking changes that are absent here.
There is no runtime behavior change.
Stable-dep-of: c426497fa205 ("wifi: ath12k: Fix memory leak due to multiple rx_stats allocation")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath12k/mac.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index f3785bc0f4c8e..3a7fb0e490fa3 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -4481,7 +4481,6 @@ static int ath12k_mac_station_add(struct ath12k *ar,
ar->max_num_stations);
goto exit;
}
-
arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL);
if (!arsta->rx_stats) {
ret = -ENOMEM;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 083/869] wifi: ath12k: Fix memory leak due to multiple rx_stats allocation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (81 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 082/869] wifi: ath12k: prepare vif data structure for MLO handling Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 084/869] mm: fix uprobe pte be overwritten when expanding vma Greg Kroah-Hartman
` (786 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sidhanta Sahu, Muna Sinada,
Mahendran P, Jeff Johnson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sidhanta Sahu <sidhanta.sahu@oss.qualcomm.com>
[ Upstream commit c426497fa2055c8005196922e7d29c41d7e0948a ]
rx_stats for each arsta is allocated when adding a station.
arsta->rx_stats will be freed when a station is removed.
Redundant allocations are occurring when the same station is added
multiple times. This causes ath12k_mac_station_add() to be called
multiple times, and rx_stats is allocated each time. As a result there
is memory leaks.
Prevent multiple allocations of rx_stats when ath12k_mac_station_add()
is called repeatedly by checking if rx_stats is already allocated
before allocating again. Allocate arsta->rx_stats if arsta->rx_stats
is NULL respectively.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Signed-off-by: Sidhanta Sahu <sidhanta.sahu@oss.qualcomm.com>
Signed-off-by: Muna Sinada <muna.sinada@oss.qualcomm.com>
Reviewed-by: Mahendran P <quic_mahep@quicinc.com>
Link: https://patch.msgid.link/20250326213538.2214194-1-muna.sinada@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath12k/mac.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 3a7fb0e490fa3..6a42c63307c8a 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -4481,10 +4481,13 @@ static int ath12k_mac_station_add(struct ath12k *ar,
ar->max_num_stations);
goto exit;
}
- arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL);
+
if (!arsta->rx_stats) {
- ret = -ENOMEM;
- goto dec_num_station;
+ arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL);
+ if (!arsta->rx_stats) {
+ ret = -ENOMEM;
+ goto dec_num_station;
+ }
}
peer_param.vdev_id = arvif->vdev_id;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 084/869] mm: fix uprobe pte be overwritten when expanding vma
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (82 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 083/869] wifi: ath12k: Fix memory leak due to multiple rx_stats allocation Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 085/869] riscv: Enable cbo.zero only when all harts support Zicboz Greg Kroah-Hartman
` (785 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pu Lehui, Lorenzo Stoakes,
David Hildenbrand, Jann Horn, Liam Howlett,
Masami Hiramatsu (Google), Oleg Nesterov, Peter Zijlstra,
Vlastimil Babka, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <pulehui@huawei.com>
[ Upstream commit 2b12d06c37fd3a394376f42f026a7478d826ed63 ]
Patch series "Fix uprobe pte be overwritten when expanding vma".
This patch (of 4):
We encountered a BUG alert triggered by Syzkaller as follows:
BUG: Bad rss-counter state mm:00000000b4a60fca type:MM_ANONPAGES val:1
And we can reproduce it with the following steps:
1. register uprobe on file at zero offset
2. mmap the file at zero offset:
addr1 = mmap(NULL, 2 * 4096, PROT_NONE, MAP_PRIVATE, fd, 0);
3. mremap part of vma1 to new vma2:
addr2 = mremap(addr1, 4096, 2 * 4096, MREMAP_MAYMOVE);
4. mremap back to orig addr1:
mremap(addr2, 4096, 4096, MREMAP_MAYMOVE | MREMAP_FIXED, addr1);
In step 3, the vma1 range [addr1, addr1 + 4096] will be remap to new vma2
with range [addr2, addr2 + 8192], and remap uprobe anon page from the vma1
to vma2, then unmap the vma1 range [addr1, addr1 + 4096].
In step 4, the vma2 range [addr2, addr2 + 4096] will be remap back to the
addr range [addr1, addr1 + 4096]. Since the addr range [addr1 + 4096,
addr1 + 8192] still maps the file, it will take vma_merge_new_range to
expand the range, and then do uprobe_mmap in vma_complete. Since the
merged vma pgoff is also zero offset, it will install uprobe anon page to
the merged vma. However, the upcomming move_page_tables step, which use
set_pte_at to remap the vma2 uprobe pte to the merged vma, will overwrite
the newly uprobe pte in the merged vma, and lead that pte to be orphan.
Since the uprobe pte will be remapped to the merged vma, we can remove the
unnecessary uprobe_mmap upon merged vma.
This problem was first found in linux-6.6.y and also exists in the
community syzkaller:
https://lore.kernel.org/all/000000000000ada39605a5e71711@google.com/T/
Link: https://lkml.kernel.org/r/20250529155650.4017699-1-pulehui@huaweicloud.com
Link: https://lkml.kernel.org/r/20250529155650.4017699-2-pulehui@huaweicloud.com
Fixes: 2b1444983508 ("uprobes, mm, x86: Add the ability to install and remove uprobes breakpoints")
Signed-off-by: Pu Lehui <pulehui@huawei.com>
Suggested-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Acked-by: David Hildenbrand <david@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/vma.c | 18 +++++++++++++++---
mm/vma.h | 7 +++++++
2 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/mm/vma.c b/mm/vma.c
index b58588cac3aab..66b0472b7d8a6 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -236,10 +236,13 @@ static void vma_complete(struct vma_prepare *vp, struct vma_iterator *vmi,
if (vp->file) {
i_mmap_unlock_write(vp->mapping);
- uprobe_mmap(vp->vma);
- if (vp->adj_next)
- uprobe_mmap(vp->adj_next);
+ if (!vp->skip_vma_uprobe) {
+ uprobe_mmap(vp->vma);
+
+ if (vp->adj_next)
+ uprobe_mmap(vp->adj_next);
+ }
}
if (vp->remove) {
@@ -592,6 +595,7 @@ static int commit_merge(struct vma_merge_struct *vmg,
struct vma_prepare vp;
init_multi_vma_prep(&vp, vmg->vma, adjust, remove, remove2);
+ vp.skip_vma_uprobe = vmg->skip_vma_uprobe;
VM_WARN_ON(vp.anon_vma && adjust && adjust->anon_vma &&
vp.anon_vma != adjust->anon_vma);
@@ -1660,6 +1664,14 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
faulted_in_anon_vma = false;
}
+ /*
+ * If the VMA we are copying might contain a uprobe PTE, ensure
+ * that we do not establish one upon merge. Otherwise, when mremap()
+ * moves page tables, it will orphan the newly created PTE.
+ */
+ if (vma->vm_file)
+ vmg.skip_vma_uprobe = true;
+
new_vma = find_vma_prev(mm, addr, &vmg.prev);
if (new_vma && new_vma->vm_start < addr + len)
return NULL; /* should never get here */
diff --git a/mm/vma.h b/mm/vma.h
index 7c2932ec62356..f7efbe41c44c5 100644
--- a/mm/vma.h
+++ b/mm/vma.h
@@ -19,6 +19,8 @@ struct vma_prepare {
struct vm_area_struct *insert;
struct vm_area_struct *remove;
struct vm_area_struct *remove2;
+
+ bool skip_vma_uprobe :1;
};
struct unlink_vma_file_batch {
@@ -93,6 +95,11 @@ struct vma_merge_struct {
* execute the merge, returning NULL.
*/
bool give_up_on_oom :1;
+
+ /*
+ * If set, skip uprobe_mmap upon merged vma.
+ */
+ bool skip_vma_uprobe :1;
};
static inline bool vmg_nomem(struct vma_merge_struct *vmg)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 085/869] riscv: Enable cbo.zero only when all harts support Zicboz
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (83 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 084/869] mm: fix uprobe pte be overwritten when expanding vma Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 086/869] riscv: Add support for per-thread envcfg CSR values Greg Kroah-Hartman
` (784 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Andrew Jones, Conor Dooley,
Deepak Gupta, Samuel Holland, Charlie Jenkins, Palmer Dabbelt,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Holland <samuel.holland@sifive.com>
[ Upstream commit 1b57747e978f920fb2affd1952ed913276019115 ]
Currently, we enable cbo.zero for usermode on each hart that supports
the Zicboz extension. This means that the [ms]envcfg CSR value may
differ between harts. Other features, such as pointer masking and CFI,
require setting [ms]envcfg bits on a per-thread basis. The combination
of these two adds quite some complexity and overhead to context
switching, as we would need to maintain two separate masks for the
per-hart and per-thread bits. Andrew Jones, who originally added Zicboz
support, writes[1][2]:
I've approached Zicboz the same way I would approach all
extensions, which is to be per-hart. I'm not currently aware of
a platform that is / will be composed of harts where some have
Zicboz and others don't, but there's nothing stopping a platform
like that from being built.
So, how about we add code that confirms Zicboz is on all harts.
If any hart does not have it, then we complain loudly and disable
it on all the other harts. If it was just a hardware description
bug, then it'll get fixed. If there's actually a platform which
doesn't have Zicboz on all harts, then, when the issue is reported,
we can decide to not support it, support it with defconfig, or
support it under a Kconfig guard which must be enabled by the user.
Let's follow his suggested solution and require the extension to be
available on all harts, so the envcfg CSR value does not need to change
when a thread migrates between harts. Since we are doing this for all
extensions with fields in envcfg, the CSR itself only needs to be saved/
restored when it is present on all harts.
This should not be a regression as no known hardware has asymmetric
Zicboz support, but if anyone reports seeing the warning, we will
re-evaluate our solution.
Link: https://lore.kernel.org/linux-riscv/20240322-168f191eeb8479b2ea169a5e@orel/ [1]
Link: https://lore.kernel.org/linux-riscv/20240323-28943722feb57a41fb0ff488@orel/ [2]
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Deepak Gupta <debug@rivosinc.com>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>
Tested-by: Charlie Jenkins <charlie@rivosinc.com>
Link: https://lore.kernel.org/r/20240814081126.956287-2-samuel.holland@sifive.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
Stable-dep-of: 788aa64c01f1 ("riscv: save the SR_SUM status over switches")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/riscv/kernel/cpufeature.c | 7 ++++++-
arch/riscv/kernel/suspend.c | 4 ++--
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 472de1ed1ad7e..8c6e91dcd32b0 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -28,6 +28,8 @@
#define NUM_ALPHA_EXTS ('z' - 'a' + 1)
+static bool any_cpu_has_zicboz;
+
unsigned long elf_hwcap __read_mostly;
/* Host ISA bitmap */
@@ -98,6 +100,7 @@ static int riscv_ext_zicboz_validate(const struct riscv_isa_ext_data *data,
pr_err("Zicboz disabled as cboz-block-size present, but is not a power-of-2\n");
return -EINVAL;
}
+ any_cpu_has_zicboz = true;
return 0;
}
@@ -920,8 +923,10 @@ unsigned long riscv_get_elf_hwcap(void)
void riscv_user_isa_enable(void)
{
- if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_ZICBOZ))
+ if (riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICBOZ))
csr_set(CSR_ENVCFG, ENVCFG_CBZE);
+ else if (any_cpu_has_zicboz)
+ pr_warn_once("Zicboz disabled as it is unavailable on some harts\n");
}
#ifdef CONFIG_RISCV_ALTERNATIVE
diff --git a/arch/riscv/kernel/suspend.c b/arch/riscv/kernel/suspend.c
index c8cec0cc5833c..9a8a0dc035b26 100644
--- a/arch/riscv/kernel/suspend.c
+++ b/arch/riscv/kernel/suspend.c
@@ -14,7 +14,7 @@
void suspend_save_csrs(struct suspend_context *context)
{
- if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_XLINUXENVCFG))
+ if (riscv_has_extension_unlikely(RISCV_ISA_EXT_XLINUXENVCFG))
context->envcfg = csr_read(CSR_ENVCFG);
context->tvec = csr_read(CSR_TVEC);
context->ie = csr_read(CSR_IE);
@@ -37,7 +37,7 @@ void suspend_save_csrs(struct suspend_context *context)
void suspend_restore_csrs(struct suspend_context *context)
{
csr_write(CSR_SCRATCH, 0);
- if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_XLINUXENVCFG))
+ if (riscv_has_extension_unlikely(RISCV_ISA_EXT_XLINUXENVCFG))
csr_write(CSR_ENVCFG, context->envcfg);
csr_write(CSR_TVEC, context->tvec);
csr_write(CSR_IE, context->ie);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 086/869] riscv: Add support for per-thread envcfg CSR values
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (84 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 085/869] riscv: Enable cbo.zero only when all harts support Zicboz Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 087/869] riscv: save the SR_SUM status over switches Greg Kroah-Hartman
` (783 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Andrew Jones, Deepak Gupta,
Samuel Holland, Charlie Jenkins, Palmer Dabbelt, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Holland <samuel.holland@sifive.com>
[ Upstream commit 5fc7355f01376e69964bb21b685025b042c37acc ]
Some bits in the [ms]envcfg CSR, such as the CFI state and pointer
masking mode, need to be controlled on a per-thread basis. Support this
by keeping a copy of the CSR value in struct thread_struct and writing
it during context switches. It is safe to discard the old CSR value
during the context switch because the CSR is modified only by software,
so the CSR will remain in sync with the copy in thread_struct.
Use ALTERNATIVE directly instead of riscv_has_extension_unlikely() to
minimize branchiness in the context switching code.
Since thread_struct is copied during fork(), setting the value for the
init task sets the default value for all other threads.
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Deepak Gupta <debug@rivosinc.com>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>
Link: https://lore.kernel.org/r/20240814081126.956287-3-samuel.holland@sifive.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
Stable-dep-of: 788aa64c01f1 ("riscv: save the SR_SUM status over switches")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/riscv/include/asm/processor.h | 1 +
arch/riscv/include/asm/switch_to.h | 8 ++++++++
arch/riscv/kernel/cpufeature.c | 2 +-
3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index efa1b3519b238..c1a4925088353 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -102,6 +102,7 @@ struct thread_struct {
unsigned long s[12]; /* s[0]: frame pointer */
struct __riscv_d_ext_state fstate;
unsigned long bad_cause;
+ unsigned long envcfg;
u32 riscv_v_flags;
u32 vstate_ctrl;
struct __riscv_v_ext_state vstate;
diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
index 7594df37cc9ff..9685cd85e57cc 100644
--- a/arch/riscv/include/asm/switch_to.h
+++ b/arch/riscv/include/asm/switch_to.h
@@ -70,6 +70,13 @@ static __always_inline bool has_fpu(void) { return false; }
#define __switch_to_fpu(__prev, __next) do { } while (0)
#endif
+static inline void __switch_to_envcfg(struct task_struct *next)
+{
+ asm volatile (ALTERNATIVE("nop", "csrw " __stringify(CSR_ENVCFG) ", %0",
+ 0, RISCV_ISA_EXT_XLINUXENVCFG, 1)
+ :: "r" (next->thread.envcfg) : "memory");
+}
+
extern struct task_struct *__switch_to(struct task_struct *,
struct task_struct *);
@@ -103,6 +110,7 @@ do { \
__switch_to_vector(__prev, __next); \
if (switch_to_should_flush_icache(__next)) \
local_flush_icache_all(); \
+ __switch_to_envcfg(__next); \
((last) = __switch_to(__prev, __next)); \
} while (0)
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 8c6e91dcd32b0..248167b802eb9 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -924,7 +924,7 @@ unsigned long riscv_get_elf_hwcap(void)
void riscv_user_isa_enable(void)
{
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICBOZ))
- csr_set(CSR_ENVCFG, ENVCFG_CBZE);
+ current->thread.envcfg |= ENVCFG_CBZE;
else if (any_cpu_has_zicboz)
pr_warn_once("Zicboz disabled as it is unavailable on some harts\n");
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 087/869] riscv: save the SR_SUM status over switches
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (85 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 086/869] riscv: Add support for per-thread envcfg CSR values Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 088/869] wifi: rtw89: pci: configure manual DAC mode via PCI config API only Greg Kroah-Hartman
` (782 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+e74b94fe601ab9552d69,
Ben Dooks, Cyril Bur, Alexandre Ghiti, Deepak Gupta,
Palmer Dabbelt, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ben Dooks <ben.dooks@codethink.co.uk>
[ Upstream commit 788aa64c01f1262310b4c1fb827a36df170d86ea ]
When threads/tasks are switched we need to ensure the old execution's
SR_SUM state is saved and the new thread has the old SR_SUM state
restored.
The issue was seen under heavy load especially with the syz-stress tool
running, with crashes as follows in schedule_tail:
Unable to handle kernel access to user memory without uaccess routines
at virtual address 000000002749f0d0
Oops [#1]
Modules linked in:
CPU: 1 PID: 4875 Comm: syz-executor.0 Not tainted
5.12.0-rc2-syzkaller-00467-g0d7588ab9ef9 #0
Hardware name: riscv-virtio,qemu (DT)
epc : schedule_tail+0x72/0xb2 kernel/sched/core.c:4264
ra : task_pid_vnr include/linux/sched.h:1421 [inline]
ra : schedule_tail+0x70/0xb2 kernel/sched/core.c:4264
epc : ffffffe00008c8b0 ra : ffffffe00008c8ae sp : ffffffe025d17ec0
gp : ffffffe005d25378 tp : ffffffe00f0d0000 t0 : 0000000000000000
t1 : 0000000000000001 t2 : 00000000000f4240 s0 : ffffffe025d17ee0
s1 : 000000002749f0d0 a0 : 000000000000002a a1 : 0000000000000003
a2 : 1ffffffc0cfac500 a3 : ffffffe0000c80cc a4 : 5ae9db91c19bbe00
a5 : 0000000000000000 a6 : 0000000000f00000 a7 : ffffffe000082eba
s2 : 0000000000040000 s3 : ffffffe00eef96c0 s4 : ffffffe022c77fe0
s5 : 0000000000004000 s6 : ffffffe067d74e00 s7 : ffffffe067d74850
s8 : ffffffe067d73e18 s9 : ffffffe067d74e00 s10: ffffffe00eef96e8
s11: 000000ae6cdf8368 t3 : 5ae9db91c19bbe00 t4 : ffffffc4043cafb2
t5 : ffffffc4043cafba t6 : 0000000000040000
status: 0000000000000120 badaddr: 000000002749f0d0 cause:
000000000000000f
Call Trace:
[<ffffffe00008c8b0>] schedule_tail+0x72/0xb2 kernel/sched/core.c:4264
[<ffffffe000005570>] ret_from_exception+0x0/0x14
Dumping ftrace buffer:
(ftrace buffer empty)
---[ end trace b5f8f9231dc87dda ]---
The issue comes from the put_user() in schedule_tail
(kernel/sched/core.c) doing the following:
asmlinkage __visible void schedule_tail(struct task_struct *prev)
{
...
if (current->set_child_tid)
put_user(task_pid_vnr(current), current->set_child_tid);
...
}
the put_user() macro causes the code sequence to come out as follows:
1: __enable_user_access()
2: reg = task_pid_vnr(current);
3: *current->set_child_tid = reg;
4: __disable_user_access()
The problem is that we may have a sleeping function as argument which
could clear SR_SUM causing the panic above. This was fixed by
evaluating the argument of the put_user() macro outside the user-enabled
section in commit 285a76bb2cf5 ("riscv: evaluate put_user() arg before
enabling user access")"
In order for riscv to take advantage of unsafe_get/put_XXX() macros and
to avoid the same issue we had with put_user() and sleeping functions we
must ensure code flow can go through switch_to() from within a region of
code with SR_SUM enabled and come back with SR_SUM still enabled. This
patch addresses the problem allowing future work to enable full use of
unsafe_get/put_XXX() macros without needing to take a CSR bit flip cost
on every access. Make switch_to() save and restore SR_SUM.
Reported-by: syzbot+e74b94fe601ab9552d69@syzkaller.appspotmail.com
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
Signed-off-by: Cyril Bur <cyrilbur@tenstorrent.com>
Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Reviewed-by: Deepak Gupta <debug@rivosinc.com>
Link: https://lore.kernel.org/r/20250410070526.3160847-2-cyrilbur@tenstorrent.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/riscv/include/asm/processor.h | 1 +
arch/riscv/kernel/asm-offsets.c | 5 +++++
arch/riscv/kernel/entry.S | 8 ++++++++
3 files changed, 14 insertions(+)
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index c1a4925088353..8b00833d24937 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -103,6 +103,7 @@ struct thread_struct {
struct __riscv_d_ext_state fstate;
unsigned long bad_cause;
unsigned long envcfg;
+ unsigned long status;
u32 riscv_v_flags;
u32 vstate_ctrl;
struct __riscv_v_ext_state vstate;
diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c
index dfed9986b45ed..1b575ddcb26ac 100644
--- a/arch/riscv/kernel/asm-offsets.c
+++ b/arch/riscv/kernel/asm-offsets.c
@@ -35,6 +35,7 @@ void asm_offsets(void)
OFFSET(TASK_THREAD_S9, task_struct, thread.s[9]);
OFFSET(TASK_THREAD_S10, task_struct, thread.s[10]);
OFFSET(TASK_THREAD_S11, task_struct, thread.s[11]);
+ OFFSET(TASK_THREAD_STATUS, task_struct, thread.status);
OFFSET(TASK_TI_CPU, task_struct, thread_info.cpu);
OFFSET(TASK_TI_FLAGS, task_struct, thread_info.flags);
@@ -348,6 +349,10 @@ void asm_offsets(void)
offsetof(struct task_struct, thread.s[11])
- offsetof(struct task_struct, thread.ra)
);
+ DEFINE(TASK_THREAD_STATUS_RA,
+ offsetof(struct task_struct, thread.status)
+ - offsetof(struct task_struct, thread.ra)
+ );
DEFINE(TASK_THREAD_F0_F0,
offsetof(struct task_struct, thread.fstate.f[0])
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index fee140a5c211c..c4d7a9ece593b 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -402,9 +402,17 @@ SYM_FUNC_START(__switch_to)
REG_S s9, TASK_THREAD_S9_RA(a3)
REG_S s10, TASK_THREAD_S10_RA(a3)
REG_S s11, TASK_THREAD_S11_RA(a3)
+
+ /* save the user space access flag */
+ li s0, SR_SUM
+ csrr s1, CSR_STATUS
+ REG_S s1, TASK_THREAD_STATUS_RA(a3)
+
/* Save the kernel shadow call stack pointer */
scs_save_current
/* Restore context from next->thread */
+ REG_L s0, TASK_THREAD_STATUS_RA(a4)
+ csrs CSR_STATUS, s0
REG_L ra, TASK_THREAD_RA_RA(a4)
REG_L sp, TASK_THREAD_SP_RA(a4)
REG_L s0, TASK_THREAD_S0_RA(a4)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 088/869] wifi: rtw89: pci: configure manual DAC mode via PCI config API only
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (86 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 087/869] riscv: save the SR_SUM status over switches Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 089/869] s390/entry: Remove __GMAP_ASCE and use _PIF_GUEST_FAULT again Greg Kroah-Hartman
` (781 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bitterblue Smith, Ping-Ke Shih,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ping-Ke Shih <pkshih@realtek.com>
[ Upstream commit a70cf04b08f44f41bce14659aa7012674b15d9de ]
To support 36-bit DMA, configure chip proprietary bit via PCI config API
or chip DBI interface. However, the PCI device mmap isn't set yet and
the DBI is also inaccessible via mmap, so only if the bit can be accessible
via PCI config API, chip can support 36-bit DMA. Otherwise, fallback to
32-bit DMA.
With NULL mmap address, kernel throws trace:
BUG: unable to handle page fault for address: 0000000000001090
#PF: supervisor write access in kernel mode
#PF: error_code(0x0002) - not-present page
PGD 0 P4D 0
Oops: Oops: 0002 [#1] PREEMPT SMP PTI
CPU: 1 UID: 0 PID: 71 Comm: irq/26-pciehp Tainted: G OE 6.14.2-061402-generic #202504101348
Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE
RIP: 0010:rtw89_pci_ops_write16+0x12/0x30 [rtw89_pci]
RSP: 0018:ffffb0ffc0acf9d8 EFLAGS: 00010206
RAX: ffffffffc158f9c0 RBX: ffff94865e702020 RCX: 0000000000000000
RDX: 0000000000000718 RSI: 0000000000001090 RDI: ffff94865e702020
RBP: ffffb0ffc0acf9d8 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000015
R13: 0000000000000719 R14: ffffb0ffc0acfa1f R15: ffffffffc1813060
FS: 0000000000000000(0000) GS:ffff9486f3480000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000001090 CR3: 0000000090440001 CR4: 00000000000626f0
Call Trace:
<TASK>
rtw89_pci_read_config_byte+0x6d/0x120 [rtw89_pci]
rtw89_pci_cfg_dac+0x5b/0xb0 [rtw89_pci]
rtw89_pci_probe+0xa96/0xbd0 [rtw89_pci]
? __pfx___device_attach_driver+0x10/0x10
? __pfx___device_attach_driver+0x10/0x10
local_pci_probe+0x47/0xa0
pci_call_probe+0x5d/0x190
pci_device_probe+0xa7/0x160
really_probe+0xf9/0x370
? pm_runtime_barrier+0x55/0xa0
__driver_probe_device+0x8c/0x140
driver_probe_device+0x24/0xd0
__device_attach_driver+0xcd/0x170
bus_for_each_drv+0x99/0x100
__device_attach+0xb4/0x1d0
device_attach+0x10/0x20
pci_bus_add_device+0x59/0x90
pci_bus_add_devices+0x31/0x80
pciehp_configure_device+0xaa/0x170
pciehp_enable_slot+0xd6/0x240
pciehp_handle_presence_or_link_change+0xf1/0x180
pciehp_ist+0x162/0x1c0
irq_thread_fn+0x24/0x70
irq_thread+0xef/0x1c0
? __pfx_irq_thread_fn+0x10/0x10
? __pfx_irq_thread_dtor+0x10/0x10
? __pfx_irq_thread+0x10/0x10
kthread+0xfc/0x230
? __pfx_kthread+0x10/0x10
ret_from_fork+0x47/0x70
? __pfx_kthread+0x10/0x10
ret_from_fork_asm+0x1a/0x30
</TASK>
Fixes: 1fd4b3fe52ef ("wifi: rtw89: pci: support 36-bit PCI DMA address")
Reported-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Closes: https://lore.kernel.org/linux-wireless/ccaf49b6-ff41-4917-90f1-f53cadaaa0da@gmail.com/T/#u
Closes: https://github.com/openwrt/openwrt/issues/17025
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250506015356.7995-1-pkshih@realtek.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/realtek/rtw89/pci.c | 34 ++++++++++++++++--------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index 48415d108045f..43285d341870e 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -3086,17 +3086,26 @@ static bool rtw89_pci_is_dac_compatible_bridge(struct rtw89_dev *rtwdev)
return false;
}
-static void rtw89_pci_cfg_dac(struct rtw89_dev *rtwdev)
+static int rtw89_pci_cfg_dac(struct rtw89_dev *rtwdev, bool force)
{
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+ struct pci_dev *pdev = rtwpci->pdev;
+ int ret;
+ u8 val;
- if (!rtwpci->enable_dac)
- return;
+ if (!rtwpci->enable_dac && !force)
+ return 0;
if (!rtw89_pci_chip_is_manual_dac(rtwdev))
- return;
+ return 0;
- rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_L1_CTRL, RTW89_PCIE_BIT_EN_64BITS);
+ /* Configure DAC only via PCI config API, not DBI interfaces */
+ ret = pci_read_config_byte(pdev, RTW89_PCIE_L1_CTRL, &val);
+ if (ret)
+ return ret;
+
+ val |= RTW89_PCIE_BIT_EN_64BITS;
+ return pci_write_config_byte(pdev, RTW89_PCIE_L1_CTRL, val);
}
static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev,
@@ -3114,13 +3123,16 @@ static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev,
}
if (!rtw89_pci_is_dac_compatible_bridge(rtwdev))
- goto no_dac;
+ goto try_dac_done;
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36));
if (!ret) {
- rtwpci->enable_dac = true;
- rtw89_pci_cfg_dac(rtwdev);
- } else {
+ ret = rtw89_pci_cfg_dac(rtwdev, true);
+ if (!ret) {
+ rtwpci->enable_dac = true;
+ goto try_dac_done;
+ }
+
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (ret) {
rtw89_err(rtwdev,
@@ -3128,7 +3140,7 @@ static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev,
goto err_release_regions;
}
}
-no_dac:
+try_dac_done:
resource_len = pci_resource_len(pdev, bar_id);
rtwpci->mmap = pci_iomap(pdev, bar_id, resource_len);
@@ -4267,7 +4279,7 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev)
rtw89_pci_hci_ldo(rtwdev);
rtw89_pci_l2_hci_ldo(rtwdev);
rtw89_pci_disable_eq(rtwdev);
- rtw89_pci_cfg_dac(rtwdev);
+ rtw89_pci_cfg_dac(rtwdev, false);
rtw89_pci_filter_out(rtwdev);
rtw89_pci_link_cfg(rtwdev);
rtw89_pci_l1ss_cfg(rtwdev);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 089/869] s390/entry: Remove __GMAP_ASCE and use _PIF_GUEST_FAULT again
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (87 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 088/869] wifi: rtw89: pci: configure manual DAC mode via PCI config API only Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 090/869] s390/kvm: Remove kvm_arch_fault_in_page() Greg Kroah-Hartman
` (780 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Claudio Imbrenda, Janosch Frank,
Heiko Carstens, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
[ Upstream commit f96cb0d61db6e25cef9d1764acfce3262e507719 ]
Now that the guest ASCE is passed as a parameter to __sie64a(),
_PIF_GUEST_FAULT can be used again to determine whether the fault was a
guest or host fault.
Since the guest ASCE will not be taken from the gmap pointer in lowcore
anymore, __GMAP_ASCE can be removed. For the same reason the guest
ASCE needs now to be saved into the cr1 save area unconditionally.
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Acked-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Link: https://lore.kernel.org/r/20241022120601.167009-2-imbrenda@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Stable-dep-of: 11709abccf93 ("s390/mm: Fix in_atomic() handling in do_secure_storage_access()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/include/asm/ptrace.h | 2 ++
arch/s390/kernel/asm-offsets.c | 2 --
arch/s390/kernel/entry.S | 26 ++++++++++++++------------
arch/s390/mm/fault.c | 6 ++----
4 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index 2ad9324f63387..788bc4467445c 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -14,11 +14,13 @@
#define PIF_SYSCALL 0 /* inside a system call */
#define PIF_EXECVE_PGSTE_RESTART 1 /* restart execve for PGSTE binaries */
#define PIF_SYSCALL_RET_SET 2 /* return value was set via ptrace */
+#define PIF_GUEST_FAULT 3 /* indicates program check in sie64a */
#define PIF_FTRACE_FULL_REGS 4 /* all register contents valid (ftrace) */
#define _PIF_SYSCALL BIT(PIF_SYSCALL)
#define _PIF_EXECVE_PGSTE_RESTART BIT(PIF_EXECVE_PGSTE_RESTART)
#define _PIF_SYSCALL_RET_SET BIT(PIF_SYSCALL_RET_SET)
+#define _PIF_GUEST_FAULT BIT(PIF_GUEST_FAULT)
#define _PIF_FTRACE_FULL_REGS BIT(PIF_FTRACE_FULL_REGS)
#define PSW32_MASK_PER _AC(0x40000000, UL)
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 8fd98a0f999f8..1848d51230004 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -14,7 +14,6 @@
#include <linux/purgatory.h>
#include <linux/pgtable.h>
#include <linux/ftrace.h>
-#include <asm/gmap.h>
#include <asm/stacktrace.h>
int main(void)
@@ -162,7 +161,6 @@ int main(void)
OFFSET(__LC_PGM_TDB, lowcore, pgm_tdb);
BLANK();
/* gmap/sie offsets */
- OFFSET(__GMAP_ASCE, gmap, asce);
OFFSET(__SIE_PROG0C, kvm_s390_sie_block, prog0c);
OFFSET(__SIE_PROG20, kvm_s390_sie_block, prog20);
/* kexec_sha_region */
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 8f5120802115b..2245f562089e4 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -328,13 +328,23 @@ SYM_CODE_START(pgm_check_handler)
GET_LC %r13
stpt __LC_SYS_ENTER_TIMER(%r13)
BPOFF
- lgr %r10,%r15
lmg %r8,%r9,__LC_PGM_OLD_PSW(%r13)
+ xgr %r10,%r10
+ xgr %r12,%r12
tmhh %r8,0x0001 # coming from user space?
jno .Lpgm_skip_asce
lctlg %c1,%c1,__LC_KERNEL_ASCE(%r13)
j 3f # -> fault in user space
.Lpgm_skip_asce:
+#if IS_ENABLED(CONFIG_KVM)
+ lg %r11,__LC_CURRENT(%r13)
+ tm __TI_sie(%r11),0xff
+ jz 1f
+ BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
+ SIEEXIT __SF_SIE_CONTROL(%r15),%r13
+ lg %r12,__SF_SIE_GUEST_ASCE(%r15)
+ lghi %r10,_PIF_GUEST_FAULT
+#endif
1: tmhh %r8,0x4000 # PER bit set in old PSW ?
jnz 2f # -> enabled, can't be a double fault
tm __LC_PGM_ILC+3(%r13),0x80 # check for per exception
@@ -345,21 +355,13 @@ SYM_CODE_START(pgm_check_handler)
CHECK_VMAP_STACK __LC_SAVE_AREA,%r13,4f
3: lg %r15,__LC_KERNEL_STACK(%r13)
4: la %r11,STACK_FRAME_OVERHEAD(%r15)
- xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
+ stg %r10,__PT_FLAGS(%r11)
+ stg %r12,__PT_CR1(%r11)
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
stmg %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA(%r13)
mvc __PT_LAST_BREAK(8,%r11),__LC_PGM_LAST_BREAK(%r13)
- stctg %c1,%c1,__PT_CR1(%r11)
-#if IS_ENABLED(CONFIG_KVM)
- ltg %r12,__LC_GMAP(%r13)
- jz 5f
- clc __GMAP_ASCE(8,%r12), __PT_CR1(%r11)
- jne 5f
- BPENTER __SF_SIE_FLAGS(%r10),_TIF_ISOLATE_BP_GUEST
- SIEEXIT __SF_SIE_CONTROL(%r10),%r13
-#endif
-5: stmg %r8,%r9,__PT_PSW(%r11)
+ stmg %r8,%r9,__PT_PSW(%r11)
# clear user controlled registers to prevent speculative use
xgr %r0,%r0
xgr %r1,%r1
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index ad8b0d6b77ea1..a6cf33b0f3390 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -68,15 +68,13 @@ early_initcall(fault_init);
static enum fault_type get_fault_type(struct pt_regs *regs)
{
union teid teid = { .val = regs->int_parm_long };
- struct gmap *gmap;
if (likely(teid.as == PSW_BITS_AS_PRIMARY)) {
if (user_mode(regs))
return USER_FAULT;
if (!IS_ENABLED(CONFIG_PGSTE))
return KERNEL_FAULT;
- gmap = (struct gmap *)get_lowcore()->gmap;
- if (gmap && gmap->asce == regs->cr1)
+ if (test_pt_regs_flag(regs, PIF_GUEST_FAULT))
return GMAP_FAULT;
return KERNEL_FAULT;
}
@@ -187,7 +185,7 @@ static void dump_fault_info(struct pt_regs *regs)
pr_cont("user ");
break;
case GMAP_FAULT:
- asce = ((struct gmap *)get_lowcore()->gmap)->asce;
+ asce = regs->cr1;
pr_cont("gmap ");
break;
case KERNEL_FAULT:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 090/869] s390/kvm: Remove kvm_arch_fault_in_page()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (88 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 089/869] s390/entry: Remove __GMAP_ASCE and use _PIF_GUEST_FAULT again Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 091/869] s390/mm/fault: Handle guest-related program interrupts in KVM Greg Kroah-Hartman
` (779 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Claudio Imbrenda, Janosch Frank,
Heiko Carstens, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
[ Upstream commit ca3c6dc3a9c520116deee7b74940835904e8ac07 ]
kvm_arch_fault_in_page() is a useless wrapper around gmap_fault(); just
use gmap_fault() directly instead.
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Link: https://lore.kernel.org/r/20241022120601.167009-3-imbrenda@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Stable-dep-of: 11709abccf93 ("s390/mm: Fix in_atomic() handling in do_secure_storage_access()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/kvm/intercept.c | 4 ++--
arch/s390/kvm/kvm-s390.c | 18 +-----------------
arch/s390/kvm/kvm-s390.h | 1 -
3 files changed, 3 insertions(+), 20 deletions(-)
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index f0be263b334ce..9c4304d484de7 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -367,7 +367,7 @@ static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
reg2, &srcaddr, GACC_FETCH, 0);
if (rc)
return kvm_s390_inject_prog_cond(vcpu, rc);
- rc = kvm_arch_fault_in_page(vcpu, srcaddr, 0);
+ rc = gmap_fault(vcpu->arch.gmap, srcaddr, 0);
if (rc != 0)
return rc;
@@ -376,7 +376,7 @@ static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
reg1, &dstaddr, GACC_STORE, 0);
if (rc)
return kvm_s390_inject_prog_cond(vcpu, rc);
- rc = kvm_arch_fault_in_page(vcpu, dstaddr, 1);
+ rc = gmap_fault(vcpu->arch.gmap, dstaddr, FAULT_FLAG_WRITE);
if (rc != 0)
return rc;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 0e3b8ee0ec264..61661e113873f 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -4582,22 +4582,6 @@ int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clo
return 1;
}
-/**
- * kvm_arch_fault_in_page - fault-in guest page if necessary
- * @vcpu: The corresponding virtual cpu
- * @gpa: Guest physical address
- * @writable: Whether the page should be writable or not
- *
- * Make sure that a guest page has been faulted-in on the host.
- *
- * Return: Zero on success, negative error code otherwise.
- */
-long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable)
-{
- return gmap_fault(vcpu->arch.gmap, gpa,
- writable ? FAULT_FLAG_WRITE : 0);
-}
-
static void __kvm_inject_pfault_token(struct kvm_vcpu *vcpu, bool start_token,
unsigned long token)
{
@@ -4800,7 +4784,7 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
if (kvm_arch_setup_async_pf(vcpu))
return 0;
vcpu->stat.pfault_sync++;
- return kvm_arch_fault_in_page(vcpu, current->thread.gmap_addr, 1);
+ return gmap_fault(vcpu->arch.gmap, current->thread.gmap_addr, FAULT_FLAG_WRITE);
}
return vcpu_post_run_fault_in_sie(vcpu);
}
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index e680c6bf0c9d9..0765ad1031c43 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -394,7 +394,6 @@ int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
/* implemented in kvm-s390.c */
int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);
-long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);
int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr);
int kvm_s390_vcpu_start(struct kvm_vcpu *vcpu);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 091/869] s390/mm/fault: Handle guest-related program interrupts in KVM
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (89 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 090/869] s390/kvm: Remove kvm_arch_fault_in_page() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 092/869] s390/mm: Simplify get_fault_type() Greg Kroah-Hartman
` (778 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Claudio Imbrenda, Heiko Carstens,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
[ Upstream commit 05066cafa925159c790904f39ddb17cfa0e96f35 ]
Any program interrupt that happens in the host during the execution of
a KVM guest will now short circuit the fault handler and return to KVM
immediately. Guest fault handling (including pfault) will happen
entirely inside KVM.
When sie64a() returns zero, current->thread.gmap_int_code will contain
the program interrupt number that caused the exit, or zero if the exit
was not caused by a host program interrupt.
KVM will now take care of handling all guest faults in vcpu_post_run().
Since gmap faults will not be visible by the rest of the kernel, remove
GMAP_FAULT, the linux fault handlers for secure execution faults, the
exception table entries for the sie instruction, the nop padding after
the sie instruction, and all other references to guest faults from the
s390 code.
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Co-developed-by: Heiko Carstens <hca@linux.ibm.com>
Link: https://lore.kernel.org/r/20241022120601.167009-6-imbrenda@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Stable-dep-of: 11709abccf93 ("s390/mm: Fix in_atomic() handling in do_secure_storage_access()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/include/asm/kvm_host.h | 3 +
arch/s390/include/asm/processor.h | 5 +-
arch/s390/kernel/entry.S | 24 +-----
arch/s390/kernel/traps.c | 24 ++++--
arch/s390/kvm/kvm-s390.c | 125 ++++++++++++++++++++++++------
arch/s390/kvm/kvm-s390.h | 7 ++
arch/s390/kvm/vsie.c | 13 ++--
arch/s390/mm/fault.c | 99 +----------------------
8 files changed, 143 insertions(+), 157 deletions(-)
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 8e77afbed58ec..603b56bfccd3b 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -527,6 +527,9 @@ struct kvm_vcpu_stat {
#define PGM_REGION_FIRST_TRANS 0x39
#define PGM_REGION_SECOND_TRANS 0x3a
#define PGM_REGION_THIRD_TRANS 0x3b
+#define PGM_SECURE_STORAGE_ACCESS 0x3d
+#define PGM_NON_SECURE_STORAGE_ACCESS 0x3e
+#define PGM_SECURE_STORAGE_VIOLATION 0x3f
#define PGM_MONITOR 0x40
#define PGM_PER 0x80
#define PGM_CRYPTO_OPERATION 0x119
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index ef622c3f88e50..6054d157a8f9a 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -39,6 +39,7 @@
#include <asm/runtime_instr.h>
#include <asm/irqflags.h>
#include <asm/alternative.h>
+#include <asm/fault.h>
struct pcpu {
unsigned long ec_mask; /* bit mask for ec_xxx functions */
@@ -186,10 +187,8 @@ struct thread_struct {
unsigned long hardirq_timer; /* task cputime in hardirq context */
unsigned long softirq_timer; /* task cputime in softirq context */
const sys_call_ptr_t *sys_call_table; /* system call table address */
- unsigned long gmap_addr; /* address of last gmap fault. */
- unsigned int gmap_write_flag; /* gmap fault write indication */
+ union teid gmap_teid; /* address and flags of last gmap fault */
unsigned int gmap_int_code; /* int code of last gmap fault */
- unsigned int gmap_pfault; /* signal of a pending guest pfault */
int ufpu_flags; /* user fpu flags */
int kfpu_flags; /* kernel fpu flags */
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 2245f562089e4..439950ddc416c 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -222,17 +222,6 @@ SYM_FUNC_START(__sie64a)
lctlg %c1,%c1,__LC_KERNEL_ASCE(%r14) # load primary asce
lg %r14,__LC_CURRENT(%r14)
mvi __TI_sie(%r14),0
-# some program checks are suppressing. C code (e.g. do_protection_exception)
-# will rewind the PSW by the ILC, which is often 4 bytes in case of SIE. There
-# are some corner cases (e.g. runtime instrumentation) where ILC is unpredictable.
-# Other instructions between __sie64a and .Lsie_done should not cause program
-# interrupts. So lets use 3 nops as a landing pad for all possible rewinds.
-.Lrewind_pad6:
- nopr 7
-.Lrewind_pad4:
- nopr 7
-.Lrewind_pad2:
- nopr 7
SYM_INNER_LABEL(sie_exit, SYM_L_GLOBAL)
lg %r14,__SF_SIE_SAVEAREA(%r15) # load guest register save area
stmg %r0,%r13,0(%r14) # save guest gprs 0-13
@@ -244,15 +233,6 @@ SYM_INNER_LABEL(sie_exit, SYM_L_GLOBAL)
lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
lg %r2,__SF_SIE_REASON(%r15) # return exit reason code
BR_EX %r14
-.Lsie_fault:
- lghi %r14,-EFAULT
- stg %r14,__SF_SIE_REASON(%r15) # set exit reason code
- j sie_exit
-
- EX_TABLE(.Lrewind_pad6,.Lsie_fault)
- EX_TABLE(.Lrewind_pad4,.Lsie_fault)
- EX_TABLE(.Lrewind_pad2,.Lsie_fault)
- EX_TABLE(sie_exit,.Lsie_fault)
SYM_FUNC_END(__sie64a)
EXPORT_SYMBOL(__sie64a)
EXPORT_SYMBOL(sie_exit)
@@ -330,7 +310,6 @@ SYM_CODE_START(pgm_check_handler)
BPOFF
lmg %r8,%r9,__LC_PGM_OLD_PSW(%r13)
xgr %r10,%r10
- xgr %r12,%r12
tmhh %r8,0x0001 # coming from user space?
jno .Lpgm_skip_asce
lctlg %c1,%c1,__LC_KERNEL_ASCE(%r13)
@@ -342,7 +321,6 @@ SYM_CODE_START(pgm_check_handler)
jz 1f
BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
SIEEXIT __SF_SIE_CONTROL(%r15),%r13
- lg %r12,__SF_SIE_GUEST_ASCE(%r15)
lghi %r10,_PIF_GUEST_FAULT
#endif
1: tmhh %r8,0x4000 # PER bit set in old PSW ?
@@ -356,7 +334,6 @@ SYM_CODE_START(pgm_check_handler)
3: lg %r15,__LC_KERNEL_STACK(%r13)
4: la %r11,STACK_FRAME_OVERHEAD(%r15)
stg %r10,__PT_FLAGS(%r11)
- stg %r12,__PT_CR1(%r11)
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
stmg %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA(%r13)
@@ -370,6 +347,7 @@ SYM_CODE_START(pgm_check_handler)
xgr %r5,%r5
xgr %r6,%r6
xgr %r7,%r7
+ xgr %r12,%r12
lgr %r2,%r11
brasl %r14,__do_pgm_check
tmhh %r8,0x0001 # returning to user space?
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 908bae8498435..b746213d3110c 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -31,6 +31,7 @@
#include <asm/asm-extable.h>
#include <asm/vtime.h>
#include <asm/fpu.h>
+#include <asm/fault.h>
#include "entry.h"
static inline void __user *get_trap_ip(struct pt_regs *regs)
@@ -317,9 +318,24 @@ void noinstr __do_pgm_check(struct pt_regs *regs)
struct lowcore *lc = get_lowcore();
irqentry_state_t state;
unsigned int trapnr;
+ union teid teid;
+ teid.val = lc->trans_exc_code;
regs->int_code = lc->pgm_int_code;
- regs->int_parm_long = lc->trans_exc_code;
+ regs->int_parm_long = teid.val;
+
+ /*
+ * In case of a guest fault, short-circuit the fault handler and return.
+ * This way the sie64a() function will return 0; fault address and
+ * other relevant bits are saved in current->thread.gmap_teid, and
+ * the fault number in current->thread.gmap_int_code. KVM will be
+ * able to use this information to handle the fault.
+ */
+ if (test_pt_regs_flag(regs, PIF_GUEST_FAULT)) {
+ current->thread.gmap_teid.val = regs->int_parm_long;
+ current->thread.gmap_int_code = regs->int_code & 0xffff;
+ return;
+ }
state = irqentry_enter(regs);
@@ -408,8 +424,8 @@ static void (*pgm_check_table[128])(struct pt_regs *regs) = {
[0x3b] = do_dat_exception,
[0x3c] = default_trap_handler,
[0x3d] = do_secure_storage_access,
- [0x3e] = do_non_secure_storage_access,
- [0x3f] = do_secure_storage_violation,
+ [0x3e] = default_trap_handler,
+ [0x3f] = default_trap_handler,
[0x40] = monitor_event_exception,
[0x41 ... 0x7f] = default_trap_handler,
};
@@ -420,5 +436,3 @@ static void (*pgm_check_table[128])(struct pt_regs *regs) = {
__stringify(default_trap_handler))
COND_TRAP(do_secure_storage_access);
-COND_TRAP(do_non_secure_storage_access);
-COND_TRAP(do_secure_storage_violation);
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 61661e113873f..885eedfc0af63 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -4649,12 +4649,11 @@ static bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu)
if (!vcpu->arch.gmap->pfault_enabled)
return false;
- hva = gfn_to_hva(vcpu->kvm, gpa_to_gfn(current->thread.gmap_addr));
- hva += current->thread.gmap_addr & ~PAGE_MASK;
+ hva = gfn_to_hva(vcpu->kvm, current->thread.gmap_teid.addr);
if (read_guest_real(vcpu, vcpu->arch.pfault_token, &arch.pfault_token, 8))
return false;
- return kvm_setup_async_pf(vcpu, current->thread.gmap_addr, hva, &arch);
+ return kvm_setup_async_pf(vcpu, current->thread.gmap_teid.addr * PAGE_SIZE, hva, &arch);
}
static int vcpu_pre_run(struct kvm_vcpu *vcpu)
@@ -4692,6 +4691,7 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu)
clear_bit(vcpu->vcpu_idx, vcpu->kvm->arch.gisa_int.kicked_mask);
vcpu->arch.sie_block->icptcode = 0;
+ current->thread.gmap_int_code = 0;
cpuflags = atomic_read(&vcpu->arch.sie_block->cpuflags);
VCPU_EVENT(vcpu, 6, "entering sie flags %x", cpuflags);
trace_kvm_s390_sie_enter(vcpu, cpuflags);
@@ -4699,7 +4699,7 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu)
return 0;
}
-static int vcpu_post_run_fault_in_sie(struct kvm_vcpu *vcpu)
+static int vcpu_post_run_addressing_exception(struct kvm_vcpu *vcpu)
{
struct kvm_s390_pgm_info pgm_info = {
.code = PGM_ADDRESSING,
@@ -4735,10 +4735,106 @@ static int vcpu_post_run_fault_in_sie(struct kvm_vcpu *vcpu)
return kvm_s390_inject_prog_irq(vcpu, &pgm_info);
}
+static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
+{
+ unsigned long gaddr;
+ unsigned int flags;
+ int rc = 0;
+
+ gaddr = current->thread.gmap_teid.addr * PAGE_SIZE;
+ if (kvm_s390_cur_gmap_fault_is_write())
+ flags = FAULT_FLAG_WRITE;
+
+ switch (current->thread.gmap_int_code) {
+ case 0:
+ vcpu->stat.exit_null++;
+ break;
+ case PGM_NON_SECURE_STORAGE_ACCESS:
+ KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm,
+ "Unexpected program interrupt 0x%x, TEID 0x%016lx",
+ current->thread.gmap_int_code, current->thread.gmap_teid.val);
+ /*
+ * This is normal operation; a page belonging to a protected
+ * guest has not been imported yet. Try to import the page into
+ * the protected guest.
+ */
+ if (gmap_convert_to_secure(vcpu->arch.gmap, gaddr) == -EINVAL)
+ send_sig(SIGSEGV, current, 0);
+ break;
+ case PGM_SECURE_STORAGE_ACCESS:
+ case PGM_SECURE_STORAGE_VIOLATION:
+ KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm,
+ "Unexpected program interrupt 0x%x, TEID 0x%016lx",
+ current->thread.gmap_int_code, current->thread.gmap_teid.val);
+ /*
+ * This can happen after a reboot with asynchronous teardown;
+ * the new guest (normal or protected) will run on top of the
+ * previous protected guest. The old pages need to be destroyed
+ * so the new guest can use them.
+ */
+ if (gmap_destroy_page(vcpu->arch.gmap, gaddr)) {
+ /*
+ * Either KVM messed up the secure guest mapping or the
+ * same page is mapped into multiple secure guests.
+ *
+ * This exception is only triggered when a guest 2 is
+ * running and can therefore never occur in kernel
+ * context.
+ */
+ pr_warn_ratelimited("Secure storage violation (%x) in task: %s, pid %d\n",
+ current->thread.gmap_int_code, current->comm,
+ current->pid);
+ send_sig(SIGSEGV, current, 0);
+ }
+ break;
+ case PGM_PROTECTION:
+ case PGM_SEGMENT_TRANSLATION:
+ case PGM_PAGE_TRANSLATION:
+ case PGM_ASCE_TYPE:
+ case PGM_REGION_FIRST_TRANS:
+ case PGM_REGION_SECOND_TRANS:
+ case PGM_REGION_THIRD_TRANS:
+ KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm,
+ "Unexpected program interrupt 0x%x, TEID 0x%016lx",
+ current->thread.gmap_int_code, current->thread.gmap_teid.val);
+ if (vcpu->arch.gmap->pfault_enabled) {
+ rc = gmap_fault(vcpu->arch.gmap, gaddr, flags | FAULT_FLAG_RETRY_NOWAIT);
+ if (rc == -EFAULT)
+ return vcpu_post_run_addressing_exception(vcpu);
+ if (rc == -EAGAIN) {
+ trace_kvm_s390_major_guest_pfault(vcpu);
+ if (kvm_arch_setup_async_pf(vcpu))
+ return 0;
+ vcpu->stat.pfault_sync++;
+ } else {
+ return rc;
+ }
+ }
+ rc = gmap_fault(vcpu->arch.gmap, gaddr, flags);
+ if (rc == -EFAULT) {
+ if (kvm_is_ucontrol(vcpu->kvm)) {
+ vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL;
+ vcpu->run->s390_ucontrol.trans_exc_code = gaddr;
+ vcpu->run->s390_ucontrol.pgm_code = 0x10;
+ return -EREMOTE;
+ }
+ return vcpu_post_run_addressing_exception(vcpu);
+ }
+ break;
+ default:
+ KVM_BUG(1, vcpu->kvm, "Unexpected program interrupt 0x%x, TEID 0x%016lx",
+ current->thread.gmap_int_code, current->thread.gmap_teid.val);
+ send_sig(SIGSEGV, current, 0);
+ break;
+ }
+ return rc;
+}
+
static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
{
struct mcck_volatile_info *mcck_info;
struct sie_page *sie_page;
+ int rc;
VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
vcpu->arch.sie_block->icptcode);
@@ -4760,7 +4856,7 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
}
if (vcpu->arch.sie_block->icptcode > 0) {
- int rc = kvm_handle_sie_intercept(vcpu);
+ rc = kvm_handle_sie_intercept(vcpu);
if (rc != -EOPNOTSUPP)
return rc;
@@ -4769,24 +4865,9 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
vcpu->run->s390_sieic.ipa = vcpu->arch.sie_block->ipa;
vcpu->run->s390_sieic.ipb = vcpu->arch.sie_block->ipb;
return -EREMOTE;
- } else if (exit_reason != -EFAULT) {
- vcpu->stat.exit_null++;
- return 0;
- } else if (kvm_is_ucontrol(vcpu->kvm)) {
- vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL;
- vcpu->run->s390_ucontrol.trans_exc_code =
- current->thread.gmap_addr;
- vcpu->run->s390_ucontrol.pgm_code = 0x10;
- return -EREMOTE;
- } else if (current->thread.gmap_pfault) {
- trace_kvm_s390_major_guest_pfault(vcpu);
- current->thread.gmap_pfault = 0;
- if (kvm_arch_setup_async_pf(vcpu))
- return 0;
- vcpu->stat.pfault_sync++;
- return gmap_fault(vcpu->arch.gmap, current->thread.gmap_addr, FAULT_FLAG_WRITE);
}
- return vcpu_post_run_fault_in_sie(vcpu);
+
+ return vcpu_post_run_handle_fault(vcpu);
}
#define PSW_INT_MASK (PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_MCHECK)
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 0765ad1031c43..597d7a71deebe 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -528,6 +528,13 @@ static inline int kvm_s390_use_sca_entries(void)
void kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu,
struct mcck_volatile_info *mcck_info);
+static inline bool kvm_s390_cur_gmap_fault_is_write(void)
+{
+ if (current->thread.gmap_int_code == PGM_PROTECTION)
+ return true;
+ return test_facility(75) && (current->thread.gmap_teid.fsi == TEID_FSI_STORE);
+}
+
/**
* kvm_s390_vcpu_crypto_reset_all
*
diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index 5b5e691b61ac6..44e25b2654a2d 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -926,16 +926,16 @@ static int handle_fault(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
if (current->thread.gmap_int_code == PGM_PROTECTION)
/* we can directly forward all protection exceptions */
return inject_fault(vcpu, PGM_PROTECTION,
- current->thread.gmap_addr, 1);
+ current->thread.gmap_teid.addr * PAGE_SIZE, 1);
rc = kvm_s390_shadow_fault(vcpu, vsie_page->gmap,
- current->thread.gmap_addr, NULL);
+ current->thread.gmap_teid.addr * PAGE_SIZE, NULL);
if (rc > 0) {
rc = inject_fault(vcpu, rc,
- current->thread.gmap_addr,
- current->thread.gmap_write_flag);
+ current->thread.gmap_teid.addr * PAGE_SIZE,
+ kvm_s390_cur_gmap_fault_is_write());
if (rc >= 0)
- vsie_page->fault_addr = current->thread.gmap_addr;
+ vsie_page->fault_addr = current->thread.gmap_teid.addr * PAGE_SIZE;
}
return rc;
}
@@ -1149,6 +1149,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
* also kick the vSIE.
*/
vcpu->arch.sie_block->prog0c |= PROG_IN_SIE;
+ current->thread.gmap_int_code = 0;
barrier();
if (!kvm_s390_vcpu_sie_inhibited(vcpu))
rc = sie64a(scb_s, vcpu->run->s.regs.gprs, gmap_get_enabled()->asce);
@@ -1173,7 +1174,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
if (rc > 0)
rc = 0; /* we could still have an icpt */
- else if (rc == -EFAULT)
+ else if (current->thread.gmap_int_code)
return handle_fault(vcpu, vsie_page);
switch (scb_s->icptcode) {
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index a6cf33b0f3390..e48910b0b8169 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -49,7 +49,6 @@
enum fault_type {
KERNEL_FAULT,
USER_FAULT,
- GMAP_FAULT,
};
static DEFINE_STATIC_KEY_FALSE(have_store_indication);
@@ -72,10 +71,6 @@ static enum fault_type get_fault_type(struct pt_regs *regs)
if (likely(teid.as == PSW_BITS_AS_PRIMARY)) {
if (user_mode(regs))
return USER_FAULT;
- if (!IS_ENABLED(CONFIG_PGSTE))
- return KERNEL_FAULT;
- if (test_pt_regs_flag(regs, PIF_GUEST_FAULT))
- return GMAP_FAULT;
return KERNEL_FAULT;
}
if (teid.as == PSW_BITS_AS_SECONDARY)
@@ -184,10 +179,6 @@ static void dump_fault_info(struct pt_regs *regs)
asce = get_lowcore()->user_asce.val;
pr_cont("user ");
break;
- case GMAP_FAULT:
- asce = regs->cr1;
- pr_cont("gmap ");
- break;
case KERNEL_FAULT:
asce = get_lowcore()->kernel_asce.val;
pr_cont("kernel ");
@@ -285,7 +276,6 @@ static void do_exception(struct pt_regs *regs, int access)
struct mm_struct *mm;
enum fault_type type;
unsigned int flags;
- struct gmap *gmap;
vm_fault_t fault;
bool is_write;
@@ -304,7 +294,6 @@ static void do_exception(struct pt_regs *regs, int access)
case KERNEL_FAULT:
return handle_fault_error_nolock(regs, 0);
case USER_FAULT:
- case GMAP_FAULT:
if (faulthandler_disabled() || !mm)
return handle_fault_error_nolock(regs, 0);
break;
@@ -348,18 +337,6 @@ static void do_exception(struct pt_regs *regs, int access)
}
lock_mmap:
mmap_read_lock(mm);
- gmap = NULL;
- if (IS_ENABLED(CONFIG_PGSTE) && type == GMAP_FAULT) {
- gmap = (struct gmap *)get_lowcore()->gmap;
- current->thread.gmap_addr = address;
- current->thread.gmap_write_flag = !!(flags & FAULT_FLAG_WRITE);
- current->thread.gmap_int_code = regs->int_code & 0xffff;
- address = __gmap_translate(gmap, address);
- if (address == -EFAULT)
- return handle_fault_error(regs, SEGV_MAPERR);
- if (gmap->pfault_enabled)
- flags |= FAULT_FLAG_RETRY_NOWAIT;
- }
retry:
vma = find_vma(mm, address);
if (!vma)
@@ -375,50 +352,22 @@ static void do_exception(struct pt_regs *regs, int access)
return handle_fault_error(regs, SEGV_ACCERR);
fault = handle_mm_fault(vma, address, flags, regs);
if (fault_signal_pending(fault, regs)) {
- if (flags & FAULT_FLAG_RETRY_NOWAIT)
- mmap_read_unlock(mm);
if (!user_mode(regs))
handle_fault_error_nolock(regs, 0);
return;
}
/* The fault is fully completed (including releasing mmap lock) */
- if (fault & VM_FAULT_COMPLETED) {
- if (gmap) {
- mmap_read_lock(mm);
- goto gmap;
- }
+ if (fault & VM_FAULT_COMPLETED)
return;
- }
if (unlikely(fault & VM_FAULT_ERROR)) {
mmap_read_unlock(mm);
goto error;
}
if (fault & VM_FAULT_RETRY) {
- if (IS_ENABLED(CONFIG_PGSTE) && gmap && (flags & FAULT_FLAG_RETRY_NOWAIT)) {
- /*
- * FAULT_FLAG_RETRY_NOWAIT has been set,
- * mmap_lock has not been released
- */
- current->thread.gmap_pfault = 1;
- return handle_fault_error(regs, 0);
- }
- flags &= ~FAULT_FLAG_RETRY_NOWAIT;
flags |= FAULT_FLAG_TRIED;
mmap_read_lock(mm);
goto retry;
}
-gmap:
- if (IS_ENABLED(CONFIG_PGSTE) && gmap) {
- address = __gmap_link(gmap, current->thread.gmap_addr,
- address);
- if (address == -EFAULT)
- return handle_fault_error(regs, SEGV_MAPERR);
- if (address == -ENOMEM) {
- fault = VM_FAULT_OOM;
- mmap_read_unlock(mm);
- goto error;
- }
- }
mmap_read_unlock(mm);
return;
error:
@@ -494,7 +443,6 @@ void do_secure_storage_access(struct pt_regs *regs)
struct folio_walk fw;
struct mm_struct *mm;
struct folio *folio;
- struct gmap *gmap;
int rc;
/*
@@ -520,15 +468,6 @@ void do_secure_storage_access(struct pt_regs *regs)
panic("Unexpected PGM 0x3d with TEID bit 61=0");
}
switch (get_fault_type(regs)) {
- case GMAP_FAULT:
- mm = current->mm;
- gmap = (struct gmap *)get_lowcore()->gmap;
- mmap_read_lock(mm);
- addr = __gmap_translate(gmap, addr);
- mmap_read_unlock(mm);
- if (IS_ERR_VALUE(addr))
- return handle_fault_error_nolock(regs, SEGV_MAPERR);
- fallthrough;
case USER_FAULT:
mm = current->mm;
mmap_read_lock(mm);
@@ -564,40 +503,4 @@ void do_secure_storage_access(struct pt_regs *regs)
}
NOKPROBE_SYMBOL(do_secure_storage_access);
-void do_non_secure_storage_access(struct pt_regs *regs)
-{
- struct gmap *gmap = (struct gmap *)get_lowcore()->gmap;
- unsigned long gaddr = get_fault_address(regs);
-
- if (WARN_ON_ONCE(get_fault_type(regs) != GMAP_FAULT))
- return handle_fault_error_nolock(regs, SEGV_MAPERR);
- if (gmap_convert_to_secure(gmap, gaddr) == -EINVAL)
- send_sig(SIGSEGV, current, 0);
-}
-NOKPROBE_SYMBOL(do_non_secure_storage_access);
-
-void do_secure_storage_violation(struct pt_regs *regs)
-{
- struct gmap *gmap = (struct gmap *)get_lowcore()->gmap;
- unsigned long gaddr = get_fault_address(regs);
-
- /*
- * If the VM has been rebooted, its address space might still contain
- * secure pages from the previous boot.
- * Clear the page so it can be reused.
- */
- if (!gmap_destroy_page(gmap, gaddr))
- return;
- /*
- * Either KVM messed up the secure guest mapping or the same
- * page is mapped into multiple secure guests.
- *
- * This exception is only triggered when a guest 2 is running
- * and can therefore never occur in kernel context.
- */
- pr_warn_ratelimited("Secure storage violation in task: %s, pid %d\n",
- current->comm, current->pid);
- send_sig(SIGSEGV, current, 0);
-}
-
#endif /* CONFIG_PGSTE */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 092/869] s390/mm: Simplify get_fault_type()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (90 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 091/869] s390/mm/fault: Handle guest-related program interrupts in KVM Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 093/869] s390/mm: Get rid of fault type switch statements Greg Kroah-Hartman
` (777 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alexander Gordeev, Heiko Carstens,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Carstens <hca@linux.ibm.com>
[ Upstream commit f76901d16008862035265037905fd84364c3d0ac ]
With the gmap code gone get_fault_type() can be simplified:
- every fault with user_mode(regs) == true must be a fault in user address
space
- every fault with user_mode(regs) == false is only a fault in user
address space if the used address space is the secondary address space
- every other fault is within the kernel address space
Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Link: https://lore.kernel.org/r/20241022120601.167009-10-imbrenda@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Stable-dep-of: 11709abccf93 ("s390/mm: Fix in_atomic() handling in do_secure_storage_access()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/mm/fault.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index e48910b0b8169..6e96fc7905fcc 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -68,17 +68,10 @@ static enum fault_type get_fault_type(struct pt_regs *regs)
{
union teid teid = { .val = regs->int_parm_long };
- if (likely(teid.as == PSW_BITS_AS_PRIMARY)) {
- if (user_mode(regs))
- return USER_FAULT;
- return KERNEL_FAULT;
- }
- if (teid.as == PSW_BITS_AS_SECONDARY)
+ if (user_mode(regs))
return USER_FAULT;
- /* Access register mode, not used in the kernel */
- if (teid.as == PSW_BITS_AS_ACCREG)
+ if (teid.as == PSW_BITS_AS_SECONDARY)
return USER_FAULT;
- /* Home space -> access via kernel ASCE */
return KERNEL_FAULT;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 093/869] s390/mm: Get rid of fault type switch statements
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (91 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 092/869] s390/mm: Simplify get_fault_type() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 094/869] s390/mm: Fix in_atomic() handling in do_secure_storage_access() Greg Kroah-Hartman
` (776 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alexander Gordeev, Heiko Carstens,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Carstens <hca@linux.ibm.com>
[ Upstream commit a12d622ad541b5db0cda36cc7f3ac89b4f9e5a2c ]
With GMAP_FAULT fault type gone, there are only KERNEL_FAULT and
USER_FAULT fault types left. Therefore there is no need for any fault
type switch statements left.
Rename get_fault_type() into is_kernel_fault() and let it return a
boolean value. Change all switch statements to if statements. This
removes quite a bit of code.
Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Link: https://lore.kernel.org/r/20241022120601.167009-11-imbrenda@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Stable-dep-of: 11709abccf93 ("s390/mm: Fix in_atomic() handling in do_secure_storage_access()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/mm/fault.c | 70 ++++++++++++++------------------------------
1 file changed, 22 insertions(+), 48 deletions(-)
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 6e96fc7905fcc..93ae097ef0e08 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -46,11 +46,6 @@
#include <asm/uv.h>
#include "../kernel/entry.h"
-enum fault_type {
- KERNEL_FAULT,
- USER_FAULT,
-};
-
static DEFINE_STATIC_KEY_FALSE(have_store_indication);
static int __init fault_init(void)
@@ -64,15 +59,15 @@ early_initcall(fault_init);
/*
* Find out which address space caused the exception.
*/
-static enum fault_type get_fault_type(struct pt_regs *regs)
+static bool is_kernel_fault(struct pt_regs *regs)
{
union teid teid = { .val = regs->int_parm_long };
if (user_mode(regs))
- return USER_FAULT;
+ return false;
if (teid.as == PSW_BITS_AS_SECONDARY)
- return USER_FAULT;
- return KERNEL_FAULT;
+ return false;
+ return true;
}
static unsigned long get_fault_address(struct pt_regs *regs)
@@ -167,17 +162,12 @@ static void dump_fault_info(struct pt_regs *regs)
break;
}
pr_cont("mode while using ");
- switch (get_fault_type(regs)) {
- case USER_FAULT:
- asce = get_lowcore()->user_asce.val;
- pr_cont("user ");
- break;
- case KERNEL_FAULT:
+ if (is_kernel_fault(regs)) {
asce = get_lowcore()->kernel_asce.val;
pr_cont("kernel ");
- break;
- default:
- unreachable();
+ } else {
+ asce = get_lowcore()->user_asce.val;
+ pr_cont("user ");
}
pr_cont("ASCE.\n");
dump_pagetable(asce, get_fault_address(regs));
@@ -212,7 +202,6 @@ static void do_sigsegv(struct pt_regs *regs, int si_code)
static void handle_fault_error_nolock(struct pt_regs *regs, int si_code)
{
- enum fault_type fault_type;
unsigned long address;
bool is_write;
@@ -223,17 +212,15 @@ static void handle_fault_error_nolock(struct pt_regs *regs, int si_code)
}
if (fixup_exception(regs))
return;
- fault_type = get_fault_type(regs);
- if (fault_type == KERNEL_FAULT) {
+ if (is_kernel_fault(regs)) {
address = get_fault_address(regs);
is_write = fault_is_write(regs);
if (kfence_handle_page_fault(address, is_write, regs))
return;
- }
- if (fault_type == KERNEL_FAULT)
pr_alert("Unable to handle kernel pointer dereference in virtual kernel address space\n");
- else
+ } else {
pr_alert("Unable to handle kernel paging request in virtual user address space\n");
+ }
dump_fault_info(regs);
die(regs, "Oops");
}
@@ -267,7 +254,6 @@ static void do_exception(struct pt_regs *regs, int access)
struct vm_area_struct *vma;
unsigned long address;
struct mm_struct *mm;
- enum fault_type type;
unsigned int flags;
vm_fault_t fault;
bool is_write;
@@ -282,15 +268,8 @@ static void do_exception(struct pt_regs *regs, int access)
mm = current->mm;
address = get_fault_address(regs);
is_write = fault_is_write(regs);
- type = get_fault_type(regs);
- switch (type) {
- case KERNEL_FAULT:
+ if (is_kernel_fault(regs) || faulthandler_disabled() || !mm)
return handle_fault_error_nolock(regs, 0);
- case USER_FAULT:
- if (faulthandler_disabled() || !mm)
- return handle_fault_error_nolock(regs, 0);
- break;
- }
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
flags = FAULT_FLAG_DEFAULT;
if (user_mode(regs))
@@ -460,8 +439,15 @@ void do_secure_storage_access(struct pt_regs *regs)
*/
panic("Unexpected PGM 0x3d with TEID bit 61=0");
}
- switch (get_fault_type(regs)) {
- case USER_FAULT:
+ if (is_kernel_fault(regs)) {
+ folio = phys_to_folio(addr);
+ if (unlikely(!folio_try_get(folio)))
+ return;
+ rc = arch_make_folio_accessible(folio);
+ folio_put(folio);
+ if (rc)
+ BUG();
+ } else {
mm = current->mm;
mmap_read_lock(mm);
vma = find_vma(mm, addr);
@@ -470,7 +456,7 @@ void do_secure_storage_access(struct pt_regs *regs)
folio = folio_walk_start(&fw, vma, addr, 0);
if (!folio) {
mmap_read_unlock(mm);
- break;
+ return;
}
/* arch_make_folio_accessible() needs a raised refcount. */
folio_get(folio);
@@ -480,18 +466,6 @@ void do_secure_storage_access(struct pt_regs *regs)
if (rc)
send_sig(SIGSEGV, current, 0);
mmap_read_unlock(mm);
- break;
- case KERNEL_FAULT:
- folio = phys_to_folio(addr);
- if (unlikely(!folio_try_get(folio)))
- break;
- rc = arch_make_folio_accessible(folio);
- folio_put(folio);
- if (rc)
- BUG();
- break;
- default:
- unreachable();
}
}
NOKPROBE_SYMBOL(do_secure_storage_access);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 094/869] s390/mm: Fix in_atomic() handling in do_secure_storage_access()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (92 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 093/869] s390/mm: Get rid of fault type switch statements Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 095/869] platform/x86/amd/pmf: Switch to platform_get_resource() and devm_ioremap_resource() Greg Kroah-Hartman
` (775 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Claudio Imbrenda, Alexander Gordeev,
Christian Borntraeger, Heiko Carstens, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Carstens <hca@linux.ibm.com>
[ Upstream commit 11709abccf93b08adde95ef313c300b0d4bc28f1 ]
Kernel user spaces accesses to not exported pages in atomic context
incorrectly try to resolve the page fault.
With debug options enabled call traces like this can be seen:
BUG: sleeping function called from invalid context at kernel/locking/rwsem.c:1523
in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 419074, name: qemu-system-s39
preempt_count: 1, expected: 0
RCU nest depth: 0, expected: 0
INFO: lockdep is turned off.
Preemption disabled at:
[<00000383ea47cfa2>] copy_page_from_iter_atomic+0xa2/0x8a0
CPU: 12 UID: 0 PID: 419074 Comm: qemu-system-s39
Tainted: G W 6.16.0-20250531.rc0.git0.69b3a602feac.63.fc42.s390x+debug #1 PREEMPT
Tainted: [W]=WARN
Hardware name: IBM 3931 A01 703 (LPAR)
Call Trace:
[<00000383e990d282>] dump_stack_lvl+0xa2/0xe8
[<00000383e99bf152>] __might_resched+0x292/0x2d0
[<00000383eaa7c374>] down_read+0x34/0x2d0
[<00000383e99432f8>] do_secure_storage_access+0x108/0x360
[<00000383eaa724b0>] __do_pgm_check+0x130/0x220
[<00000383eaa842e4>] pgm_check_handler+0x114/0x160
[<00000383ea47d028>] copy_page_from_iter_atomic+0x128/0x8a0
([<00000383ea47d016>] copy_page_from_iter_atomic+0x116/0x8a0)
[<00000383e9c45eae>] generic_perform_write+0x16e/0x310
[<00000383e9eb87f4>] ext4_buffered_write_iter+0x84/0x160
[<00000383e9da0de4>] vfs_write+0x1c4/0x460
[<00000383e9da123c>] ksys_write+0x7c/0x100
[<00000383eaa7284e>] __do_syscall+0x15e/0x280
[<00000383eaa8417e>] system_call+0x6e/0x90
INFO: lockdep is turned off.
It is not allowed to take the mmap_lock while in atomic context. Therefore
handle such a secure storage access fault as if the accessed page is not
mapped: the uaccess function will return -EFAULT, and the caller has to
deal with this. Usually this means that the access is retried in process
context, which allows to resolve the page fault (or in this case export the
page).
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Link: https://lore.kernel.org/r/20250603134936.1314139-1-hca@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/mm/fault.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 93ae097ef0e08..f907e916aa20d 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -448,6 +448,8 @@ void do_secure_storage_access(struct pt_regs *regs)
if (rc)
BUG();
} else {
+ if (faulthandler_disabled())
+ return handle_fault_error_nolock(regs, 0);
mm = current->mm;
mmap_read_lock(mm);
vma = find_vma(mm, addr);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 095/869] platform/x86/amd/pmf: Switch to platform_get_resource() and devm_ioremap_resource()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (93 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 094/869] s390/mm: Fix in_atomic() handling in do_secure_storage_access() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 096/869] platform/x86/amd: pmf: Use device managed allocations Greg Kroah-Hartman
` (774 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Patil Rajesh Reddy, Shyam Sundar S K,
Ilpo Järvinen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
[ Upstream commit ba6ad33d5c870d8b1d22388292c872ba4af98ea1 ]
Use platform_get_resource() to fetch the memory resource instead of
acpi_walk_resources() and devm_ioremap_resource() for mapping the
resources.
PS: We cannot use resource_size() here because it adds an extra byte to
round off the size. In the case of PMF ResourceTemplate(), this rounding
is already handled within the _CRS. Using resource_size() would increase
the resource size by 1, causing a mismatch with the length field and
leading to issues. Therefore, simply use end-start of the ACPI resource to
obtain the actual length.
Co-developed-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
Signed-off-by: Patil Rajesh Reddy <Patil.Reddy@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
Link: https://lore.kernel.org/r/20241104054829.620858-4-Shyam-sundar.S-k@amd.com
[ij: added a cast to resource_size_t printing]
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Keep the existing staged error unwinding after a policy mapping failure.
Also carry the callback mutex storage and its initialization and
destruction so the follow-up device-managed allocation conversion
applies cleanly without importing custom BIOS input support.
Stable-dep-of: d9db3a941270 ("platform/x86/amd: pmf: Use device managed allocations")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/platform/x86/amd/pmf/Kconfig | 1 +
drivers/platform/x86/amd/pmf/acpi.c | 46 +++++++++++----------------
drivers/platform/x86/amd/pmf/core.c | 2 ++
drivers/platform/x86/amd/pmf/pmf.h | 7 ++--
drivers/platform/x86/amd/pmf/tee-if.c | 8 ++---
5 files changed, 31 insertions(+), 33 deletions(-)
diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig
index f4fa8bd8bda83..99d67cdbd91e5 100644
--- a/drivers/platform/x86/amd/pmf/Kconfig
+++ b/drivers/platform/x86/amd/pmf/Kconfig
@@ -11,6 +11,7 @@ config AMD_PMF
select ACPI_PLATFORM_PROFILE
depends on TEE && AMDTEE
depends on AMD_SFH_HID
+ depends on HAS_IOMEM
help
This driver provides support for the AMD Platform Management Framework.
The goal is to enhance end user experience by making AMD PCs smarter,
diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c
index d5b496433d697..1b9c7acf0ddf5 100644
--- a/drivers/platform/x86/amd/pmf/acpi.c
+++ b/drivers/platform/x86/amd/pmf/acpi.c
@@ -433,37 +433,29 @@ int apmf_install_handler(struct amd_pmf_dev *pmf_dev)
return 0;
}
-static acpi_status apmf_walk_resources(struct acpi_resource *res, void *data)
+int apmf_check_smart_pc(struct amd_pmf_dev *pmf_dev)
{
- struct amd_pmf_dev *dev = data;
+ struct platform_device *pdev = to_platform_device(pmf_dev->dev);
- switch (res->type) {
- case ACPI_RESOURCE_TYPE_ADDRESS64:
- dev->policy_addr = res->data.address64.address.minimum;
- dev->policy_sz = res->data.address64.address.address_length;
- break;
- case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
- dev->policy_addr = res->data.fixed_memory32.address;
- dev->policy_sz = res->data.fixed_memory32.address_length;
- break;
- }
-
- if (!dev->policy_addr || dev->policy_sz > POLICY_BUF_MAX_SZ || dev->policy_sz == 0) {
- pr_err("Incorrect Policy params, possibly a SBIOS bug\n");
- return AE_ERROR;
+ pmf_dev->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!pmf_dev->res) {
+ dev_dbg(pmf_dev->dev, "Failed to get I/O memory resource\n");
+ return -EINVAL;
}
- return AE_OK;
-}
-
-int apmf_check_smart_pc(struct amd_pmf_dev *pmf_dev)
-{
- acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev);
- acpi_status status;
-
- status = acpi_walk_resources(ahandle, METHOD_NAME__CRS, apmf_walk_resources, pmf_dev);
- if (ACPI_FAILURE(status)) {
- dev_dbg(pmf_dev->dev, "acpi_walk_resources failed :%d\n", status);
+ pmf_dev->policy_addr = pmf_dev->res->start;
+ /*
+ * We cannot use resource_size() here because it adds an extra byte to round off the size.
+ * In the case of PMF ResourceTemplate(), this rounding is already handled within the _CRS.
+ * Using resource_size() would increase the resource size by 1, causing a mismatch with the
+ * length field and leading to issues. Therefore, simply use end-start of the ACPI resource
+ * to obtain the actual length.
+ */
+ pmf_dev->policy_sz = pmf_dev->res->end - pmf_dev->res->start;
+
+ if (!pmf_dev->policy_addr || pmf_dev->policy_sz > POLICY_BUF_MAX_SZ ||
+ pmf_dev->policy_sz == 0) {
+ dev_err(pmf_dev->dev, "Incorrect policy params, possibly a SBIOS bug\n");
return -EINVAL;
}
diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
index 2e352e475b562..e45a207c7425b 100644
--- a/drivers/platform/x86/amd/pmf/core.c
+++ b/drivers/platform/x86/amd/pmf/core.c
@@ -530,6 +530,7 @@ static int amd_pmf_probe(struct platform_device *pdev)
mutex_init(&dev->lock);
mutex_init(&dev->update_mutex);
+ mutex_init(&dev->cb_mutex);
amd_pmf_quirks_init(dev);
apmf_acpi_init(dev);
@@ -556,6 +557,7 @@ static void amd_pmf_remove(struct platform_device *pdev)
amd_pmf_dbgfs_unregister(dev);
mutex_destroy(&dev->lock);
mutex_destroy(&dev->update_mutex);
+ mutex_destroy(&dev->cb_mutex);
kfree(dev->buf);
}
diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
index b857ef4498903..8e9a07a082b78 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -13,6 +13,7 @@
#include <linux/acpi.h>
#include <linux/input.h>
+#include <linux/platform_device.h>
#include <linux/platform_profile.h>
#define POLICY_BUF_MAX_SZ 0x4b000
@@ -364,19 +365,21 @@ struct amd_pmf_dev {
/* Smart PC solution builder */
struct dentry *esbin;
unsigned char *policy_buf;
- u32 policy_sz;
+ resource_size_t policy_sz;
struct tee_context *tee_ctx;
struct tee_shm *fw_shm_pool;
u32 session_id;
void *shbuf;
struct delayed_work pb_work;
struct pmf_action_table *prev_data;
- u64 policy_addr;
+ resource_size_t policy_addr;
void __iomem *policy_base;
bool smart_pc_enabled;
u16 pmf_if_version;
struct input_dev *pmf_idev;
size_t mtable_size;
+ struct resource *res;
+ struct mutex cb_mutex;
};
struct apmf_sps_prop_granular_v2 {
diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c
index 6254423d05b06..0ddd76149425a 100644
--- a/drivers/platform/x86/amd/pmf/tee-if.c
+++ b/drivers/platform/x86/amd/pmf/tee-if.c
@@ -256,7 +256,7 @@ static int amd_pmf_invoke_cmd_init(struct amd_pmf_dev *dev)
return -ENODEV;
}
- dev_dbg(dev->dev, "Policy Binary size: %u bytes\n", dev->policy_sz);
+ dev_dbg(dev->dev, "Policy Binary size: %llu bytes\n", (unsigned long long)dev->policy_sz);
memset(dev->shbuf, 0, dev->policy_sz);
ta_sm = dev->shbuf;
in = &ta_sm->pmf_input.init_table;
@@ -528,9 +528,9 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
if (ret)
goto err_cancel_work;
- dev->policy_base = devm_ioremap(dev->dev, dev->policy_addr, dev->policy_sz);
- if (!dev->policy_base) {
- ret = -ENOMEM;
+ dev->policy_base = devm_ioremap_resource(dev->dev, dev->res);
+ if (IS_ERR(dev->policy_base)) {
+ ret = PTR_ERR(dev->policy_base);
goto err_free_dram_buf;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 096/869] platform/x86/amd: pmf: Use device managed allocations
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (94 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 095/869] platform/x86/amd/pmf: Switch to platform_get_resource() and devm_ioremap_resource() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 097/869] drm/rockchip: vop2: Consistently use dev_err_probe() Greg Kroah-Hartman
` (773 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Mario Limonciello,
Ilpo Järvinen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <mario.limonciello@amd.com>
[ Upstream commit d9db3a941270d92bbd1a6a6b54a10324484f2f2d ]
If setting up smart PC fails for any reason then this can lead to
a double free when unloading amd-pmf. This is because dev->buf was
freed but never set to NULL and is again freed in amd_pmf_remove().
To avoid subtle allocation bugs in failures leading to a double free
change all allocations into device managed allocations.
Fixes: 5b1122fc4995f ("platform/x86/amd/pmf: fix cleanup in amd_pmf_init_smart_pc()")
Link: https://lore.kernel.org/r/20250512211154.2510397-2-superm1@kernel.org
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Link: https://lore.kernel.org/r/20250522003457.1516679-2-superm1@kernel.org
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/platform/x86/amd/pmf/core.c | 3 +-
drivers/platform/x86/amd/pmf/tee-if.c | 56 ++++++++++-----------------
2 files changed, 22 insertions(+), 37 deletions(-)
diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
index e45a207c7425b..496fea1389fca 100644
--- a/drivers/platform/x86/amd/pmf/core.c
+++ b/drivers/platform/x86/amd/pmf/core.c
@@ -282,7 +282,7 @@ int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer)
dev_err(dev->dev, "Invalid CPU id: 0x%x", dev->cpu_id);
}
- dev->buf = kzalloc(dev->mtable_size, GFP_KERNEL);
+ dev->buf = devm_kzalloc(dev->dev, dev->mtable_size, GFP_KERNEL);
if (!dev->buf)
return -ENOMEM;
}
@@ -558,7 +558,6 @@ static void amd_pmf_remove(struct platform_device *pdev)
mutex_destroy(&dev->lock);
mutex_destroy(&dev->update_mutex);
mutex_destroy(&dev->cb_mutex);
- kfree(dev->buf);
}
static const struct attribute_group *amd_pmf_driver_groups[] = {
diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c
index 0ddd76149425a..7789d44c61c43 100644
--- a/drivers/platform/x86/amd/pmf/tee-if.c
+++ b/drivers/platform/x86/amd/pmf/tee-if.c
@@ -352,30 +352,28 @@ static ssize_t amd_pmf_get_pb_data(struct file *filp, const char __user *buf,
return -EINVAL;
/* re-alloc to the new buffer length of the policy binary */
- new_policy_buf = memdup_user(buf, length);
- if (IS_ERR(new_policy_buf))
- return PTR_ERR(new_policy_buf);
+ new_policy_buf = devm_kzalloc(dev->dev, length, GFP_KERNEL);
+ if (!new_policy_buf)
+ return -ENOMEM;
+
+ if (copy_from_user(new_policy_buf, buf, length)) {
+ devm_kfree(dev->dev, new_policy_buf);
+ return -EFAULT;
+ }
- kfree(dev->policy_buf);
+ devm_kfree(dev->dev, dev->policy_buf);
dev->policy_buf = new_policy_buf;
dev->policy_sz = length;
- if (!amd_pmf_pb_valid(dev)) {
- ret = -EINVAL;
- goto cleanup;
- }
+ if (!amd_pmf_pb_valid(dev))
+ return -EINVAL;
amd_pmf_hex_dump_pb(dev);
ret = amd_pmf_start_policy_engine(dev);
if (ret < 0)
- goto cleanup;
+ return ret;
return length;
-
-cleanup:
- kfree(dev->policy_buf);
- dev->policy_buf = NULL;
- return ret;
}
static const struct file_operations pb_fops = {
@@ -531,13 +529,13 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
dev->policy_base = devm_ioremap_resource(dev->dev, dev->res);
if (IS_ERR(dev->policy_base)) {
ret = PTR_ERR(dev->policy_base);
- goto err_free_dram_buf;
+ goto err_cancel_work;
}
- dev->policy_buf = kzalloc(dev->policy_sz, GFP_KERNEL);
+ dev->policy_buf = devm_kzalloc(dev->dev, dev->policy_sz, GFP_KERNEL);
if (!dev->policy_buf) {
ret = -ENOMEM;
- goto err_free_dram_buf;
+ goto err_cancel_work;
}
memcpy_fromio(dev->policy_buf, dev->policy_base, dev->policy_sz);
@@ -545,21 +543,21 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
if (!amd_pmf_pb_valid(dev)) {
dev_info(dev->dev, "No Smart PC policy present\n");
ret = -EINVAL;
- goto err_free_policy;
+ goto err_cancel_work;
}
amd_pmf_hex_dump_pb(dev);
- dev->prev_data = kzalloc(sizeof(*dev->prev_data), GFP_KERNEL);
+ dev->prev_data = devm_kzalloc(dev->dev, sizeof(*dev->prev_data), GFP_KERNEL);
if (!dev->prev_data) {
ret = -ENOMEM;
- goto err_free_policy;
+ goto err_cancel_work;
}
for (i = 0; i < ARRAY_SIZE(amd_pmf_ta_uuid); i++) {
ret = amd_pmf_tee_init(dev, &amd_pmf_ta_uuid[i]);
if (ret)
- goto err_free_prev_data;
+ goto err_cancel_work;
ret = amd_pmf_start_policy_engine(dev);
switch (ret) {
@@ -574,7 +572,7 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
default:
ret = -EINVAL;
amd_pmf_tee_deinit(dev);
- goto err_free_prev_data;
+ goto err_cancel_work;
}
if (status)
@@ -583,7 +581,7 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
if (!status && !pb_side_load) {
ret = -EINVAL;
- goto err_free_prev_data;
+ goto err_cancel_work;
}
if (pb_side_load)
@@ -599,12 +597,6 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
if (pb_side_load && dev->esbin)
amd_pmf_remove_pb(dev);
amd_pmf_tee_deinit(dev);
-err_free_prev_data:
- kfree(dev->prev_data);
-err_free_policy:
- kfree(dev->policy_buf);
-err_free_dram_buf:
- kfree(dev->buf);
err_cancel_work:
cancel_delayed_work_sync(&dev->pb_work);
@@ -620,11 +612,5 @@ void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev)
amd_pmf_remove_pb(dev);
cancel_delayed_work_sync(&dev->pb_work);
- kfree(dev->prev_data);
- dev->prev_data = NULL;
- kfree(dev->policy_buf);
- dev->policy_buf = NULL;
- kfree(dev->buf);
- dev->buf = NULL;
amd_pmf_tee_deinit(dev);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 097/869] drm/rockchip: vop2: Consistently use dev_err_probe()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (95 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 096/869] platform/x86/amd: pmf: Use device managed allocations Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 098/869] drm/rockchip: vop2: Register the primary plane and overlay plane separately Greg Kroah-Hartman
` (772 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Cristian Ciocaltea, Heiko Stuebner,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
[ Upstream commit b06d1ef3355571383cdb463cf0195b7a02efdfbf ]
Replace drm_err() calls in vop2_bind() and vop2_create_crtcs() with
dev_err_probe(), to simplify error handling and improve consistency.
Additionally, ensure the already existing dev_err_probe() invocations
pass drm->dev instead of dev as their first argument, so that we get the
actual reason in case of -EPROBE_DEFER errors:
platform display-subsystem: deferred probe pending: (reason unknown)
vs.
platform display-subsystem: deferred probe pending: rockchip-drm: <actual reason>
While at it, add the missing '\n' to some of the message strings.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20250223-vop2-hdmi1-disp-modes-v2-2-f4cec5e06fbe@collabora.com
Stable-dep-of: f9f68bf1d0ef ("drm/rockchip: vop2: fail cleanly if missing a primary plane for a video-port")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 83 +++++++++-----------
1 file changed, 37 insertions(+), 46 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 42521bd2ac16f..3654e74191adf 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -2806,10 +2806,9 @@ static int vop2_create_crtcs(struct vop2 *vop2)
snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id);
vp->dclk = devm_clk_get(vop2->dev, dclk_name);
- if (IS_ERR(vp->dclk)) {
- drm_err(vop2->drm, "failed to get %s\n", dclk_name);
- return PTR_ERR(vp->dclk);
- }
+ if (IS_ERR(vp->dclk))
+ return dev_err_probe(drm->dev, PTR_ERR(vp->dclk),
+ "failed to get %s\n", dclk_name);
np = of_graph_get_remote_node(dev->of_node, i, -1);
if (!np) {
@@ -2819,11 +2818,9 @@ static int vop2_create_crtcs(struct vop2 *vop2)
of_node_put(np);
port = of_graph_get_port_by_id(dev->of_node, i);
- if (!port) {
- drm_err(vop2->drm, "no port node found for video_port%d\n", i);
- return -ENOENT;
- }
-
+ if (!port)
+ return dev_err_probe(drm->dev, -ENOENT,
+ "no port node found for video_port%d\n", i);
vp->crtc.port = port;
nvps++;
}
@@ -2863,11 +2860,9 @@ static int vop2_create_crtcs(struct vop2 *vop2)
possible_crtcs = (1 << nvps) - 1;
ret = vop2_plane_init(vop2, win, possible_crtcs);
- if (ret) {
- drm_err(vop2->drm, "failed to init plane %s: %d\n",
- win->data->name, ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(drm->dev, ret, "failed to init plane %s\n",
+ win->data->name);
}
for (i = 0; i < vop2_data->nr_vps; i++) {
@@ -2881,10 +2876,9 @@ static int vop2_create_crtcs(struct vop2 *vop2)
ret = drm_crtc_init_with_planes(drm, &vp->crtc, plane, NULL,
&vop2_crtc_funcs,
"video_port%d", vp->id);
- if (ret) {
- drm_err(vop2->drm, "crtc init for video_port%d failed\n", i);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(drm->dev, ret,
+ "crtc init for video_port%d failed\n", i);
drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs);
@@ -3206,10 +3200,9 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
dev_set_drvdata(dev, vop2);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vop");
- if (!res) {
- drm_err(vop2->drm, "failed to get vop2 register byname\n");
- return -EINVAL;
- }
+ if (!res)
+ return dev_err_probe(drm->dev, -EINVAL,
+ "failed to get vop2 register byname\n");
vop2->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(vop2->regs))
@@ -3233,56 +3226,54 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
if (vop2_data->feature & VOP2_FEATURE_HAS_SYS_GRF) {
vop2->sys_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
if (IS_ERR(vop2->sys_grf))
- return dev_err_probe(dev, PTR_ERR(vop2->sys_grf), "cannot get sys_grf");
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->sys_grf),
+ "cannot get sys_grf\n");
}
if (vop2_data->feature & VOP2_FEATURE_HAS_VOP_GRF) {
vop2->vop_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vop-grf");
if (IS_ERR(vop2->vop_grf))
- return dev_err_probe(dev, PTR_ERR(vop2->vop_grf), "cannot get vop_grf");
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->vop_grf),
+ "cannot get vop_grf\n");
}
if (vop2_data->feature & VOP2_FEATURE_HAS_VO1_GRF) {
vop2->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vo1-grf");
if (IS_ERR(vop2->vo1_grf))
- return dev_err_probe(dev, PTR_ERR(vop2->vo1_grf), "cannot get vo1_grf");
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->vo1_grf),
+ "cannot get vo1_grf\n");
}
if (vop2_data->feature & VOP2_FEATURE_HAS_SYS_PMU) {
vop2->sys_pmu = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pmu");
if (IS_ERR(vop2->sys_pmu))
- return dev_err_probe(dev, PTR_ERR(vop2->sys_pmu), "cannot get sys_pmu");
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->sys_pmu),
+ "cannot get sys_pmu\n");
}
vop2->hclk = devm_clk_get(vop2->dev, "hclk");
- if (IS_ERR(vop2->hclk)) {
- drm_err(vop2->drm, "failed to get hclk source\n");
- return PTR_ERR(vop2->hclk);
- }
+ if (IS_ERR(vop2->hclk))
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->hclk),
+ "failed to get hclk source\n");
vop2->aclk = devm_clk_get(vop2->dev, "aclk");
- if (IS_ERR(vop2->aclk)) {
- drm_err(vop2->drm, "failed to get aclk source\n");
- return PTR_ERR(vop2->aclk);
- }
+ if (IS_ERR(vop2->aclk))
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->aclk),
+ "failed to get aclk source\n");
vop2->pclk = devm_clk_get_optional(vop2->dev, "pclk_vop");
- if (IS_ERR(vop2->pclk)) {
- drm_err(vop2->drm, "failed to get pclk source\n");
- return PTR_ERR(vop2->pclk);
- }
+ if (IS_ERR(vop2->pclk))
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->pclk),
+ "failed to get pclk source\n");
vop2->pll_hdmiphy0 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy0");
- if (IS_ERR(vop2->pll_hdmiphy0)) {
- drm_err(vop2->drm, "failed to get pll_hdmiphy0\n");
- return PTR_ERR(vop2->pll_hdmiphy0);
- }
+ if (IS_ERR(vop2->pll_hdmiphy0))
+ return dev_err_probe(drm->dev, PTR_ERR(vop2->pll_hdmiphy0),
+ "failed to get pll_hdmiphy0\n");
vop2->irq = platform_get_irq(pdev, 0);
- if (vop2->irq < 0) {
- drm_err(vop2->drm, "cannot find irq for vop2\n");
- return vop2->irq;
- }
+ if (vop2->irq < 0)
+ return dev_err_probe(drm->dev, vop2->irq, "cannot find irq for vop2\n");
mutex_init(&vop2->vop2_lock);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 098/869] drm/rockchip: vop2: Register the primary plane and overlay plane separately
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (96 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 097/869] drm/rockchip: vop2: Consistently use dev_err_probe() Greg Kroah-Hartman
@ 2026-10-17 15:48 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 099/869] drm/rockchip: vop2: fail cleanly if missing a primary plane for a video-port Greg Kroah-Hartman
` (771 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Andy Yan, Detlev Casanova,
Heiko Stuebner, Sasha Levin, Michael Riesch
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Yan <andy.yan@rock-chips.com>
[ Upstream commit 6fd4f8a26a21dd2075cfcc7eae3b9d440d886571 ]
In the upcoming VOP of rk3576, a Window cannot attach to all Video Ports,
so make sure all VP find it's suitable primary plane, then register the
remain windows as overlay plane will make code easier.
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
Tested-by: Michael Riesch <michael.riesch@wolfvision.net> # on RK3568
Tested-by: Detlev Casanova <detlev.casanova@collabora.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20250303034436.192400-2-andyshrk@163.com
Stable-dep-of: f9f68bf1d0ef ("drm/rockchip: vop2: fail cleanly if missing a primary plane for a video-port")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 97 ++++++++++++--------
1 file changed, 59 insertions(+), 38 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 3654e74191adf..b3dcb387fb972 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -2764,22 +2764,29 @@ static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win,
return 0;
}
-static struct vop2_video_port *find_vp_without_primary(struct vop2 *vop2)
+/*
+ * On RK3566 these windows don't have an independent
+ * framebuffer. They can only share/mirror the framebuffer
+ * with smart0, esmart0 and cluster0 respectively.
+ * And RK3566 share the same vop version with Rk3568, so we
+ * need to use soc_id for identification here.
+ */
+static bool vop2_is_mirror_win(struct vop2_win *win)
{
- int i;
-
- for (i = 0; i < vop2->data->nr_vps; i++) {
- struct vop2_video_port *vp = &vop2->vps[i];
-
- if (!vp->crtc.port)
- continue;
- if (vp->primary_plane)
- continue;
+ struct vop2 *vop2 = win->vop2;
- return vp;
+ if (vop2->data->soc_id == 3566) {
+ switch (win->data->phys_id) {
+ case ROCKCHIP_VOP2_SMART1:
+ case ROCKCHIP_VOP2_ESMART1:
+ case ROCKCHIP_VOP2_CLUSTER1:
+ return true;
+ default:
+ return false;
+ }
+ } else {
+ return false;
}
-
- return NULL;
}
static int vop2_create_crtcs(struct vop2 *vop2)
@@ -2790,7 +2797,9 @@ static int vop2_create_crtcs(struct vop2 *vop2)
struct drm_plane *plane;
struct device_node *port;
struct vop2_video_port *vp;
- int i, nvp, nvps = 0;
+ struct vop2_win *win;
+ u32 possible_crtcs;
+ int i, j, nvp, nvps = 0;
int ret;
for (i = 0; i < vop2_data->nr_vps; i++) {
@@ -2826,42 +2835,54 @@ static int vop2_create_crtcs(struct vop2 *vop2)
}
nvp = 0;
- for (i = 0; i < vop2->registered_num_wins; i++) {
- struct vop2_win *win = &vop2->win[i];
- u32 possible_crtcs = 0;
+ /* Register a primary plane for every crtc */
+ for (i = 0; i < vop2_data->nr_vps; i++) {
+ vp = &vop2->vps[i];
- if (vop2->data->soc_id == 3566) {
- /*
- * On RK3566 these windows don't have an independent
- * framebuffer. They share the framebuffer with smart0,
- * esmart0 and cluster0 respectively.
- */
- switch (win->data->phys_id) {
- case ROCKCHIP_VOP2_SMART1:
- case ROCKCHIP_VOP2_ESMART1:
- case ROCKCHIP_VOP2_CLUSTER1:
+ if (!vp->crtc.port)
+ continue;
+
+ for (j = 0; j < vop2->registered_num_wins; j++) {
+ win = &vop2->win[j];
+
+ /* Aready registered as primary plane */
+ if (win->base.type == DRM_PLANE_TYPE_PRIMARY)
continue;
- }
- }
- if (win->type == DRM_PLANE_TYPE_PRIMARY) {
- vp = find_vp_without_primary(vop2);
- if (vp) {
+ if (vop2_is_mirror_win(win))
+ continue;
+
+ if (win->type == DRM_PLANE_TYPE_PRIMARY) {
possible_crtcs = BIT(nvp);
vp->primary_plane = win;
+ ret = vop2_plane_init(vop2, win, possible_crtcs);
+ if (ret)
+ return dev_err_probe(drm->dev, ret,
+ "failed to init primary plane %s\n",
+ win->data->name);
nvp++;
- } else {
- /* change the unused primary window to overlay window */
- win->type = DRM_PLANE_TYPE_OVERLAY;
+ break;
}
}
+ }
+
+ /* Register all unused window as overlay plane */
+ for (i = 0; i < vop2->registered_num_wins; i++) {
+ win = &vop2->win[i];
+
+ /* Aready registered as primary plane */
+ if (win->base.type == DRM_PLANE_TYPE_PRIMARY)
+ continue;
+
+ if (vop2_is_mirror_win(win))
+ continue;
- if (win->type == DRM_PLANE_TYPE_OVERLAY)
- possible_crtcs = (1 << nvps) - 1;
+ win->type = DRM_PLANE_TYPE_OVERLAY;
+ possible_crtcs = (1 << nvps) - 1;
ret = vop2_plane_init(vop2, win, possible_crtcs);
if (ret)
- return dev_err_probe(drm->dev, ret, "failed to init plane %s\n",
+ return dev_err_probe(drm->dev, ret, "failed to init overlay plane %s\n",
win->data->name);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 099/869] drm/rockchip: vop2: fail cleanly if missing a primary plane for a video-port
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (97 preceding siblings ...)
2026-10-17 15:48 ` [PATCH 6.12 098/869] drm/rockchip: vop2: Register the primary plane and overlay plane separately Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 100/869] wifi: ath12k: Pass ab pointer directly to ath12k_dp_tx_get_encap_type() Greg Kroah-Hartman
` (770 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Andy Yan, Heiko Stuebner,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Stuebner <heiko@sntech.de>
[ Upstream commit f9f68bf1d0efeadb6c427c9dbb30f307a7def19b ]
Each window of a vop2 is usable by a specific set of video ports, so while
binding the vop2, we look through the list of available windows trying to
find one designated as primary-plane and usable by that specific port.
The code later wants to use drm_crtc_init_with_planes with that found
primary plane, but nothing has checked so far if a primary plane was
actually found.
For whatever reason, the rk3576 vp2 does not have a usable primary window
(if vp0 is also in use) which brought the issue to light and ended in a
null-pointer dereference further down.
As we expect a primary-plane to exist for a video-port, add a check at
the end of the window-iteration and fail probing if none was found.
Fixes: 604be85547ce ("drm/rockchip: Add VOP2 driver")
Reviewed-by: Andy Yan <andy.yan@rock-chips.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Link: https://lore.kernel.org/r/20250610212748.1062375-1-heiko@sntech.de
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index b3dcb387fb972..e3a65056c9c56 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -2864,6 +2864,10 @@ static int vop2_create_crtcs(struct vop2 *vop2)
break;
}
}
+
+ if (!vp->primary_plane)
+ return dev_err_probe(drm->dev, -ENOENT,
+ "no primary plane for vp %d\n", i);
}
/* Register all unused window as overlay plane */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 100/869] wifi: ath12k: Pass ab pointer directly to ath12k_dp_tx_get_encap_type()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (98 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 099/869] drm/rockchip: vop2: fail cleanly if missing a primary plane for a video-port Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 101/869] rv: Remove trailing whitespace from tracepoint string Greg Kroah-Hartman
` (769 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Tamizh Chelvam Raja,
Vasanthakumar Thiagarajan, Jeff Johnson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
[ Upstream commit 05062834350f0bf7ad1abcebc2807220e90220eb ]
In ath12k_dp_tx_get_encap_type(), the arvif parameter is only used to
retrieve the ab pointer. In vdev delete sequence the arvif->ar could
become NULL and that would trigger kernel panic.
Since the caller ath12k_dp_tx() already has a valid ab pointer, pass it
directly to avoid panic and unnecessary dereferencing.
PC points to "ath12k_dp_tx+0x228/0x988 [ath12k]"
LR points to "ath12k_dp_tx+0xc8/0x988 [ath12k]".
The Backtrace obtained is as follows:
ath12k_dp_tx+0x228/0x988 [ath12k]
ath12k_mac_tx_check_max_limit+0x608/0x920 [ath12k]
ieee80211_process_measurement_req+0x320/0x348 [mac80211]
ieee80211_tx_dequeue+0x9ac/0x1518 [mac80211]
ieee80211_tx_dequeue+0xb14/0x1518 [mac80211]
ieee80211_tx_prepare_skb+0x224/0x254 [mac80211]
ieee80211_xmit+0xec/0x100 [mac80211]
__ieee80211_subif_start_xmit+0xc50/0xf40 [mac80211]
ieee80211_subif_start_xmit+0x2e8/0x308 [mac80211]
netdev_start_xmit+0x150/0x18c
dev_hard_start_xmit+0x74/0xc0
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00173-QCAHKSWPL_SILICONZ-1
Fixes: e93bbd65547e ("wifi: ath12k: fix packets are sent in native wifi mode while we set raw mode")
Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250606044936.3989400-1-tamizh.raja@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath12k/dp_tx.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c
index 21e07b5cee570..f08ab5a4112c0 100644
--- a/drivers/net/wireless/ath/ath12k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
@@ -10,10 +10,9 @@
#include "hw.h"
static enum hal_tcl_encap_type
-ath12k_dp_tx_get_encap_type(struct ath12k_vif *arvif, struct sk_buff *skb)
+ath12k_dp_tx_get_encap_type(struct ath12k_base *ab, struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ath12k_base *ab = arvif->ar->ab;
if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags))
return HAL_TCL_ENCAP_TYPE_RAW;
@@ -289,7 +288,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
msdu_ext_desc = true;
}
- ti.encap_type = ath12k_dp_tx_get_encap_type(arvif, skb);
+ ti.encap_type = ath12k_dp_tx_get_encap_type(ab, skb);
ti.addr_search_flags = arvif->hal_addr_search_flags;
ti.search_type = arvif->search_type;
ti.type = HAL_TCL_DESC_TYPE_BUFFER;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 101/869] rv: Remove trailing whitespace from tracepoint string
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (99 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 100/869] wifi: ath12k: Pass ab pointer directly to ath12k_dp_tx_get_encap_type() Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 102/869] rv: Use strings in da monitors tracepoints Greg Kroah-Hartman
` (768 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Masami Hiramatsu, Ingo Molnar,
Peter Zijlstra, Tomas Glozar, Juri Lelli, Clark Williams,
John Kacur, Nam Cao, Gabriele Monaco, Steven Rostedt (Google),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gabriele Monaco <gmonaco@redhat.com>
[ Upstream commit 7b70ac4cad2b20eaf415276bbaa0d9df9abb428c ]
RV event tracepoints print a line with the format:
"event_xyz: S0 x event -> S1 "
"event_xyz: S1 x event -> S0 (final)"
While printing an event leading to a non-final state, the line
has a trailing white space (visible above before the closing ").
Adapt the format string not to print the trailing whitespace if we are
not printing "(final)".
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Tomas Glozar <tglozar@redhat.com>
Cc: Juri Lelli <jlelli@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Link: https://lore.kernel.org/20250728135022.255578-3-gmonaco@redhat.com
Reviewed-by: Nam Cao <namcao@linutronix.de>
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Stable-dep-of: 7f904ff6e58d ("rv: Use strings in da monitors tracepoints")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/trace/events/rv.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/include/trace/events/rv.h b/include/trace/events/rv.h
index 56592da9301c0..17bab55546fad 100644
--- a/include/trace/events/rv.h
+++ b/include/trace/events/rv.h
@@ -29,11 +29,11 @@ DECLARE_EVENT_CLASS(event_da_monitor,
__entry->final_state = final_state;
),
- TP_printk("%s x %s -> %s %s",
+ TP_printk("%s x %s -> %s%s",
__entry->state,
__entry->event,
__entry->next_state,
- __entry->final_state ? "(final)" : "")
+ __entry->final_state ? " (final)" : "")
);
DECLARE_EVENT_CLASS(error_da_monitor,
@@ -91,12 +91,12 @@ DECLARE_EVENT_CLASS(event_da_monitor_id,
__entry->final_state = final_state;
),
- TP_printk("%d: %s x %s -> %s %s",
+ TP_printk("%d: %s x %s -> %s%s",
__entry->id,
__entry->state,
__entry->event,
__entry->next_state,
- __entry->final_state ? "(final)" : "")
+ __entry->final_state ? " (final)" : "")
);
DECLARE_EVENT_CLASS(error_da_monitor_id,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 102/869] rv: Use strings in da monitors tracepoints
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (100 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 101/869] rv: Remove trailing whitespace from tracepoint string Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 103/869] wifi: iwlwifi: return ERR_PTR from opmode start() Greg Kroah-Hartman
` (767 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Masami Hiramatsu, Ingo Molnar,
Peter Zijlstra, Tomas Glozar, Juri Lelli, Clark Williams,
John Kacur, Nam Cao, Gabriele Monaco, Steven Rostedt (Google),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gabriele Monaco <gmonaco@redhat.com>
[ Upstream commit 7f904ff6e58d398c4336f3c19c42b338324451f7 ]
Using DA monitors tracepoints with KASAN enabled triggers the following
warning:
BUG: KASAN: global-out-of-bounds in do_trace_event_raw_event_event_da_monitor+0xd6/0x1a0
Read of size 32 at addr ffffffffaada8980 by task ...
Call Trace:
<TASK>
[...]
do_trace_event_raw_event_event_da_monitor+0xd6/0x1a0
? __pfx_do_trace_event_raw_event_event_da_monitor+0x10/0x10
? trace_event_sncid+0x83/0x200
trace_event_sncid+0x163/0x200
[...]
The buggy address belongs to the variable:
automaton_snep+0x4e0/0x5e0
This is caused by the tracepoints reading 32 bytes __array instead of
__string from the automata definition. Such strings are literals and
reading 32 bytes ends up in out of bound memory accesses (e.g. the next
automaton's data in this case).
The error is harmless as, while printing the string, we stop at the null
terminator, but it should still be fixed.
Use the __string facilities while defining the tracepoints to avoid
reading out of bound memory.
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Tomas Glozar <tglozar@redhat.com>
Cc: Juri Lelli <jlelli@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Link: https://lore.kernel.org/20250728135022.255578-4-gmonaco@redhat.com
Fixes: 792575348ff7 ("rv/include: Add deterministic automata monitor definition via C macros")
Reviewed-by: Nam Cao <namcao@linutronix.de>
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/trace/events/rv.h | 76 +++++++++++++++++++--------------------
1 file changed, 38 insertions(+), 38 deletions(-)
diff --git a/include/trace/events/rv.h b/include/trace/events/rv.h
index 17bab55546fad..add8b64a11045 100644
--- a/include/trace/events/rv.h
+++ b/include/trace/events/rv.h
@@ -16,23 +16,23 @@ DECLARE_EVENT_CLASS(event_da_monitor,
TP_ARGS(state, event, next_state, final_state),
TP_STRUCT__entry(
- __array( char, state, MAX_DA_NAME_LEN )
- __array( char, event, MAX_DA_NAME_LEN )
- __array( char, next_state, MAX_DA_NAME_LEN )
- __field( bool, final_state )
+ __string( state, state )
+ __string( event, event )
+ __string( next_state, next_state )
+ __field( bool, final_state )
),
TP_fast_assign(
- memcpy(__entry->state, state, MAX_DA_NAME_LEN);
- memcpy(__entry->event, event, MAX_DA_NAME_LEN);
- memcpy(__entry->next_state, next_state, MAX_DA_NAME_LEN);
- __entry->final_state = final_state;
+ __assign_str(state);
+ __assign_str(event);
+ __assign_str(next_state);
+ __entry->final_state = final_state;
),
TP_printk("%s x %s -> %s%s",
- __entry->state,
- __entry->event,
- __entry->next_state,
+ __get_str(state),
+ __get_str(event),
+ __get_str(next_state),
__entry->final_state ? " (final)" : "")
);
@@ -43,18 +43,18 @@ DECLARE_EVENT_CLASS(error_da_monitor,
TP_ARGS(state, event),
TP_STRUCT__entry(
- __array( char, state, MAX_DA_NAME_LEN )
- __array( char, event, MAX_DA_NAME_LEN )
+ __string( state, state )
+ __string( event, event )
),
TP_fast_assign(
- memcpy(__entry->state, state, MAX_DA_NAME_LEN);
- memcpy(__entry->event, event, MAX_DA_NAME_LEN);
+ __assign_str(state);
+ __assign_str(event);
),
TP_printk("event %s not expected in the state %s",
- __entry->event,
- __entry->state)
+ __get_str(event),
+ __get_str(state))
);
#ifdef CONFIG_RV_MON_WIP
@@ -76,26 +76,26 @@ DECLARE_EVENT_CLASS(event_da_monitor_id,
TP_ARGS(id, state, event, next_state, final_state),
TP_STRUCT__entry(
- __field( int, id )
- __array( char, state, MAX_DA_NAME_LEN )
- __array( char, event, MAX_DA_NAME_LEN )
- __array( char, next_state, MAX_DA_NAME_LEN )
- __field( bool, final_state )
+ __field( int, id )
+ __string( state, state )
+ __string( event, event )
+ __string( next_state, next_state )
+ __field( bool, final_state )
),
TP_fast_assign(
- memcpy(__entry->state, state, MAX_DA_NAME_LEN);
- memcpy(__entry->event, event, MAX_DA_NAME_LEN);
- memcpy(__entry->next_state, next_state, MAX_DA_NAME_LEN);
- __entry->id = id;
- __entry->final_state = final_state;
+ __assign_str(state);
+ __assign_str(event);
+ __assign_str(next_state);
+ __entry->id = id;
+ __entry->final_state = final_state;
),
TP_printk("%d: %s x %s -> %s%s",
__entry->id,
- __entry->state,
- __entry->event,
- __entry->next_state,
+ __get_str(state),
+ __get_str(event),
+ __get_str(next_state),
__entry->final_state ? " (final)" : "")
);
@@ -106,21 +106,21 @@ DECLARE_EVENT_CLASS(error_da_monitor_id,
TP_ARGS(id, state, event),
TP_STRUCT__entry(
- __field( int, id )
- __array( char, state, MAX_DA_NAME_LEN )
- __array( char, event, MAX_DA_NAME_LEN )
+ __field( int, id )
+ __string( state, state )
+ __string( event, event )
),
TP_fast_assign(
- memcpy(__entry->state, state, MAX_DA_NAME_LEN);
- memcpy(__entry->event, event, MAX_DA_NAME_LEN);
- __entry->id = id;
+ __assign_str(state);
+ __assign_str(event);
+ __entry->id = id;
),
TP_printk("%d: event %s not expected in the state %s",
__entry->id,
- __entry->event,
- __entry->state)
+ __get_str(event),
+ __get_str(state))
);
#ifdef CONFIG_RV_MON_WWNR
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 103/869] wifi: iwlwifi: return ERR_PTR from opmode start()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (101 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 102/869] rv: Use strings in da monitors tracepoints Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 104/869] wifi: iwlwifi: Fix error code in iwl_op_mode_dvm_start() Greg Kroah-Hartman
` (766 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johannes Berg, Miri Korenblit,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Berg <johannes.berg@intel.com>
[ Upstream commit 8b0fc79f9e5b49a1ab27b53edc64d9ffbceeb312 ]
In order to restrict the retry loops for timeouts, first
pass the error code up using ERR_PTR(). This of course
requires all existing functions to be updated accordingly.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20241227095718.3fe5031d5784.I7307996c91dac69619ff9c616b8a077423fac19f@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Stable-dep-of: cf80c02a9fdb ("wifi: iwlwifi: Fix error code in iwl_op_mode_dvm_start()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/intel/iwlwifi/dvm/main.c | 34 ++++++++++++-------
drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 24 +++++++++----
3 files changed, 40 insertions(+), 20 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
index b8713ebd71908..bc065c7089f71 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
@@ -1245,7 +1245,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
STATISTICS_NOTIFICATION,
REPLY_TX,
};
- int i;
+ int i, err;
/************************
* 1. Allocating HW data
@@ -1253,6 +1253,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
hw = iwl_alloc_all();
if (!hw) {
pr_err("%s: Cannot allocate network device\n", trans->name);
+ err = -ENOMEM;
goto out;
}
@@ -1303,8 +1304,10 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
break;
}
- if (WARN_ON(!priv->lib))
+ if (WARN_ON(!priv->lib)) {
+ err = -ENODEV;
goto out_free_hw;
+ }
/*
* Populate the state variables that the transport layer needs
@@ -1381,12 +1384,14 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
IWL_INFO(priv, "Detected %s, REV=0x%X\n",
priv->trans->name, priv->trans->hw_rev);
- if (iwl_trans_start_hw(priv->trans))
+ err = iwl_trans_start_hw(priv->trans);
+ if (err)
goto out_free_hw;
/* Read the EEPROM */
- if (iwl_read_eeprom(priv->trans, &priv->eeprom_blob,
- &priv->eeprom_blob_size)) {
+ err = iwl_read_eeprom(priv->trans, &priv->eeprom_blob,
+ &priv->eeprom_blob_size);
+ if (err) {
IWL_ERR(priv, "Unable to init EEPROM\n");
goto out_free_hw;
}
@@ -1397,13 +1402,17 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
priv->nvm_data = iwl_parse_eeprom_data(priv->trans, priv->cfg,
priv->eeprom_blob,
priv->eeprom_blob_size);
- if (!priv->nvm_data)
+ if (!priv->nvm_data) {
+ err = -ENOMEM;
goto out_free_eeprom_blob;
+ }
- if (iwl_nvm_check_version(priv->nvm_data, priv->trans))
+ err = iwl_nvm_check_version(priv->nvm_data, priv->trans);
+ if (err)
goto out_free_eeprom;
- if (iwl_eeprom_init_hw_params(priv))
+ err = iwl_eeprom_init_hw_params(priv);
+ if (err)
goto out_free_eeprom;
/* extract MAC Address */
@@ -1450,7 +1459,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
atomic_set(&priv->queue_stop_count[i], 0);
}
- if (iwl_init_drv(priv))
+ err = iwl_init_drv(priv);
+ if (err)
goto out_free_eeprom;
/* At this point both hw and priv are initialized. */
@@ -1486,7 +1496,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
*
* 7. Setup and register with mac80211 and debugfs
**************************************************/
- if (iwlagn_mac_setup_register(priv, &fw->ucode_capa))
+ err = iwlagn_mac_setup_register(priv, &fw->ucode_capa);
+ if (err)
goto out_destroy_workqueue;
iwl_dbgfs_register(priv, dbgfs_dir);
@@ -1507,8 +1518,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
out_free_hw:
ieee80211_free_hw(priv->hw);
out:
- op_mode = NULL;
- return op_mode;
+ return ERR_PTR(err);
}
static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index c7c21c79a7436..8654f17a1eb86 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1438,7 +1438,7 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op)
op_mode = ops->start(drv->trans, drv->trans->cfg,
&drv->fw, dbgfs_dir);
- if (op_mode)
+ if (!IS_ERR(op_mode))
return op_mode;
if (test_bit(STATUS_TRANS_DEAD, &drv->trans->status))
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 96de7edf17929..52fd6b2093c9c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -1287,6 +1287,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
size_t scan_size;
u32 min_backoff;
struct iwl_mvm_csme_conn_info *csme_conn_info __maybe_unused;
+ int err;
/*
* We use IWL_STATION_COUNT_MAX to check the validity of the station
@@ -1304,7 +1305,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_mvm_has_mld_api(fw) ? &iwl_mvm_mld_hw_ops :
&iwl_mvm_hw_ops);
if (!hw)
- return NULL;
+ return ERR_PTR(-ENOMEM);
if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
max_agg = 512;
@@ -1348,8 +1349,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
trans->rx_mpdu_cmd_hdr_size =
sizeof(struct iwl_rx_mpdu_res_start);
- if (WARN_ON(trans->num_rx_queues > 1))
+ if (WARN_ON(trans->num_rx_queues > 1)) {
+ err = -EINVAL;
goto out_free;
+ }
}
mvm->fw_restart = iwlwifi_mod_params.fw_restart ? -1 : 0;
@@ -1426,8 +1429,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_fw_lookup_notif_ver(mvm->fw, LOCATION_GROUP,
TOF_RANGE_RESPONSE_NOTIF, 5);
/* we only support up to version 9 */
- if (WARN_ON_ONCE(mvm->cmd_ver.range_resp > 9))
+ if (WARN_ON_ONCE(mvm->cmd_ver.range_resp > 9)) {
+ err = -EINVAL;
goto out_free;
+ }
/*
* Populate the state variables that the transport layer needs
@@ -1490,6 +1495,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->phy_db = iwl_phy_db_init(trans);
if (!mvm->phy_db) {
IWL_ERR(mvm, "Cannot init phy_db\n");
+ err = -ENOMEM;
goto out_free;
}
@@ -1502,8 +1508,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
scan_size = iwl_mvm_scan_size(mvm);
mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL);
- if (!mvm->scan_cmd)
+ if (!mvm->scan_cmd) {
+ err = -ENOMEM;
goto out_free;
+ }
mvm->scan_cmd_size = scan_size;
/* invalidate ids to prevent accidental removal of sta_id 0 */
@@ -1532,7 +1540,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_mvm_mei_scan_filter_init(&mvm->mei_scan_filter);
- if (iwl_mvm_start_get_nvm(mvm)) {
+ err = iwl_mvm_start_get_nvm(mvm);
+ if (err) {
/*
* Getting NVM failed while CSME is the owner, but we are
* registered to MEI, we'll get the NVM later when it'll be
@@ -1545,7 +1554,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
}
- if (iwl_mvm_start_post_nvm(mvm))
+ err = iwl_mvm_start_post_nvm(mvm);
+ if (err)
goto out_thermal_exit;
return op_mode;
@@ -1565,7 +1575,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_trans_op_mode_leave(trans);
ieee80211_free_hw(mvm->hw);
- return NULL;
+ return ERR_PTR(err);
}
void iwl_mvm_stop_device(struct iwl_mvm *mvm)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 104/869] wifi: iwlwifi: Fix error code in iwl_op_mode_dvm_start()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (102 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 103/869] wifi: iwlwifi: return ERR_PTR from opmode start() Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 105/869] net/sched: Fix backlog accounting in qdisc_dequeue_internal Greg Kroah-Hartman
` (765 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dan Carpenter, Miri Korenblit,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <dan.carpenter@linaro.org>
[ Upstream commit cf80c02a9fdb6c5bc8508beb6a0f6a1294fc32f6 ]
Preserve the error code if iwl_setup_deferred_work() fails. The current
code returns ERR_PTR(0) (which is NULL) on this path. I believe the
missing error code potentially leads to a use after free involving
debugfs.
Fixes: 90a0d9f33996 ("iwlwifi: Add missing check for alloc_ordered_workqueue")
Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
Link: https://patch.msgid.link/a7a1cd2c-ce01-461a-9afd-dbe535f8df01@sabinyo.mountain
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/intel/iwlwifi/dvm/main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
index bc065c7089f71..a4f6e5a8f3a9d 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
@@ -1468,7 +1468,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
/********************
* 6. Setup services
********************/
- if (iwl_setup_deferred_work(priv))
+ err = iwl_setup_deferred_work(priv);
+ if (err)
goto out_uninit_drv;
iwl_setup_rx_handlers(priv);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 105/869] net/sched: Fix backlog accounting in qdisc_dequeue_internal
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (103 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 104/869] wifi: iwlwifi: Fix error code in iwl_op_mode_dvm_start() Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 106/869] mm/mremap: fix WARN with uffd that has remap events disabled Greg Kroah-Hartman
` (764 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, William Liu, Savino Dicanosa,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: William Liu <will@willsroot.io>
[ Upstream commit 52bf272636bda69587952b35ae97690b8dc89941 ]
This issue applies for the following qdiscs: hhf, fq, fq_codel, and
fq_pie, and occurs in their change handlers when adjusting to the new
limit. The problem is the following in the values passed to the
subsequent qdisc_tree_reduce_backlog call given a tbf parent:
When the tbf parent runs out of tokens, skbs of these qdiscs will
be placed in gso_skb. Their peek handlers are qdisc_peek_dequeued,
which accounts for both qlen and backlog. However, in the case of
qdisc_dequeue_internal, ONLY qlen is accounted for when pulling
from gso_skb. This means that these qdiscs are missing a
qdisc_qstats_backlog_dec when dropping packets to satisfy the
new limit in their change handlers.
One can observe this issue with the following (with tc patched to
support a limit of 0):
export TARGET=fq
tc qdisc del dev lo root
tc qdisc add dev lo root handle 1: tbf rate 8bit burst 100b latency 1ms
tc qdisc replace dev lo handle 3: parent 1:1 $TARGET limit 1000
echo ''; echo 'add child'; tc -s -d qdisc show dev lo
ping -I lo -f -c2 -s32 -W0.001 127.0.0.1 2>&1 >/dev/null
echo ''; echo 'after ping'; tc -s -d qdisc show dev lo
tc qdisc change dev lo handle 3: parent 1:1 $TARGET limit 0
echo ''; echo 'after limit drop'; tc -s -d qdisc show dev lo
tc qdisc replace dev lo handle 2: parent 1:1 sfq
echo ''; echo 'post graft'; tc -s -d qdisc show dev lo
The second to last show command shows 0 packets but a positive
number (74) of backlog bytes. The problem becomes clearer in the
last show command, where qdisc_purge_queue triggers
qdisc_tree_reduce_backlog with the positive backlog and causes an
underflow in the tbf parent's backlog (4096 Mb instead of 0).
To fix this issue, the codepath for all clients of qdisc_dequeue_internal
has been simplified: codel, pie, hhf, fq, fq_pie, and fq_codel.
qdisc_dequeue_internal handles the backlog adjustments for all cases that
do not directly use the dequeue handler.
The old fq_codel_change limit adjustment loop accumulated the arguments to
the subsequent qdisc_tree_reduce_backlog call through the cstats field.
However, this is confusing and error prone as fq_codel_dequeue could also
potentially mutate this field (which qdisc_dequeue_internal calls in the
non gso_skb case), so we have unified the code here with other qdiscs.
Fixes: 2d3cbfd6d54a ("net_sched: Flush gso_skb list too during ->change()")
Fixes: 4b549a2ef4be ("fq_codel: Fair Queue Codel AQM")
Fixes: 10239edf86f1 ("net-qdisc-hhf: Heavy-Hitter Filter (HHF) qdisc")
Signed-off-by: William Liu <will@willsroot.io>
Reviewed-by: Savino Dicanosa <savy@syst3mfailure.io>
Link: https://patch.msgid.link/20250812235725.45243-1-will@willsroot.io
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/sch_generic.h | 11 ++++++++---
net/sched/sch_codel.c | 12 +++++++-----
net/sched/sch_fq.c | 12 +++++++-----
net/sched/sch_fq_codel.c | 12 +++++++-----
net/sched/sch_fq_pie.c | 12 +++++++-----
net/sched/sch_hhf.c | 12 +++++++-----
net/sched/sch_pie.c | 12 +++++++-----
7 files changed, 50 insertions(+), 33 deletions(-)
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 4f38a7a5dd6a6..d174283373470 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -1094,12 +1094,17 @@ static inline struct sk_buff *qdisc_dequeue_internal(struct Qdisc *sch, bool dir
skb = __skb_dequeue(&sch->gso_skb);
if (skb) {
sch->q.qlen--;
+ qdisc_qstats_backlog_dec(sch, skb);
return skb;
}
- if (direct)
- return __qdisc_dequeue_head(&sch->q);
- else
+ if (direct) {
+ skb = __qdisc_dequeue_head(&sch->q);
+ if (skb)
+ qdisc_qstats_backlog_dec(sch, skb);
+ return skb;
+ } else {
return sch->dequeue(sch);
+ }
}
static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch)
diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c
index f12a8f491108e..a491250caf338 100644
--- a/net/sched/sch_codel.c
+++ b/net/sched/sch_codel.c
@@ -138,9 +138,9 @@ static const struct nla_policy codel_policy[TCA_CODEL_MAX + 1] = {
static int codel_change(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
+ unsigned int dropped_pkts = 0, dropped_bytes = 0;
struct codel_sched_data *q = qdisc_priv(sch);
struct nlattr *tb[TCA_CODEL_MAX + 1];
- unsigned int qlen, dropped = 0;
int err;
err = nla_parse_nested_deprecated(tb, TCA_CODEL_MAX, opt,
@@ -179,15 +179,17 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt,
WRITE_ONCE(q->params.ecn,
!!nla_get_u32(tb[TCA_CODEL_ECN]));
- qlen = sch->q.qlen;
while (sch->q.qlen > sch->limit) {
struct sk_buff *skb = qdisc_dequeue_internal(sch, true);
- dropped += qdisc_pkt_len(skb);
- qdisc_qstats_backlog_dec(sch, skb);
+ if (!skb)
+ break;
+
+ dropped_pkts++;
+ dropped_bytes += qdisc_pkt_len(skb);
rtnl_qdisc_drop(skb, sch);
}
- qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped);
+ qdisc_tree_reduce_backlog(sch, dropped_pkts, dropped_bytes);
sch_tree_unlock(sch);
return 0;
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
index 6b85bb2a4f8ab..d06e12d16b0e5 100644
--- a/net/sched/sch_fq.c
+++ b/net/sched/sch_fq.c
@@ -1002,11 +1002,11 @@ static int fq_load_priomap(struct fq_sched_data *q,
static int fq_change(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
+ unsigned int dropped_pkts = 0, dropped_bytes = 0;
struct fq_sched_data *q = qdisc_priv(sch);
struct nlattr *tb[TCA_FQ_MAX + 1];
- int err, drop_count = 0;
- unsigned drop_len = 0;
u32 fq_log;
+ int err;
err = nla_parse_nested_deprecated(tb, TCA_FQ_MAX, opt, fq_policy,
NULL);
@@ -1109,16 +1109,18 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt,
err = fq_resize(sch, fq_log);
sch_tree_lock(sch);
}
+
while (sch->q.qlen > sch->limit) {
struct sk_buff *skb = qdisc_dequeue_internal(sch, false);
if (!skb)
break;
- drop_len += qdisc_pkt_len(skb);
+
+ dropped_pkts++;
+ dropped_bytes += qdisc_pkt_len(skb);
rtnl_kfree_skbs(skb, skb);
- drop_count++;
}
- qdisc_tree_reduce_backlog(sch, drop_count, drop_len);
+ qdisc_tree_reduce_backlog(sch, dropped_pkts, dropped_bytes);
sch_tree_unlock(sch);
return err;
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
index 4b0196eed7a9c..7cfe8eaf3331c 100644
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -402,6 +402,7 @@ static const struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = {
static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
+ unsigned int dropped_pkts = 0, dropped_bytes = 0;
struct fq_codel_sched_data *q = qdisc_priv(sch);
struct nlattr *tb[TCA_FQ_CODEL_MAX + 1];
u32 quantum = 0;
@@ -479,13 +480,14 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt,
q->memory_usage > q->memory_limit) {
struct sk_buff *skb = qdisc_dequeue_internal(sch, false);
- q->cstats.drop_len += qdisc_pkt_len(skb);
+ if (!skb)
+ break;
+
+ dropped_pkts++;
+ dropped_bytes += qdisc_pkt_len(skb);
rtnl_kfree_skbs(skb, skb);
- q->cstats.drop_count++;
}
- qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, q->cstats.drop_len);
- q->cstats.drop_count = 0;
- q->cstats.drop_len = 0;
+ qdisc_tree_reduce_backlog(sch, dropped_pkts, dropped_bytes);
sch_tree_unlock(sch);
return 0;
diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c
index 4b96e26cb4202..d2588cc40d04e 100644
--- a/net/sched/sch_fq_pie.c
+++ b/net/sched/sch_fq_pie.c
@@ -285,10 +285,9 @@ static struct sk_buff *fq_pie_qdisc_dequeue(struct Qdisc *sch)
static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
+ unsigned int dropped_pkts = 0, dropped_bytes = 0;
struct fq_pie_sched_data *q = qdisc_priv(sch);
struct nlattr *tb[TCA_FQ_PIE_MAX + 1];
- unsigned int len_dropped = 0;
- unsigned int num_dropped = 0;
int err;
err = nla_parse_nested(tb, TCA_FQ_PIE_MAX, opt, fq_pie_policy, extack);
@@ -367,11 +366,14 @@ static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt,
while (sch->q.qlen > sch->limit) {
struct sk_buff *skb = qdisc_dequeue_internal(sch, false);
- len_dropped += qdisc_pkt_len(skb);
- num_dropped += 1;
+ if (!skb)
+ break;
+
+ dropped_pkts++;
+ dropped_bytes += qdisc_pkt_len(skb);
rtnl_kfree_skbs(skb, skb);
}
- qdisc_tree_reduce_backlog(sch, num_dropped, len_dropped);
+ qdisc_tree_reduce_backlog(sch, dropped_pkts, dropped_bytes);
sch_tree_unlock(sch);
return 0;
diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c
index 7d7bc1d7e0498..d6a60ae8938c5 100644
--- a/net/sched/sch_hhf.c
+++ b/net/sched/sch_hhf.c
@@ -536,9 +536,9 @@ static const struct nla_policy hhf_policy[TCA_HHF_MAX + 1] = {
static int hhf_change(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
+ unsigned int dropped_pkts = 0, dropped_bytes = 0;
struct hhf_sched_data *q = qdisc_priv(sch);
struct nlattr *tb[TCA_HHF_MAX + 1];
- unsigned int qlen, prev_backlog;
int err;
u64 non_hh_quantum;
u32 new_quantum = q->quantum;
@@ -589,15 +589,17 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt,
usecs_to_jiffies(us));
}
- qlen = sch->q.qlen;
- prev_backlog = sch->qstats.backlog;
while (sch->q.qlen > sch->limit) {
struct sk_buff *skb = qdisc_dequeue_internal(sch, false);
+ if (!skb)
+ break;
+
+ dropped_pkts++;
+ dropped_bytes += qdisc_pkt_len(skb);
rtnl_kfree_skbs(skb, skb);
}
- qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen,
- prev_backlog - sch->qstats.backlog);
+ qdisc_tree_reduce_backlog(sch, dropped_pkts, dropped_bytes);
sch_tree_unlock(sch);
return 0;
diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c
index 793a155e27f99..d697adba1a947 100644
--- a/net/sched/sch_pie.c
+++ b/net/sched/sch_pie.c
@@ -138,9 +138,9 @@ static const struct nla_policy pie_policy[TCA_PIE_MAX + 1] = {
static int pie_change(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
+ unsigned int dropped_pkts = 0, dropped_bytes = 0;
struct pie_sched_data *q = qdisc_priv(sch);
struct nlattr *tb[TCA_PIE_MAX + 1];
- unsigned int qlen, dropped = 0;
int err;
err = nla_parse_nested_deprecated(tb, TCA_PIE_MAX, opt, pie_policy,
@@ -190,15 +190,17 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt,
nla_get_u32(tb[TCA_PIE_DQ_RATE_ESTIMATOR]));
/* Drop excess packets if new limit is lower */
- qlen = sch->q.qlen;
while (sch->q.qlen > sch->limit) {
struct sk_buff *skb = qdisc_dequeue_internal(sch, true);
- dropped += qdisc_pkt_len(skb);
- qdisc_qstats_backlog_dec(sch, skb);
+ if (!skb)
+ break;
+
+ dropped_pkts++;
+ dropped_bytes += qdisc_pkt_len(skb);
rtnl_qdisc_drop(skb, sch);
}
- qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped);
+ qdisc_tree_reduce_backlog(sch, dropped_pkts, dropped_bytes);
sch_tree_unlock(sch);
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 106/869] mm/mremap: fix WARN with uffd that has remap events disabled
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (104 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 105/869] net/sched: Fix backlog accounting in qdisc_dequeue_internal Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 107/869] crypto: x86/aegis128 - eliminate some indirect calls Greg Kroah-Hartman
` (763 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Hildenbrand,
syzbot+4d9a13f0797c46a29e42, Harry Yoo, Liam R. Howlett,
Lorenzo Stoakes, Vlastimil Babka, Jann Horn, Pedro Falcato,
Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Hildenbrand <david@redhat.com>
[ Upstream commit 772e5b4a5e8360743645b9a466842d16092c4f94 ]
Registering userfaultd on a VMA that spans at least one PMD and then
mremap()'ing that VMA can trigger a WARN when recovering from a failed
page table move due to a page table allocation error.
The code ends up doing the right thing (recurse, avoiding moving actual
page tables), but triggering that WARN is unpleasant:
WARNING: CPU: 2 PID: 6133 at mm/mremap.c:357 move_normal_pmd mm/mremap.c:357 [inline]
WARNING: CPU: 2 PID: 6133 at mm/mremap.c:357 move_pgt_entry mm/mremap.c:595 [inline]
WARNING: CPU: 2 PID: 6133 at mm/mremap.c:357 move_page_tables+0x3832/0x44a0 mm/mremap.c:852
Modules linked in:
CPU: 2 UID: 0 PID: 6133 Comm: syz.0.19 Not tainted 6.17.0-rc1-syzkaller-00004-g53e760d89498 #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
RIP: 0010:move_normal_pmd mm/mremap.c:357 [inline]
RIP: 0010:move_pgt_entry mm/mremap.c:595 [inline]
RIP: 0010:move_page_tables+0x3832/0x44a0 mm/mremap.c:852
Code: ...
RSP: 0018:ffffc900037a76d8 EFLAGS: 00010293
RAX: 0000000000000000 RBX: 0000000032930007 RCX: ffffffff820c6645
RDX: ffff88802e56a440 RSI: ffffffff820c7201 RDI: 0000000000000007
RBP: ffff888037728fc0 R08: 0000000000000007 R09: 0000000000000000
R10: 0000000032930007 R11: 0000000000000000 R12: 0000000000000000
R13: ffffc900037a79a8 R14: 0000000000000001 R15: dffffc0000000000
FS: 000055556316a500(0000) GS:ffff8880d68bc000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000001b30863fff CR3: 0000000050171000 CR4: 0000000000352ef0
Call Trace:
<TASK>
copy_vma_and_data+0x468/0x790 mm/mremap.c:1215
move_vma+0x548/0x1780 mm/mremap.c:1282
mremap_to+0x1b7/0x450 mm/mremap.c:1406
do_mremap+0xfad/0x1f80 mm/mremap.c:1921
__do_sys_mremap+0x119/0x170 mm/mremap.c:1977
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xcd/0x4c0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f00d0b8ebe9
Code: ...
RSP: 002b:00007ffe5ea5ee98 EFLAGS: 00000246 ORIG_RAX: 0000000000000019
RAX: ffffffffffffffda RBX: 00007f00d0db5fa0 RCX: 00007f00d0b8ebe9
RDX: 0000000000400000 RSI: 0000000000c00000 RDI: 0000200000000000
RBP: 00007ffe5ea5eef0 R08: 0000200000c00000 R09: 0000000000000000
R10: 0000000000000003 R11: 0000000000000246 R12: 0000000000000002
R13: 00007f00d0db5fa0 R14: 00007f00d0db5fa0 R15: 0000000000000005
</TASK>
The underlying issue is that we recurse during the original page table
move, but not during the recovery move.
Fix it by checking for both VMAs and performing the check before the
pmd_none() sanity check.
Add a new helper where we perform+document that check for the PMD and PUD
level.
Thanks to Harry for bisecting.
Link: https://lkml.kernel.org/r/20250818175358.1184757-1-david@redhat.com
Fixes: 0cef0bb836e3 ("mm: clear uffd-wp PTE/PMD state on mremap()")
Signed-off-by: David Hildenbrand <david@redhat.com>
Reported-by: syzbot+4d9a13f0797c46a29e42@syzkaller.appspotmail.com
Closes: https://lkml.kernel.org/r/689bb893.050a0220.7f033.013a.GAE@google.com
Tested-by: Harry Yoo <harry.yoo@oracle.com>
Cc: "Liam R. Howlett" <Liam.Howlett@oracle.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Jann Horn <jannh@google.com>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/mremap.c | 40 ++++++++++++++++++++--------------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/mm/mremap.c b/mm/mremap.c
index 83c37ad39d345..8b507e228a274 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -281,15 +281,6 @@ static bool move_normal_pmd(struct vm_area_struct *vma, unsigned long old_addr,
if (WARN_ON_ONCE(!pmd_none(*new_pmd)))
return false;
- /* If this pmd belongs to a uffd vma with remap events disabled, we need
- * to ensure that the uffd-wp state is cleared from all pgtables. This
- * means recursing into lower page tables in move_page_tables(), and we
- * can reuse the existing code if we simply treat the entry as "not
- * moved".
- */
- if (vma_has_uffd_without_event_remap(vma))
- return false;
-
/*
* We don't have to worry about the ordering of src and dst
* ptlocks because exclusive mmap_lock prevents deadlock.
@@ -345,15 +336,6 @@ static bool move_normal_pud(struct vm_area_struct *vma, unsigned long old_addr,
if (WARN_ON_ONCE(!pud_none(*new_pud)))
return false;
- /* If this pud belongs to a uffd vma with remap events disabled, we need
- * to ensure that the uffd-wp state is cleared from all pgtables. This
- * means recursing into lower page tables in move_page_tables(), and we
- * can reuse the existing code if we simply treat the entry as "not
- * moved".
- */
- if (vma_has_uffd_without_event_remap(vma))
- return false;
-
/*
* We don't have to worry about the ordering of src and dst
* ptlocks because exclusive mmap_lock prevents deadlock.
@@ -587,6 +569,7 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
struct mmu_notifier_range range;
pmd_t *old_pmd, *new_pmd;
pud_t *old_pud, *new_pud;
+ bool uffd_supports_move;
if (!len)
return 0;
@@ -597,6 +580,22 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
return move_hugetlb_page_tables(vma, new_vma, old_addr,
new_addr, len);
+ /*
+ * If we are moving a VMA that has uffd-wp registered but with
+ * remap events disabled (new VMA will not be registered with uffd), we
+ * need to ensure that the uffd-wp state is cleared from all pgtables.
+ * This means recursing into lower page tables in move_page_tables().
+ *
+ * We might get called with VMAs reversed when recovering from a
+ * failed page table move. In that case, the
+ * "old"-but-actually-"originally new" VMA during recovery will not have
+ * a uffd context. Recursing into lower page tables during the original
+ * move but not during the recovery move will cause trouble, because we
+ * run into already-existing page tables. So check both VMAs.
+ */
+ uffd_supports_move = !vma_has_uffd_without_event_remap(vma) &&
+ !vma_has_uffd_without_event_remap(new_vma);
+
/*
* If possible, realign addresses to PMD boundary for faster copy.
* Only realign if the mremap copying hits a PMD boundary.
@@ -631,7 +630,8 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
/* We ignore and continue on error? */
continue;
}
- } else if (IS_ENABLED(CONFIG_HAVE_MOVE_PUD) && extent == PUD_SIZE) {
+ } else if (IS_ENABLED(CONFIG_HAVE_MOVE_PUD) &&
+ extent == PUD_SIZE && uffd_supports_move) {
if (move_pgt_entry(NORMAL_PUD, vma, old_addr, new_addr,
old_pud, new_pud, true))
@@ -654,7 +654,7 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
continue;
split_huge_pmd(vma, old_pmd, old_addr);
} else if (IS_ENABLED(CONFIG_HAVE_MOVE_PMD) &&
- extent == PMD_SIZE) {
+ extent == PMD_SIZE && uffd_supports_move) {
/*
* If the extent is PMD-sized, try to speed the move by
* moving at the PMD level if possible.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 107/869] crypto: x86/aegis128 - eliminate some indirect calls
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (105 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 106/869] mm/mremap: fix WARN with uffd that has remap events disabled Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 108/869] crypto: x86/aegis128 - optimize length block preparation using SSE4.1 Greg Kroah-Hartman
` (762 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ondrej Mosnacek, Eric Biggers,
Herbert Xu, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <ebiggers@google.com>
[ Upstream commit b8d2e7bac3f768e5ab0b52a4a6dd65aa130113be ]
Instead of using a struct of function pointers to decide whether to call
the encryption or decryption assembly functions, use a conditional
branch on a bool. Force-inline the functions to avoid actually
generating the branch. This improves performance slightly since
indirect calls are slow. Remove the now-unnecessary CFI stubs.
Note that just force-inlining the existing functions might cause the
compiler to optimize out the indirect branches, but that would not be a
reliable way to do it and the CFI stubs would still be required.
Reviewed-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Stable-dep-of: 3d9eb180fbe8 ("crypto: x86/aegis - Add missing error checks")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/crypto/aegis128-aesni-asm.S | 9 ++--
arch/x86/crypto/aegis128-aesni-glue.c | 74 +++++++++++++--------------
2 files changed, 40 insertions(+), 43 deletions(-)
diff --git a/arch/x86/crypto/aegis128-aesni-asm.S b/arch/x86/crypto/aegis128-aesni-asm.S
index 2de859173940e..1b57558548c78 100644
--- a/arch/x86/crypto/aegis128-aesni-asm.S
+++ b/arch/x86/crypto/aegis128-aesni-asm.S
@@ -7,7 +7,6 @@
*/
#include <linux/linkage.h>
-#include <linux/cfi_types.h>
#include <asm/frame.h>
#define STATE0 %xmm0
@@ -403,7 +402,7 @@ SYM_FUNC_END(crypto_aegis128_aesni_ad)
* void crypto_aegis128_aesni_enc(void *state, unsigned int length,
* const void *src, void *dst);
*/
-SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc)
+SYM_FUNC_START(crypto_aegis128_aesni_enc)
FRAME_BEGIN
cmp $0x10, LEN
@@ -500,7 +499,7 @@ SYM_FUNC_END(crypto_aegis128_aesni_enc)
* void crypto_aegis128_aesni_enc_tail(void *state, unsigned int length,
* const void *src, void *dst);
*/
-SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc_tail)
+SYM_FUNC_START(crypto_aegis128_aesni_enc_tail)
FRAME_BEGIN
/* load the state: */
@@ -557,7 +556,7 @@ SYM_FUNC_END(crypto_aegis128_aesni_enc_tail)
* void crypto_aegis128_aesni_dec(void *state, unsigned int length,
* const void *src, void *dst);
*/
-SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec)
+SYM_FUNC_START(crypto_aegis128_aesni_dec)
FRAME_BEGIN
cmp $0x10, LEN
@@ -654,7 +653,7 @@ SYM_FUNC_END(crypto_aegis128_aesni_dec)
* void crypto_aegis128_aesni_dec_tail(void *state, unsigned int length,
* const void *src, void *dst);
*/
-SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec_tail)
+SYM_FUNC_START(crypto_aegis128_aesni_dec_tail)
FRAME_BEGIN
/* load the state: */
diff --git a/arch/x86/crypto/aegis128-aesni-glue.c b/arch/x86/crypto/aegis128-aesni-glue.c
index 4623189000d89..6c4c2cda2c2d1 100644
--- a/arch/x86/crypto/aegis128-aesni-glue.c
+++ b/arch/x86/crypto/aegis128-aesni-glue.c
@@ -56,16 +56,6 @@ struct aegis_ctx {
struct aegis_block key;
};
-struct aegis_crypt_ops {
- int (*skcipher_walk_init)(struct skcipher_walk *walk,
- struct aead_request *req, bool atomic);
-
- void (*crypt_blocks)(void *state, unsigned int length, const void *src,
- void *dst);
- void (*crypt_tail)(void *state, unsigned int length, const void *src,
- void *dst);
-};
-
static void crypto_aegis128_aesni_process_ad(
struct aegis_state *state, struct scatterlist *sg_src,
unsigned int assoclen)
@@ -114,20 +104,37 @@ static void crypto_aegis128_aesni_process_ad(
}
}
-static void crypto_aegis128_aesni_process_crypt(
- struct aegis_state *state, struct skcipher_walk *walk,
- const struct aegis_crypt_ops *ops)
+static __always_inline void
+crypto_aegis128_aesni_process_crypt(struct aegis_state *state,
+ struct skcipher_walk *walk, bool enc)
{
while (walk->nbytes >= AEGIS128_BLOCK_SIZE) {
- ops->crypt_blocks(state,
- round_down(walk->nbytes, AEGIS128_BLOCK_SIZE),
- walk->src.virt.addr, walk->dst.virt.addr);
+ if (enc)
+ crypto_aegis128_aesni_enc(
+ state,
+ round_down(walk->nbytes,
+ AEGIS128_BLOCK_SIZE),
+ walk->src.virt.addr,
+ walk->dst.virt.addr);
+ else
+ crypto_aegis128_aesni_dec(
+ state,
+ round_down(walk->nbytes,
+ AEGIS128_BLOCK_SIZE),
+ walk->src.virt.addr,
+ walk->dst.virt.addr);
skcipher_walk_done(walk, walk->nbytes % AEGIS128_BLOCK_SIZE);
}
if (walk->nbytes) {
- ops->crypt_tail(state, walk->nbytes, walk->src.virt.addr,
- walk->dst.virt.addr);
+ if (enc)
+ crypto_aegis128_aesni_enc_tail(state, walk->nbytes,
+ walk->src.virt.addr,
+ walk->dst.virt.addr);
+ else
+ crypto_aegis128_aesni_dec_tail(state, walk->nbytes,
+ walk->src.virt.addr,
+ walk->dst.virt.addr);
skcipher_walk_done(walk, 0);
}
}
@@ -162,23 +169,26 @@ static int crypto_aegis128_aesni_setauthsize(struct crypto_aead *tfm,
return 0;
}
-static void crypto_aegis128_aesni_crypt(struct aead_request *req,
- struct aegis_block *tag_xor,
- unsigned int cryptlen,
- const struct aegis_crypt_ops *ops)
+static __always_inline void
+crypto_aegis128_aesni_crypt(struct aead_request *req,
+ struct aegis_block *tag_xor,
+ unsigned int cryptlen, bool enc)
{
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
struct aegis_ctx *ctx = crypto_aegis128_aesni_ctx(tfm);
struct skcipher_walk walk;
struct aegis_state state;
- ops->skcipher_walk_init(&walk, req, true);
+ if (enc)
+ skcipher_walk_aead_encrypt(&walk, req, true);
+ else
+ skcipher_walk_aead_decrypt(&walk, req, true);
kernel_fpu_begin();
crypto_aegis128_aesni_init(&state, ctx->key.bytes, req->iv);
crypto_aegis128_aesni_process_ad(&state, req->src, req->assoclen);
- crypto_aegis128_aesni_process_crypt(&state, &walk, ops);
+ crypto_aegis128_aesni_process_crypt(&state, &walk, enc);
crypto_aegis128_aesni_final(&state, tag_xor, req->assoclen, cryptlen);
kernel_fpu_end();
@@ -186,18 +196,12 @@ static void crypto_aegis128_aesni_crypt(struct aead_request *req,
static int crypto_aegis128_aesni_encrypt(struct aead_request *req)
{
- static const struct aegis_crypt_ops OPS = {
- .skcipher_walk_init = skcipher_walk_aead_encrypt,
- .crypt_blocks = crypto_aegis128_aesni_enc,
- .crypt_tail = crypto_aegis128_aesni_enc_tail,
- };
-
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
struct aegis_block tag = {};
unsigned int authsize = crypto_aead_authsize(tfm);
unsigned int cryptlen = req->cryptlen;
- crypto_aegis128_aesni_crypt(req, &tag, cryptlen, &OPS);
+ crypto_aegis128_aesni_crypt(req, &tag, cryptlen, true);
scatterwalk_map_and_copy(tag.bytes, req->dst,
req->assoclen + cryptlen, authsize, 1);
@@ -208,12 +212,6 @@ static int crypto_aegis128_aesni_decrypt(struct aead_request *req)
{
static const struct aegis_block zeros = {};
- static const struct aegis_crypt_ops OPS = {
- .skcipher_walk_init = skcipher_walk_aead_decrypt,
- .crypt_blocks = crypto_aegis128_aesni_dec,
- .crypt_tail = crypto_aegis128_aesni_dec_tail,
- };
-
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
struct aegis_block tag;
unsigned int authsize = crypto_aead_authsize(tfm);
@@ -222,7 +220,7 @@ static int crypto_aegis128_aesni_decrypt(struct aead_request *req)
scatterwalk_map_and_copy(tag.bytes, req->src,
req->assoclen + cryptlen, authsize, 0);
- crypto_aegis128_aesni_crypt(req, &tag, cryptlen, &OPS);
+ crypto_aegis128_aesni_crypt(req, &tag, cryptlen, false);
return crypto_memneq(tag.bytes, zeros.bytes, authsize) ? -EBADMSG : 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 108/869] crypto: x86/aegis128 - optimize length block preparation using SSE4.1
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (106 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 107/869] crypto: x86/aegis128 - eliminate some indirect calls Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 109/869] crypto: x86/aegis128 - improve assembly function prototypes Greg Kroah-Hartman
` (761 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ondrej Mosnacek, Eric Biggers,
Herbert Xu, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <ebiggers@google.com>
[ Upstream commit af2aff7caf8afb7abbe219a838d61b4c17d88a47 ]
Start using SSE4.1 instructions in the AES-NI AEGIS code, with the first
use case being preparing the length block in fewer instructions.
In practice this does not reduce the set of CPUs on which the code can
run, because all Intel and AMD CPUs with AES-NI also have SSE4.1.
Upgrade the existing SSE2 feature check to SSE4.1, though it seems this
check is not strictly necessary; the aesni-intel module has been getting
away with using SSE4.1 despite checking for AES-NI only.
Reviewed-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Stable-dep-of: 3d9eb180fbe8 ("crypto: x86/aegis - Add missing error checks")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/crypto/Kconfig | 4 ++--
arch/x86/crypto/aegis128-aesni-asm.S | 6 ++----
arch/x86/crypto/aegis128-aesni-glue.c | 6 +++---
3 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/arch/x86/crypto/Kconfig b/arch/x86/crypto/Kconfig
index 46b53ab061657..0cf89264db08c 100644
--- a/arch/x86/crypto/Kconfig
+++ b/arch/x86/crypto/Kconfig
@@ -366,7 +366,7 @@ config CRYPTO_CHACHA20_X86_64
- AVX-512VL (Advanced Vector Extensions-512VL)
config CRYPTO_AEGIS128_AESNI_SSE2
- tristate "AEAD ciphers: AEGIS-128 (AES-NI/SSE2)"
+ tristate "AEAD ciphers: AEGIS-128 (AES-NI/SSE4.1)"
depends on X86 && 64BIT
select CRYPTO_AEAD
select CRYPTO_SIMD
@@ -375,7 +375,7 @@ config CRYPTO_AEGIS128_AESNI_SSE2
Architecture: x86_64 using:
- AES-NI (AES New Instructions)
- - SSE2 (Streaming SIMD Extensions 2)
+ - SSE4.1 (Streaming SIMD Extensions 4.1)
config CRYPTO_NHPOLY1305_SSE2
tristate "Hash functions: NHPoly1305 (SSE2)"
diff --git a/arch/x86/crypto/aegis128-aesni-asm.S b/arch/x86/crypto/aegis128-aesni-asm.S
index 1b57558548c78..639ba6f31a90e 100644
--- a/arch/x86/crypto/aegis128-aesni-asm.S
+++ b/arch/x86/crypto/aegis128-aesni-asm.S
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * AES-NI + SSE2 implementation of AEGIS-128
+ * AES-NI + SSE4.1 implementation of AEGIS-128
*
* Copyright (c) 2017-2018 Ondrej Mosnacek <omosnacek@gmail.com>
* Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved.
@@ -716,9 +716,7 @@ SYM_FUNC_START(crypto_aegis128_aesni_final)
/* prepare length block: */
movd %edx, MSG
- movd %ecx, T0
- pslldq $8, T0
- pxor T0, MSG
+ pinsrd $2, %ecx, MSG
psllq $3, MSG /* multiply by 8 (to get bit count) */
pxor STATE3, MSG
diff --git a/arch/x86/crypto/aegis128-aesni-glue.c b/arch/x86/crypto/aegis128-aesni-glue.c
index 6c4c2cda2c2d1..9b52451f6feec 100644
--- a/arch/x86/crypto/aegis128-aesni-glue.c
+++ b/arch/x86/crypto/aegis128-aesni-glue.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* The AEGIS-128 Authenticated-Encryption Algorithm
- * Glue for AES-NI + SSE2 implementation
+ * Glue for AES-NI + SSE4.1 implementation
*
* Copyright (c) 2017-2018 Ondrej Mosnacek <omosnacek@gmail.com>
* Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved.
@@ -265,7 +265,7 @@ static struct simd_aead_alg *simd_alg;
static int __init crypto_aegis128_aesni_module_init(void)
{
- if (!boot_cpu_has(X86_FEATURE_XMM2) ||
+ if (!boot_cpu_has(X86_FEATURE_XMM4_1) ||
!boot_cpu_has(X86_FEATURE_AES) ||
!cpu_has_xfeatures(XFEATURE_MASK_SSE, NULL))
return -ENODEV;
@@ -284,6 +284,6 @@ module_exit(crypto_aegis128_aesni_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>");
-MODULE_DESCRIPTION("AEGIS-128 AEAD algorithm -- AESNI+SSE2 implementation");
+MODULE_DESCRIPTION("AEGIS-128 AEAD algorithm -- AESNI+SSE4.1 implementation");
MODULE_ALIAS_CRYPTO("aegis128");
MODULE_ALIAS_CRYPTO("aegis128-aesni");
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 109/869] crypto: x86/aegis128 - improve assembly function prototypes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (107 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 108/869] crypto: x86/aegis128 - optimize length block preparation using SSE4.1 Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 110/869] crypto: x86/aegis - Fix sleeping when disallowed on PREEMPT_RT Greg Kroah-Hartman
` (760 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ondrej Mosnacek, Eric Biggers,
Herbert Xu, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <ebiggers@google.com>
[ Upstream commit 8da94b300f67240fbd8880d918200aa9046fc398 ]
Adjust the prototypes of the AEGIS assembly functions:
- Use proper types instead of 'void *', when applicable.
- Move the length parameter to after the buffers it describes rather
than before, to match the usual convention. Also shorten its name to
just len (which is the name used in the assembly code).
- Declare register aliases at the beginning of each function rather than
once per file. This was necessary because len was moved, but also it
allows adding some aliases where raw registers were used before.
- Put assoclen and cryptlen in the correct order when declaring the
finalization function in the .c file.
- Remove the unnecessary "crypto_" prefix.
Reviewed-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Stable-dep-of: 3d9eb180fbe8 ("crypto: x86/aegis - Add missing error checks")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/crypto/aegis128-aesni-asm.S | 105 ++++++++++++++++----------
arch/x86/crypto/aegis128-aesni-glue.c | 92 +++++++++++-----------
2 files changed, 112 insertions(+), 85 deletions(-)
diff --git a/arch/x86/crypto/aegis128-aesni-asm.S b/arch/x86/crypto/aegis128-aesni-asm.S
index 639ba6f31a90e..6520d0ed98146 100644
--- a/arch/x86/crypto/aegis128-aesni-asm.S
+++ b/arch/x86/crypto/aegis128-aesni-asm.S
@@ -19,11 +19,6 @@
#define T0 %xmm6
#define T1 %xmm7
-#define STATEP %rdi
-#define LEN %esi
-#define SRC %rdx
-#define DST %rcx
-
.section .rodata.cst16.aegis128_const, "aM", @progbits, 32
.align 16
.Laegis128_const_0:
@@ -72,6 +67,8 @@
* %r9
*/
SYM_FUNC_START_LOCAL(__load_partial)
+ .set LEN, %ecx
+ .set SRC, %rsi
xor %r9d, %r9d
pxor MSG, MSG
@@ -138,6 +135,8 @@ SYM_FUNC_END(__load_partial)
* %r10
*/
SYM_FUNC_START_LOCAL(__store_partial)
+ .set LEN, %ecx
+ .set DST, %rdx
mov LEN, %r8d
mov DST, %r9
@@ -184,16 +183,21 @@ SYM_FUNC_START_LOCAL(__store_partial)
SYM_FUNC_END(__store_partial)
/*
- * void crypto_aegis128_aesni_init(void *state, const void *key, const void *iv);
+ * void aegis128_aesni_init(struct aegis_state *state,
+ * const struct aegis_block *key,
+ * const u8 iv[AEGIS128_NONCE_SIZE]);
*/
-SYM_FUNC_START(crypto_aegis128_aesni_init)
+SYM_FUNC_START(aegis128_aesni_init)
+ .set STATEP, %rdi
+ .set KEYP, %rsi
+ .set IVP, %rdx
FRAME_BEGIN
/* load IV: */
- movdqu (%rdx), T1
+ movdqu (IVP), T1
/* load key: */
- movdqa (%rsi), KEY
+ movdqa (KEYP), KEY
pxor KEY, T1
movdqa T1, STATE0
movdqa KEY, STATE3
@@ -226,13 +230,16 @@ SYM_FUNC_START(crypto_aegis128_aesni_init)
FRAME_END
RET
-SYM_FUNC_END(crypto_aegis128_aesni_init)
+SYM_FUNC_END(aegis128_aesni_init)
/*
- * void crypto_aegis128_aesni_ad(void *state, unsigned int length,
- * const void *data);
+ * void aegis128_aesni_ad(struct aegis_state *state, const u8 *data,
+ * unsigned int len);
*/
-SYM_FUNC_START(crypto_aegis128_aesni_ad)
+SYM_FUNC_START(aegis128_aesni_ad)
+ .set STATEP, %rdi
+ .set SRC, %rsi
+ .set LEN, %edx
FRAME_BEGIN
cmp $0x10, LEN
@@ -378,7 +385,7 @@ SYM_FUNC_START(crypto_aegis128_aesni_ad)
.Lad_out:
FRAME_END
RET
-SYM_FUNC_END(crypto_aegis128_aesni_ad)
+SYM_FUNC_END(aegis128_aesni_ad)
.macro encrypt_block a s0 s1 s2 s3 s4 i
movdq\a (\i * 0x10)(SRC), MSG
@@ -399,10 +406,14 @@ SYM_FUNC_END(crypto_aegis128_aesni_ad)
.endm
/*
- * void crypto_aegis128_aesni_enc(void *state, unsigned int length,
- * const void *src, void *dst);
+ * void aegis128_aesni_enc(struct aegis_state *state, const u8 *src, u8 *dst,
+ * unsigned int len);
*/
-SYM_FUNC_START(crypto_aegis128_aesni_enc)
+SYM_FUNC_START(aegis128_aesni_enc)
+ .set STATEP, %rdi
+ .set SRC, %rsi
+ .set DST, %rdx
+ .set LEN, %ecx
FRAME_BEGIN
cmp $0x10, LEN
@@ -493,13 +504,17 @@ SYM_FUNC_START(crypto_aegis128_aesni_enc)
.Lenc_out:
FRAME_END
RET
-SYM_FUNC_END(crypto_aegis128_aesni_enc)
+SYM_FUNC_END(aegis128_aesni_enc)
/*
- * void crypto_aegis128_aesni_enc_tail(void *state, unsigned int length,
- * const void *src, void *dst);
+ * void aegis128_aesni_enc_tail(struct aegis_state *state, const u8 *src,
+ * u8 *dst, unsigned int len);
*/
-SYM_FUNC_START(crypto_aegis128_aesni_enc_tail)
+SYM_FUNC_START(aegis128_aesni_enc_tail)
+ .set STATEP, %rdi
+ .set SRC, %rsi
+ .set DST, %rdx
+ .set LEN, %ecx
FRAME_BEGIN
/* load the state: */
@@ -533,7 +548,7 @@ SYM_FUNC_START(crypto_aegis128_aesni_enc_tail)
FRAME_END
RET
-SYM_FUNC_END(crypto_aegis128_aesni_enc_tail)
+SYM_FUNC_END(aegis128_aesni_enc_tail)
.macro decrypt_block a s0 s1 s2 s3 s4 i
movdq\a (\i * 0x10)(SRC), MSG
@@ -553,10 +568,14 @@ SYM_FUNC_END(crypto_aegis128_aesni_enc_tail)
.endm
/*
- * void crypto_aegis128_aesni_dec(void *state, unsigned int length,
- * const void *src, void *dst);
+ * void aegis128_aesni_dec(struct aegis_state *state, const u8 *src, u8 *dst,
+ * unsigned int len);
*/
-SYM_FUNC_START(crypto_aegis128_aesni_dec)
+SYM_FUNC_START(aegis128_aesni_dec)
+ .set STATEP, %rdi
+ .set SRC, %rsi
+ .set DST, %rdx
+ .set LEN, %ecx
FRAME_BEGIN
cmp $0x10, LEN
@@ -647,13 +666,17 @@ SYM_FUNC_START(crypto_aegis128_aesni_dec)
.Ldec_out:
FRAME_END
RET
-SYM_FUNC_END(crypto_aegis128_aesni_dec)
+SYM_FUNC_END(aegis128_aesni_dec)
/*
- * void crypto_aegis128_aesni_dec_tail(void *state, unsigned int length,
- * const void *src, void *dst);
+ * void aegis128_aesni_dec_tail(struct aegis_state *state, const u8 *src,
+ * u8 *dst, unsigned int len);
*/
-SYM_FUNC_START(crypto_aegis128_aesni_dec_tail)
+SYM_FUNC_START(aegis128_aesni_dec_tail)
+ .set STATEP, %rdi
+ .set SRC, %rsi
+ .set DST, %rdx
+ .set LEN, %ecx
FRAME_BEGIN
/* load the state: */
@@ -697,14 +720,18 @@ SYM_FUNC_START(crypto_aegis128_aesni_dec_tail)
FRAME_END
RET
-SYM_FUNC_END(crypto_aegis128_aesni_dec_tail)
+SYM_FUNC_END(aegis128_aesni_dec_tail)
/*
- * void crypto_aegis128_aesni_final(void *state, void *tag_xor,
- * unsigned int assoclen,
- * unsigned int cryptlen);
+ * void aegis128_aesni_final(struct aegis_state *state,
+ * struct aegis_block *tag_xor,
+ * unsigned int assoclen, unsigned int cryptlen);
*/
-SYM_FUNC_START(crypto_aegis128_aesni_final)
+SYM_FUNC_START(aegis128_aesni_final)
+ .set STATEP, %rdi
+ .set TAG_XOR, %rsi
+ .set ASSOCLEN, %edx
+ .set CRYPTLEN, %ecx
FRAME_BEGIN
/* load the state: */
@@ -715,8 +742,8 @@ SYM_FUNC_START(crypto_aegis128_aesni_final)
movdqu 0x40(STATEP), STATE4
/* prepare length block: */
- movd %edx, MSG
- pinsrd $2, %ecx, MSG
+ movd ASSOCLEN, MSG
+ pinsrd $2, CRYPTLEN, MSG
psllq $3, MSG /* multiply by 8 (to get bit count) */
pxor STATE3, MSG
@@ -731,7 +758,7 @@ SYM_FUNC_START(crypto_aegis128_aesni_final)
aegis128_update; pxor MSG, STATE3
/* xor tag: */
- movdqu (%rsi), MSG
+ movdqu (TAG_XOR), MSG
pxor STATE0, MSG
pxor STATE1, MSG
@@ -739,8 +766,8 @@ SYM_FUNC_START(crypto_aegis128_aesni_final)
pxor STATE3, MSG
pxor STATE4, MSG
- movdqu MSG, (%rsi)
+ movdqu MSG, (TAG_XOR)
FRAME_END
RET
-SYM_FUNC_END(crypto_aegis128_aesni_final)
+SYM_FUNC_END(aegis128_aesni_final)
diff --git a/arch/x86/crypto/aegis128-aesni-glue.c b/arch/x86/crypto/aegis128-aesni-glue.c
index 9b52451f6feec..e7a28ccf273bf 100644
--- a/arch/x86/crypto/aegis128-aesni-glue.c
+++ b/arch/x86/crypto/aegis128-aesni-glue.c
@@ -23,27 +23,6 @@
#define AEGIS128_MIN_AUTH_SIZE 8
#define AEGIS128_MAX_AUTH_SIZE 16
-asmlinkage void crypto_aegis128_aesni_init(void *state, void *key, void *iv);
-
-asmlinkage void crypto_aegis128_aesni_ad(
- void *state, unsigned int length, const void *data);
-
-asmlinkage void crypto_aegis128_aesni_enc(
- void *state, unsigned int length, const void *src, void *dst);
-
-asmlinkage void crypto_aegis128_aesni_dec(
- void *state, unsigned int length, const void *src, void *dst);
-
-asmlinkage void crypto_aegis128_aesni_enc_tail(
- void *state, unsigned int length, const void *src, void *dst);
-
-asmlinkage void crypto_aegis128_aesni_dec_tail(
- void *state, unsigned int length, const void *src, void *dst);
-
-asmlinkage void crypto_aegis128_aesni_final(
- void *state, void *tag_xor, unsigned int cryptlen,
- unsigned int assoclen);
-
struct aegis_block {
u8 bytes[AEGIS128_BLOCK_SIZE] __aligned(AEGIS128_BLOCK_ALIGN);
};
@@ -56,6 +35,32 @@ struct aegis_ctx {
struct aegis_block key;
};
+asmlinkage void aegis128_aesni_init(struct aegis_state *state,
+ const struct aegis_block *key,
+ const u8 iv[AEGIS128_NONCE_SIZE]);
+
+asmlinkage void aegis128_aesni_ad(struct aegis_state *state, const u8 *data,
+ unsigned int len);
+
+asmlinkage void aegis128_aesni_enc(struct aegis_state *state, const u8 *src,
+ u8 *dst, unsigned int len);
+
+asmlinkage void aegis128_aesni_dec(struct aegis_state *state, const u8 *src,
+ u8 *dst, unsigned int len);
+
+asmlinkage void aegis128_aesni_enc_tail(struct aegis_state *state,
+ const u8 *src, u8 *dst,
+ unsigned int len);
+
+asmlinkage void aegis128_aesni_dec_tail(struct aegis_state *state,
+ const u8 *src, u8 *dst,
+ unsigned int len);
+
+asmlinkage void aegis128_aesni_final(struct aegis_state *state,
+ struct aegis_block *tag_xor,
+ unsigned int assoclen,
+ unsigned int cryptlen);
+
static void crypto_aegis128_aesni_process_ad(
struct aegis_state *state, struct scatterlist *sg_src,
unsigned int assoclen)
@@ -75,15 +80,14 @@ static void crypto_aegis128_aesni_process_ad(
if (pos > 0) {
unsigned int fill = AEGIS128_BLOCK_SIZE - pos;
memcpy(buf.bytes + pos, src, fill);
- crypto_aegis128_aesni_ad(state,
- AEGIS128_BLOCK_SIZE,
- buf.bytes);
+ aegis128_aesni_ad(state, buf.bytes,
+ AEGIS128_BLOCK_SIZE);
pos = 0;
left -= fill;
src += fill;
}
- crypto_aegis128_aesni_ad(state, left, src);
+ aegis128_aesni_ad(state, src, left);
src += left & ~(AEGIS128_BLOCK_SIZE - 1);
left &= AEGIS128_BLOCK_SIZE - 1;
@@ -100,7 +104,7 @@ static void crypto_aegis128_aesni_process_ad(
if (pos > 0) {
memset(buf.bytes + pos, 0, AEGIS128_BLOCK_SIZE - pos);
- crypto_aegis128_aesni_ad(state, AEGIS128_BLOCK_SIZE, buf.bytes);
+ aegis128_aesni_ad(state, buf.bytes, AEGIS128_BLOCK_SIZE);
}
}
@@ -110,31 +114,27 @@ crypto_aegis128_aesni_process_crypt(struct aegis_state *state,
{
while (walk->nbytes >= AEGIS128_BLOCK_SIZE) {
if (enc)
- crypto_aegis128_aesni_enc(
- state,
- round_down(walk->nbytes,
- AEGIS128_BLOCK_SIZE),
- walk->src.virt.addr,
- walk->dst.virt.addr);
+ aegis128_aesni_enc(state, walk->src.virt.addr,
+ walk->dst.virt.addr,
+ round_down(walk->nbytes,
+ AEGIS128_BLOCK_SIZE));
else
- crypto_aegis128_aesni_dec(
- state,
- round_down(walk->nbytes,
- AEGIS128_BLOCK_SIZE),
- walk->src.virt.addr,
- walk->dst.virt.addr);
+ aegis128_aesni_dec(state, walk->src.virt.addr,
+ walk->dst.virt.addr,
+ round_down(walk->nbytes,
+ AEGIS128_BLOCK_SIZE));
skcipher_walk_done(walk, walk->nbytes % AEGIS128_BLOCK_SIZE);
}
if (walk->nbytes) {
if (enc)
- crypto_aegis128_aesni_enc_tail(state, walk->nbytes,
- walk->src.virt.addr,
- walk->dst.virt.addr);
+ aegis128_aesni_enc_tail(state, walk->src.virt.addr,
+ walk->dst.virt.addr,
+ walk->nbytes);
else
- crypto_aegis128_aesni_dec_tail(state, walk->nbytes,
- walk->src.virt.addr,
- walk->dst.virt.addr);
+ aegis128_aesni_dec_tail(state, walk->src.virt.addr,
+ walk->dst.virt.addr,
+ walk->nbytes);
skcipher_walk_done(walk, 0);
}
}
@@ -186,10 +186,10 @@ crypto_aegis128_aesni_crypt(struct aead_request *req,
kernel_fpu_begin();
- crypto_aegis128_aesni_init(&state, ctx->key.bytes, req->iv);
+ aegis128_aesni_init(&state, &ctx->key, req->iv);
crypto_aegis128_aesni_process_ad(&state, req->src, req->assoclen);
crypto_aegis128_aesni_process_crypt(&state, &walk, enc);
- crypto_aegis128_aesni_final(&state, tag_xor, req->assoclen, cryptlen);
+ aegis128_aesni_final(&state, tag_xor, req->assoclen, cryptlen);
kernel_fpu_end();
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 110/869] crypto: x86/aegis - Fix sleeping when disallowed on PREEMPT_RT
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (108 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 109/869] crypto: x86/aegis128 - improve assembly function prototypes Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 111/869] crypto: x86/aegis - Add missing error checks Greg Kroah-Hartman
` (759 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Eric Biggers, Herbert Xu,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <ebiggers@kernel.org>
[ Upstream commit c7f49dadfcdf27e1f747442e874e9baa52ab7674 ]
skcipher_walk_done() can call kfree(), which takes a spinlock, which
makes it incorrect to call while preemption is disabled on PREEMPT_RT.
Therefore, end the kernel-mode FPU section before calling
skcipher_walk_done(), and restart it afterwards.
Moreover, pass atomic=false to skcipher_walk_aead_encrypt() instead of
atomic=true. The point of atomic=true was to make skcipher_walk_done()
safe to call while in a kernel-mode FPU section, but that does not
actually work. So just use the usual atomic=false.
Fixes: 1d373d4e8e15 ("crypto: x86 - Add optimized AEGIS implementations")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Stable-dep-of: 3d9eb180fbe8 ("crypto: x86/aegis - Add missing error checks")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/crypto/aegis128-aesni-glue.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/x86/crypto/aegis128-aesni-glue.c b/arch/x86/crypto/aegis128-aesni-glue.c
index e7a28ccf273bf..de0aab6997d41 100644
--- a/arch/x86/crypto/aegis128-aesni-glue.c
+++ b/arch/x86/crypto/aegis128-aesni-glue.c
@@ -123,7 +123,9 @@ crypto_aegis128_aesni_process_crypt(struct aegis_state *state,
walk->dst.virt.addr,
round_down(walk->nbytes,
AEGIS128_BLOCK_SIZE));
+ kernel_fpu_end();
skcipher_walk_done(walk, walk->nbytes % AEGIS128_BLOCK_SIZE);
+ kernel_fpu_begin();
}
if (walk->nbytes) {
@@ -135,7 +137,9 @@ crypto_aegis128_aesni_process_crypt(struct aegis_state *state,
aegis128_aesni_dec_tail(state, walk->src.virt.addr,
walk->dst.virt.addr,
walk->nbytes);
+ kernel_fpu_end();
skcipher_walk_done(walk, 0);
+ kernel_fpu_begin();
}
}
@@ -180,9 +184,9 @@ crypto_aegis128_aesni_crypt(struct aead_request *req,
struct aegis_state state;
if (enc)
- skcipher_walk_aead_encrypt(&walk, req, true);
+ skcipher_walk_aead_encrypt(&walk, req, false);
else
- skcipher_walk_aead_decrypt(&walk, req, true);
+ skcipher_walk_aead_decrypt(&walk, req, false);
kernel_fpu_begin();
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 111/869] crypto: x86/aegis - Add missing error checks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (109 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 110/869] crypto: x86/aegis - Fix sleeping when disallowed on PREEMPT_RT Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 112/869] net/mlx5: HWS, denote how refcounts are protected Greg Kroah-Hartman
` (758 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Eric Biggers, Herbert Xu,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <ebiggers@kernel.org>
[ Upstream commit 3d9eb180fbe8828cce43bce4c370124685b205c3 ]
The skcipher_walk functions can allocate memory and can fail, so
checking for errors is necessary.
Fixes: 1d373d4e8e15 ("crypto: x86 - Add optimized AEGIS implementations")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/crypto/aegis128-aesni-glue.c | 36 +++++++++++++++++++--------
1 file changed, 25 insertions(+), 11 deletions(-)
diff --git a/arch/x86/crypto/aegis128-aesni-glue.c b/arch/x86/crypto/aegis128-aesni-glue.c
index de0aab6997d41..f5bbf274a54e9 100644
--- a/arch/x86/crypto/aegis128-aesni-glue.c
+++ b/arch/x86/crypto/aegis128-aesni-glue.c
@@ -108,10 +108,12 @@ static void crypto_aegis128_aesni_process_ad(
}
}
-static __always_inline void
+static __always_inline int
crypto_aegis128_aesni_process_crypt(struct aegis_state *state,
struct skcipher_walk *walk, bool enc)
{
+ int err = 0;
+
while (walk->nbytes >= AEGIS128_BLOCK_SIZE) {
if (enc)
aegis128_aesni_enc(state, walk->src.virt.addr,
@@ -124,7 +126,8 @@ crypto_aegis128_aesni_process_crypt(struct aegis_state *state,
round_down(walk->nbytes,
AEGIS128_BLOCK_SIZE));
kernel_fpu_end();
- skcipher_walk_done(walk, walk->nbytes % AEGIS128_BLOCK_SIZE);
+ err = skcipher_walk_done(walk,
+ walk->nbytes % AEGIS128_BLOCK_SIZE);
kernel_fpu_begin();
}
@@ -138,9 +141,10 @@ crypto_aegis128_aesni_process_crypt(struct aegis_state *state,
walk->dst.virt.addr,
walk->nbytes);
kernel_fpu_end();
- skcipher_walk_done(walk, 0);
+ err = skcipher_walk_done(walk, 0);
kernel_fpu_begin();
}
+ return err;
}
static struct aegis_ctx *crypto_aegis128_aesni_ctx(struct crypto_aead *aead)
@@ -173,7 +177,7 @@ static int crypto_aegis128_aesni_setauthsize(struct crypto_aead *tfm,
return 0;
}
-static __always_inline void
+static __always_inline int
crypto_aegis128_aesni_crypt(struct aead_request *req,
struct aegis_block *tag_xor,
unsigned int cryptlen, bool enc)
@@ -182,20 +186,24 @@ crypto_aegis128_aesni_crypt(struct aead_request *req,
struct aegis_ctx *ctx = crypto_aegis128_aesni_ctx(tfm);
struct skcipher_walk walk;
struct aegis_state state;
+ int err;
if (enc)
- skcipher_walk_aead_encrypt(&walk, req, false);
+ err = skcipher_walk_aead_encrypt(&walk, req, false);
else
- skcipher_walk_aead_decrypt(&walk, req, false);
+ err = skcipher_walk_aead_decrypt(&walk, req, false);
+ if (err)
+ return err;
kernel_fpu_begin();
aegis128_aesni_init(&state, &ctx->key, req->iv);
crypto_aegis128_aesni_process_ad(&state, req->src, req->assoclen);
- crypto_aegis128_aesni_process_crypt(&state, &walk, enc);
- aegis128_aesni_final(&state, tag_xor, req->assoclen, cryptlen);
-
+ err = crypto_aegis128_aesni_process_crypt(&state, &walk, enc);
+ if (err == 0)
+ aegis128_aesni_final(&state, tag_xor, req->assoclen, cryptlen);
kernel_fpu_end();
+ return err;
}
static int crypto_aegis128_aesni_encrypt(struct aead_request *req)
@@ -204,8 +212,11 @@ static int crypto_aegis128_aesni_encrypt(struct aead_request *req)
struct aegis_block tag = {};
unsigned int authsize = crypto_aead_authsize(tfm);
unsigned int cryptlen = req->cryptlen;
+ int err;
- crypto_aegis128_aesni_crypt(req, &tag, cryptlen, true);
+ err = crypto_aegis128_aesni_crypt(req, &tag, cryptlen, true);
+ if (err)
+ return err;
scatterwalk_map_and_copy(tag.bytes, req->dst,
req->assoclen + cryptlen, authsize, 1);
@@ -220,11 +231,14 @@ static int crypto_aegis128_aesni_decrypt(struct aead_request *req)
struct aegis_block tag;
unsigned int authsize = crypto_aead_authsize(tfm);
unsigned int cryptlen = req->cryptlen - authsize;
+ int err;
scatterwalk_map_and_copy(tag.bytes, req->src,
req->assoclen + cryptlen, authsize, 0);
- crypto_aegis128_aesni_crypt(req, &tag, cryptlen, false);
+ err = crypto_aegis128_aesni_crypt(req, &tag, cryptlen, false);
+ if (err)
+ return err;
return crypto_memneq(tag.bytes, zeros.bytes, authsize) ? -EBADMSG : 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 112/869] net/mlx5: HWS, denote how refcounts are protected
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (110 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 111/869] crypto: x86/aegis - Add missing error checks Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 113/869] net/mlx5: HWS, simplify allocations as we support only FDB Greg Kroah-Hartman
` (757 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yevgeny Kliteynik, Erez Shitrit,
Mark Bloch, Tariq Toukan, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yevgeny Kliteynik <kliteyn@nvidia.com>
[ Upstream commit 0a1ef807a403b2f386a571133eb35e25c6511808 ]
Some HWS structs have refcounts that are just u32.
Comment how they are protected and add '__must_hold()'
annotation where applicable.
Signed-off-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Erez Shitrit <erezsh@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/20250102181415.1477316-4-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 2c0a959bebdc ("net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h | 4 ++--
.../ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.h | 2 +-
.../mellanox/mlx5/core/steering/hws/mlx5hws_definer.h | 2 +-
.../mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.h | 2 +-
.../ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c | 3 ++-
5 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h
index bf5c1b2410060..2de7c3c842f64 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h
@@ -70,12 +70,12 @@ struct mlx5hws_action_default_stc {
struct mlx5hws_pool_chunk nop_dw6;
struct mlx5hws_pool_chunk nop_dw7;
struct mlx5hws_pool_chunk default_hit;
- u32 refcount;
+ u32 refcount; /* protected by context ctrl lock */
};
struct mlx5hws_action_shared_stc {
struct mlx5hws_pool_chunk stc_chunk;
- u32 refcount;
+ u32 refcount; /* protected by context ctrl lock */
};
struct mlx5hws_actions_apply_data {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.h
index 2fbcf4ff571a0..e93955ddfbb83 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.h
@@ -63,7 +63,7 @@ struct mlx5hws_cmd_forward_tbl {
u8 type;
u32 ft_id;
u32 fg_id;
- u32 refcount;
+ u32 refcount; /* protected by context ctrl lock */
};
struct mlx5hws_cmd_rtc_create_attr {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.h
index 2f6a7df4021c8..5d186350dc089 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.h
@@ -785,7 +785,7 @@ struct mlx5hws_definer_cache {
struct mlx5hws_definer_cache_item {
struct mlx5hws_definer definer;
- u32 refcount;
+ u32 refcount; /* protected by context ctrl lock */
struct list_head list_node;
};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.h
index 27ca93385b084..8ddb519800445 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.h
@@ -31,7 +31,7 @@ struct mlx5hws_pattern_cache_item {
u8 *data;
u16 num_of_actions;
} mh_data;
- u32 refcount;
+ u32 refcount; /* protected by pattern_cache lock */
struct list_head ptrn_list_node;
};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c
index 9cbe3d71e6f3d..6544d2fcb48ba 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c
@@ -37,6 +37,7 @@ static void hws_table_set_cap_attr(struct mlx5hws_table *tbl,
}
static int hws_table_up_default_fdb_miss_tbl(struct mlx5hws_table *tbl)
+__must_hold(&tbl->ctx->ctrl_lock)
{
struct mlx5hws_cmd_ft_create_attr ft_attr = {0};
struct mlx5hws_cmd_set_fte_attr fte_attr = {0};
@@ -70,7 +71,6 @@ static int hws_table_up_default_fdb_miss_tbl(struct mlx5hws_table *tbl)
return -EINVAL;
}
- /* ctx->ctrl_lock must be held here */
ctx->common_res[tbl_type].default_miss = default_miss;
ctx->common_res[tbl_type].default_miss->refcount++;
@@ -79,6 +79,7 @@ static int hws_table_up_default_fdb_miss_tbl(struct mlx5hws_table *tbl)
/* Called under ctx->ctrl_lock */
static void hws_table_down_default_fdb_miss_tbl(struct mlx5hws_table *tbl)
+__must_hold(&tbl->ctx->ctrl_lock)
{
struct mlx5hws_cmd_forward_tbl *default_miss;
struct mlx5hws_context *ctx = tbl->ctx;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 113/869] net/mlx5: HWS, simplify allocations as we support only FDB
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (111 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 112/869] net/mlx5: HWS, denote how refcounts are protected Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 114/869] net/mlx5: HWS, handle returned error value in pool alloc Greg Kroah-Hartman
` (756 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yevgeny Kliteynik, Erez Shitrit,
Mark Bloch, Tariq Toukan, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yevgeny Kliteynik <kliteyn@nvidia.com>
[ Upstream commit c86963aae5b83a865a552408b40e743c3610bd9f ]
In pools, STCs and actions: no need to allocate array for various
table types, as HWS is used to manage only FDB flow tables.
Signed-off-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Erez Shitrit <erezsh@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/20250102181415.1477316-5-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 2c0a959bebdc ("net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../mlx5/core/steering/hws/mlx5hws_action.c | 107 +++++++++---------
.../mlx5/core/steering/hws/mlx5hws_action.h | 2 +-
.../mlx5/core/steering/hws/mlx5hws_cmd.c | 2 +-
.../mlx5/core/steering/hws/mlx5hws_context.c | 29 ++---
.../mlx5/core/steering/hws/mlx5hws_context.h | 4 +-
.../mlx5/core/steering/hws/mlx5hws_debug.c | 36 +++---
.../mlx5/core/steering/hws/mlx5hws_matcher.c | 4 +-
.../mlx5/core/steering/hws/mlx5hws_rule.c | 2 +-
.../mlx5/core/steering/hws/mlx5hws_table.c | 13 +--
9 files changed, 87 insertions(+), 112 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
index b27bb41065326..ef3e5caf75495 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
@@ -11,31 +11,29 @@
/* This is the longest supported action sequence for FDB table:
* DECAP, POP_VLAN, MODIFY, CTR, ASO, PUSH_VLAN, MODIFY, ENCAP, Term.
*/
-static const u32 action_order_arr[MLX5HWS_TABLE_TYPE_MAX][MLX5HWS_ACTION_TYP_MAX] = {
- [MLX5HWS_TABLE_TYPE_FDB] = {
- BIT(MLX5HWS_ACTION_TYP_REMOVE_HEADER) |
- BIT(MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2) |
- BIT(MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2),
- BIT(MLX5HWS_ACTION_TYP_POP_VLAN),
- BIT(MLX5HWS_ACTION_TYP_POP_VLAN),
- BIT(MLX5HWS_ACTION_TYP_MODIFY_HDR),
- BIT(MLX5HWS_ACTION_TYP_PUSH_VLAN),
- BIT(MLX5HWS_ACTION_TYP_PUSH_VLAN),
- BIT(MLX5HWS_ACTION_TYP_INSERT_HEADER) |
- BIT(MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2) |
- BIT(MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3),
- BIT(MLX5HWS_ACTION_TYP_CTR),
- BIT(MLX5HWS_ACTION_TYP_TAG),
- BIT(MLX5HWS_ACTION_TYP_ASO_METER),
- BIT(MLX5HWS_ACTION_TYP_MODIFY_HDR),
- BIT(MLX5HWS_ACTION_TYP_TBL) |
- BIT(MLX5HWS_ACTION_TYP_VPORT) |
- BIT(MLX5HWS_ACTION_TYP_DROP) |
- BIT(MLX5HWS_ACTION_TYP_SAMPLER) |
- BIT(MLX5HWS_ACTION_TYP_RANGE) |
- BIT(MLX5HWS_ACTION_TYP_DEST_ARRAY),
- BIT(MLX5HWS_ACTION_TYP_LAST),
- },
+static const u32 action_order_arr[MLX5HWS_ACTION_TYP_MAX] = {
+ BIT(MLX5HWS_ACTION_TYP_REMOVE_HEADER) |
+ BIT(MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2) |
+ BIT(MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2),
+ BIT(MLX5HWS_ACTION_TYP_POP_VLAN),
+ BIT(MLX5HWS_ACTION_TYP_POP_VLAN),
+ BIT(MLX5HWS_ACTION_TYP_MODIFY_HDR),
+ BIT(MLX5HWS_ACTION_TYP_PUSH_VLAN),
+ BIT(MLX5HWS_ACTION_TYP_PUSH_VLAN),
+ BIT(MLX5HWS_ACTION_TYP_INSERT_HEADER) |
+ BIT(MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2) |
+ BIT(MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3),
+ BIT(MLX5HWS_ACTION_TYP_CTR),
+ BIT(MLX5HWS_ACTION_TYP_TAG),
+ BIT(MLX5HWS_ACTION_TYP_ASO_METER),
+ BIT(MLX5HWS_ACTION_TYP_MODIFY_HDR),
+ BIT(MLX5HWS_ACTION_TYP_TBL) |
+ BIT(MLX5HWS_ACTION_TYP_VPORT) |
+ BIT(MLX5HWS_ACTION_TYP_DROP) |
+ BIT(MLX5HWS_ACTION_TYP_SAMPLER) |
+ BIT(MLX5HWS_ACTION_TYP_RANGE) |
+ BIT(MLX5HWS_ACTION_TYP_DEST_ARRAY),
+ BIT(MLX5HWS_ACTION_TYP_LAST),
};
static const char * const mlx5hws_action_type_str[] = {
@@ -83,8 +81,8 @@ static int hws_action_get_shared_stc_nic(struct mlx5hws_context *ctx,
int ret;
mutex_lock(&ctx->ctrl_lock);
- if (ctx->common_res[tbl_type].shared_stc[stc_type]) {
- ctx->common_res[tbl_type].shared_stc[stc_type]->refcount++;
+ if (ctx->common_res.shared_stc[stc_type]) {
+ ctx->common_res.shared_stc[stc_type]->refcount++;
mutex_unlock(&ctx->ctrl_lock);
return 0;
}
@@ -124,8 +122,8 @@ static int hws_action_get_shared_stc_nic(struct mlx5hws_context *ctx,
goto free_shared_stc;
}
- ctx->common_res[tbl_type].shared_stc[stc_type] = shared_stc;
- ctx->common_res[tbl_type].shared_stc[stc_type]->refcount = 1;
+ ctx->common_res.shared_stc[stc_type] = shared_stc;
+ ctx->common_res.shared_stc[stc_type]->refcount = 1;
mutex_unlock(&ctx->ctrl_lock);
@@ -178,16 +176,16 @@ static void hws_action_put_shared_stc(struct mlx5hws_action *action,
}
mutex_lock(&ctx->ctrl_lock);
- if (--ctx->common_res[tbl_type].shared_stc[stc_type]->refcount) {
+ if (--ctx->common_res.shared_stc[stc_type]->refcount) {
mutex_unlock(&ctx->ctrl_lock);
return;
}
- shared_stc = ctx->common_res[tbl_type].shared_stc[stc_type];
+ shared_stc = ctx->common_res.shared_stc[stc_type];
mlx5hws_action_free_single_stc(ctx, tbl_type, &shared_stc->stc_chunk);
kfree(shared_stc);
- ctx->common_res[tbl_type].shared_stc[stc_type] = NULL;
+ ctx->common_res.shared_stc[stc_type] = NULL;
mutex_unlock(&ctx->ctrl_lock);
}
@@ -206,10 +204,10 @@ bool mlx5hws_action_check_combo(struct mlx5hws_context *ctx,
enum mlx5hws_action_type *user_actions,
enum mlx5hws_table_type table_type)
{
- const u32 *order_arr = action_order_arr[table_type];
+ const u32 *order_arr = action_order_arr;
+ bool valid_combo;
u8 order_idx = 0;
u8 user_idx = 0;
- bool valid_combo;
if (table_type >= MLX5HWS_TABLE_TYPE_MAX) {
mlx5hws_err(ctx, "Invalid table_type %d", table_type);
@@ -321,8 +319,8 @@ int mlx5hws_action_alloc_single_stc(struct mlx5hws_context *ctx,
__must_hold(&ctx->ctrl_lock)
{
struct mlx5hws_cmd_stc_modify_attr cleanup_stc_attr = {0};
- struct mlx5hws_pool *stc_pool = ctx->stc_pool[table_type];
struct mlx5hws_cmd_stc_modify_attr fixup_stc_attr = {0};
+ struct mlx5hws_pool *stc_pool = ctx->stc_pool;
bool use_fixup;
u32 obj_0_id;
int ret;
@@ -387,8 +385,8 @@ void mlx5hws_action_free_single_stc(struct mlx5hws_context *ctx,
struct mlx5hws_pool_chunk *stc)
__must_hold(&ctx->ctrl_lock)
{
- struct mlx5hws_pool *stc_pool = ctx->stc_pool[table_type];
struct mlx5hws_cmd_stc_modify_attr stc_attr = {0};
+ struct mlx5hws_pool *stc_pool = ctx->stc_pool;
u32 obj_id;
/* Modify the STC not to point to an object */
@@ -561,7 +559,7 @@ hws_action_create_stcs(struct mlx5hws_action *action, u32 obj_id)
if (action->flags & MLX5HWS_ACTION_FLAG_HWS_FDB) {
ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr,
MLX5HWS_TABLE_TYPE_FDB,
- &action->stc[MLX5HWS_TABLE_TYPE_FDB]);
+ &action->stc);
if (ret)
goto out_err;
}
@@ -585,7 +583,7 @@ hws_action_destroy_stcs(struct mlx5hws_action *action)
if (action->flags & MLX5HWS_ACTION_FLAG_HWS_FDB)
mlx5hws_action_free_single_stc(ctx, MLX5HWS_TABLE_TYPE_FDB,
- &action->stc[MLX5HWS_TABLE_TYPE_FDB]);
+ &action->stc);
mutex_unlock(&ctx->ctrl_lock);
}
@@ -1639,8 +1637,8 @@ hws_action_create_dest_match_range_table(struct mlx5hws_context *ctx,
rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(MLX5HWS_TABLE_TYPE_FDB, false);
/* STC is a single resource (obj_id), use any STC for the ID */
- stc_pool = ctx->stc_pool[MLX5HWS_TABLE_TYPE_FDB];
- default_stc = ctx->common_res[MLX5HWS_TABLE_TYPE_FDB].default_stc;
+ stc_pool = ctx->stc_pool;
+ default_stc = ctx->common_res.default_stc;
obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, &default_stc->default_hit);
rtc_attr.stc_base = obj_id;
@@ -1731,7 +1729,7 @@ hws_action_create_dest_match_range_fill_table(struct mlx5hws_context *ctx,
ste_attr.used_id_rtc_0 = &used_rtc_0_id;
ste_attr.used_id_rtc_1 = &used_rtc_1_id;
- common_res = &ctx->common_res[MLX5HWS_TABLE_TYPE_FDB];
+ common_res = &ctx->common_res;
/* init an empty match STE which will always hit */
ste_attr.wqe_ctrl = &wqe_ctrl;
@@ -1750,7 +1748,7 @@ hws_action_create_dest_match_range_fill_table(struct mlx5hws_context *ctx,
wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_CTRL] |=
htonl(MLX5HWS_ACTION_STC_IDX_LAST_COMBO2 << 29);
wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_HIT] =
- htonl(hit_ft_action->stc[MLX5HWS_TABLE_TYPE_FDB].offset);
+ htonl(hit_ft_action->stc.offset);
wqe_data_arr = (__force __be32 *)&range_wqe_data;
@@ -1843,7 +1841,7 @@ mlx5hws_action_create_dest_match_range(struct mlx5hws_context *ctx,
stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer;
ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, MLX5HWS_TABLE_TYPE_FDB,
- &action->stc[MLX5HWS_TABLE_TYPE_FDB]);
+ &action->stc);
if (ret)
goto error_unlock;
@@ -1970,8 +1968,8 @@ __must_hold(&ctx->ctrl_lock)
struct mlx5hws_action_default_stc *default_stc;
int ret;
- if (ctx->common_res[tbl_type].default_stc) {
- ctx->common_res[tbl_type].default_stc->refcount++;
+ if (ctx->common_res.default_stc) {
+ ctx->common_res.default_stc->refcount++;
return 0;
}
@@ -2023,8 +2021,8 @@ __must_hold(&ctx->ctrl_lock)
goto free_nop_dw7;
}
- ctx->common_res[tbl_type].default_stc = default_stc;
- ctx->common_res[tbl_type].default_stc->refcount++;
+ ctx->common_res.default_stc = default_stc;
+ ctx->common_res.default_stc->refcount++;
return 0;
@@ -2046,9 +2044,7 @@ __must_hold(&ctx->ctrl_lock)
{
struct mlx5hws_action_default_stc *default_stc;
- default_stc = ctx->common_res[tbl_type].default_stc;
-
- default_stc = ctx->common_res[tbl_type].default_stc;
+ default_stc = ctx->common_res.default_stc;
if (--default_stc->refcount)
return;
@@ -2058,7 +2054,7 @@ __must_hold(&ctx->ctrl_lock)
mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5);
mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr);
kfree(default_stc);
- ctx->common_res[tbl_type].default_stc = NULL;
+ ctx->common_res.default_stc = NULL;
}
static void hws_action_modify_write(struct mlx5hws_send_engine *queue,
@@ -2150,8 +2146,7 @@ hws_action_apply_stc(struct mlx5hws_actions_apply_data *apply,
{
struct mlx5hws_action *action = apply->rule_action[action_idx].action;
- apply->wqe_ctrl->stc_ix[stc_idx] =
- htonl(action->stc[apply->tbl_type].offset);
+ apply->wqe_ctrl->stc_ix[stc_idx] = htonl(action->stc.offset);
}
static void
@@ -2181,7 +2176,7 @@ hws_action_setter_modify_header(struct mlx5hws_actions_apply_data *apply,
rule_action = &apply->rule_action[setter->idx_double];
action = rule_action->action;
- stc_idx = htonl(action->stc[apply->tbl_type].offset);
+ stc_idx = htonl(action->stc.offset);
apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = stc_idx;
apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0;
@@ -2240,7 +2235,7 @@ hws_action_setter_insert_ptr(struct mlx5hws_actions_apply_data *apply,
apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0;
apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = htonl(arg_idx);
- stc_idx = htonl(action->stc[apply->tbl_type].offset);
+ stc_idx = htonl(action->stc.offset);
apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = stc_idx;
apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0;
@@ -2272,7 +2267,7 @@ hws_action_setter_tnl_l3_to_l2(struct mlx5hws_actions_apply_data *apply,
apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0;
apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = htonl(arg_idx);
- stc_idx = htonl(action->stc[apply->tbl_type].offset);
+ stc_idx = htonl(action->stc.offset);
apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = stc_idx;
apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h
index 2de7c3c842f64..2283eefeb2233 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h
@@ -124,7 +124,7 @@ struct mlx5hws_action {
struct mlx5hws_context *ctx;
union {
struct {
- struct mlx5hws_pool_chunk stc[MLX5HWS_TABLE_TYPE_MAX];
+ struct mlx5hws_pool_chunk stc;
union {
struct {
u32 pat_id;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.c
index 2c7b14172049b..7b8eefead1a02 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.c
@@ -359,7 +359,7 @@ void mlx5hws_cmd_set_attr_connect_miss_tbl(struct mlx5hws_context *ctx,
ft_attr->type = fw_ft_type;
ft_attr->table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_GOTO_TBL;
- default_miss_tbl = ctx->common_res[type].default_miss->ft_id;
+ default_miss_tbl = ctx->common_res.default_miss->ft_id;
if (!default_miss_tbl) {
pr_warn("HWS: no flow table ID for default miss\n");
return;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c
index 00e4fdf4a558b..a4cc81849ebe2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c
@@ -23,7 +23,6 @@ static int hws_context_pools_init(struct mlx5hws_context *ctx)
struct mlx5hws_pool_attr pool_attr = {0};
u8 max_log_sz;
int ret;
- int i;
ret = mlx5hws_pat_init_pattern_cache(&ctx->pattern_cache);
if (ret)
@@ -39,23 +38,17 @@ static int hws_context_pools_init(struct mlx5hws_context *ctx)
max_log_sz = min(MLX5HWS_POOL_STC_LOG_SZ, ctx->caps->stc_alloc_log_max);
pool_attr.alloc_log_sz = max(max_log_sz, ctx->caps->stc_alloc_log_gran);
- for (i = 0; i < MLX5HWS_TABLE_TYPE_MAX; i++) {
- pool_attr.table_type = i;
- ctx->stc_pool[i] = mlx5hws_pool_create(ctx, &pool_attr);
- if (!ctx->stc_pool[i]) {
- mlx5hws_err(ctx, "Failed to allocate STC pool [%d]", i);
- ret = -ENOMEM;
- goto free_stc_pools;
- }
+ pool_attr.table_type = MLX5HWS_TABLE_TYPE_FDB;
+ ctx->stc_pool = mlx5hws_pool_create(ctx, &pool_attr);
+ if (!ctx->stc_pool) {
+ mlx5hws_err(ctx, "Failed to allocate STC pool\n");
+ ret = -ENOMEM;
+ goto uninit_cache;
}
return 0;
-free_stc_pools:
- for (i = 0; i < MLX5HWS_TABLE_TYPE_MAX; i++)
- if (ctx->stc_pool[i])
- mlx5hws_pool_destroy(ctx->stc_pool[i]);
-
+uninit_cache:
mlx5hws_definer_uninit_cache(ctx->definer_cache);
uninit_pat_cache:
mlx5hws_pat_uninit_pattern_cache(ctx->pattern_cache);
@@ -64,12 +57,8 @@ static int hws_context_pools_init(struct mlx5hws_context *ctx)
static void hws_context_pools_uninit(struct mlx5hws_context *ctx)
{
- int i;
-
- for (i = 0; i < MLX5HWS_TABLE_TYPE_MAX; i++) {
- if (ctx->stc_pool[i])
- mlx5hws_pool_destroy(ctx->stc_pool[i]);
- }
+ if (ctx->stc_pool)
+ mlx5hws_pool_destroy(ctx->stc_pool);
mlx5hws_definer_uninit_cache(ctx->definer_cache);
mlx5hws_pat_uninit_pattern_cache(ctx->pattern_cache);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.h
index 8ab548aa402be..6cd3c613eac18 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.h
@@ -37,8 +37,8 @@ struct mlx5hws_context {
struct mlx5_core_dev *mdev;
struct mlx5hws_cmd_query_caps *caps;
u32 pd_num;
- struct mlx5hws_pool *stc_pool[MLX5HWS_TABLE_TYPE_MAX];
- struct mlx5hws_context_common_res common_res[MLX5HWS_TABLE_TYPE_MAX];
+ struct mlx5hws_pool *stc_pool;
+ struct mlx5hws_context_common_res common_res;
struct mlx5hws_pattern_cache *pattern_cache;
struct mlx5hws_definer_cache *definer_cache;
struct mutex ctrl_lock; /* control lock to protect the whole context */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c
index 2b8c5a4e1c4c0..0ec60c25596dd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c
@@ -368,9 +368,10 @@ static int hws_debug_dump_context_info(struct seq_file *f, struct mlx5hws_contex
static int hws_debug_dump_context_stc_resource(struct seq_file *f,
struct mlx5hws_context *ctx,
- u32 tbl_type,
struct mlx5hws_pool_resource *resource)
{
+ u32 tbl_type = MLX5HWS_TABLE_TYPE_BASE + MLX5HWS_TABLE_TYPE_FDB;
+
seq_printf(f, "%d,0x%llx,%u,%u\n",
MLX5HWS_DEBUG_RES_TYPE_CONTEXT_STC,
HWS_PTR_TO_ID(ctx),
@@ -382,31 +383,22 @@ static int hws_debug_dump_context_stc_resource(struct seq_file *f,
static int hws_debug_dump_context_stc(struct seq_file *f, struct mlx5hws_context *ctx)
{
- struct mlx5hws_pool *stc_pool;
- u32 table_type;
+ struct mlx5hws_pool *stc_pool = ctx->stc_pool;
int ret;
- int i;
-
- for (i = 0; i < MLX5HWS_TABLE_TYPE_MAX; i++) {
- stc_pool = ctx->stc_pool[i];
- table_type = MLX5HWS_TABLE_TYPE_BASE + i;
- if (!stc_pool)
- continue;
+ if (!stc_pool)
+ return 0;
- if (stc_pool->resource[0]) {
- ret = hws_debug_dump_context_stc_resource(f, ctx, table_type,
- stc_pool->resource[0]);
- if (ret)
- return ret;
- }
+ if (stc_pool->resource[0]) {
+ ret = hws_debug_dump_context_stc_resource(f, ctx, stc_pool->resource[0]);
+ if (ret)
+ return ret;
+ }
- if (i == MLX5HWS_TABLE_TYPE_FDB && stc_pool->mirror_resource[0]) {
- ret = hws_debug_dump_context_stc_resource(f, ctx, table_type,
- stc_pool->mirror_resource[0]);
- if (ret)
- return ret;
- }
+ if (stc_pool->mirror_resource[0]) {
+ ret = hws_debug_dump_context_stc_resource(f, ctx, stc_pool->mirror_resource[0]);
+ if (ret)
+ return ret;
}
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
index ce541c60c5b49..e4b24996bb74c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
@@ -310,8 +310,8 @@ static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher,
hws_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, false);
/* STC is a single resource (obj_id), use any STC for the ID */
- stc_pool = ctx->stc_pool[tbl->type];
- default_stc = ctx->common_res[tbl->type].default_stc;
+ stc_pool = ctx->stc_pool;
+ default_stc = ctx->common_res.default_stc;
obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, &default_stc->default_hit);
rtc_attr.stc_base = obj_id;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c
index 8a011b958b431..a40c66410585b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c
@@ -315,7 +315,7 @@ static void hws_rule_create_init(struct mlx5hws_rule *rule,
/* Init default action apply */
apply->tbl_type = tbl->type;
- apply->common_res = &ctx->common_res[tbl->type];
+ apply->common_res = &ctx->common_res;
apply->jump_to_action_stc = matcher->action_ste[0].stc.offset;
apply->require_dep = 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c
index 6544d2fcb48ba..0f413547e89b8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c
@@ -49,8 +49,8 @@ __must_hold(&tbl->ctx->ctrl_lock)
if (tbl->type != MLX5HWS_TABLE_TYPE_FDB)
return 0;
- if (ctx->common_res[tbl_type].default_miss) {
- ctx->common_res[tbl_type].default_miss->refcount++;
+ if (ctx->common_res.default_miss) {
+ ctx->common_res.default_miss->refcount++;
return 0;
}
@@ -71,8 +71,8 @@ __must_hold(&tbl->ctx->ctrl_lock)
return -EINVAL;
}
- ctx->common_res[tbl_type].default_miss = default_miss;
- ctx->common_res[tbl_type].default_miss->refcount++;
+ ctx->common_res.default_miss = default_miss;
+ ctx->common_res.default_miss->refcount++;
return 0;
}
@@ -83,17 +83,16 @@ __must_hold(&tbl->ctx->ctrl_lock)
{
struct mlx5hws_cmd_forward_tbl *default_miss;
struct mlx5hws_context *ctx = tbl->ctx;
- u8 tbl_type = tbl->type;
if (tbl->type != MLX5HWS_TABLE_TYPE_FDB)
return;
- default_miss = ctx->common_res[tbl_type].default_miss;
+ default_miss = ctx->common_res.default_miss;
if (--default_miss->refcount)
return;
mlx5hws_cmd_forward_tbl_destroy(ctx->mdev, default_miss);
- ctx->common_res[tbl_type].default_miss = NULL;
+ ctx->common_res.default_miss = NULL;
}
static int hws_table_connect_to_default_miss_tbl(struct mlx5hws_table *tbl, u32 ft_id)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 114/869] net/mlx5: HWS, handle returned error value in pool alloc
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (112 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 113/869] net/mlx5: HWS, simplify allocations as we support only FDB Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 115/869] net/mlx5: HWS, update flow - remove the use of dual RTCs Greg Kroah-Hartman
` (755 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vlad Dogaru, Yevgeny Kliteynik,
Mark Bloch, Tariq Toukan, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vlad Dogaru <vdogaru@nvidia.com>
[ Upstream commit a105db854cf2e495caaa17f00ac0321b503def9b ]
Handle all negative return values as errors, not just -1.
The code previously treated -ENOMEM (and potentially other negative
values) as valid segment numbers, leading to incorrect behavior.
This fix ensures that any negative return value is treated as an error.
Signed-off-by: Vlad Dogaru <vdogaru@nvidia.com>
Signed-off-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/20250102181415.1477316-13-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 2c0a959bebdc ("net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
index a8a63e3278be3..048b97de07625 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
@@ -183,7 +183,7 @@ static int hws_pool_buddy_get_mem_chunk(struct mlx5hws_pool *pool,
*seg = -1;
/* Find the next free place from the buddy array */
- while (*seg == -1) {
+ while (*seg < 0) {
for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) {
buddy = hws_pool_buddy_get_next_buddy(pool, i,
order,
@@ -194,7 +194,7 @@ static int hws_pool_buddy_get_mem_chunk(struct mlx5hws_pool *pool,
}
*seg = mlx5hws_buddy_alloc_mem(buddy, order);
- if (*seg != -1)
+ if (*seg >= 0)
goto found;
if (pool->flags & MLX5HWS_POOL_FLAGS_ONE_RESOURCE) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 115/869] net/mlx5: HWS, update flow - remove the use of dual RTCs
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (113 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 114/869] net/mlx5: HWS, handle returned error value in pool alloc Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 116/869] net/mlx5: HWS, Remove unused element array Greg Kroah-Hartman
` (754 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yevgeny Kliteynik, Vlad Dogaru,
Mark Bloch, Tariq Toukan, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yevgeny Kliteynik <kliteyn@nvidia.com>
[ Upstream commit ab6912ff6558a504d9a02c01333ef8f4247681ad ]
This patch is the first part of update flow implementation.
Update flow should support rules with single STE (match STE only),
as well as rules with multiple STEs (match STE plus action STEs).
Supporting the rules with single STE is straightforward: we just
overwrite the STE, which is an atomic operation.
Supporting the rules with action STEs is a more complicated case.
The existing implementation uses two action RTCs per matcher and
alternates between the two for each update request.
This implementation was unnecessarily complex and lead to some
unhandled edge cases, so the support for rule update with multiple
STEs wasn't really functional.
This patch removes this code, and the next patch adds implementation
of a different approach.
Note that after applying this patch and before applying the next
patch we still have support for update rule with single STE (only
match STE w/o action STEs), but update will fail for rules with
action STEs.
Signed-off-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Signed-off-by: Vlad Dogaru <vdogaru@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/20250109160546.1733647-15-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 2c0a959bebdc ("net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../mlx5/core/steering/hws/mlx5hws_debug.c | 10 +-
.../mlx5/core/steering/hws/mlx5hws_internal.h | 1 -
.../mlx5/core/steering/hws/mlx5hws_matcher.c | 170 +++++++-----------
.../mlx5/core/steering/hws/mlx5hws_matcher.h | 8 +-
.../mlx5/core/steering/hws/mlx5hws_rule.c | 73 ++------
.../mlx5/core/steering/hws/mlx5hws_rule.h | 3 +-
6 files changed, 81 insertions(+), 184 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c
index 0ec60c25596dd..d8ac4a445e099 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c
@@ -148,8 +148,8 @@ static int hws_debug_dump_matcher(struct seq_file *f, struct mlx5hws_matcher *ma
matcher->match_ste.rtc_1_id,
(int)ste_1_id);
- ste = &matcher->action_ste[0].ste;
- ste_pool = matcher->action_ste[0].pool;
+ ste = &matcher->action_ste.ste;
+ ste_pool = matcher->action_ste.pool;
if (ste_pool) {
ste_0_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste);
if (tbl_type == MLX5HWS_TABLE_TYPE_FDB)
@@ -171,10 +171,8 @@ static int hws_debug_dump_matcher(struct seq_file *f, struct mlx5hws_matcher *ma
return ret;
seq_printf(f, ",%d,%d,%d,%d,%d,0x%llx,0x%llx\n",
- matcher->action_ste[0].rtc_0_id,
- (int)ste_0_id,
- matcher->action_ste[0].rtc_1_id,
- (int)ste_1_id,
+ matcher->action_ste.rtc_0_id, (int)ste_0_id,
+ matcher->action_ste.rtc_1_id, (int)ste_1_id,
0,
mlx5hws_debug_icm_to_idx(icm_addr_0),
mlx5hws_debug_icm_to_idx(icm_addr_1));
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_internal.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_internal.h
index 5643be1cd5bf3..73511a5ab02ae 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_internal.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_internal.h
@@ -39,7 +39,6 @@
#define mlx5hws_dbg(ctx, arg...) mlx5_core_dbg((ctx)->mdev, ##arg)
#define MLX5HWS_TABLE_TYPE_BASE 2
-#define MLX5HWS_ACTION_STE_IDX_ANY 0
static inline bool is_mem_zero(const u8 *mem, size_t size)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
index e4b24996bb74c..41511d0b6268d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
@@ -200,7 +200,7 @@ static void hws_matcher_set_rtc_attr_sz(struct mlx5hws_matcher *matcher,
enum mlx5hws_matcher_rtc_type rtc_type,
bool is_mirror)
{
- struct mlx5hws_pool_chunk *ste = &matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].ste;
+ struct mlx5hws_pool_chunk *ste = &matcher->action_ste.ste;
enum mlx5hws_matcher_flow_src flow_src = matcher->attr.optimize_flow_src;
bool is_match_rtc = rtc_type == HWS_MATCHER_RTC_TYPE_MATCH;
@@ -217,8 +217,7 @@ static void hws_matcher_set_rtc_attr_sz(struct mlx5hws_matcher *matcher,
}
static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher,
- enum mlx5hws_matcher_rtc_type rtc_type,
- u8 action_ste_selector)
+ enum mlx5hws_matcher_rtc_type rtc_type)
{
struct mlx5hws_matcher_attr *attr = &matcher->attr;
struct mlx5hws_cmd_rtc_create_attr rtc_attr = {0};
@@ -278,7 +277,7 @@ static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher,
break;
case HWS_MATCHER_RTC_TYPE_STE_ARRAY:
- action_ste = &matcher->action_ste[action_ste_selector];
+ action_ste = &matcher->action_ste;
rtc_0_id = &action_ste->rtc_0_id;
rtc_1_id = &action_ste->rtc_1_id;
@@ -350,8 +349,7 @@ static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher,
}
static void hws_matcher_destroy_rtc(struct mlx5hws_matcher *matcher,
- enum mlx5hws_matcher_rtc_type rtc_type,
- u8 action_ste_selector)
+ enum mlx5hws_matcher_rtc_type rtc_type)
{
struct mlx5hws_matcher_action_ste *action_ste;
struct mlx5hws_table *tbl = matcher->tbl;
@@ -367,7 +365,7 @@ static void hws_matcher_destroy_rtc(struct mlx5hws_matcher *matcher,
ste = &matcher->match_ste.ste;
break;
case HWS_MATCHER_RTC_TYPE_STE_ARRAY:
- action_ste = &matcher->action_ste[action_ste_selector];
+ action_ste = &matcher->action_ste;
rtc_0_id = action_ste->rtc_0_id;
rtc_1_id = action_ste->rtc_1_id;
ste_pool = action_ste->pool;
@@ -458,20 +456,13 @@ static int hws_matcher_resize_init(struct mlx5hws_matcher *src_matcher)
if (!resize_data)
return -ENOMEM;
- resize_data->max_stes = src_matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes;
-
- resize_data->action_ste[0].stc = src_matcher->action_ste[0].stc;
- resize_data->action_ste[0].rtc_0_id = src_matcher->action_ste[0].rtc_0_id;
- resize_data->action_ste[0].rtc_1_id = src_matcher->action_ste[0].rtc_1_id;
- resize_data->action_ste[0].pool = src_matcher->action_ste[0].max_stes ?
- src_matcher->action_ste[0].pool :
- NULL;
- resize_data->action_ste[1].stc = src_matcher->action_ste[1].stc;
- resize_data->action_ste[1].rtc_0_id = src_matcher->action_ste[1].rtc_0_id;
- resize_data->action_ste[1].rtc_1_id = src_matcher->action_ste[1].rtc_1_id;
- resize_data->action_ste[1].pool = src_matcher->action_ste[1].max_stes ?
- src_matcher->action_ste[1].pool :
- NULL;
+ resize_data->max_stes = src_matcher->action_ste.max_stes;
+
+ resize_data->stc = src_matcher->action_ste.stc;
+ resize_data->rtc_0_id = src_matcher->action_ste.rtc_0_id;
+ resize_data->rtc_1_id = src_matcher->action_ste.rtc_1_id;
+ resize_data->pool = src_matcher->action_ste.max_stes ?
+ src_matcher->action_ste.pool : NULL;
/* Place the new resized matcher on the dst matcher's list */
list_add(&resize_data->list_node, &src_matcher->resize_dst->resize_data);
@@ -504,42 +495,60 @@ static void hws_matcher_resize_uninit(struct mlx5hws_matcher *matcher)
if (resize_data->max_stes) {
mlx5hws_action_free_single_stc(matcher->tbl->ctx,
matcher->tbl->type,
- &resize_data->action_ste[1].stc);
- mlx5hws_action_free_single_stc(matcher->tbl->ctx,
- matcher->tbl->type,
- &resize_data->action_ste[0].stc);
+ &resize_data->stc);
- if (matcher->tbl->type == MLX5HWS_TABLE_TYPE_FDB) {
+ if (matcher->tbl->type == MLX5HWS_TABLE_TYPE_FDB)
mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev,
- resize_data->action_ste[1].rtc_1_id);
- mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev,
- resize_data->action_ste[0].rtc_1_id);
- }
- mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev,
- resize_data->action_ste[1].rtc_0_id);
+ resize_data->rtc_1_id);
+
mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev,
- resize_data->action_ste[0].rtc_0_id);
- if (resize_data->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].pool) {
- mlx5hws_pool_destroy(resize_data->action_ste[1].pool);
- mlx5hws_pool_destroy(resize_data->action_ste[0].pool);
- }
+ resize_data->rtc_0_id);
+
+ if (resize_data->pool)
+ mlx5hws_pool_destroy(resize_data->pool);
}
kfree(resize_data);
}
}
-static int
-hws_matcher_bind_at_idx(struct mlx5hws_matcher *matcher, u8 action_ste_selector)
+static int hws_matcher_bind_at(struct mlx5hws_matcher *matcher)
{
+ bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(matcher->mt);
struct mlx5hws_cmd_stc_modify_attr stc_attr = {0};
struct mlx5hws_matcher_action_ste *action_ste;
struct mlx5hws_table *tbl = matcher->tbl;
struct mlx5hws_pool_attr pool_attr = {0};
struct mlx5hws_context *ctx = tbl->ctx;
- int ret;
+ u32 required_stes;
+ u8 max_stes = 0;
+ int i, ret;
- action_ste = &matcher->action_ste[action_ste_selector];
+ if (matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION)
+ return 0;
+
+ for (i = 0; i < matcher->num_of_at; i++) {
+ struct mlx5hws_action_template *at = &matcher->at[i];
+
+ ret = hws_matcher_check_and_process_at(matcher, at);
+ if (ret) {
+ mlx5hws_err(ctx, "Invalid at %d", i);
+ return ret;
+ }
+
+ required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term);
+ max_stes = max(max_stes, required_stes);
+
+ /* Future: Optimize reparse */
+ }
+
+ /* There are no additional STEs required for matcher */
+ if (!max_stes)
+ return 0;
+
+ matcher->action_ste.max_stes = max_stes;
+
+ action_ste = &matcher->action_ste;
/* Allocate action STE mempool */
pool_attr.table_type = tbl->type;
@@ -555,7 +564,7 @@ hws_matcher_bind_at_idx(struct mlx5hws_matcher *matcher, u8 action_ste_selector)
}
/* Allocate action RTC */
- ret = hws_matcher_create_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY, action_ste_selector);
+ ret = hws_matcher_create_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY);
if (ret) {
mlx5hws_err(ctx, "Failed to create action RTC\n");
goto free_ste_pool;
@@ -579,18 +588,18 @@ hws_matcher_bind_at_idx(struct mlx5hws_matcher *matcher, u8 action_ste_selector)
return 0;
free_rtc:
- hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY, action_ste_selector);
+ hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY);
free_ste_pool:
mlx5hws_pool_destroy(action_ste->pool);
return ret;
}
-static void hws_matcher_unbind_at_idx(struct mlx5hws_matcher *matcher, u8 action_ste_selector)
+static void hws_matcher_unbind_at(struct mlx5hws_matcher *matcher)
{
struct mlx5hws_matcher_action_ste *action_ste;
struct mlx5hws_table *tbl = matcher->tbl;
- action_ste = &matcher->action_ste[action_ste_selector];
+ action_ste = &matcher->action_ste;
if (!action_ste->max_stes ||
matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION ||
@@ -598,65 +607,10 @@ static void hws_matcher_unbind_at_idx(struct mlx5hws_matcher *matcher, u8 action
return;
mlx5hws_action_free_single_stc(tbl->ctx, tbl->type, &action_ste->stc);
- hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY, action_ste_selector);
+ hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY);
mlx5hws_pool_destroy(action_ste->pool);
}
-static int hws_matcher_bind_at(struct mlx5hws_matcher *matcher)
-{
- bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(matcher->mt);
- struct mlx5hws_table *tbl = matcher->tbl;
- struct mlx5hws_context *ctx = tbl->ctx;
- u32 required_stes;
- u8 max_stes = 0;
- int i, ret;
-
- if (matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION)
- return 0;
-
- for (i = 0; i < matcher->num_of_at; i++) {
- struct mlx5hws_action_template *at = &matcher->at[i];
-
- ret = hws_matcher_check_and_process_at(matcher, at);
- if (ret) {
- mlx5hws_err(ctx, "Invalid at %d", i);
- return ret;
- }
-
- required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term);
- max_stes = max(max_stes, required_stes);
-
- /* Future: Optimize reparse */
- }
-
- /* There are no additional STEs required for matcher */
- if (!max_stes)
- return 0;
-
- matcher->action_ste[0].max_stes = max_stes;
- matcher->action_ste[1].max_stes = max_stes;
-
- ret = hws_matcher_bind_at_idx(matcher, 0);
- if (ret)
- return ret;
-
- ret = hws_matcher_bind_at_idx(matcher, 1);
- if (ret)
- goto free_at_0;
-
- return 0;
-
-free_at_0:
- hws_matcher_unbind_at_idx(matcher, 0);
- return ret;
-}
-
-static void hws_matcher_unbind_at(struct mlx5hws_matcher *matcher)
-{
- hws_matcher_unbind_at_idx(matcher, 1);
- hws_matcher_unbind_at_idx(matcher, 0);
-}
-
static int hws_matcher_bind_mt(struct mlx5hws_matcher *matcher)
{
struct mlx5hws_context *ctx = matcher->tbl->ctx;
@@ -802,7 +756,7 @@ static int hws_matcher_create_and_connect(struct mlx5hws_matcher *matcher)
goto unbind_at;
/* Allocate the RTC for the new matcher */
- ret = hws_matcher_create_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH, 0);
+ ret = hws_matcher_create_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH);
if (ret)
goto destroy_end_ft;
@@ -814,7 +768,7 @@ static int hws_matcher_create_and_connect(struct mlx5hws_matcher *matcher)
return 0;
destroy_rtc:
- hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH, 0);
+ hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH);
destroy_end_ft:
hws_matcher_destroy_end_ft(matcher);
unbind_at:
@@ -828,7 +782,7 @@ static void hws_matcher_destroy_and_disconnect(struct mlx5hws_matcher *matcher)
{
hws_matcher_resize_uninit(matcher);
hws_matcher_disconnect(matcher);
- hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH, 0);
+ hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH);
hws_matcher_destroy_end_ft(matcher);
hws_matcher_unbind_at(matcher);
hws_matcher_unbind_mt(matcher);
@@ -962,10 +916,9 @@ int mlx5hws_matcher_attach_at(struct mlx5hws_matcher *matcher,
return ret;
required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term);
- if (matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes < required_stes) {
+ if (matcher->action_ste.max_stes < required_stes) {
mlx5hws_dbg(ctx, "Required STEs [%d] exceeds initial action template STE [%d]\n",
- required_stes,
- matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes);
+ required_stes, matcher->action_ste.max_stes);
return -ENOMEM;
}
@@ -1149,8 +1102,7 @@ static int hws_matcher_resize_precheck(struct mlx5hws_matcher *src_matcher,
return -EINVAL;
}
- if (src_matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes >
- dst_matcher->action_ste[0].max_stes) {
+ if (src_matcher->action_ste.max_stes > dst_matcher->action_ste.max_stes) {
mlx5hws_err(ctx, "Src/dst matcher max STEs mismatch\n");
return -EINVAL;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.h
index 125391d1a1148..b9075919a4c96 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.h
@@ -52,15 +52,11 @@ struct mlx5hws_matcher_action_ste {
u8 max_stes;
};
-struct mlx5hws_matcher_resize_data_node {
+struct mlx5hws_matcher_resize_data {
struct mlx5hws_pool_chunk stc;
u32 rtc_0_id;
u32 rtc_1_id;
struct mlx5hws_pool *pool;
-};
-
-struct mlx5hws_matcher_resize_data {
- struct mlx5hws_matcher_resize_data_node action_ste[2];
u8 max_stes;
struct list_head list_node;
};
@@ -78,7 +74,7 @@ struct mlx5hws_matcher {
struct mlx5hws_matcher *col_matcher;
struct mlx5hws_matcher *resize_dst;
struct mlx5hws_matcher_match_ste match_ste;
- struct mlx5hws_matcher_action_ste action_ste[2];
+ struct mlx5hws_matcher_action_ste action_ste;
struct list_head list_node;
struct list_head resize_data;
};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c
index a40c66410585b..97195c643a583 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c
@@ -142,14 +142,9 @@ hws_rule_save_resize_info(struct mlx5hws_rule *rule,
return;
}
- rule->resize_info->max_stes =
- rule->matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes;
- rule->resize_info->action_ste_pool[0] = rule->matcher->action_ste[0].max_stes ?
- rule->matcher->action_ste[0].pool :
- NULL;
- rule->resize_info->action_ste_pool[1] = rule->matcher->action_ste[1].max_stes ?
- rule->matcher->action_ste[1].pool :
- NULL;
+ rule->resize_info->max_stes = rule->matcher->action_ste.max_stes;
+ rule->resize_info->action_ste_pool = rule->matcher->action_ste.max_stes ?
+ rule->matcher->action_ste.pool : NULL;
}
memcpy(rule->resize_info->ctrl_seg, ste_attr->wqe_ctrl,
@@ -204,15 +199,15 @@ hws_rule_load_delete_info(struct mlx5hws_rule *rule,
}
}
-static int hws_rule_alloc_action_ste_idx(struct mlx5hws_rule *rule,
- u8 action_ste_selector)
+static int hws_rule_alloc_action_ste(struct mlx5hws_rule *rule,
+ struct mlx5hws_rule_attr *attr)
{
struct mlx5hws_matcher *matcher = rule->matcher;
struct mlx5hws_matcher_action_ste *action_ste;
struct mlx5hws_pool_chunk ste = {0};
int ret;
- action_ste = &matcher->action_ste[action_ste_selector];
+ action_ste = &matcher->action_ste;
ste.order = ilog2(roundup_pow_of_two(action_ste->max_stes));
ret = mlx5hws_pool_chunk_alloc(action_ste->pool, &ste);
if (unlikely(ret)) {
@@ -225,8 +220,7 @@ static int hws_rule_alloc_action_ste_idx(struct mlx5hws_rule *rule,
return 0;
}
-static void hws_rule_free_action_ste_idx(struct mlx5hws_rule *rule,
- u8 action_ste_selector)
+void mlx5hws_rule_free_action_ste(struct mlx5hws_rule *rule)
{
struct mlx5hws_matcher *matcher = rule->matcher;
struct mlx5hws_pool_chunk ste = {0};
@@ -236,10 +230,10 @@ static void hws_rule_free_action_ste_idx(struct mlx5hws_rule *rule,
if (mlx5hws_matcher_is_resizable(matcher)) {
/* Free the original action pool if rule was resized */
max_stes = rule->resize_info->max_stes;
- pool = rule->resize_info->action_ste_pool[action_ste_selector];
+ pool = rule->resize_info->action_ste_pool;
} else {
- max_stes = matcher->action_ste[action_ste_selector].max_stes;
- pool = matcher->action_ste[action_ste_selector].pool;
+ max_stes = matcher->action_ste.max_stes;
+ pool = matcher->action_ste.pool;
}
/* This release is safe only when the rule match part was deleted */
@@ -249,41 +243,6 @@ static void hws_rule_free_action_ste_idx(struct mlx5hws_rule *rule,
mlx5hws_pool_chunk_free(pool, &ste);
}
-static int hws_rule_alloc_action_ste(struct mlx5hws_rule *rule,
- struct mlx5hws_rule_attr *attr)
-{
- int action_ste_idx;
- int ret;
-
- ret = hws_rule_alloc_action_ste_idx(rule, 0);
- if (unlikely(ret))
- return ret;
-
- action_ste_idx = rule->action_ste_idx;
-
- ret = hws_rule_alloc_action_ste_idx(rule, 1);
- if (unlikely(ret)) {
- hws_rule_free_action_ste_idx(rule, 0);
- return ret;
- }
-
- /* Both pools have to return the same index */
- if (unlikely(rule->action_ste_idx != action_ste_idx)) {
- pr_warn("HWS: allocation of action STE failed - pool indexes mismatch\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-void mlx5hws_rule_free_action_ste(struct mlx5hws_rule *rule)
-{
- if (rule->action_ste_idx > -1) {
- hws_rule_free_action_ste_idx(rule, 1);
- hws_rule_free_action_ste_idx(rule, 0);
- }
-}
-
static void hws_rule_create_init(struct mlx5hws_rule *rule,
struct mlx5hws_send_ste_attr *ste_attr,
struct mlx5hws_actions_apply_data *apply,
@@ -298,9 +257,6 @@ static void hws_rule_create_init(struct mlx5hws_rule *rule,
/* In update we use these rtc's */
rule->rtc_0 = 0;
rule->rtc_1 = 0;
- rule->action_ste_selector = 0;
- } else {
- rule->action_ste_selector = !rule->action_ste_selector;
}
rule->pending_wqes = 0;
@@ -316,7 +272,7 @@ static void hws_rule_create_init(struct mlx5hws_rule *rule,
/* Init default action apply */
apply->tbl_type = tbl->type;
apply->common_res = &ctx->common_res;
- apply->jump_to_action_stc = matcher->action_ste[0].stc.offset;
+ apply->jump_to_action_stc = matcher->action_ste.stc.offset;
apply->require_dep = 0;
}
@@ -333,7 +289,6 @@ static void hws_rule_move_init(struct mlx5hws_rule *rule,
rule->pending_wqes = 0;
rule->action_ste_idx = -1;
- rule->action_ste_selector = 0;
rule->status = MLX5HWS_RULE_STATUS_CREATING;
rule->resize_info->state = MLX5HWS_RULE_RESIZE_STATE_WRITING;
}
@@ -403,10 +358,8 @@ static int hws_rule_create_hws(struct mlx5hws_rule *rule,
}
}
/* Skip RX/TX based on the dep_wqe init */
- ste_attr.rtc_0 = dep_wqe->rtc_0 ?
- matcher->action_ste[rule->action_ste_selector].rtc_0_id : 0;
- ste_attr.rtc_1 = dep_wqe->rtc_1 ?
- matcher->action_ste[rule->action_ste_selector].rtc_1_id : 0;
+ ste_attr.rtc_0 = dep_wqe->rtc_0 ? matcher->action_ste.rtc_0_id : 0;
+ ste_attr.rtc_1 = dep_wqe->rtc_1 ? matcher->action_ste.rtc_1_id : 0;
/* Action STEs are written to a specific index last to first */
ste_attr.direct_index = rule->action_ste_idx + action_stes;
apply.next_direct_idx = ste_attr.direct_index;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.h
index 495cdd17e9f3c..fd2bef87116be 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.h
@@ -42,7 +42,7 @@ struct mlx5hws_rule_match_tag {
};
struct mlx5hws_rule_resize_info {
- struct mlx5hws_pool *action_ste_pool[2];
+ struct mlx5hws_pool *action_ste_pool;
u32 rtc_0;
u32 rtc_1;
u32 rule_idx;
@@ -62,7 +62,6 @@ struct mlx5hws_rule {
u32 rtc_1; /* The RTC into which the STE was inserted */
int action_ste_idx; /* STE array index */
u8 status; /* enum mlx5hws_rule_status */
- u8 action_ste_selector; /* For rule update - which action STE is in use */
u8 pending_wqes;
bool skip_delete; /* For complex rules - another rule with same tag
* still exists, so don't actually delete this rule.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 116/869] net/mlx5: HWS, Remove unused element array
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (114 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 115/869] net/mlx5: HWS, update flow - remove the use of dual RTCs Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 117/869] net/mlx5: HWS, Make pool single resource Greg Kroah-Hartman
` (753 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vlad Dogaru, Yevgeny Kliteynik,
Mark Bloch, Tariq Toukan, Michal Kubiak, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vlad Dogaru <vdogaru@nvidia.com>
[ Upstream commit b2ae16214ffeda3e1c25223eebe19f85b0876181 ]
Remove the array of elements wrapped in a struct because in reality only
the first element was ever used.
Signed-off-by: Vlad Dogaru <vdogaru@nvidia.com>
Reviewed-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Reviewed-by: Michal Kubiak <michal.kubiak@intel.com>
Link: https://patch.msgid.link/1744312662-356571-3-git-send-email-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 2c0a959bebdc ("net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../mlx5/core/steering/hws/mlx5hws_pool.c | 55 ++++++++-----------
.../mlx5/core/steering/hws/mlx5hws_pool.h | 6 +-
2 files changed, 23 insertions(+), 38 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
index 048b97de07625..866e6938e340c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
@@ -293,7 +293,7 @@ static int hws_pool_create_resource_on_index(struct mlx5hws_pool *pool,
}
static struct mlx5hws_pool_elements *
-hws_pool_element_create_new_elem(struct mlx5hws_pool *pool, u32 order, int idx)
+hws_pool_element_create_new_elem(struct mlx5hws_pool *pool, u32 order)
{
struct mlx5hws_pool_elements *elem;
u32 alloc_size;
@@ -311,21 +311,21 @@ hws_pool_element_create_new_elem(struct mlx5hws_pool *pool, u32 order, int idx)
elem->bitmap = hws_pool_create_and_init_bitmap(alloc_size - order);
if (!elem->bitmap) {
mlx5hws_err(pool->ctx,
- "Failed to create bitmap type: %d: size %d index: %d\n",
- pool->type, alloc_size, idx);
+ "Failed to create bitmap type: %d: size %d\n",
+ pool->type, alloc_size);
goto free_elem;
}
elem->log_size = alloc_size - order;
}
- if (hws_pool_create_resource_on_index(pool, alloc_size, idx)) {
- mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d index: %d\n",
- pool->type, alloc_size, idx);
+ if (hws_pool_create_resource_on_index(pool, alloc_size, 0)) {
+ mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d\n",
+ pool->type, alloc_size);
goto free_db;
}
- pool->db.element_manager->elements[idx] = elem;
+ pool->db.element = elem;
return elem;
@@ -359,9 +359,9 @@ hws_pool_onesize_element_get_mem_chunk(struct mlx5hws_pool *pool, u32 order,
{
struct mlx5hws_pool_elements *elem;
- elem = pool->db.element_manager->elements[0];
+ elem = pool->db.element;
if (!elem)
- elem = hws_pool_element_create_new_elem(pool, order, 0);
+ elem = hws_pool_element_create_new_elem(pool, order);
if (!elem)
goto err_no_elem;
@@ -451,16 +451,14 @@ static int hws_pool_general_element_db_init(struct mlx5hws_pool *pool)
return 0;
}
-static void hws_onesize_element_db_destroy_element(struct mlx5hws_pool *pool,
- struct mlx5hws_pool_elements *elem,
- struct mlx5hws_pool_chunk *chunk)
+static void
+hws_onesize_element_db_destroy_element(struct mlx5hws_pool *pool,
+ struct mlx5hws_pool_elements *elem)
{
- if (unlikely(!pool->resource[chunk->resource_idx]))
- pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx);
-
- hws_pool_resource_free(pool, chunk->resource_idx);
+ hws_pool_resource_free(pool, 0);
+ bitmap_free(elem->bitmap);
kfree(elem);
- pool->db.element_manager->elements[chunk->resource_idx] = NULL;
+ pool->db.element = NULL;
}
static void hws_onesize_element_db_put_chunk(struct mlx5hws_pool *pool,
@@ -471,7 +469,7 @@ static void hws_onesize_element_db_put_chunk(struct mlx5hws_pool *pool,
if (unlikely(chunk->resource_idx))
pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx);
- elem = pool->db.element_manager->elements[chunk->resource_idx];
+ elem = pool->db.element;
if (!elem) {
mlx5hws_err(pool->ctx, "No such element (%d)\n", chunk->resource_idx);
return;
@@ -483,7 +481,7 @@ static void hws_onesize_element_db_put_chunk(struct mlx5hws_pool *pool,
if (pool->flags & MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE &&
!elem->num_of_elements)
- hws_onesize_element_db_destroy_element(pool, elem, chunk);
+ hws_onesize_element_db_destroy_element(pool, elem);
}
static int hws_onesize_element_db_get_chunk(struct mlx5hws_pool *pool,
@@ -504,18 +502,13 @@ static int hws_onesize_element_db_get_chunk(struct mlx5hws_pool *pool,
static void hws_onesize_element_db_uninit(struct mlx5hws_pool *pool)
{
- struct mlx5hws_pool_elements *elem;
- int i;
+ struct mlx5hws_pool_elements *elem = pool->db.element;
- for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) {
- elem = pool->db.element_manager->elements[i];
- if (elem) {
- bitmap_free(elem->bitmap);
- kfree(elem);
- pool->db.element_manager->elements[i] = NULL;
- }
+ if (elem) {
+ bitmap_free(elem->bitmap);
+ kfree(elem);
+ pool->db.element = NULL;
}
- kfree(pool->db.element_manager);
}
/* This memory management works as the following:
@@ -526,10 +519,6 @@ static void hws_onesize_element_db_uninit(struct mlx5hws_pool *pool)
*/
static int hws_pool_onesize_element_db_init(struct mlx5hws_pool *pool)
{
- pool->db.element_manager = kzalloc(sizeof(*pool->db.element_manager), GFP_KERNEL);
- if (!pool->db.element_manager)
- return -ENOMEM;
-
pool->p_db_uninit = &hws_onesize_element_db_uninit;
pool->p_get_chunk = &hws_onesize_element_db_get_chunk;
pool->p_put_chunk = &hws_onesize_element_db_put_chunk;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h
index 621298b352b24..f4258f83fdbf7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h
@@ -87,14 +87,10 @@ struct mlx5hws_pool_elements {
bool is_full;
};
-struct mlx5hws_element_manager {
- struct mlx5hws_pool_elements *elements[MLX5HWS_POOL_RESOURCE_ARR_SZ];
-};
-
struct mlx5hws_pool_db {
enum mlx5hws_db_type type;
union {
- struct mlx5hws_element_manager *element_manager;
+ struct mlx5hws_pool_elements *element;
struct mlx5hws_buddy_manager *buddy_manager;
};
};
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 117/869] net/mlx5: HWS, Make pool single resource
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (115 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 116/869] net/mlx5: HWS, Remove unused element array Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 118/869] net/mlx5: HWS, Refactor pool implementation Greg Kroah-Hartman
` (752 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vlad Dogaru, Yevgeny Kliteynik,
Mark Bloch, Tariq Toukan, Michal Kubiak, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vlad Dogaru <vdogaru@nvidia.com>
[ Upstream commit 38956bea7349ce75c1519b57c27cd97580b4c822 ]
The pool implementation claimed to support multiple resources, but this
does not really make sense in context. Callers always allocate a single
STC or STE chunk of exactly the size provided.
The code that handled multiple resources was unused (and likely buggy)
due to the combination of flags passed by callers.
Simplify the pool by having it handle a single resource. As a result of
this simplification, chunks no longer contain a resource offset (there
is now only one resource per pool), and the get_base_id functions no
longer take a chunk parameter.
Signed-off-by: Vlad Dogaru <vdogaru@nvidia.com>
Reviewed-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Reviewed-by: Michal Kubiak <michal.kubiak@intel.com>
Link: https://patch.msgid.link/1744312662-356571-4-git-send-email-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 2c0a959bebdc ("net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../mlx5/core/steering/hws/mlx5hws_action.c | 27 ++-
.../mlx5/core/steering/hws/mlx5hws_debug.c | 22 +--
.../mlx5/core/steering/hws/mlx5hws_matcher.c | 10 +-
.../mlx5/core/steering/hws/mlx5hws_pool.c | 182 ++++++------------
.../mlx5/core/steering/hws/mlx5hws_pool.h | 28 +--
5 files changed, 91 insertions(+), 178 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
index ef3e5caf75495..041b063730bd9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
@@ -238,6 +238,7 @@ hws_action_fixup_stc_attr(struct mlx5hws_context *ctx,
enum mlx5hws_table_type table_type,
bool is_mirror)
{
+ struct mlx5hws_pool *pool;
bool use_fixup = false;
u32 fw_tbl_type;
u32 base_id;
@@ -253,13 +254,11 @@ hws_action_fixup_stc_attr(struct mlx5hws_context *ctx,
use_fixup = true;
break;
}
+ pool = stc_attr->ste_table.ste_pool;
if (!is_mirror)
- base_id = mlx5hws_pool_chunk_get_base_id(stc_attr->ste_table.ste_pool,
- &stc_attr->ste_table.ste);
+ base_id = mlx5hws_pool_get_base_id(pool);
else
- base_id =
- mlx5hws_pool_chunk_get_base_mirror_id(stc_attr->ste_table.ste_pool,
- &stc_attr->ste_table.ste);
+ base_id = mlx5hws_pool_get_base_mirror_id(pool);
*fixup_stc_attr = *stc_attr;
fixup_stc_attr->ste_table.ste_obj_id = base_id;
@@ -337,7 +336,7 @@ __must_hold(&ctx->ctrl_lock)
if (!mlx5hws_context_cap_dynamic_reparse(ctx))
stc_attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE;
- obj_0_id = mlx5hws_pool_chunk_get_base_id(stc_pool, stc);
+ obj_0_id = mlx5hws_pool_get_base_id(stc_pool);
/* According to table/action limitation change the stc_attr */
use_fixup = hws_action_fixup_stc_attr(ctx, stc_attr, &fixup_stc_attr, table_type, false);
@@ -353,7 +352,7 @@ __must_hold(&ctx->ctrl_lock)
if (table_type == MLX5HWS_TABLE_TYPE_FDB) {
u32 obj_1_id;
- obj_1_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, stc);
+ obj_1_id = mlx5hws_pool_get_base_mirror_id(stc_pool);
use_fixup = hws_action_fixup_stc_attr(ctx, stc_attr,
&fixup_stc_attr,
@@ -393,11 +392,11 @@ __must_hold(&ctx->ctrl_lock)
stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT;
stc_attr.stc_offset = stc->offset;
- obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, stc);
+ obj_id = mlx5hws_pool_get_base_id(stc_pool);
mlx5hws_cmd_stc_modify(ctx->mdev, obj_id, &stc_attr);
if (table_type == MLX5HWS_TABLE_TYPE_FDB) {
- obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, stc);
+ obj_id = mlx5hws_pool_get_base_mirror_id(stc_pool);
mlx5hws_cmd_stc_modify(ctx->mdev, obj_id, &stc_attr);
}
@@ -1580,7 +1579,6 @@ hws_action_create_dest_match_range_table(struct mlx5hws_context *ctx,
u32 miss_ft_id)
{
struct mlx5hws_cmd_rtc_create_attr rtc_attr = {0};
- struct mlx5hws_action_default_stc *default_stc;
struct mlx5hws_matcher_action_ste *table_ste;
struct mlx5hws_pool_attr pool_attr = {0};
struct mlx5hws_pool *ste_pool, *stc_pool;
@@ -1628,7 +1626,7 @@ hws_action_create_dest_match_range_table(struct mlx5hws_context *ctx,
rtc_attr.fw_gen_wqe = true;
rtc_attr.is_scnd_range = true;
- obj_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste);
+ obj_id = mlx5hws_pool_get_base_id(ste_pool);
rtc_attr.pd = ctx->pd_num;
rtc_attr.ste_base = obj_id;
@@ -1638,8 +1636,7 @@ hws_action_create_dest_match_range_table(struct mlx5hws_context *ctx,
/* STC is a single resource (obj_id), use any STC for the ID */
stc_pool = ctx->stc_pool;
- default_stc = ctx->common_res.default_stc;
- obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, &default_stc->default_hit);
+ obj_id = mlx5hws_pool_get_base_id(stc_pool);
rtc_attr.stc_base = obj_id;
ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_0_id);
@@ -1649,11 +1646,11 @@ hws_action_create_dest_match_range_table(struct mlx5hws_context *ctx,
}
/* Create mirror RTC */
- obj_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste);
+ obj_id = mlx5hws_pool_get_base_mirror_id(ste_pool);
rtc_attr.ste_base = obj_id;
rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(MLX5HWS_TABLE_TYPE_FDB, true);
- obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, &default_stc->default_hit);
+ obj_id = mlx5hws_pool_get_base_mirror_id(stc_pool);
rtc_attr.stc_base = obj_id;
ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_1_id);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c
index d8ac4a445e099..e0a8de812dae9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c
@@ -118,7 +118,6 @@ static int hws_debug_dump_matcher(struct seq_file *f, struct mlx5hws_matcher *ma
{
enum mlx5hws_table_type tbl_type = matcher->tbl->type;
struct mlx5hws_cmd_ft_query_attr ft_attr = {0};
- struct mlx5hws_pool_chunk *ste;
struct mlx5hws_pool *ste_pool;
u64 icm_addr_0 = 0;
u64 icm_addr_1 = 0;
@@ -134,12 +133,11 @@ static int hws_debug_dump_matcher(struct seq_file *f, struct mlx5hws_matcher *ma
matcher->end_ft_id,
matcher->col_matcher ? HWS_PTR_TO_ID(matcher->col_matcher) : 0);
- ste = &matcher->match_ste.ste;
ste_pool = matcher->match_ste.pool;
if (ste_pool) {
- ste_0_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste);
+ ste_0_id = mlx5hws_pool_get_base_id(ste_pool);
if (tbl_type == MLX5HWS_TABLE_TYPE_FDB)
- ste_1_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste);
+ ste_1_id = mlx5hws_pool_get_base_mirror_id(ste_pool);
}
seq_printf(f, ",%d,%d,%d,%d",
@@ -148,12 +146,11 @@ static int hws_debug_dump_matcher(struct seq_file *f, struct mlx5hws_matcher *ma
matcher->match_ste.rtc_1_id,
(int)ste_1_id);
- ste = &matcher->action_ste.ste;
ste_pool = matcher->action_ste.pool;
if (ste_pool) {
- ste_0_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste);
+ ste_0_id = mlx5hws_pool_get_base_id(ste_pool);
if (tbl_type == MLX5HWS_TABLE_TYPE_FDB)
- ste_1_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste);
+ ste_1_id = mlx5hws_pool_get_base_mirror_id(ste_pool);
else
ste_1_id = -1;
} else {
@@ -387,14 +384,17 @@ static int hws_debug_dump_context_stc(struct seq_file *f, struct mlx5hws_context
if (!stc_pool)
return 0;
- if (stc_pool->resource[0]) {
- ret = hws_debug_dump_context_stc_resource(f, ctx, stc_pool->resource[0]);
+ if (stc_pool->resource) {
+ ret = hws_debug_dump_context_stc_resource(f, ctx,
+ stc_pool->resource);
if (ret)
return ret;
}
- if (stc_pool->mirror_resource[0]) {
- ret = hws_debug_dump_context_stc_resource(f, ctx, stc_pool->mirror_resource[0]);
+ if (stc_pool->mirror_resource) {
+ struct mlx5hws_pool_resource *res = stc_pool->mirror_resource;
+
+ ret = hws_debug_dump_context_stc_resource(f, ctx, res);
if (ret)
return ret;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
index 41511d0b6268d..270a00b68e614 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
@@ -223,7 +223,6 @@ static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher,
struct mlx5hws_cmd_rtc_create_attr rtc_attr = {0};
struct mlx5hws_match_template *mt = matcher->mt;
struct mlx5hws_context *ctx = matcher->tbl->ctx;
- struct mlx5hws_action_default_stc *default_stc;
struct mlx5hws_matcher_action_ste *action_ste;
struct mlx5hws_table *tbl = matcher->tbl;
struct mlx5hws_pool *ste_pool, *stc_pool;
@@ -299,7 +298,7 @@ static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher,
return -EINVAL;
}
- obj_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste);
+ obj_id = mlx5hws_pool_get_base_id(ste_pool);
rtc_attr.pd = ctx->pd_num;
rtc_attr.ste_base = obj_id;
@@ -310,8 +309,7 @@ static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher,
/* STC is a single resource (obj_id), use any STC for the ID */
stc_pool = ctx->stc_pool;
- default_stc = ctx->common_res.default_stc;
- obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, &default_stc->default_hit);
+ obj_id = mlx5hws_pool_get_base_id(stc_pool);
rtc_attr.stc_base = obj_id;
ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_0_id);
@@ -322,11 +320,11 @@ static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher,
}
if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) {
- obj_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste);
+ obj_id = mlx5hws_pool_get_base_mirror_id(ste_pool);
rtc_attr.ste_base = obj_id;
rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(tbl->type, true);
- obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, &default_stc->default_hit);
+ obj_id = mlx5hws_pool_get_base_mirror_id(stc_pool);
rtc_attr.stc_base = obj_id;
hws_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, true);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
index 866e6938e340c..4302565b49b5e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
@@ -20,15 +20,14 @@ static void hws_pool_free_one_resource(struct mlx5hws_pool_resource *resource)
kfree(resource);
}
-static void hws_pool_resource_free(struct mlx5hws_pool *pool,
- int resource_idx)
+static void hws_pool_resource_free(struct mlx5hws_pool *pool)
{
- hws_pool_free_one_resource(pool->resource[resource_idx]);
- pool->resource[resource_idx] = NULL;
+ hws_pool_free_one_resource(pool->resource);
+ pool->resource = NULL;
if (pool->tbl_type == MLX5HWS_TABLE_TYPE_FDB) {
- hws_pool_free_one_resource(pool->mirror_resource[resource_idx]);
- pool->mirror_resource[resource_idx] = NULL;
+ hws_pool_free_one_resource(pool->mirror_resource);
+ pool->mirror_resource = NULL;
}
}
@@ -78,7 +77,7 @@ hws_pool_create_one_resource(struct mlx5hws_pool *pool, u32 log_range,
}
static int
-hws_pool_resource_alloc(struct mlx5hws_pool *pool, u32 log_range, int idx)
+hws_pool_resource_alloc(struct mlx5hws_pool *pool, u32 log_range)
{
struct mlx5hws_pool_resource *resource;
u32 fw_ft_type, opt_log_range;
@@ -91,7 +90,7 @@ hws_pool_resource_alloc(struct mlx5hws_pool *pool, u32 log_range, int idx)
return -EINVAL;
}
- pool->resource[idx] = resource;
+ pool->resource = resource;
if (pool->tbl_type == MLX5HWS_TABLE_TYPE_FDB) {
struct mlx5hws_pool_resource *mirror_resource;
@@ -102,10 +101,10 @@ hws_pool_resource_alloc(struct mlx5hws_pool *pool, u32 log_range, int idx)
if (!mirror_resource) {
mlx5hws_err(pool->ctx, "Failed allocating mirrored resource\n");
hws_pool_free_one_resource(resource);
- pool->resource[idx] = NULL;
+ pool->resource = NULL;
return -EINVAL;
}
- pool->mirror_resource[idx] = mirror_resource;
+ pool->mirror_resource = mirror_resource;
}
return 0;
@@ -129,9 +128,9 @@ static void hws_pool_buddy_db_put_chunk(struct mlx5hws_pool *pool,
{
struct mlx5hws_buddy_mem *buddy;
- buddy = pool->db.buddy_manager->buddies[chunk->resource_idx];
+ buddy = pool->db.buddy;
if (!buddy) {
- mlx5hws_err(pool->ctx, "No such buddy (%d)\n", chunk->resource_idx);
+ mlx5hws_err(pool->ctx, "Bad buddy state\n");
return;
}
@@ -139,86 +138,50 @@ static void hws_pool_buddy_db_put_chunk(struct mlx5hws_pool *pool,
}
static struct mlx5hws_buddy_mem *
-hws_pool_buddy_get_next_buddy(struct mlx5hws_pool *pool, int idx,
- u32 order, bool *is_new_buddy)
+hws_pool_buddy_get_buddy(struct mlx5hws_pool *pool, u32 order)
{
static struct mlx5hws_buddy_mem *buddy;
u32 new_buddy_size;
- buddy = pool->db.buddy_manager->buddies[idx];
+ buddy = pool->db.buddy;
if (buddy)
return buddy;
new_buddy_size = max(pool->alloc_log_sz, order);
- *is_new_buddy = true;
buddy = mlx5hws_buddy_create(new_buddy_size);
if (!buddy) {
- mlx5hws_err(pool->ctx, "Failed to create buddy order: %d index: %d\n",
- new_buddy_size, idx);
+ mlx5hws_err(pool->ctx, "Failed to create buddy order: %d\n",
+ new_buddy_size);
return NULL;
}
- if (hws_pool_resource_alloc(pool, new_buddy_size, idx) != 0) {
- mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d index: %d\n",
- pool->type, new_buddy_size, idx);
+ if (hws_pool_resource_alloc(pool, new_buddy_size) != 0) {
+ mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d\n",
+ pool->type, new_buddy_size);
mlx5hws_buddy_cleanup(buddy);
return NULL;
}
- pool->db.buddy_manager->buddies[idx] = buddy;
+ pool->db.buddy = buddy;
return buddy;
}
static int hws_pool_buddy_get_mem_chunk(struct mlx5hws_pool *pool,
int order,
- u32 *buddy_idx,
int *seg)
{
struct mlx5hws_buddy_mem *buddy;
- bool new_mem = false;
- int ret = 0;
- int i;
-
- *seg = -1;
-
- /* Find the next free place from the buddy array */
- while (*seg < 0) {
- for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) {
- buddy = hws_pool_buddy_get_next_buddy(pool, i,
- order,
- &new_mem);
- if (!buddy) {
- ret = -ENOMEM;
- goto out;
- }
-
- *seg = mlx5hws_buddy_alloc_mem(buddy, order);
- if (*seg >= 0)
- goto found;
-
- if (pool->flags & MLX5HWS_POOL_FLAGS_ONE_RESOURCE) {
- mlx5hws_err(pool->ctx,
- "Fail to allocate seg for one resource pool\n");
- ret = -ENOMEM;
- goto out;
- }
-
- if (new_mem) {
- /* We have new memory pool, should be place for us */
- mlx5hws_err(pool->ctx,
- "No memory for order: %d with buddy no: %d\n",
- order, i);
- ret = -ENOMEM;
- goto out;
- }
- }
- }
-found:
- *buddy_idx = i;
-out:
- return ret;
+ buddy = hws_pool_buddy_get_buddy(pool, order);
+ if (!buddy)
+ return -ENOMEM;
+
+ *seg = mlx5hws_buddy_alloc_mem(buddy, order);
+ if (*seg >= 0)
+ return 0;
+
+ return -ENOMEM;
}
static int hws_pool_buddy_db_get_chunk(struct mlx5hws_pool *pool,
@@ -226,9 +189,7 @@ static int hws_pool_buddy_db_get_chunk(struct mlx5hws_pool *pool,
{
int ret = 0;
- /* Go over the buddies and find next free slot */
ret = hws_pool_buddy_get_mem_chunk(pool, chunk->order,
- &chunk->resource_idx,
&chunk->offset);
if (ret)
mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n",
@@ -240,33 +201,21 @@ static int hws_pool_buddy_db_get_chunk(struct mlx5hws_pool *pool,
static void hws_pool_buddy_db_uninit(struct mlx5hws_pool *pool)
{
struct mlx5hws_buddy_mem *buddy;
- int i;
-
- for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) {
- buddy = pool->db.buddy_manager->buddies[i];
- if (buddy) {
- mlx5hws_buddy_cleanup(buddy);
- kfree(buddy);
- pool->db.buddy_manager->buddies[i] = NULL;
- }
- }
- kfree(pool->db.buddy_manager);
+ buddy = pool->db.buddy;
+ if (buddy) {
+ mlx5hws_buddy_cleanup(buddy);
+ kfree(buddy);
+ pool->db.buddy = NULL;
+ }
}
static int hws_pool_buddy_db_init(struct mlx5hws_pool *pool, u32 log_range)
{
- pool->db.buddy_manager = kzalloc(sizeof(*pool->db.buddy_manager), GFP_KERNEL);
- if (!pool->db.buddy_manager)
- return -ENOMEM;
-
if (pool->flags & MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE) {
- bool new_buddy;
-
- if (!hws_pool_buddy_get_next_buddy(pool, 0, log_range, &new_buddy)) {
+ if (!hws_pool_buddy_get_buddy(pool, log_range)) {
mlx5hws_err(pool->ctx,
"Failed allocating memory on create log_sz: %d\n", log_range);
- kfree(pool->db.buddy_manager);
return -ENOMEM;
}
}
@@ -278,14 +227,13 @@ static int hws_pool_buddy_db_init(struct mlx5hws_pool *pool, u32 log_range)
return 0;
}
-static int hws_pool_create_resource_on_index(struct mlx5hws_pool *pool,
- u32 alloc_size, int idx)
+static int hws_pool_create_resource(struct mlx5hws_pool *pool, u32 alloc_size)
{
- int ret = hws_pool_resource_alloc(pool, alloc_size, idx);
+ int ret = hws_pool_resource_alloc(pool, alloc_size);
if (ret) {
- mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d index: %d\n",
- pool->type, alloc_size, idx);
+ mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d\n",
+ pool->type, alloc_size);
return ret;
}
@@ -319,7 +267,7 @@ hws_pool_element_create_new_elem(struct mlx5hws_pool *pool, u32 order)
elem->log_size = alloc_size - order;
}
- if (hws_pool_create_resource_on_index(pool, alloc_size, 0)) {
+ if (hws_pool_create_resource(pool, alloc_size)) {
mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d\n",
pool->type, alloc_size);
goto free_db;
@@ -355,7 +303,7 @@ static int hws_pool_element_find_seg(struct mlx5hws_pool_elements *elem, int *se
static int
hws_pool_onesize_element_get_mem_chunk(struct mlx5hws_pool *pool, u32 order,
- u32 *idx, int *seg)
+ int *seg)
{
struct mlx5hws_pool_elements *elem;
@@ -370,7 +318,6 @@ hws_pool_onesize_element_get_mem_chunk(struct mlx5hws_pool *pool, u32 order,
return -ENOMEM;
}
- *idx = 0;
elem->num_of_elements++;
return 0;
@@ -379,21 +326,17 @@ hws_pool_onesize_element_get_mem_chunk(struct mlx5hws_pool *pool, u32 order,
return -ENOMEM;
}
-static int
-hws_pool_general_element_get_mem_chunk(struct mlx5hws_pool *pool, u32 order,
- u32 *idx, int *seg)
+static int hws_pool_general_element_get_mem_chunk(struct mlx5hws_pool *pool,
+ u32 order, int *seg)
{
- int ret, i;
-
- for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) {
- if (!pool->resource[i]) {
- ret = hws_pool_create_resource_on_index(pool, order, i);
- if (ret)
- goto err_no_res;
- *idx = i;
- *seg = 0; /* One memory slot in that element */
- return 0;
- }
+ int ret;
+
+ if (!pool->resource) {
+ ret = hws_pool_create_resource(pool, order);
+ if (ret)
+ goto err_no_res;
+ *seg = 0; /* One memory slot in that element */
+ return 0;
}
mlx5hws_err(pool->ctx, "No more resources (last request order: %d)\n", order);
@@ -409,9 +352,7 @@ static int hws_pool_general_element_db_get_chunk(struct mlx5hws_pool *pool,
{
int ret;
- /* Go over all memory elements and find/allocate free slot */
ret = hws_pool_general_element_get_mem_chunk(pool, chunk->order,
- &chunk->resource_idx,
&chunk->offset);
if (ret)
mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n",
@@ -423,11 +364,8 @@ static int hws_pool_general_element_db_get_chunk(struct mlx5hws_pool *pool,
static void hws_pool_general_element_db_put_chunk(struct mlx5hws_pool *pool,
struct mlx5hws_pool_chunk *chunk)
{
- if (unlikely(!pool->resource[chunk->resource_idx]))
- pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx);
-
if (pool->flags & MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE)
- hws_pool_resource_free(pool, chunk->resource_idx);
+ hws_pool_resource_free(pool);
}
static void hws_pool_general_element_db_uninit(struct mlx5hws_pool *pool)
@@ -455,7 +393,7 @@ static void
hws_onesize_element_db_destroy_element(struct mlx5hws_pool *pool,
struct mlx5hws_pool_elements *elem)
{
- hws_pool_resource_free(pool, 0);
+ hws_pool_resource_free(pool);
bitmap_free(elem->bitmap);
kfree(elem);
pool->db.element = NULL;
@@ -466,12 +404,9 @@ static void hws_onesize_element_db_put_chunk(struct mlx5hws_pool *pool,
{
struct mlx5hws_pool_elements *elem;
- if (unlikely(chunk->resource_idx))
- pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx);
-
elem = pool->db.element;
if (!elem) {
- mlx5hws_err(pool->ctx, "No such element (%d)\n", chunk->resource_idx);
+ mlx5hws_err(pool->ctx, "Pool element was not allocated\n");
return;
}
@@ -489,9 +424,7 @@ static int hws_onesize_element_db_get_chunk(struct mlx5hws_pool *pool,
{
int ret = 0;
- /* Go over all memory elements and find/allocate free slot */
ret = hws_pool_onesize_element_get_mem_chunk(pool, chunk->order,
- &chunk->resource_idx,
&chunk->offset);
if (ret)
mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n",
@@ -614,13 +547,10 @@ mlx5hws_pool_create(struct mlx5hws_context *ctx, struct mlx5hws_pool_attr *pool_
int mlx5hws_pool_destroy(struct mlx5hws_pool *pool)
{
- int i;
-
mutex_destroy(&pool->lock);
- for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++)
- if (pool->resource[i])
- hws_pool_resource_free(pool, i);
+ if (pool->resource)
+ hws_pool_resource_free(pool);
hws_pool_db_unint(pool);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h
index f4258f83fdbf7..112a61cd29979 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h
@@ -6,16 +6,12 @@
#define MLX5HWS_POOL_STC_LOG_SZ 15
-#define MLX5HWS_POOL_RESOURCE_ARR_SZ 100
-
enum mlx5hws_pool_type {
MLX5HWS_POOL_TYPE_STE,
MLX5HWS_POOL_TYPE_STC,
};
struct mlx5hws_pool_chunk {
- u32 resource_idx;
- /* Internal offset, relative to base index */
int offset;
int order;
};
@@ -72,14 +68,10 @@ enum mlx5hws_db_type {
MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE,
/* One resource only, all the elements are with same one size */
MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE,
- /* Many resources, the memory allocated with buddy mechanism */
+ /* Entries are managed using a buddy mechanism. */
MLX5HWS_POOL_DB_TYPE_BUDDY,
};
-struct mlx5hws_buddy_manager {
- struct mlx5hws_buddy_mem *buddies[MLX5HWS_POOL_RESOURCE_ARR_SZ];
-};
-
struct mlx5hws_pool_elements {
u32 num_of_elements;
unsigned long *bitmap;
@@ -91,7 +83,7 @@ struct mlx5hws_pool_db {
enum mlx5hws_db_type type;
union {
struct mlx5hws_pool_elements *element;
- struct mlx5hws_buddy_manager *buddy_manager;
+ struct mlx5hws_buddy_mem *buddy;
};
};
@@ -109,8 +101,8 @@ struct mlx5hws_pool {
size_t alloc_log_sz;
enum mlx5hws_table_type tbl_type;
enum mlx5hws_pool_optimize opt_type;
- struct mlx5hws_pool_resource *resource[MLX5HWS_POOL_RESOURCE_ARR_SZ];
- struct mlx5hws_pool_resource *mirror_resource[MLX5HWS_POOL_RESOURCE_ARR_SZ];
+ struct mlx5hws_pool_resource *resource;
+ struct mlx5hws_pool_resource *mirror_resource;
/* DB */
struct mlx5hws_pool_db db;
/* Functions */
@@ -131,17 +123,13 @@ int mlx5hws_pool_chunk_alloc(struct mlx5hws_pool *pool,
void mlx5hws_pool_chunk_free(struct mlx5hws_pool *pool,
struct mlx5hws_pool_chunk *chunk);
-static inline u32
-mlx5hws_pool_chunk_get_base_id(struct mlx5hws_pool *pool,
- struct mlx5hws_pool_chunk *chunk)
+static inline u32 mlx5hws_pool_get_base_id(struct mlx5hws_pool *pool)
{
- return pool->resource[chunk->resource_idx]->base_id;
+ return pool->resource->base_id;
}
-static inline u32
-mlx5hws_pool_chunk_get_base_mirror_id(struct mlx5hws_pool *pool,
- struct mlx5hws_pool_chunk *chunk)
+static inline u32 mlx5hws_pool_get_base_mirror_id(struct mlx5hws_pool *pool)
{
- return pool->mirror_resource[chunk->resource_idx]->base_id;
+ return pool->mirror_resource->base_id;
}
#endif /* MLX5HWS_POOL_H_ */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 118/869] net/mlx5: HWS, Refactor pool implementation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (116 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 117/869] net/mlx5: HWS, Make pool single resource Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 119/869] net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path Greg Kroah-Hartman
` (751 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vlad Dogaru, Yevgeny Kliteynik,
Mark Bloch, Tariq Toukan, Michal Kubiak, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vlad Dogaru <vdogaru@nvidia.com>
[ Upstream commit d171ce3d988868bed9dc3c9eeb8428f87dd9ac85 ]
Refactor the pool implementation to remove unused flags and clarify its
usage. A pool represents a single range of STEs or STCs which are
allocated at pool creation time.
Pools are used under three patterns:
1. STCs are allocated one at a time from a global pool using a bitmap
based implementation.
2. Action STEs are allocated in power-of-two blocks using a buddy
algorithm.
3. Match STEs do not use allocation, since insertion into these tables
is based on hashes or direct addressing. In such cases we use a pool
only to create the STE range.
Signed-off-by: Vlad Dogaru <vdogaru@nvidia.com>
Reviewed-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Reviewed-by: Michal Kubiak <michal.kubiak@intel.com>
Link: https://patch.msgid.link/1744312662-356571-5-git-send-email-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 2c0a959bebdc ("net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../mlx5/core/steering/hws/mlx5hws_action.c | 1 -
.../mlx5/core/steering/hws/mlx5hws_context.c | 1 -
.../mlx5/core/steering/hws/mlx5hws_matcher.c | 19 +-
.../mlx5/core/steering/hws/mlx5hws_pool.c | 387 +++++-------------
.../mlx5/core/steering/hws/mlx5hws_pool.h | 45 +-
5 files changed, 116 insertions(+), 337 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
index 041b063730bd9..667fa29830b6f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
@@ -1601,7 +1601,6 @@ hws_action_create_dest_match_range_table(struct mlx5hws_context *ctx,
pool_attr.table_type = MLX5HWS_TABLE_TYPE_FDB;
pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE;
- pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL;
pool_attr.alloc_log_sz = 1;
table_ste->pool = mlx5hws_pool_create(ctx, &pool_attr);
if (!table_ste->pool) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c
index a4cc81849ebe2..876123b0a573d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c
@@ -34,7 +34,6 @@ static int hws_context_pools_init(struct mlx5hws_context *ctx)
/* Create an STC pool per FT type */
pool_attr.pool_type = MLX5HWS_POOL_TYPE_STC;
- pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STC_POOL;
max_log_sz = min(MLX5HWS_POOL_STC_LOG_SZ, ctx->caps->stc_alloc_log_max);
pool_attr.alloc_log_sz = max(max_log_sz, ctx->caps->stc_alloc_log_gran);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
index 270a00b68e614..21d27fad5a330 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
@@ -265,14 +265,6 @@ static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher,
rtc_attr.match_definer_0 = ctx->caps->linear_match_definer;
}
}
-
- /* Match pool requires implicit allocation */
- ret = mlx5hws_pool_chunk_alloc(ste_pool, ste);
- if (ret) {
- mlx5hws_err(ctx, "Failed to allocate STE for %s RTC",
- hws_matcher_rtc_type_to_str(rtc_type));
- return ret;
- }
break;
case HWS_MATCHER_RTC_TYPE_STE_ARRAY:
@@ -351,23 +343,17 @@ static void hws_matcher_destroy_rtc(struct mlx5hws_matcher *matcher,
{
struct mlx5hws_matcher_action_ste *action_ste;
struct mlx5hws_table *tbl = matcher->tbl;
- struct mlx5hws_pool_chunk *ste;
- struct mlx5hws_pool *ste_pool;
u32 rtc_0_id, rtc_1_id;
switch (rtc_type) {
case HWS_MATCHER_RTC_TYPE_MATCH:
rtc_0_id = matcher->match_ste.rtc_0_id;
rtc_1_id = matcher->match_ste.rtc_1_id;
- ste_pool = matcher->match_ste.pool;
- ste = &matcher->match_ste.ste;
break;
case HWS_MATCHER_RTC_TYPE_STE_ARRAY:
action_ste = &matcher->action_ste;
rtc_0_id = action_ste->rtc_0_id;
rtc_1_id = action_ste->rtc_1_id;
- ste_pool = action_ste->pool;
- ste = &action_ste->ste;
break;
default:
return;
@@ -377,8 +363,6 @@ static void hws_matcher_destroy_rtc(struct mlx5hws_matcher *matcher,
mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, rtc_1_id);
mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, rtc_0_id);
- if (rtc_type == HWS_MATCHER_RTC_TYPE_MATCH)
- mlx5hws_pool_chunk_free(ste_pool, ste);
}
static int
@@ -551,7 +535,7 @@ static int hws_matcher_bind_at(struct mlx5hws_matcher *matcher)
/* Allocate action STE mempool */
pool_attr.table_type = tbl->type;
pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE;
- pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL;
+ pool_attr.flags = MLX5HWS_POOL_FLAG_BUDDY;
pool_attr.alloc_log_sz = ilog2(roundup_pow_of_two(action_ste->max_stes)) +
matcher->attr.table.sz_row_log;
hws_matcher_set_pool_attr(&pool_attr, matcher);
@@ -628,7 +612,6 @@ static int hws_matcher_bind_mt(struct mlx5hws_matcher *matcher)
/* Create an STE pool per matcher*/
pool_attr.table_type = matcher->tbl->type;
pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE;
- pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_MATCHER_STE_POOL;
pool_attr.alloc_log_sz = matcher->attr.table.sz_col_log +
matcher->attr.table.sz_row_log;
hws_matcher_set_pool_attr(&pool_attr, matcher);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
index 4302565b49b5e..2fc0e5dfbaefc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
@@ -60,10 +60,8 @@ hws_pool_create_one_resource(struct mlx5hws_pool *pool, u32 log_range,
ret = -EINVAL;
}
- if (ret) {
- mlx5hws_err(pool->ctx, "Failed to allocate resource objects\n");
+ if (ret)
goto free_resource;
- }
resource->pool = pool;
resource->range = 1 << log_range;
@@ -76,17 +74,17 @@ hws_pool_create_one_resource(struct mlx5hws_pool *pool, u32 log_range,
return NULL;
}
-static int
-hws_pool_resource_alloc(struct mlx5hws_pool *pool, u32 log_range)
+static int hws_pool_resource_alloc(struct mlx5hws_pool *pool)
{
struct mlx5hws_pool_resource *resource;
u32 fw_ft_type, opt_log_range;
fw_ft_type = mlx5hws_table_get_res_fw_ft_type(pool->tbl_type, false);
- opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_ORIG ? 0 : log_range;
+ opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_ORIG ?
+ 0 : pool->alloc_log_sz;
resource = hws_pool_create_one_resource(pool, opt_log_range, fw_ft_type);
if (!resource) {
- mlx5hws_err(pool->ctx, "Failed allocating resource\n");
+ mlx5hws_err(pool->ctx, "Failed to allocate resource\n");
return -EINVAL;
}
@@ -96,10 +94,11 @@ hws_pool_resource_alloc(struct mlx5hws_pool *pool, u32 log_range)
struct mlx5hws_pool_resource *mirror_resource;
fw_ft_type = mlx5hws_table_get_res_fw_ft_type(pool->tbl_type, true);
- opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_MIRROR ? 0 : log_range;
+ opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_MIRROR ?
+ 0 : pool->alloc_log_sz;
mirror_resource = hws_pool_create_one_resource(pool, opt_log_range, fw_ft_type);
if (!mirror_resource) {
- mlx5hws_err(pool->ctx, "Failed allocating mirrored resource\n");
+ mlx5hws_err(pool->ctx, "Failed to allocate mirrored resource\n");
hws_pool_free_one_resource(resource);
pool->resource = NULL;
return -EINVAL;
@@ -110,92 +109,58 @@ hws_pool_resource_alloc(struct mlx5hws_pool *pool, u32 log_range)
return 0;
}
-static unsigned long *hws_pool_create_and_init_bitmap(u32 log_range)
-{
- unsigned long *cur_bmp;
-
- cur_bmp = bitmap_zalloc(1 << log_range, GFP_KERNEL);
- if (!cur_bmp)
- return NULL;
-
- bitmap_fill(cur_bmp, 1 << log_range);
-
- return cur_bmp;
-}
-
-static void hws_pool_buddy_db_put_chunk(struct mlx5hws_pool *pool,
- struct mlx5hws_pool_chunk *chunk)
+static int hws_pool_buddy_init(struct mlx5hws_pool *pool)
{
struct mlx5hws_buddy_mem *buddy;
- buddy = pool->db.buddy;
+ buddy = mlx5hws_buddy_create(pool->alloc_log_sz);
if (!buddy) {
- mlx5hws_err(pool->ctx, "Bad buddy state\n");
- return;
- }
-
- mlx5hws_buddy_free_mem(buddy, chunk->offset, chunk->order);
-}
-
-static struct mlx5hws_buddy_mem *
-hws_pool_buddy_get_buddy(struct mlx5hws_pool *pool, u32 order)
-{
- static struct mlx5hws_buddy_mem *buddy;
- u32 new_buddy_size;
-
- buddy = pool->db.buddy;
- if (buddy)
- return buddy;
-
- new_buddy_size = max(pool->alloc_log_sz, order);
- buddy = mlx5hws_buddy_create(new_buddy_size);
- if (!buddy) {
- mlx5hws_err(pool->ctx, "Failed to create buddy order: %d\n",
- new_buddy_size);
- return NULL;
+ mlx5hws_err(pool->ctx, "Failed to create buddy order: %zu\n",
+ pool->alloc_log_sz);
+ return -ENOMEM;
}
- if (hws_pool_resource_alloc(pool, new_buddy_size) != 0) {
- mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d\n",
- pool->type, new_buddy_size);
+ if (hws_pool_resource_alloc(pool) != 0) {
+ mlx5hws_err(pool->ctx, "Failed to create resource type: %d size %zu\n",
+ pool->type, pool->alloc_log_sz);
mlx5hws_buddy_cleanup(buddy);
- return NULL;
+ return -ENOMEM;
}
pool->db.buddy = buddy;
- return buddy;
+ return 0;
}
-static int hws_pool_buddy_get_mem_chunk(struct mlx5hws_pool *pool,
- int order,
- int *seg)
+static int hws_pool_buddy_db_get_chunk(struct mlx5hws_pool *pool,
+ struct mlx5hws_pool_chunk *chunk)
{
- struct mlx5hws_buddy_mem *buddy;
+ struct mlx5hws_buddy_mem *buddy = pool->db.buddy;
- buddy = hws_pool_buddy_get_buddy(pool, order);
- if (!buddy)
- return -ENOMEM;
+ if (!buddy) {
+ mlx5hws_err(pool->ctx, "Bad buddy state\n");
+ return -EINVAL;
+ }
- *seg = mlx5hws_buddy_alloc_mem(buddy, order);
- if (*seg >= 0)
+ chunk->offset = mlx5hws_buddy_alloc_mem(buddy, chunk->order);
+ if (chunk->offset >= 0)
return 0;
return -ENOMEM;
}
-static int hws_pool_buddy_db_get_chunk(struct mlx5hws_pool *pool,
- struct mlx5hws_pool_chunk *chunk)
+static void hws_pool_buddy_db_put_chunk(struct mlx5hws_pool *pool,
+ struct mlx5hws_pool_chunk *chunk)
{
- int ret = 0;
+ struct mlx5hws_buddy_mem *buddy;
- ret = hws_pool_buddy_get_mem_chunk(pool, chunk->order,
- &chunk->offset);
- if (ret)
- mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n",
- chunk->order);
+ buddy = pool->db.buddy;
+ if (!buddy) {
+ mlx5hws_err(pool->ctx, "Bad buddy state\n");
+ return;
+ }
- return ret;
+ mlx5hws_buddy_free_mem(buddy, chunk->offset, chunk->order);
}
static void hws_pool_buddy_db_uninit(struct mlx5hws_pool *pool)
@@ -210,15 +175,13 @@ static void hws_pool_buddy_db_uninit(struct mlx5hws_pool *pool)
}
}
-static int hws_pool_buddy_db_init(struct mlx5hws_pool *pool, u32 log_range)
+static int hws_pool_buddy_db_init(struct mlx5hws_pool *pool)
{
- if (pool->flags & MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE) {
- if (!hws_pool_buddy_get_buddy(pool, log_range)) {
- mlx5hws_err(pool->ctx,
- "Failed allocating memory on create log_sz: %d\n", log_range);
- return -ENOMEM;
- }
- }
+ int ret;
+
+ ret = hws_pool_buddy_init(pool);
+ if (ret)
+ return ret;
pool->p_db_uninit = &hws_pool_buddy_db_uninit;
pool->p_get_chunk = &hws_pool_buddy_db_get_chunk;
@@ -227,234 +190,105 @@ static int hws_pool_buddy_db_init(struct mlx5hws_pool *pool, u32 log_range)
return 0;
}
-static int hws_pool_create_resource(struct mlx5hws_pool *pool, u32 alloc_size)
-{
- int ret = hws_pool_resource_alloc(pool, alloc_size);
-
- if (ret) {
- mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d\n",
- pool->type, alloc_size);
- return ret;
- }
-
- return 0;
-}
-
-static struct mlx5hws_pool_elements *
-hws_pool_element_create_new_elem(struct mlx5hws_pool *pool, u32 order)
+static unsigned long *hws_pool_create_and_init_bitmap(u32 log_range)
{
- struct mlx5hws_pool_elements *elem;
- u32 alloc_size;
-
- alloc_size = pool->alloc_log_sz;
+ unsigned long *bitmap;
- elem = kzalloc(sizeof(*elem), GFP_KERNEL);
- if (!elem)
+ bitmap = bitmap_zalloc(1 << log_range, GFP_KERNEL);
+ if (!bitmap)
return NULL;
- /* Sharing the same resource, also means that all the elements are with size 1 */
- if ((pool->flags & MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS) &&
- !(pool->flags & MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK)) {
- /* Currently all chunks in size 1 */
- elem->bitmap = hws_pool_create_and_init_bitmap(alloc_size - order);
- if (!elem->bitmap) {
- mlx5hws_err(pool->ctx,
- "Failed to create bitmap type: %d: size %d\n",
- pool->type, alloc_size);
- goto free_elem;
- }
-
- elem->log_size = alloc_size - order;
- }
-
- if (hws_pool_create_resource(pool, alloc_size)) {
- mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d\n",
- pool->type, alloc_size);
- goto free_db;
- }
-
- pool->db.element = elem;
+ bitmap_fill(bitmap, 1 << log_range);
- return elem;
-
-free_db:
- bitmap_free(elem->bitmap);
-free_elem:
- kfree(elem);
- return NULL;
+ return bitmap;
}
-static int hws_pool_element_find_seg(struct mlx5hws_pool_elements *elem, int *seg)
+static int hws_pool_bitmap_init(struct mlx5hws_pool *pool)
{
- unsigned int segment, size;
+ unsigned long *bitmap;
- size = 1 << elem->log_size;
-
- segment = find_first_bit(elem->bitmap, size);
- if (segment >= size) {
- elem->is_full = true;
+ bitmap = hws_pool_create_and_init_bitmap(pool->alloc_log_sz);
+ if (!bitmap) {
+ mlx5hws_err(pool->ctx, "Failed to create bitmap order: %zu\n",
+ pool->alloc_log_sz);
return -ENOMEM;
}
- bitmap_clear(elem->bitmap, segment, 1);
- *seg = segment;
- return 0;
-}
-
-static int
-hws_pool_onesize_element_get_mem_chunk(struct mlx5hws_pool *pool, u32 order,
- int *seg)
-{
- struct mlx5hws_pool_elements *elem;
-
- elem = pool->db.element;
- if (!elem)
- elem = hws_pool_element_create_new_elem(pool, order);
- if (!elem)
- goto err_no_elem;
-
- if (hws_pool_element_find_seg(elem, seg) != 0) {
- mlx5hws_err(pool->ctx, "No more resources (last request order: %d)\n", order);
+ if (hws_pool_resource_alloc(pool) != 0) {
+ mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %zu\n",
+ pool->type, pool->alloc_log_sz);
+ bitmap_free(bitmap);
return -ENOMEM;
}
- elem->num_of_elements++;
- return 0;
+ pool->db.bitmap = bitmap;
-err_no_elem:
- mlx5hws_err(pool->ctx, "Failed to allocate element for order: %d\n", order);
- return -ENOMEM;
+ return 0;
}
-static int hws_pool_general_element_get_mem_chunk(struct mlx5hws_pool *pool,
- u32 order, int *seg)
+static int hws_pool_bitmap_db_get_chunk(struct mlx5hws_pool *pool,
+ struct mlx5hws_pool_chunk *chunk)
{
- int ret;
+ unsigned long *bitmap, size;
- if (!pool->resource) {
- ret = hws_pool_create_resource(pool, order);
- if (ret)
- goto err_no_res;
- *seg = 0; /* One memory slot in that element */
- return 0;
+ if (chunk->order != 0) {
+ mlx5hws_err(pool->ctx, "Pool only supports order 0 allocs\n");
+ return -EINVAL;
}
- mlx5hws_err(pool->ctx, "No more resources (last request order: %d)\n", order);
- return -ENOMEM;
-
-err_no_res:
- mlx5hws_err(pool->ctx, "Failed to allocate element for order: %d\n", order);
- return -ENOMEM;
-}
-
-static int hws_pool_general_element_db_get_chunk(struct mlx5hws_pool *pool,
- struct mlx5hws_pool_chunk *chunk)
-{
- int ret;
-
- ret = hws_pool_general_element_get_mem_chunk(pool, chunk->order,
- &chunk->offset);
- if (ret)
- mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n",
- chunk->order);
-
- return ret;
-}
+ bitmap = pool->db.bitmap;
+ if (!bitmap) {
+ mlx5hws_err(pool->ctx, "Bad bitmap state\n");
+ return -EINVAL;
+ }
-static void hws_pool_general_element_db_put_chunk(struct mlx5hws_pool *pool,
- struct mlx5hws_pool_chunk *chunk)
-{
- if (pool->flags & MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE)
- hws_pool_resource_free(pool);
-}
+ size = 1 << pool->alloc_log_sz;
-static void hws_pool_general_element_db_uninit(struct mlx5hws_pool *pool)
-{
- (void)pool;
-}
+ chunk->offset = find_first_bit(bitmap, size);
+ if (chunk->offset >= size)
+ return -ENOMEM;
-/* This memory management works as the following:
- * - At start doesn't allocate no mem at all.
- * - When new request for chunk arrived:
- * allocate resource and give it.
- * - When free that chunk:
- * the resource is freed.
- */
-static int hws_pool_general_element_db_init(struct mlx5hws_pool *pool)
-{
- pool->p_db_uninit = &hws_pool_general_element_db_uninit;
- pool->p_get_chunk = &hws_pool_general_element_db_get_chunk;
- pool->p_put_chunk = &hws_pool_general_element_db_put_chunk;
+ bitmap_clear(bitmap, chunk->offset, 1);
return 0;
}
-static void
-hws_onesize_element_db_destroy_element(struct mlx5hws_pool *pool,
- struct mlx5hws_pool_elements *elem)
-{
- hws_pool_resource_free(pool);
- bitmap_free(elem->bitmap);
- kfree(elem);
- pool->db.element = NULL;
-}
-
-static void hws_onesize_element_db_put_chunk(struct mlx5hws_pool *pool,
- struct mlx5hws_pool_chunk *chunk)
+static void hws_pool_bitmap_db_put_chunk(struct mlx5hws_pool *pool,
+ struct mlx5hws_pool_chunk *chunk)
{
- struct mlx5hws_pool_elements *elem;
+ unsigned long *bitmap;
- elem = pool->db.element;
- if (!elem) {
- mlx5hws_err(pool->ctx, "Pool element was not allocated\n");
+ bitmap = pool->db.bitmap;
+ if (!bitmap) {
+ mlx5hws_err(pool->ctx, "Bad bitmap state\n");
return;
}
- bitmap_set(elem->bitmap, chunk->offset, 1);
- elem->is_full = false;
- elem->num_of_elements--;
-
- if (pool->flags & MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE &&
- !elem->num_of_elements)
- hws_onesize_element_db_destroy_element(pool, elem);
+ bitmap_set(bitmap, chunk->offset, 1);
}
-static int hws_onesize_element_db_get_chunk(struct mlx5hws_pool *pool,
- struct mlx5hws_pool_chunk *chunk)
+static void hws_pool_bitmap_db_uninit(struct mlx5hws_pool *pool)
{
- int ret = 0;
-
- ret = hws_pool_onesize_element_get_mem_chunk(pool, chunk->order,
- &chunk->offset);
- if (ret)
- mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n",
- chunk->order);
+ unsigned long *bitmap;
- return ret;
+ bitmap = pool->db.bitmap;
+ if (bitmap) {
+ bitmap_free(bitmap);
+ pool->db.bitmap = NULL;
+ }
}
-static void hws_onesize_element_db_uninit(struct mlx5hws_pool *pool)
+static int hws_pool_bitmap_db_init(struct mlx5hws_pool *pool)
{
- struct mlx5hws_pool_elements *elem = pool->db.element;
+ int ret;
- if (elem) {
- bitmap_free(elem->bitmap);
- kfree(elem);
- pool->db.element = NULL;
- }
-}
+ ret = hws_pool_bitmap_init(pool);
+ if (ret)
+ return ret;
-/* This memory management works as the following:
- * - At start doesn't allocate no mem at all.
- * - When new request for chunk arrived:
- * aloocate the first and only slot of memory/resource
- * when it ended return error.
- */
-static int hws_pool_onesize_element_db_init(struct mlx5hws_pool *pool)
-{
- pool->p_db_uninit = &hws_onesize_element_db_uninit;
- pool->p_get_chunk = &hws_onesize_element_db_get_chunk;
- pool->p_put_chunk = &hws_onesize_element_db_put_chunk;
+ pool->p_db_uninit = &hws_pool_bitmap_db_uninit;
+ pool->p_get_chunk = &hws_pool_bitmap_db_get_chunk;
+ pool->p_put_chunk = &hws_pool_bitmap_db_put_chunk;
return 0;
}
@@ -464,15 +298,14 @@ static int hws_pool_db_init(struct mlx5hws_pool *pool,
{
int ret;
- if (db_type == MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE)
- ret = hws_pool_general_element_db_init(pool);
- else if (db_type == MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE)
- ret = hws_pool_onesize_element_db_init(pool);
+ if (db_type == MLX5HWS_POOL_DB_TYPE_BITMAP)
+ ret = hws_pool_bitmap_db_init(pool);
else
- ret = hws_pool_buddy_db_init(pool, pool->alloc_log_sz);
+ ret = hws_pool_buddy_db_init(pool);
if (ret) {
- mlx5hws_err(pool->ctx, "Failed to init general db : %d (ret: %d)\n", db_type, ret);
+ mlx5hws_err(pool->ctx, "Failed to init pool type: %d (ret: %d)\n",
+ db_type, ret);
return ret;
}
@@ -521,15 +354,10 @@ mlx5hws_pool_create(struct mlx5hws_context *ctx, struct mlx5hws_pool_attr *pool_
pool->tbl_type = pool_attr->table_type;
pool->opt_type = pool_attr->opt_type;
- /* Support general db */
- if (pool->flags == (MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE |
- MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK))
- res_db_type = MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE;
- else if (pool->flags == (MLX5HWS_POOL_FLAGS_ONE_RESOURCE |
- MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS))
- res_db_type = MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE;
- else
+ if (pool->flags & MLX5HWS_POOL_FLAG_BUDDY)
res_db_type = MLX5HWS_POOL_DB_TYPE_BUDDY;
+ else
+ res_db_type = MLX5HWS_POOL_DB_TYPE_BITMAP;
pool->alloc_log_sz = pool_attr->alloc_log_sz;
@@ -545,7 +373,7 @@ mlx5hws_pool_create(struct mlx5hws_context *ctx, struct mlx5hws_pool_attr *pool_
return NULL;
}
-int mlx5hws_pool_destroy(struct mlx5hws_pool *pool)
+void mlx5hws_pool_destroy(struct mlx5hws_pool *pool)
{
mutex_destroy(&pool->lock);
@@ -555,5 +383,4 @@ int mlx5hws_pool_destroy(struct mlx5hws_pool *pool)
hws_pool_db_unint(pool);
kfree(pool);
- return 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h
index 112a61cd29979..9a781a87f097b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h
@@ -23,29 +23,10 @@ struct mlx5hws_pool_resource {
};
enum mlx5hws_pool_flags {
- /* Only a one resource in that pool */
- MLX5HWS_POOL_FLAGS_ONE_RESOURCE = 1 << 0,
- MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE = 1 << 1,
- /* No sharing resources between chunks */
- MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK = 1 << 2,
- /* All objects are in the same size */
- MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS = 1 << 3,
- /* Managed by buddy allocator */
- MLX5HWS_POOL_FLAGS_BUDDY_MANAGED = 1 << 4,
- /* Allocate pool_type memory on pool creation */
- MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE = 1 << 5,
-
- /* These values should be used by the caller */
- MLX5HWS_POOL_FLAGS_FOR_STC_POOL =
- MLX5HWS_POOL_FLAGS_ONE_RESOURCE |
- MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS,
- MLX5HWS_POOL_FLAGS_FOR_MATCHER_STE_POOL =
- MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE |
- MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK,
- MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL =
- MLX5HWS_POOL_FLAGS_ONE_RESOURCE |
- MLX5HWS_POOL_FLAGS_BUDDY_MANAGED |
- MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE,
+ /* Managed by a buddy allocator. If this is not set only allocations of
+ * order 0 are supported.
+ */
+ MLX5HWS_POOL_FLAG_BUDDY = BIT(0),
};
enum mlx5hws_pool_optimize {
@@ -64,25 +45,16 @@ struct mlx5hws_pool_attr {
};
enum mlx5hws_db_type {
- /* Uses for allocating chunk of big memory, each element has its own resource in the FW*/
- MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE,
- /* One resource only, all the elements are with same one size */
- MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE,
+ /* Uses a bitmap, supports only allocations of order 0. */
+ MLX5HWS_POOL_DB_TYPE_BITMAP,
/* Entries are managed using a buddy mechanism. */
MLX5HWS_POOL_DB_TYPE_BUDDY,
};
-struct mlx5hws_pool_elements {
- u32 num_of_elements;
- unsigned long *bitmap;
- u32 log_size;
- bool is_full;
-};
-
struct mlx5hws_pool_db {
enum mlx5hws_db_type type;
union {
- struct mlx5hws_pool_elements *element;
+ unsigned long *bitmap;
struct mlx5hws_buddy_mem *buddy;
};
};
@@ -103,7 +75,6 @@ struct mlx5hws_pool {
enum mlx5hws_pool_optimize opt_type;
struct mlx5hws_pool_resource *resource;
struct mlx5hws_pool_resource *mirror_resource;
- /* DB */
struct mlx5hws_pool_db db;
/* Functions */
mlx5hws_pool_unint_db p_db_uninit;
@@ -115,7 +86,7 @@ struct mlx5hws_pool *
mlx5hws_pool_create(struct mlx5hws_context *ctx,
struct mlx5hws_pool_attr *pool_attr);
-int mlx5hws_pool_destroy(struct mlx5hws_pool *pool);
+void mlx5hws_pool_destroy(struct mlx5hws_pool *pool);
int mlx5hws_pool_chunk_alloc(struct mlx5hws_pool *pool,
struct mlx5hws_pool_chunk *chunk);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 119/869] net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (117 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 118/869] net/mlx5: HWS, Refactor pool implementation Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 120/869] net/mlx5: HWS, Fix memory leak in hws_action_get_shared_stc_nic error flow Greg Kroah-Hartman
` (750 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lama Kayal, Tariq Toukan, Mark Bloch,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lama Kayal <lkayal@nvidia.com>
[ Upstream commit 2c0a959bebdc1ada13cf9a8242f177c5400299e6 ]
In the error path of hws_pool_buddy_init(), the buddy allocator cleanup
doesn't free the allocator structure itself, causing a memory leak.
Add the missing kfree() to properly release all allocated memory.
Fixes: c61afff94373 ("net/mlx5: HWS, added memory management handling")
Signed-off-by: Lama Kayal <lkayal@nvidia.com>
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
Signed-off-by: Mark Bloch <mbloch@nvidia.com>
Link: https://patch.msgid.link/20250825143435.598584-2-mbloch@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
index 2fc0e5dfbaefc..a6f542704fe46 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
@@ -124,6 +124,7 @@ static int hws_pool_buddy_init(struct mlx5hws_pool *pool)
mlx5hws_err(pool->ctx, "Failed to create resource type: %d size %zu\n",
pool->type, pool->alloc_log_sz);
mlx5hws_buddy_cleanup(buddy);
+ kfree(buddy);
return -ENOMEM;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 120/869] net/mlx5: HWS, Fix memory leak in hws_action_get_shared_stc_nic error flow
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (118 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 119/869] net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 121/869] ptp: ocp: fix use-after-free bugs causing by ptp_ocp_watchdog Greg Kroah-Hartman
` (749 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lama Kayal, Tariq Toukan, Mark Bloch,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lama Kayal <lkayal@nvidia.com>
[ Upstream commit a630f83592cdad1253523a1b760cfe78fef6cd9c ]
When an invalid stc_type is provided, the function allocates memory for
shared_stc but jumps to unlock_and_out without freeing it, causing a
memory leak.
Fix by jumping to free_shared_stc label instead to ensure proper cleanup.
Fixes: 504e536d9010 ("net/mlx5: HWS, added actions handling")
Signed-off-by: Lama Kayal <lkayal@nvidia.com>
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
Signed-off-by: Mark Bloch <mbloch@nvidia.com>
Link: https://patch.msgid.link/20250825143435.598584-3-mbloch@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
index 667fa29830b6f..4fbe0d9d594db 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
@@ -112,7 +112,7 @@ static int hws_action_get_shared_stc_nic(struct mlx5hws_context *ctx,
mlx5hws_err(ctx, "No such stc_type: %d\n", stc_type);
pr_warn("HWS: Invalid stc_type: %d\n", stc_type);
ret = -EINVAL;
- goto unlock_and_out;
+ goto free_shared_stc;
}
ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 121/869] ptp: ocp: fix use-after-free bugs causing by ptp_ocp_watchdog
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (119 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 120/869] net/mlx5: HWS, Fix memory leak in hws_action_get_shared_stc_nic error flow Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 122/869] wifi: mt76: mt7915: fix list corruption after hardware restart Greg Kroah-Hartman
` (748 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Duoming Zhou, Vadim Fedorenko,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Duoming Zhou <duoming@zju.edu.cn>
[ Upstream commit 8bf935cf789872350b04c1a6468b0a509f67afb2 ]
The ptp_ocp_detach() only shuts down the watchdog timer if it is
pending. However, if the timer handler is already running, the
timer_delete_sync() is not called. This leads to race conditions
where the devlink that contains the ptp_ocp is deallocated while
the timer handler is still accessing it, resulting in use-after-free
bugs. The following details one of the race scenarios.
(thread 1) | (thread 2)
ptp_ocp_remove() |
ptp_ocp_detach() | ptp_ocp_watchdog()
if (timer_pending(&bp->watchdog))| bp = timer_container_of()
timer_delete_sync() |
|
devlink_free(devlink) //free |
| bp-> //use
Resolve this by unconditionally calling timer_delete_sync() to ensure
the timer is reliably deactivated, preventing any access after free.
Fixes: 773bda964921 ("ptp: ocp: Expose various resources on the timecard.")
Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Link: https://patch.msgid.link/20250828082949.28189-1-duoming@zju.edu.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ptp/ptp_ocp.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 42263c68d5e0d..e4187eb6fd775 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -4558,8 +4558,7 @@ ptp_ocp_detach(struct ptp_ocp *bp)
ptp_ocp_debugfs_remove_device(bp);
ptp_ocp_detach_sysfs(bp);
ptp_ocp_attr_group_del(bp);
- if (timer_pending(&bp->watchdog))
- del_timer_sync(&bp->watchdog);
+ timer_delete_sync(&bp->watchdog);
if (bp->ts0)
ptp_ocp_unregister_ext(bp->ts0);
if (bp->ts1)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 122/869] wifi: mt76: mt7915: fix list corruption after hardware restart
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (120 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 121/869] ptp: ocp: fix use-after-free bugs causing by ptp_ocp_watchdog Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 123/869] mm/vmalloc, mm/kasan: respect gfp mask in kasan_populate_vmalloc() Greg Kroah-Hartman
` (747 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Felix Fietkau, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <nbd@nbd.name>
[ Upstream commit 065c79df595af21d6d1b27d642860faa1d938774 ]
Since stations are recreated from scratch, all lists that wcids are added
to must be cleared before calling ieee80211_restart_hw.
Set wcid->sta = 0 for each wcid entry in order to ensure that they are
not added again before they are ready.
Fixes: 8a55712d124f ("wifi: mt76: mt7915: enable full system reset support")
Link: https://patch.msgid.link/20250827085352.51636-4-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mac80211.c | 37 +++++++++++++++++++
drivers/net/wireless/mediatek/mt76/mt76.h | 1 +
.../net/wireless/mediatek/mt76/mt7915/mac.c | 12 +++---
3 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index e1856664ca5d1..ca1f7b2991c51 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -791,6 +791,43 @@ void mt76_free_device(struct mt76_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76_free_device);
+static void mt76_reset_phy(struct mt76_phy *phy)
+{
+ if (!phy)
+ return;
+
+ INIT_LIST_HEAD(&phy->tx_list);
+}
+
+void mt76_reset_device(struct mt76_dev *dev)
+{
+ int i;
+
+ rcu_read_lock();
+ for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) {
+ struct mt76_wcid *wcid;
+
+ wcid = rcu_dereference(dev->wcid[i]);
+ if (!wcid)
+ continue;
+
+ wcid->sta = 0;
+ mt76_wcid_cleanup(dev, wcid);
+ rcu_assign_pointer(dev->wcid[i], NULL);
+ }
+ rcu_read_unlock();
+
+ INIT_LIST_HEAD(&dev->wcid_list);
+ INIT_LIST_HEAD(&dev->sta_poll_list);
+ dev->vif_mask = 0;
+ memset(dev->wcid_mask, 0, sizeof(dev->wcid_mask));
+
+ mt76_reset_phy(&dev->phy);
+ for (i = 0; i < ARRAY_SIZE(dev->phys); i++)
+ mt76_reset_phy(dev->phys[i]);
+}
+EXPORT_SYMBOL_GPL(mt76_reset_device);
+
static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
{
struct sk_buff *skb = phy->rx_amsdu[q].head;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index daa78f52c15ea..ffcd4509dfcae 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -1168,6 +1168,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
struct ieee80211_rate *rates, int n_rates);
void mt76_unregister_device(struct mt76_dev *dev);
void mt76_free_device(struct mt76_dev *dev);
+void mt76_reset_device(struct mt76_dev *dev);
void mt76_unregister_phy(struct mt76_phy *phy);
struct mt76_phy *mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index f165e61ed28f7..147c0fbfbeb84 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -1458,17 +1458,15 @@ mt7915_mac_full_reset(struct mt7915_dev *dev)
if (i == 10)
dev_err(dev->mt76.dev, "chip full reset failed\n");
- spin_lock_bh(&dev->mt76.sta_poll_lock);
- while (!list_empty(&dev->mt76.sta_poll_list))
- list_del_init(dev->mt76.sta_poll_list.next);
- spin_unlock_bh(&dev->mt76.sta_poll_lock);
-
- memset(dev->mt76.wcid_mask, 0, sizeof(dev->mt76.wcid_mask));
- dev->mt76.vif_mask = 0;
dev->phy.omac_mask = 0;
if (phy2)
phy2->omac_mask = 0;
+ mt76_reset_device(&dev->mt76);
+
+ INIT_LIST_HEAD(&dev->sta_rc_list);
+ INIT_LIST_HEAD(&dev->twt_list);
+
i = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
dev->mt76.global_wcid.idx = i;
dev->recovery.hw_full_reset = false;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 123/869] mm/vmalloc, mm/kasan: respect gfp mask in kasan_populate_vmalloc()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (121 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 122/869] wifi: mt76: mt7915: fix list corruption after hardware restart Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 124/869] smb: client: let recv_done verify data_offset, data_length and remaining_data_length Greg Kroah-Hartman
` (746 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Uladzislau Rezki (Sony),
syzbot+3470c9ffee63e4abafeb, Andrey Ryabinin, Baoquan He,
Michal Hocko, Alexander Potapenko, Andrey Konovalov,
Dmitry Vyukov, Vincenzo Frascino, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uladzislau Rezki (Sony) <urezki@gmail.com>
[ Upstream commit 79357cd06d41d0f5a11b17d7c86176e395d10ef2 ]
kasan_populate_vmalloc() and its helpers ignore the caller's gfp_mask and
always allocate memory using the hardcoded GFP_KERNEL flag. This makes
them inconsistent with vmalloc(), which was recently extended to support
GFP_NOFS and GFP_NOIO allocations.
Page table allocations performed during shadow population also ignore the
external gfp_mask. To preserve the intended semantics of GFP_NOFS and
GFP_NOIO, wrap the apply_to_page_range() calls into the appropriate
memalloc scope.
xfs calls vmalloc with GFP_NOFS, so this bug could lead to deadlock.
There was a report here
https://lkml.kernel.org/r/686ea951.050a0220.385921.0016.GAE@google.com
This patch:
- Extends kasan_populate_vmalloc() and helpers to take gfp_mask;
- Passes gfp_mask down to alloc_pages_bulk() and __get_free_page();
- Enforces GFP_NOFS/NOIO semantics with memalloc_*_save()/restore()
around apply_to_page_range();
- Updates vmalloc.c and percpu allocator call sites accordingly.
Link: https://lkml.kernel.org/r/20250831121058.92971-1-urezki@gmail.com
Fixes: 451769ebb7e7 ("mm/vmalloc: alloc GFP_NO{FS,IO} for vmalloc")
Signed-off-by: Uladzislau Rezki (Sony) <urezki@gmail.com>
Reported-by: syzbot+3470c9ffee63e4abafeb@syzkaller.appspotmail.com
Reviewed-by: Andrey Ryabinin <ryabinin.a.a@gmail.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Alexander Potapenko <glider@google.com>
Cc: Andrey Konovalov <andreyknvl@gmail.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/kasan.h | 6 +++---
mm/kasan/shadow.c | 31 ++++++++++++++++++++++++-------
mm/vmalloc.c | 8 ++++----
3 files changed, 31 insertions(+), 14 deletions(-)
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index 5814bf8298b25..ff10e5740a4c3 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -565,7 +565,7 @@ static inline void kasan_init_hw_tags(void) { }
#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
void kasan_populate_early_vm_area_shadow(void *start, unsigned long size);
-int kasan_populate_vmalloc(unsigned long addr, unsigned long size);
+int kasan_populate_vmalloc(unsigned long addr, unsigned long size, gfp_t gfp_mask);
void kasan_release_vmalloc(unsigned long start, unsigned long end,
unsigned long free_region_start,
unsigned long free_region_end,
@@ -577,7 +577,7 @@ static inline void kasan_populate_early_vm_area_shadow(void *start,
unsigned long size)
{ }
static inline int kasan_populate_vmalloc(unsigned long start,
- unsigned long size)
+ unsigned long size, gfp_t gfp_mask)
{
return 0;
}
@@ -634,7 +634,7 @@ static __always_inline void kasan_vrealloc(const void *start,
static inline void kasan_populate_early_vm_area_shadow(void *start,
unsigned long size) { }
static inline int kasan_populate_vmalloc(unsigned long start,
- unsigned long size)
+ unsigned long size, gfp_t gfp_mask)
{
return 0;
}
diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c
index 1cf08821af9d6..53240f7bf4e8f 100644
--- a/mm/kasan/shadow.c
+++ b/mm/kasan/shadow.c
@@ -335,13 +335,13 @@ static void ___free_pages_bulk(struct page **pages, int nr_pages)
}
}
-static int ___alloc_pages_bulk(struct page **pages, int nr_pages)
+static int ___alloc_pages_bulk(struct page **pages, int nr_pages, gfp_t gfp_mask)
{
unsigned long nr_populated, nr_total = nr_pages;
struct page **page_array = pages;
while (nr_pages) {
- nr_populated = alloc_pages_bulk_array(GFP_KERNEL, nr_pages, pages);
+ nr_populated = alloc_pages_bulk_array(gfp_mask, nr_pages, pages);
if (!nr_populated) {
___free_pages_bulk(page_array, nr_total - nr_pages);
return -ENOMEM;
@@ -353,25 +353,42 @@ static int ___alloc_pages_bulk(struct page **pages, int nr_pages)
return 0;
}
-static int __kasan_populate_vmalloc(unsigned long start, unsigned long end)
+static int __kasan_populate_vmalloc(unsigned long start, unsigned long end, gfp_t gfp_mask)
{
unsigned long nr_pages, nr_total = PFN_UP(end - start);
struct vmalloc_populate_data data;
+ unsigned int flags;
int ret = 0;
- data.pages = (struct page **)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+ data.pages = (struct page **)__get_free_page(gfp_mask | __GFP_ZERO);
if (!data.pages)
return -ENOMEM;
while (nr_total) {
nr_pages = min(nr_total, PAGE_SIZE / sizeof(data.pages[0]));
- ret = ___alloc_pages_bulk(data.pages, nr_pages);
+ ret = ___alloc_pages_bulk(data.pages, nr_pages, gfp_mask);
if (ret)
break;
data.start = start;
+
+ /*
+ * page tables allocations ignore external gfp mask, enforce it
+ * by the scope API
+ */
+ if ((gfp_mask & (__GFP_FS | __GFP_IO)) == __GFP_IO)
+ flags = memalloc_nofs_save();
+ else if ((gfp_mask & (__GFP_FS | __GFP_IO)) == 0)
+ flags = memalloc_noio_save();
+
ret = apply_to_page_range(&init_mm, start, nr_pages * PAGE_SIZE,
kasan_populate_vmalloc_pte, &data);
+
+ if ((gfp_mask & (__GFP_FS | __GFP_IO)) == __GFP_IO)
+ memalloc_nofs_restore(flags);
+ else if ((gfp_mask & (__GFP_FS | __GFP_IO)) == 0)
+ memalloc_noio_restore(flags);
+
___free_pages_bulk(data.pages, nr_pages);
if (ret)
break;
@@ -385,7 +402,7 @@ static int __kasan_populate_vmalloc(unsigned long start, unsigned long end)
return ret;
}
-int kasan_populate_vmalloc(unsigned long addr, unsigned long size)
+int kasan_populate_vmalloc(unsigned long addr, unsigned long size, gfp_t gfp_mask)
{
unsigned long shadow_start, shadow_end;
int ret;
@@ -414,7 +431,7 @@ int kasan_populate_vmalloc(unsigned long addr, unsigned long size)
shadow_start = PAGE_ALIGN_DOWN(shadow_start);
shadow_end = PAGE_ALIGN(shadow_end);
- ret = __kasan_populate_vmalloc(shadow_start, shadow_end);
+ ret = __kasan_populate_vmalloc(shadow_start, shadow_end, gfp_mask);
if (ret)
return ret;
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index e0066c100b794..b11552177f2d7 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -2025,6 +2025,8 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
if (unlikely(!vmap_initialized))
return ERR_PTR(-EBUSY);
+ /* Only reclaim behaviour flags are relevant. */
+ gfp_mask = gfp_mask & GFP_RECLAIM_MASK;
might_sleep();
/*
@@ -2037,8 +2039,6 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
*/
va = node_alloc(size, align, vstart, vend, &addr, &vn_id);
if (!va) {
- gfp_mask = gfp_mask & GFP_RECLAIM_MASK;
-
va = kmem_cache_alloc_node(vmap_area_cachep, gfp_mask, node);
if (unlikely(!va))
return ERR_PTR(-ENOMEM);
@@ -2088,7 +2088,7 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
BUG_ON(va->va_start < vstart);
BUG_ON(va->va_end > vend);
- ret = kasan_populate_vmalloc(addr, size);
+ ret = kasan_populate_vmalloc(addr, size, gfp_mask);
if (ret) {
free_vmap_area(va);
return ERR_PTR(ret);
@@ -4844,7 +4844,7 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
/* populate the kasan shadow space */
for (area = 0; area < nr_vms; area++) {
- if (kasan_populate_vmalloc(vas[area]->va_start, sizes[area]))
+ if (kasan_populate_vmalloc(vas[area]->va_start, sizes[area], GFP_KERNEL))
goto err_free_shadow;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 124/869] smb: client: let recv_done verify data_offset, data_length and remaining_data_length
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (122 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 123/869] mm/vmalloc, mm/kasan: respect gfp mask in kasan_populate_vmalloc() Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 125/869] iommu/s390: handle IOAT registration based on domain Greg Kroah-Hartman
` (745 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Tom Talpey, Long Li, linux-cifs,
samba-technical, Namjae Jeon, Stefan Metzmacher, Steve French,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefan Metzmacher <metze@samba.org>
[ Upstream commit f57e53ea252363234f86674db475839e5b87102e ]
This is inspired by the related server fixes.
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Fixes: f198186aa9bb ("CIFS: SMBD: Establish SMB Direct connection")
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/smbdirect.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index 07f71a9481a36..c4c1435e8114f 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -460,7 +460,10 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
struct smbd_response *response =
container_of(wc->wr_cqe, struct smbd_response, cqe);
struct smbd_connection *info = response->info;
- int data_length = 0;
+ struct smbdirect_socket_parameters *sp = &info->socket.parameters;
+ u32 data_offset = 0;
+ u32 data_length = 0;
+ u32 remaining_data_length = 0;
log_rdma_recv(INFO, "response=0x%p type=%d wc status=%d wc opcode %d byte_len=%d pkey_index=%u\n",
response, response->type, wc->status, wc->opcode,
@@ -492,7 +495,22 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
/* SMBD data transfer packet */
case SMBD_TRANSFER_DATA:
data_transfer = smbd_response_payload(response);
+
+ if (wc->byte_len <
+ offsetof(struct smbdirect_data_transfer, padding))
+ goto error;
+
+ remaining_data_length = le32_to_cpu(data_transfer->remaining_data_length);
+ data_offset = le32_to_cpu(data_transfer->data_offset);
data_length = le32_to_cpu(data_transfer->data_length);
+ if (wc->byte_len < data_offset ||
+ (u64)wc->byte_len < (u64)data_offset + data_length)
+ goto error;
+
+ if (remaining_data_length > sp->max_fragmented_recv_size ||
+ data_length > sp->max_fragmented_recv_size ||
+ (u64)remaining_data_length + (u64)data_length > (u64)sp->max_fragmented_recv_size)
+ goto error;
if (data_length) {
if (info->full_packet_received)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 125/869] iommu/s390: handle IOAT registration based on domain
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (123 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 124/869] smb: client: let recv_done verify data_offset, data_length and remaining_data_length Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 126/869] iommu/s390: set appropriate IOTA region type Greg Kroah-Hartman
` (744 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Niklas Schnelle, Matthew Rosato,
Joerg Roedel, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Rosato <mjrosato@linux.ibm.com>
[ Upstream commit 0ed5967a0a63552e5ca0f2382ce362f84e83801c ]
At this point, the dma_table is really a property of the s390-iommu
domain. Rather than checking its contents elsewhere in the codebase,
move the code that registers the table with firmware into
s390-iommu and make a decision what to register with firmware based
upon the type of domain in use for the device in question.
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Link: https://lore.kernel.org/r/20250212213418.182902-4-mjrosato@linux.ibm.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Stable-dep-of: 9ffaf5229055 ("iommu/s390: Make attach succeed when the device was surprise removed")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/include/asm/pci.h | 2 ++
arch/s390/kvm/pci.c | 17 ++-------------
arch/s390/pci/pci.c | 35 +++++++++++++++++-------------
arch/s390/pci/pci_sysfs.c | 11 +---------
drivers/iommu/s390-iommu.c | 43 +++++++++++++++++++++++++++++++++++--
5 files changed, 66 insertions(+), 42 deletions(-)
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index edf346a148207..1b919f1e0ff7f 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -215,6 +215,7 @@ extern struct airq_iv *zpci_aif_sbv;
struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state);
int zpci_add_device(struct zpci_dev *zdev);
int zpci_enable_device(struct zpci_dev *);
+int zpci_reenable_device(struct zpci_dev *zdev);
int zpci_disable_device(struct zpci_dev *);
int zpci_scan_configured_device(struct zpci_dev *zdev, u32 fh);
int zpci_deconfigure_device(struct zpci_dev *zdev);
@@ -243,6 +244,7 @@ void update_uid_checking(bool new);
/* IOMMU Interface */
int zpci_init_iommu(struct zpci_dev *zdev);
void zpci_destroy_iommu(struct zpci_dev *zdev);
+int zpci_iommu_register_ioat(struct zpci_dev *zdev, u8 *status);
#ifdef CONFIG_PCI
static inline bool zpci_use_mio(struct zpci_dev *zdev)
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index d9fcbf41025e0..86a8939fc3d9c 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -502,7 +502,6 @@ static void kvm_s390_pci_dev_release(struct zpci_dev *zdev)
static int kvm_s390_pci_register_kvm(void *opaque, struct kvm *kvm)
{
struct zpci_dev *zdev = opaque;
- u8 status;
int rc;
if (!zdev)
@@ -549,13 +548,7 @@ static int kvm_s390_pci_register_kvm(void *opaque, struct kvm *kvm)
*/
zdev->gisa = (u32)virt_to_phys(&kvm->arch.sie_page2->gisa);
- rc = zpci_enable_device(zdev);
- if (rc)
- goto clear_gisa;
-
- /* Re-register the IOMMU that was already created */
- rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
- virt_to_phys(zdev->dma_table), &status);
+ rc = zpci_reenable_device(zdev);
if (rc)
goto clear_gisa;
@@ -585,7 +578,6 @@ static void kvm_s390_pci_unregister_kvm(void *opaque)
{
struct zpci_dev *zdev = opaque;
struct kvm *kvm;
- u8 status;
if (!zdev)
return;
@@ -619,12 +611,7 @@ static void kvm_s390_pci_unregister_kvm(void *opaque)
goto out;
}
- if (zpci_enable_device(zdev))
- goto out;
-
- /* Re-register the IOMMU that was already created */
- zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
- virt_to_phys(zdev->dma_table), &status);
+ zpci_reenable_device(zdev);
out:
spin_lock(&kvm->arch.kzdev_list_lock);
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 2fe5b91c3d90f..554492f07b04e 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -134,14 +134,13 @@ int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
struct zpci_fib fib = {0};
u8 cc;
- WARN_ON_ONCE(iota & 0x3fff);
fib.pba = base;
/* Work around off by one in ISM virt device */
if (zdev->pft == PCI_FUNC_TYPE_ISM && limit > base)
fib.pal = limit + (1 << 12);
else
fib.pal = limit;
- fib.iota = iota | ZPCI_IOTA_RTTO_FLAG;
+ fib.iota = iota;
fib.gd = zdev->gisa;
cc = zpci_mod_fc(req, &fib, status);
if (cc)
@@ -709,6 +708,23 @@ int zpci_enable_device(struct zpci_dev *zdev)
}
EXPORT_SYMBOL_GPL(zpci_enable_device);
+int zpci_reenable_device(struct zpci_dev *zdev)
+{
+ u8 status;
+ int rc;
+
+ rc = zpci_enable_device(zdev);
+ if (rc)
+ return rc;
+
+ rc = zpci_iommu_register_ioat(zdev, &status);
+ if (rc)
+ zpci_disable_device(zdev);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(zpci_reenable_device);
+
int zpci_disable_device(struct zpci_dev *zdev)
{
u32 fh = zdev->fh;
@@ -758,7 +774,6 @@ EXPORT_SYMBOL_GPL(zpci_disable_device);
*/
int zpci_hot_reset_device(struct zpci_dev *zdev)
{
- u8 status;
int rc;
lockdep_assert_held(&zdev->state_lock);
@@ -777,19 +792,9 @@ int zpci_hot_reset_device(struct zpci_dev *zdev)
return rc;
}
- rc = zpci_enable_device(zdev);
- if (rc)
- return rc;
-
- if (zdev->dma_table)
- rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
- virt_to_phys(zdev->dma_table), &status);
- if (rc) {
- zpci_disable_device(zdev);
- return rc;
- }
+ rc = zpci_reenable_device(zdev);
- return 0;
+ return rc;
}
/**
diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c
index 1f81f6ff7b954..56df97850c94b 100644
--- a/arch/s390/pci/pci_sysfs.c
+++ b/arch/s390/pci/pci_sysfs.c
@@ -51,7 +51,6 @@ static DEVICE_ATTR_RO(mio_enabled);
static int _do_recover(struct pci_dev *pdev, struct zpci_dev *zdev)
{
- u8 status;
int ret;
pci_stop_and_remove_bus_device(pdev);
@@ -69,16 +68,8 @@ static int _do_recover(struct pci_dev *pdev, struct zpci_dev *zdev)
return ret;
}
- ret = zpci_enable_device(zdev);
- if (ret)
- return ret;
+ ret = zpci_reenable_device(zdev);
- if (zdev->dma_table) {
- ret = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
- virt_to_phys(zdev->dma_table), &status);
- if (ret)
- zpci_disable_device(zdev);
- }
return ret;
}
diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c
index fbdeded3d48b5..007ccfdad4954 100644
--- a/drivers/iommu/s390-iommu.c
+++ b/drivers/iommu/s390-iommu.c
@@ -381,6 +381,46 @@ static void zdev_s390_domain_update(struct zpci_dev *zdev,
spin_unlock_irqrestore(&zdev->dom_lock, flags);
}
+static int s390_iommu_domain_reg_ioat(struct zpci_dev *zdev,
+ struct iommu_domain *domain, u8 *status)
+{
+ struct s390_domain *s390_domain;
+ int rc = 0;
+ u64 iota;
+
+ switch (domain->type) {
+ case IOMMU_DOMAIN_IDENTITY:
+ rc = zpci_register_ioat(zdev, 0, zdev->start_dma,
+ zdev->end_dma, 0, status);
+ break;
+ case IOMMU_DOMAIN_BLOCKED:
+ /* Nothing to do in this case */
+ break;
+ default:
+ s390_domain = to_s390_domain(domain);
+ iota = virt_to_phys(s390_domain->dma_table) |
+ ZPCI_IOTA_RTTO_FLAG;
+ rc = zpci_register_ioat(zdev, 0, zdev->start_dma,
+ zdev->end_dma, iota, status);
+ }
+
+ return rc;
+}
+
+int zpci_iommu_register_ioat(struct zpci_dev *zdev, u8 *status)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&zdev->dom_lock, flags);
+
+ rc = s390_iommu_domain_reg_ioat(zdev, zdev->s390_domain, status);
+
+ spin_unlock_irqrestore(&zdev->dom_lock, flags);
+
+ return rc;
+}
+
static int blocking_domain_attach_device(struct iommu_domain *domain,
struct device *dev)
{
@@ -422,8 +462,7 @@ static int s390_iommu_attach_device(struct iommu_domain *domain,
blocking_domain_attach_device(&blocking_domain, dev);
/* If we fail now DMA remains blocked via blocking domain */
- cc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
- virt_to_phys(s390_domain->dma_table), &status);
+ cc = s390_iommu_domain_reg_ioat(zdev, domain, &status);
if (cc && status != ZPCI_PCI_ST_FUNC_NOT_AVAIL)
return -EIO;
zdev->dma_table = s390_domain->dma_table;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 126/869] iommu/s390: set appropriate IOTA region type
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (124 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 125/869] iommu/s390: handle IOAT registration based on domain Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 127/869] iommu/s390: Make attach succeed when the device was surprise removed Greg Kroah-Hartman
` (743 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Niklas Schnelle, Matthew Rosato,
Joerg Roedel, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Rosato <mjrosato@linux.ibm.com>
[ Upstream commit 83c1aec21064c762a2ee475f0fd19f5241de25bc ]
When registering the I/O Translation Anchor, use the current table type
stored in the s390_domain to set the appropriate region type
indication. For the moment, the table type will always be stored as
region third.
Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Tested-by: Niklas Schnelle <schnelle@linux.ibm.com>
Link: https://lore.kernel.org/r/20250411202433.181683-2-mjrosato@linux.ibm.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Stable-dep-of: 9ffaf5229055 ("iommu/s390: Make attach succeed when the device was surprise removed")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/iommu/s390-iommu.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c
index 007ccfdad4954..3df6b3e322271 100644
--- a/drivers/iommu/s390-iommu.c
+++ b/drivers/iommu/s390-iommu.c
@@ -31,6 +31,7 @@ struct s390_domain {
unsigned long *dma_table;
spinlock_t list_lock;
struct rcu_head rcu;
+ u8 origin_type;
};
static struct iommu_domain blocking_domain;
@@ -345,6 +346,7 @@ static struct iommu_domain *s390_domain_alloc_paging(struct device *dev)
s390_domain->domain.geometry.force_aperture = true;
s390_domain->domain.geometry.aperture_start = 0;
s390_domain->domain.geometry.aperture_end = ZPCI_TABLE_SIZE_RT - 1;
+ s390_domain->origin_type = ZPCI_TABLE_TYPE_RTX;
spin_lock_init(&s390_domain->list_lock);
INIT_LIST_HEAD_RCU(&s390_domain->devices);
@@ -381,6 +383,21 @@ static void zdev_s390_domain_update(struct zpci_dev *zdev,
spin_unlock_irqrestore(&zdev->dom_lock, flags);
}
+static u64 get_iota_region_flag(struct s390_domain *domain)
+{
+ switch (domain->origin_type) {
+ case ZPCI_TABLE_TYPE_RTX:
+ return ZPCI_IOTA_RTTO_FLAG;
+ case ZPCI_TABLE_TYPE_RSX:
+ return ZPCI_IOTA_RSTO_FLAG;
+ case ZPCI_TABLE_TYPE_RFX:
+ return ZPCI_IOTA_RFTO_FLAG;
+ default:
+ WARN_ONCE(1, "Invalid IOMMU table (%x)\n", domain->origin_type);
+ return 0;
+ }
+}
+
static int s390_iommu_domain_reg_ioat(struct zpci_dev *zdev,
struct iommu_domain *domain, u8 *status)
{
@@ -399,7 +416,7 @@ static int s390_iommu_domain_reg_ioat(struct zpci_dev *zdev,
default:
s390_domain = to_s390_domain(domain);
iota = virt_to_phys(s390_domain->dma_table) |
- ZPCI_IOTA_RTTO_FLAG;
+ get_iota_region_flag(s390_domain);
rc = zpci_register_ioat(zdev, 0, zdev->start_dma,
zdev->end_dma, iota, status);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 127/869] iommu/s390: Make attach succeed when the device was surprise removed
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (125 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 126/869] iommu/s390: set appropriate IOTA region type Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 128/869] RISC-V: KVM: Write hgatp register with valid mode bits Greg Kroah-Hartman
` (742 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jason Gunthorpe, Niklas Schnelle,
Matthew Rosato, Benjamin Block, Joerg Roedel, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Niklas Schnelle <schnelle@linux.ibm.com>
[ Upstream commit 9ffaf5229055fcfbb3b3d6f1c7e58d63715c3f73 ]
When a PCI device is removed with surprise hotplug, there may still be
attempts to attach the device to the default domain as part of tear down
via (__iommu_release_dma_ownership()), or because the removal happens
during probe (__iommu_probe_device()). In both cases zpci_register_ioat()
fails with a cc value indicating that the device handle is invalid. This
is because the device is no longer part of the instance as far as the
hypervisor is concerned.
Currently this leads to an error return and s390_iommu_attach_device()
fails. This triggers the WARN_ON() in __iommu_group_set_domain_nofail()
because attaching to the default domain must never fail.
With the device fenced by the hypervisor no DMAs to or from memory are
possible and the IOMMU translations have no effect. Proceed as if the
registration was successful and let the hotplug event handling clean up
the device.
This is similar to how devices in the error state are handled since
commit 59bbf596791b ("iommu/s390: Make attach succeed even if the device
is in error state") except that for removal the domain will not be
registered later. This approach was also previously discussed at the
link.
Handle both cases, error state and removal, in a helper which checks if
the error needs to be propagated or ignored. Avoid magic number
condition codes by using the pre-existing, but never used, defines for
PCI load/store condition codes and rename them to reflect that they
apply to all PCI instructions.
Cc: stable@vger.kernel.org # v6.2
Link: https://lore.kernel.org/linux-iommu/20240808194155.GD1985367@ziepe.ca/
Suggested-by: Jason Gunthorpe <jgg@ziepe.ca>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Link: https://lore.kernel.org/r/20250904-iommu_succeed_attach_removed-v1-1-e7f333d2f80f@linux.ibm.com
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/include/asm/pci_insn.h | 10 +++++-----
drivers/iommu/s390-iommu.c | 3 ++-
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h
index e5f57cfe1d458..025c6dcbf8933 100644
--- a/arch/s390/include/asm/pci_insn.h
+++ b/arch/s390/include/asm/pci_insn.h
@@ -16,11 +16,11 @@
#define ZPCI_PCI_ST_FUNC_NOT_AVAIL 40
#define ZPCI_PCI_ST_ALREADY_IN_RQ_STATE 44
-/* Load/Store return codes */
-#define ZPCI_PCI_LS_OK 0
-#define ZPCI_PCI_LS_ERR 1
-#define ZPCI_PCI_LS_BUSY 2
-#define ZPCI_PCI_LS_INVAL_HANDLE 3
+/* PCI instruction condition codes */
+#define ZPCI_CC_OK 0
+#define ZPCI_CC_ERR 1
+#define ZPCI_CC_BUSY 2
+#define ZPCI_CC_INVAL_HANDLE 3
/* Load/Store address space identifiers */
#define ZPCI_PCIAS_MEMIO_0 0
diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c
index 3df6b3e322271..067b175231ad1 100644
--- a/drivers/iommu/s390-iommu.c
+++ b/drivers/iommu/s390-iommu.c
@@ -480,7 +480,8 @@ static int s390_iommu_attach_device(struct iommu_domain *domain,
/* If we fail now DMA remains blocked via blocking domain */
cc = s390_iommu_domain_reg_ioat(zdev, domain, &status);
- if (cc && status != ZPCI_PCI_ST_FUNC_NOT_AVAIL)
+ if (cc != ZPCI_CC_OK && cc != ZPCI_CC_INVAL_HANDLE &&
+ (cc != ZPCI_CC_ERR || status != ZPCI_PCI_ST_FUNC_NOT_AVAIL))
return -EIO;
zdev->dma_table = s390_domain->dma_table;
zdev_s390_domain_update(zdev, domain);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 128/869] RISC-V: KVM: Write hgatp register with valid mode bits
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (126 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 127/869] iommu/s390: Make attach succeed when the device was surprise removed Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 129/869] drm/xe: Dont allow evicting of BOs in same VM in array of VM binds Greg Kroah-Hartman
` (741 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nutty Liu, Troy Mitchell,
Guo Ren (Alibaba DAMO Academy), Fangyu Yu, Anup Patel,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
[ Upstream commit 2b351e3d04be9e1533f26c3464f1e44a5beace30 ]
According to the RISC-V Privileged Architecture Spec, when MODE=Bare
is selected,software must write zero to the remaining fields of hgatp.
We have detected the valid mode supported by the HW before, So using a
valid mode to detect how many vmid bits are supported.
Fixes: fd7bb4a251df ("RISC-V: KVM: Implement VMID allocator")
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Reviewed-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
Reviewed-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org>
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org>
Link: https://lore.kernel.org/r/20250821142542.2472079-2-guoren@kernel.org
Signed-off-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/riscv/kvm/vmid.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/riscv/kvm/vmid.c b/arch/riscv/kvm/vmid.c
index ddc98714ce8ed..38f30f5a608cf 100644
--- a/arch/riscv/kvm/vmid.c
+++ b/arch/riscv/kvm/vmid.c
@@ -26,7 +26,7 @@ void __init kvm_riscv_gstage_vmid_detect(void)
/* Figure-out number of VMID bits in HW */
old = csr_read(CSR_HGATP);
- csr_write(CSR_HGATP, old | HGATP_VMID);
+ csr_write(CSR_HGATP, (kvm_riscv_gstage_mode() << HGATP_MODE_SHIFT) | HGATP_VMID);
vmid_bits = csr_read(CSR_HGATP);
vmid_bits = (vmid_bits & HGATP_VMID) >> HGATP_VMID_SHIFT;
vmid_bits = fls_long(vmid_bits);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 129/869] drm/xe: Dont allow evicting of BOs in same VM in array of VM binds
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (127 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 128/869] RISC-V: KVM: Write hgatp register with valid mode bits Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 130/869] remoteproc: Switch back to struct platform_driver::remove() Greg Kroah-Hartman
` (740 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Paulo Zanoni, Matthew Brost,
Thomas Hellström, Lucas De Marchi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Brost <matthew.brost@intel.com>
[ Upstream commit 7ac74613e5f2ef3450f44fd2127198662c2563a9 ]
An array of VM binds can potentially evict other buffer objects (BOs)
within the same VM under certain conditions, which may lead to NULL
pointer dereferences later in the bind pipeline. To prevent this, clear
the allow_res_evict flag in the xe_bo_validate call.
v2:
- Invert polarity of no_res_evict (Thomas)
- Add comment in code explaining issue (Thomas)
Cc: stable@vger.kernel.org
Reported-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/6268
Fixes: 774b5fa509a9 ("drm/xe: Avoid evicting object of the same vm in none fault mode")
Fixes: 77f2ef3f16f5 ("drm/xe: Lock all gpuva ops during VM bind IOCTL")
Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs")
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Tested-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Link: https://lore.kernel.org/r/20251009110618.3481870-1-matthew.brost@intel.com
(cherry picked from commit 8b9ba8d6d95fe75fed6b0480bb03da4b321bea08)
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/xe/xe_vm.c | 31 ++++++++++++++++++++++---------
drivers/gpu/drm/xe/xe_vm_types.h | 3 +++
2 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index fa0d7c6414022..da148df421057 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -2469,7 +2469,7 @@ static void vm_bind_ioctl_ops_unwind(struct xe_vm *vm,
}
static int vma_lock_and_validate(struct drm_exec *exec, struct xe_vma *vma,
- bool validate)
+ bool res_evict, bool validate)
{
struct xe_bo *bo = xe_vma_bo(vma);
int err = 0;
@@ -2478,7 +2478,7 @@ static int vma_lock_and_validate(struct drm_exec *exec, struct xe_vma *vma,
if (!bo->vm)
err = drm_exec_lock_obj(exec, &bo->ttm.base);
if (!err && validate)
- err = xe_bo_validate(bo, xe_vma_vm(vma), true);
+ err = xe_bo_validate(bo, xe_vma_vm(vma), res_evict);
}
return err;
@@ -2500,13 +2500,22 @@ static int check_ufence(struct xe_vma *vma)
}
static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
- struct xe_vma_op *op)
+ struct xe_vma_ops *vops, struct xe_vma_op *op)
{
int err = 0;
+ bool res_evict;
+
+ /*
+ * We only allow evicting a BO within the VM if it is not part of an
+ * array of binds, as an array of binds can evict another BO within the
+ * bind.
+ */
+ res_evict = !(vops->flags & XE_VMA_OPS_ARRAY_OF_BINDS);
switch (op->base.op) {
case DRM_GPUVA_OP_MAP:
err = vma_lock_and_validate(exec, op->map.vma,
+ res_evict,
!xe_vm_in_fault_mode(vm) ||
op->map.immediate);
break;
@@ -2517,11 +2526,13 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
err = vma_lock_and_validate(exec,
gpuva_to_vma(op->base.remap.unmap->va),
- false);
+ res_evict, false);
if (!err && op->remap.prev)
- err = vma_lock_and_validate(exec, op->remap.prev, true);
+ err = vma_lock_and_validate(exec, op->remap.prev,
+ res_evict, true);
if (!err && op->remap.next)
- err = vma_lock_and_validate(exec, op->remap.next, true);
+ err = vma_lock_and_validate(exec, op->remap.next,
+ res_evict, true);
break;
case DRM_GPUVA_OP_UNMAP:
err = check_ufence(gpuva_to_vma(op->base.unmap.va));
@@ -2530,7 +2541,7 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
err = vma_lock_and_validate(exec,
gpuva_to_vma(op->base.unmap.va),
- false);
+ res_evict, false);
break;
case DRM_GPUVA_OP_PREFETCH:
{
@@ -2541,7 +2552,7 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
err = vma_lock_and_validate(exec,
gpuva_to_vma(op->base.prefetch.va),
- false);
+ res_evict, false);
if (!err && !xe_vma_has_no_bo(vma))
err = xe_bo_migrate(xe_vma_bo(vma),
region_to_mem_type[region]);
@@ -2566,7 +2577,7 @@ static int vm_bind_ioctl_ops_lock_and_prep(struct drm_exec *exec,
return err;
list_for_each_entry(op, &vops->list, link) {
- err = op_lock_and_prep(exec, vm, op);
+ err = op_lock_and_prep(exec, vm, vops, op);
if (err)
return err;
}
@@ -3163,6 +3174,8 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
}
xe_vma_ops_init(&vops, vm, q, syncs, num_syncs);
+ if (args->num_binds > 1)
+ vops.flags |= XE_VMA_OPS_ARRAY_OF_BINDS;
for (i = 0; i < args->num_binds; ++i) {
u64 range = bind_ops[i].range;
u64 addr = bind_ops[i].addr;
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index b280e335c5bb4..e75dc50446164 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -377,6 +377,9 @@ struct xe_vma_ops {
u32 num_syncs;
/** @pt_update_ops: page table update operations */
struct xe_vm_pgtable_update_ops pt_update_ops[XE_MAX_TILES_PER_DEVICE];
+ /** @flags: signify the properties within xe_vma_ops */
+#define XE_VMA_OPS_ARRAY_OF_BINDS BIT(2)
+ u32 flags;
#ifdef TEST_VM_OPS_ERROR
/** @inject_error: inject error to test error handling */
bool inject_error;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 130/869] remoteproc: Switch back to struct platform_driver::remove()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (128 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 129/869] drm/xe: Dont allow evicting of BOs in same VM in array of VM binds Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 131/869] remoteproc: qcom: pas: Make remoteproc name human friendly Greg Kroah-Hartman
` (739 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Uwe Kleine-König,
Mathieu Poirier, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
[ Upstream commit ad64a7c4a49d30c5d909a35e2c7882d3870ddafc ]
After commit 0edb555a65d1 ("platform: Make platform_driver::remove()
return void") .remove() is (again) the right callback to implement for
platform drivers.
Convert all platform drivers below drivers/remoteproc to use .remove(),
with the eventual goal to drop struct platform_driver::remove_new(). As
.remove() and .remove_new() have the same prototypes, conversion is done
by just changing the structure member name in the driver initializer.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Link: https://lore.kernel.org/r/20241025131340.258233-2-u.kleine-koenig@baylibre.com
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Stable-dep-of: 142964960c7c ("remoteproc: qcom: pas: Shutdown lite ADSP DTB on X1E")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/remoteproc/da8xx_remoteproc.c | 2 +-
drivers/remoteproc/imx_dsp_rproc.c | 2 +-
drivers/remoteproc/imx_rproc.c | 2 +-
drivers/remoteproc/keystone_remoteproc.c | 2 +-
drivers/remoteproc/meson_mx_ao_arc.c | 2 +-
drivers/remoteproc/mtk_scp.c | 2 +-
drivers/remoteproc/pru_rproc.c | 2 +-
drivers/remoteproc/qcom_q6v5_adsp.c | 2 +-
drivers/remoteproc/qcom_q6v5_mss.c | 2 +-
drivers/remoteproc/qcom_q6v5_pas.c | 2 +-
drivers/remoteproc/qcom_q6v5_wcss.c | 2 +-
drivers/remoteproc/qcom_wcnss.c | 2 +-
drivers/remoteproc/rcar_rproc.c | 2 +-
drivers/remoteproc/remoteproc_virtio.c | 2 +-
drivers/remoteproc/st_remoteproc.c | 2 +-
drivers/remoteproc/stm32_rproc.c | 2 +-
drivers/remoteproc/ti_k3_dsp_remoteproc.c | 2 +-
drivers/remoteproc/wkup_m3_rproc.c | 2 +-
18 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c
index 8770d0cf1255f..fe0179f4044f3 100644
--- a/drivers/remoteproc/da8xx_remoteproc.c
+++ b/drivers/remoteproc/da8xx_remoteproc.c
@@ -378,7 +378,7 @@ MODULE_DEVICE_TABLE(of, davinci_rproc_of_match);
static struct platform_driver da8xx_rproc_driver = {
.probe = da8xx_rproc_probe,
- .remove_new = da8xx_rproc_remove,
+ .remove = da8xx_rproc_remove,
.driver = {
.name = "davinci-rproc",
.of_match_table = of_match_ptr(davinci_rproc_of_match),
diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
index 713a57200cf09..427c200a175c3 100644
--- a/drivers/remoteproc/imx_dsp_rproc.c
+++ b/drivers/remoteproc/imx_dsp_rproc.c
@@ -1267,7 +1267,7 @@ MODULE_DEVICE_TABLE(of, imx_dsp_rproc_of_match);
static struct platform_driver imx_dsp_rproc_driver = {
.probe = imx_dsp_rproc_probe,
- .remove_new = imx_dsp_rproc_remove,
+ .remove = imx_dsp_rproc_remove,
.driver = {
.name = "imx-dsp-rproc",
.of_match_table = imx_dsp_rproc_of_match,
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 2797b7e971429..4f73b1ea05ffb 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -1202,7 +1202,7 @@ MODULE_DEVICE_TABLE(of, imx_rproc_of_match);
static struct platform_driver imx_rproc_driver = {
.probe = imx_rproc_probe,
- .remove_new = imx_rproc_remove,
+ .remove = imx_rproc_remove,
.driver = {
.name = "imx-rproc",
.of_match_table = imx_rproc_of_match,
diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
index 8f0f7a4cfef26..6e54093d17323 100644
--- a/drivers/remoteproc/keystone_remoteproc.c
+++ b/drivers/remoteproc/keystone_remoteproc.c
@@ -490,7 +490,7 @@ MODULE_DEVICE_TABLE(of, keystone_rproc_of_match);
static struct platform_driver keystone_rproc_driver = {
.probe = keystone_rproc_probe,
- .remove_new = keystone_rproc_remove,
+ .remove = keystone_rproc_remove,
.driver = {
.name = "keystone-rproc",
.of_match_table = keystone_rproc_of_match,
diff --git a/drivers/remoteproc/meson_mx_ao_arc.c b/drivers/remoteproc/meson_mx_ao_arc.c
index f6744b5383230..7dfdf11b00368 100644
--- a/drivers/remoteproc/meson_mx_ao_arc.c
+++ b/drivers/remoteproc/meson_mx_ao_arc.c
@@ -246,7 +246,7 @@ MODULE_DEVICE_TABLE(of, meson_mx_ao_arc_rproc_match);
static struct platform_driver meson_mx_ao_arc_rproc_driver = {
.probe = meson_mx_ao_arc_rproc_probe,
- .remove_new = meson_mx_ao_arc_rproc_remove,
+ .remove = meson_mx_ao_arc_rproc_remove,
.driver = {
.name = "meson-mx-ao-arc-rproc",
.of_match_table = meson_mx_ao_arc_rproc_match,
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
index 81ca0fc3820f9..b3613802730c1 100644
--- a/drivers/remoteproc/mtk_scp.c
+++ b/drivers/remoteproc/mtk_scp.c
@@ -1591,7 +1591,7 @@ static const struct dev_pm_ops scp_pm_ops = {
static struct platform_driver mtk_scp_driver = {
.probe = scp_probe,
- .remove_new = scp_remove,
+ .remove = scp_remove,
.driver = {
.name = "mtk-scp",
.of_match_table = mtk_scp_of_match,
diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index 7ffbae209a31f..985daf6945dd4 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -1133,7 +1133,7 @@ static struct platform_driver pru_rproc_driver = {
.suppress_bind_attrs = true,
},
.probe = pru_rproc_probe,
- .remove_new = pru_rproc_remove,
+ .remove = pru_rproc_remove,
};
module_platform_driver(pru_rproc_driver);
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index 0345940268126..13c9898447b2d 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -848,7 +848,7 @@ MODULE_DEVICE_TABLE(of, adsp_of_match);
static struct platform_driver adsp_pil_driver = {
.probe = adsp_probe,
- .remove_new = adsp_remove,
+ .remove = adsp_remove,
.driver = {
.name = "qcom_q6v5_adsp",
.of_match_table = adsp_of_match,
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index e19081d530226..5ddc146435cda 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -2546,7 +2546,7 @@ MODULE_DEVICE_TABLE(of, q6v5_of_match);
static struct platform_driver q6v5_driver = {
.probe = q6v5_probe,
- .remove_new = q6v5_remove,
+ .remove = q6v5_remove,
.driver = {
.name = "qcom-q6v5-mss",
.of_match_table = q6v5_of_match,
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index 23f928323bcfd..bc1d56a2684e6 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -1510,7 +1510,7 @@ MODULE_DEVICE_TABLE(of, adsp_of_match);
static struct platform_driver adsp_driver = {
.probe = adsp_probe,
- .remove_new = adsp_remove,
+ .remove = adsp_remove,
.driver = {
.name = "qcom_q6v5_pas",
.of_match_table = adsp_of_match,
diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
index c560b81b72631..a89faabc11ce1 100644
--- a/drivers/remoteproc/qcom_q6v5_wcss.c
+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
@@ -1111,7 +1111,7 @@ MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match);
static struct platform_driver q6v5_wcss_driver = {
.probe = q6v5_wcss_probe,
- .remove_new = q6v5_wcss_remove,
+ .remove = q6v5_wcss_remove,
.driver = {
.name = "qcom-q6v5-wcss-pil",
.of_match_table = q6v5_wcss_of_match,
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index a2ae6adf0053a..2c7e519a2254b 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -702,7 +702,7 @@ MODULE_DEVICE_TABLE(of, wcnss_of_match);
static struct platform_driver wcnss_driver = {
.probe = wcnss_probe,
- .remove_new = wcnss_remove,
+ .remove = wcnss_remove,
.driver = {
.name = "qcom-wcnss-pil",
.of_match_table = wcnss_of_match,
diff --git a/drivers/remoteproc/rcar_rproc.c b/drivers/remoteproc/rcar_rproc.c
index cc17e8421f65b..921d853594f42 100644
--- a/drivers/remoteproc/rcar_rproc.c
+++ b/drivers/remoteproc/rcar_rproc.c
@@ -214,7 +214,7 @@ MODULE_DEVICE_TABLE(of, rcar_rproc_of_match);
static struct platform_driver rcar_rproc_driver = {
.probe = rcar_rproc_probe,
- .remove_new = rcar_rproc_remove,
+ .remove = rcar_rproc_remove,
.driver = {
.name = "rcar-rproc",
.of_match_table = rcar_rproc_of_match,
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index d3f39009b28ed..25a655f33ec0e 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -593,7 +593,7 @@ static void rproc_virtio_remove(struct platform_device *pdev)
/* Platform driver */
static struct platform_driver rproc_virtio_driver = {
.probe = rproc_virtio_probe,
- .remove_new = rproc_virtio_remove,
+ .remove = rproc_virtio_remove,
.driver = {
.name = "rproc-virtio",
},
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
index 1340be9d01101..5df99bae7131a 100644
--- a/drivers/remoteproc/st_remoteproc.c
+++ b/drivers/remoteproc/st_remoteproc.c
@@ -457,7 +457,7 @@ static void st_rproc_remove(struct platform_device *pdev)
static struct platform_driver st_rproc_driver = {
.probe = st_rproc_probe,
- .remove_new = st_rproc_remove,
+ .remove = st_rproc_remove,
.driver = {
.name = "st-rproc",
.of_match_table = of_match_ptr(st_rproc_match),
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index 8c7f7950b80ee..b02b36a3f5156 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -946,7 +946,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stm32_rproc_pm_ops,
static struct platform_driver stm32_rproc_driver = {
.probe = stm32_rproc_probe,
- .remove_new = stm32_rproc_remove,
+ .remove = stm32_rproc_remove,
.driver = {
.name = "stm32-rproc",
.pm = pm_ptr(&stm32_rproc_pm_ops),
diff --git a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c
index 73be3d2167914..f48146e8077f5 100644
--- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c
+++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c
@@ -783,7 +783,7 @@ MODULE_DEVICE_TABLE(of, k3_dsp_of_match);
static struct platform_driver k3_dsp_rproc_driver = {
.probe = k3_dsp_rproc_probe,
- .remove_new = k3_dsp_rproc_remove,
+ .remove = k3_dsp_rproc_remove,
.driver = {
.name = "k3-dsp-rproc",
.of_match_table = k3_dsp_of_match,
diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
index c39bd2bf2c1e7..35c2145b12db7 100644
--- a/drivers/remoteproc/wkup_m3_rproc.c
+++ b/drivers/remoteproc/wkup_m3_rproc.c
@@ -251,7 +251,7 @@ static const struct dev_pm_ops wkup_m3_rproc_pm_ops = {
static struct platform_driver wkup_m3_rproc_driver = {
.probe = wkup_m3_rproc_probe,
- .remove_new = wkup_m3_rproc_remove,
+ .remove = wkup_m3_rproc_remove,
.driver = {
.name = "wkup_m3_rproc",
.of_match_table = wkup_m3_rproc_of_match,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 131/869] remoteproc: qcom: pas: Make remoteproc name human friendly
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (129 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 130/869] remoteproc: Switch back to struct platform_driver::remove() Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 132/869] remoteproc: qcom_q6v5_pas: Simplify with dev_err_probe() Greg Kroah-Hartman
` (738 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bjorn Andersson, Dmitry Baryshkov,
Chris Lew, Bjorn Andersson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
[ Upstream commit b64b1266d6195d9bbfa75a93b4265fba2d447c86 ]
The remoteproc "name" property is supposed to present the "human
readable" name of the remoteproc, while using the device name is
readable, it's not "friendly".
Instead, use the "sysmon_name" as the identifier for the remoteproc
instance. It matches the typical names used when we speak about each
instance, while still being unique.
Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Chris Lew <quic_clew@quicinc.com>
Link: https://lore.kernel.org/r/20241022-rproc-friendly-name-v1-1-350c82b075cb@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Stable-dep-of: 142964960c7c ("remoteproc: qcom: pas: Shutdown lite ADSP DTB on X1E")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/remoteproc/qcom_q6v5_pas.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index bc1d56a2684e6..c3a634454d53d 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -714,7 +714,7 @@ static int adsp_probe(struct platform_device *pdev)
if (desc->minidump_id)
ops = &adsp_minidump_ops;
- rproc = devm_rproc_alloc(&pdev->dev, pdev->name, ops, fw_name, sizeof(*adsp));
+ rproc = devm_rproc_alloc(&pdev->dev, desc->sysmon_name, ops, fw_name, sizeof(*adsp));
if (!rproc) {
dev_err(&pdev->dev, "unable to allocate remoteproc\n");
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 132/869] remoteproc: qcom_q6v5_pas: Simplify with dev_err_probe()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (130 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 131/869] remoteproc: qcom: pas: Make remoteproc name human friendly Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 133/869] remoteproc: qcom: pas: Conclude the rename from adsp Greg Kroah-Hartman
` (737 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Krzysztof Kozlowski,
Dmitry Baryshkov, Bjorn Andersson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
[ Upstream commit 427442e873d7af7a06ff4382b57197f43afa8ed4 ]
Use dev_err_probe() to make error and defer code handling simpler.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://lore.kernel.org/r/20241011-remote-proc-dev-err-probe-v1-8-5abb4fc61eca@linaro.org
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Stable-dep-of: 142964960c7c ("remoteproc: qcom: pas: Shutdown lite ADSP DTB on X1E")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/remoteproc/qcom_q6v5_pas.c | 22 +++++++---------------
1 file changed, 7 insertions(+), 15 deletions(-)
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index c3a634454d53d..62b7e23eed4a1 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -451,24 +451,16 @@ static const struct rproc_ops adsp_minidump_ops = {
static int adsp_init_clock(struct qcom_adsp *adsp)
{
- int ret;
-
adsp->xo = devm_clk_get(adsp->dev, "xo");
- if (IS_ERR(adsp->xo)) {
- ret = PTR_ERR(adsp->xo);
- if (ret != -EPROBE_DEFER)
- dev_err(adsp->dev, "failed to get xo clock");
- return ret;
- }
+ if (IS_ERR(adsp->xo))
+ return dev_err_probe(adsp->dev, PTR_ERR(adsp->xo),
+ "failed to get xo clock");
+
adsp->aggre2_clk = devm_clk_get_optional(adsp->dev, "aggre2");
- if (IS_ERR(adsp->aggre2_clk)) {
- ret = PTR_ERR(adsp->aggre2_clk);
- if (ret != -EPROBE_DEFER)
- dev_err(adsp->dev,
- "failed to get aggre2 clock");
- return ret;
- }
+ if (IS_ERR(adsp->aggre2_clk))
+ return dev_err_probe(adsp->dev, PTR_ERR(adsp->aggre2_clk),
+ "failed to get aggre2 clock");
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 133/869] remoteproc: qcom: pas: Conclude the rename from adsp
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (131 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 132/869] remoteproc: qcom_q6v5_pas: Simplify with dev_err_probe() Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 134/869] remoteproc: qcom: pas: Shutdown lite ADSP DTB on X1E Greg Kroah-Hartman
` (736 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bjorn Andersson, Wasim Nazir,
Bjorn Andersson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
[ Upstream commit 2c0c883f895f16fd9d367ec2e64bccab907d8d87 ]
The change that renamed the driver from "adsp" to "pas" didn't change
any of the implementation. The result is an aesthetic eyesore, and
confusing to many.
Conclude the rename of the driver, by updating function, structures and
variable names to match what the driver actually is. The "Hexagon v5" is
also dropped from the name and Kconfig, as this isn't correct either.
No functional change.
Fixes: 9e004f97161d ("remoteproc: qcom: Rename Hexagon v5 PAS driver")
Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
Reviewed-by: Wasim Nazir <quic_wasimn@quicinc.com>
Link: https://lore.kernel.org/r/20250605-pas-rename-v2-1-f1c89e49e691@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Retain the existing PAS context allocation and metadata-release API
while applying the identifier renames. Preserve the current DTB load
error paths and omit the rename of the absent SM8750 MPSS descriptor.
Stable-dep-of: 142964960c7c ("remoteproc: qcom: pas: Shutdown lite ADSP DTB on X1E")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/remoteproc/Kconfig | 11 +-
drivers/remoteproc/qcom_q6v5_pas.c | 611 ++++++++++++++---------------
2 files changed, 308 insertions(+), 314 deletions(-)
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 62f8548fb46a5..85bb276b80258 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -214,7 +214,7 @@ config QCOM_Q6V5_MSS
handled by QCOM_Q6V5_PAS driver.
config QCOM_Q6V5_PAS
- tristate "Qualcomm Hexagon v5 Peripheral Authentication Service support"
+ tristate "Qualcomm Peripheral Authentication Service support"
depends on OF && ARCH_QCOM
depends on QCOM_SMEM
depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n
@@ -229,11 +229,10 @@ config QCOM_Q6V5_PAS
select QCOM_RPROC_COMMON
select QCOM_SCM
help
- Say y here to support the TrustZone based Peripheral Image Loader
- for the Qualcomm Hexagon v5 based remote processors. This is commonly
- used to control subsystems such as ADSP (Audio DSP),
- CDSP (Compute DSP), MPSS (Modem Peripheral SubSystem), and
- SLPI (Sensor Low Power Island).
+ Say y here to support the TrustZone based Peripheral Image Loader for
+ the Qualcomm remote processors. This is commonly used to control
+ subsystems such as ADSP (Audio DSP), CDSP (Compute DSP), MPSS (Modem
+ Peripheral SubSystem), and SLPI (Sensor Low Power Island).
config QCOM_Q6V5_WCSS
tristate "Qualcomm Hexagon based WCSS Peripheral Image Loader"
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index 62b7e23eed4a1..001ac642c63b1 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Qualcomm ADSP/SLPI Peripheral Image Loader for MSM8974 and MSM8996
+ * Qualcomm Peripheral Authentication Service remoteproc driver
*
* Copyright (C) 2016 Linaro Ltd
* Copyright (C) 2014 Sony Mobile Communications AB
@@ -31,11 +31,11 @@
#include "qcom_q6v5.h"
#include "remoteproc_internal.h"
-#define ADSP_DECRYPT_SHUTDOWN_DELAY_MS 100
+#define QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS 100
#define MAX_ASSIGN_COUNT 3
-struct adsp_data {
+struct qcom_pas_data {
int crash_reason_smem;
const char *firmware_name;
const char *dtb_firmware_name;
@@ -60,7 +60,7 @@ struct adsp_data {
int region_assign_vmid;
};
-struct qcom_adsp {
+struct qcom_pas {
struct device *dev;
struct rproc *rproc;
@@ -119,36 +119,37 @@ struct qcom_adsp {
struct qcom_scm_pas_context *dtb_pas_ctx;
};
-static void adsp_segment_dump(struct rproc *rproc, struct rproc_dump_segment *segment,
- void *dest, size_t offset, size_t size)
+static void qcom_pas_segment_dump(struct rproc *rproc,
+ struct rproc_dump_segment *segment,
+ void *dest, size_t offset, size_t size)
{
- struct qcom_adsp *adsp = rproc->priv;
+ struct qcom_pas *pas = rproc->priv;
int total_offset;
- total_offset = segment->da + segment->offset + offset - adsp->mem_phys;
- if (total_offset < 0 || total_offset + size > adsp->mem_size) {
- dev_err(adsp->dev,
+ total_offset = segment->da + segment->offset + offset - pas->mem_phys;
+ if (total_offset < 0 || total_offset + size > pas->mem_size) {
+ dev_err(pas->dev,
"invalid copy request for segment %pad with offset %zu and size %zu)\n",
&segment->da, offset, size);
memset(dest, 0xff, size);
return;
}
- memcpy_fromio(dest, adsp->mem_region + total_offset, size);
+ memcpy_fromio(dest, pas->mem_region + total_offset, size);
}
-static void adsp_minidump(struct rproc *rproc)
+static void qcom_pas_minidump(struct rproc *rproc)
{
- struct qcom_adsp *adsp = rproc->priv;
+ struct qcom_pas *pas = rproc->priv;
if (rproc->dump_conf == RPROC_COREDUMP_DISABLED)
return;
- qcom_minidump(rproc, adsp->minidump_id, adsp_segment_dump);
+ qcom_minidump(rproc, pas->minidump_id, qcom_pas_segment_dump);
}
-static int adsp_pds_enable(struct qcom_adsp *adsp, struct device **pds,
- size_t pd_count)
+static int qcom_pas_pds_enable(struct qcom_pas *pas, struct device **pds,
+ size_t pd_count)
{
int ret;
int i;
@@ -174,8 +175,8 @@ static int adsp_pds_enable(struct qcom_adsp *adsp, struct device **pds,
return ret;
};
-static void adsp_pds_disable(struct qcom_adsp *adsp, struct device **pds,
- size_t pd_count)
+static void qcom_pas_pds_disable(struct qcom_pas *pas, struct device **pds,
+ size_t pd_count)
{
int i;
@@ -185,42 +186,42 @@ static void adsp_pds_disable(struct qcom_adsp *adsp, struct device **pds,
}
}
-static int adsp_shutdown_poll_decrypt(struct qcom_adsp *adsp)
+static int qcom_pas_shutdown_poll_decrypt(struct qcom_pas *pas)
{
unsigned int retry_num = 50;
int ret;
do {
- msleep(ADSP_DECRYPT_SHUTDOWN_DELAY_MS);
- ret = qcom_scm_pas_shutdown(adsp->pas_id);
+ msleep(QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS);
+ ret = qcom_scm_pas_shutdown(pas->pas_id);
} while (ret == -EINVAL && --retry_num);
return ret;
}
-static int adsp_unprepare(struct rproc *rproc)
+static int qcom_pas_unprepare(struct rproc *rproc)
{
- struct qcom_adsp *adsp = rproc->priv;
+ struct qcom_pas *pas = rproc->priv;
/*
- * adsp_load() did pass the PAS context to the SCM driver for storing
+ * qcom_pas_load() did pass the PAS context to the SCM driver for storing
* metadata context. It might have been released already if
* auth_and_reset() was successful, but in other cases clean it up
* here.
*/
- qcom_pas_metadata_release(adsp->pas_ctx);
- if (adsp->dtb_pas_id)
- qcom_pas_metadata_release(adsp->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->pas_ctx);
+ if (pas->dtb_pas_id)
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
return 0;
}
-static int adsp_load(struct rproc *rproc, const struct firmware *fw)
+static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw)
{
- struct qcom_adsp *pas = rproc->priv;
+ struct qcom_pas *pas = rproc->priv;
int ret;
- /* Store firmware handle to be used in adsp_start() */
+ /* Store firmware handle to be used in qcom_pas_start() */
pas->firmware = fw;
if (pas->lite_pas_id)
@@ -257,240 +258,238 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
return 0;
}
-static int adsp_start(struct rproc *rproc)
+static int qcom_pas_start(struct rproc *rproc)
{
- struct qcom_adsp *adsp = rproc->priv;
+ struct qcom_pas *pas = rproc->priv;
int ret;
- ret = qcom_q6v5_prepare(&adsp->q6v5);
+ ret = qcom_q6v5_prepare(&pas->q6v5);
if (ret)
return ret;
- ret = adsp_pds_enable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
+ ret = qcom_pas_pds_enable(pas, pas->proxy_pds, pas->proxy_pd_count);
if (ret < 0)
goto disable_irqs;
- ret = clk_prepare_enable(adsp->xo);
+ ret = clk_prepare_enable(pas->xo);
if (ret)
goto disable_proxy_pds;
- ret = clk_prepare_enable(adsp->aggre2_clk);
+ ret = clk_prepare_enable(pas->aggre2_clk);
if (ret)
goto disable_xo_clk;
- if (adsp->cx_supply) {
- ret = regulator_enable(adsp->cx_supply);
+ if (pas->cx_supply) {
+ ret = regulator_enable(pas->cx_supply);
if (ret)
goto disable_aggre2_clk;
}
- if (adsp->px_supply) {
- ret = regulator_enable(adsp->px_supply);
+ if (pas->px_supply) {
+ ret = regulator_enable(pas->px_supply);
if (ret)
goto disable_cx_supply;
}
- if (adsp->dtb_pas_id) {
- ret = qcom_scm_pas_auth_and_reset(adsp->dtb_pas_id);
+ if (pas->dtb_pas_id) {
+ ret = qcom_scm_pas_auth_and_reset(pas->dtb_pas_id);
if (ret) {
- dev_err(adsp->dev,
+ dev_err(pas->dev,
"failed to authenticate dtb image and release reset\n");
goto disable_px_supply;
}
}
- ret = qcom_mdt_pas_init(adsp->dev, adsp->firmware, rproc->firmware, adsp->pas_id,
- adsp->mem_phys, adsp->pas_ctx);
+ ret = qcom_mdt_pas_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id,
+ pas->mem_phys, pas->pas_ctx);
if (ret)
goto disable_px_supply;
- ret = qcom_mdt_load_no_init(adsp->dev, adsp->firmware, rproc->firmware, adsp->pas_id,
- adsp->mem_region, adsp->mem_phys, adsp->mem_size,
- &adsp->mem_reloc);
+ ret = qcom_mdt_load_no_init(pas->dev, pas->firmware, rproc->firmware, pas->pas_id,
+ pas->mem_region, pas->mem_phys, pas->mem_size,
+ &pas->mem_reloc);
if (ret)
goto release_pas_metadata;
- qcom_pil_info_store(adsp->info_name, adsp->mem_phys, adsp->mem_size);
+ qcom_pil_info_store(pas->info_name, pas->mem_phys, pas->mem_size);
- ret = qcom_scm_pas_auth_and_reset(adsp->pas_id);
+ ret = qcom_scm_pas_auth_and_reset(pas->pas_id);
if (ret) {
- dev_err(adsp->dev,
+ dev_err(pas->dev,
"failed to authenticate image and release reset\n");
goto release_pas_metadata;
}
- ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000));
+ ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000));
if (ret == -ETIMEDOUT) {
- dev_err(adsp->dev, "start timed out\n");
- qcom_scm_pas_shutdown(adsp->pas_id);
+ dev_err(pas->dev, "start timed out\n");
+ qcom_scm_pas_shutdown(pas->pas_id);
goto release_pas_metadata;
}
- qcom_pas_metadata_release(adsp->pas_ctx);
- if (adsp->dtb_pas_id)
- qcom_pas_metadata_release(adsp->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->pas_ctx);
+ if (pas->dtb_pas_id)
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
- /* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */
- adsp->firmware = NULL;
+ /* firmware is used to pass reference from qcom_pas_start(), drop it now */
+ pas->firmware = NULL;
return 0;
release_pas_metadata:
- qcom_pas_metadata_release(adsp->pas_ctx);
- if (adsp->dtb_pas_id)
- qcom_pas_metadata_release(adsp->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->pas_ctx);
+ if (pas->dtb_pas_id)
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
disable_px_supply:
- if (adsp->px_supply)
- regulator_disable(adsp->px_supply);
+ if (pas->px_supply)
+ regulator_disable(pas->px_supply);
disable_cx_supply:
- if (adsp->cx_supply)
- regulator_disable(adsp->cx_supply);
+ if (pas->cx_supply)
+ regulator_disable(pas->cx_supply);
disable_aggre2_clk:
- clk_disable_unprepare(adsp->aggre2_clk);
+ clk_disable_unprepare(pas->aggre2_clk);
disable_xo_clk:
- clk_disable_unprepare(adsp->xo);
+ clk_disable_unprepare(pas->xo);
disable_proxy_pds:
- adsp_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
+ qcom_pas_pds_disable(pas, pas->proxy_pds, pas->proxy_pd_count);
disable_irqs:
- qcom_q6v5_unprepare(&adsp->q6v5);
+ qcom_q6v5_unprepare(&pas->q6v5);
- /* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */
- adsp->firmware = NULL;
+ /* firmware is used to pass reference from qcom_pas_start(), drop it now */
+ pas->firmware = NULL;
return ret;
}
static void qcom_pas_handover(struct qcom_q6v5 *q6v5)
{
- struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5);
-
- if (adsp->px_supply)
- regulator_disable(adsp->px_supply);
- if (adsp->cx_supply)
- regulator_disable(adsp->cx_supply);
- clk_disable_unprepare(adsp->aggre2_clk);
- clk_disable_unprepare(adsp->xo);
- adsp_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
+ struct qcom_pas *pas = container_of(q6v5, struct qcom_pas, q6v5);
+
+ if (pas->px_supply)
+ regulator_disable(pas->px_supply);
+ if (pas->cx_supply)
+ regulator_disable(pas->cx_supply);
+ clk_disable_unprepare(pas->aggre2_clk);
+ clk_disable_unprepare(pas->xo);
+ qcom_pas_pds_disable(pas, pas->proxy_pds, pas->proxy_pd_count);
}
-static int adsp_stop(struct rproc *rproc)
+static int qcom_pas_stop(struct rproc *rproc)
{
- struct qcom_adsp *adsp = rproc->priv;
+ struct qcom_pas *pas = rproc->priv;
int handover;
int ret;
- ret = qcom_q6v5_request_stop(&adsp->q6v5, adsp->sysmon);
+ ret = qcom_q6v5_request_stop(&pas->q6v5, pas->sysmon);
if (ret == -ETIMEDOUT)
- dev_err(adsp->dev, "timed out on wait\n");
+ dev_err(pas->dev, "timed out on wait\n");
- ret = qcom_scm_pas_shutdown(adsp->pas_id);
- if (ret && adsp->decrypt_shutdown)
- ret = adsp_shutdown_poll_decrypt(adsp);
+ ret = qcom_scm_pas_shutdown(pas->pas_id);
+ if (ret && pas->decrypt_shutdown)
+ ret = qcom_pas_shutdown_poll_decrypt(pas);
if (ret)
- dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
+ dev_err(pas->dev, "failed to shutdown: %d\n", ret);
- if (adsp->dtb_pas_id) {
- ret = qcom_scm_pas_shutdown(adsp->dtb_pas_id);
+ if (pas->dtb_pas_id) {
+ ret = qcom_scm_pas_shutdown(pas->dtb_pas_id);
if (ret)
- dev_err(adsp->dev, "failed to shutdown dtb: %d\n", ret);
+ dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret);
}
- handover = qcom_q6v5_unprepare(&adsp->q6v5);
+ handover = qcom_q6v5_unprepare(&pas->q6v5);
if (handover)
- qcom_pas_handover(&adsp->q6v5);
+ qcom_pas_handover(&pas->q6v5);
- if (adsp->smem_host_id)
- ret = qcom_smem_bust_hwspin_lock_by_host(adsp->smem_host_id);
+ if (pas->smem_host_id)
+ ret = qcom_smem_bust_hwspin_lock_by_host(pas->smem_host_id);
return ret;
}
-static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
+static void *qcom_pas_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
{
- struct qcom_adsp *adsp = rproc->priv;
+ struct qcom_pas *pas = rproc->priv;
int offset;
- offset = da - adsp->mem_reloc;
- if (offset < 0 || offset + len > adsp->mem_size)
+ offset = da - pas->mem_reloc;
+ if (offset < 0 || offset + len > pas->mem_size)
return NULL;
if (is_iomem)
*is_iomem = true;
- return adsp->mem_region + offset;
+ return pas->mem_region + offset;
}
-static unsigned long adsp_panic(struct rproc *rproc)
+static unsigned long qcom_pas_panic(struct rproc *rproc)
{
- struct qcom_adsp *adsp = rproc->priv;
+ struct qcom_pas *pas = rproc->priv;
- return qcom_q6v5_panic(&adsp->q6v5);
+ return qcom_q6v5_panic(&pas->q6v5);
}
-static const struct rproc_ops adsp_ops = {
- .unprepare = adsp_unprepare,
- .start = adsp_start,
- .stop = adsp_stop,
- .da_to_va = adsp_da_to_va,
+static const struct rproc_ops qcom_pas_ops = {
+ .unprepare = qcom_pas_unprepare,
+ .start = qcom_pas_start,
+ .stop = qcom_pas_stop,
+ .da_to_va = qcom_pas_da_to_va,
.parse_fw = qcom_register_dump_segments,
- .load = adsp_load,
- .panic = adsp_panic,
+ .load = qcom_pas_load,
+ .panic = qcom_pas_panic,
};
-static const struct rproc_ops adsp_minidump_ops = {
- .unprepare = adsp_unprepare,
- .start = adsp_start,
- .stop = adsp_stop,
- .da_to_va = adsp_da_to_va,
+static const struct rproc_ops qcom_pas_minidump_ops = {
+ .unprepare = qcom_pas_unprepare,
+ .start = qcom_pas_start,
+ .stop = qcom_pas_stop,
+ .da_to_va = qcom_pas_da_to_va,
.parse_fw = qcom_register_dump_segments,
- .load = adsp_load,
- .panic = adsp_panic,
- .coredump = adsp_minidump,
+ .load = qcom_pas_load,
+ .panic = qcom_pas_panic,
+ .coredump = qcom_pas_minidump,
};
-static int adsp_init_clock(struct qcom_adsp *adsp)
+static int qcom_pas_init_clock(struct qcom_pas *pas)
{
- adsp->xo = devm_clk_get(adsp->dev, "xo");
- if (IS_ERR(adsp->xo))
- return dev_err_probe(adsp->dev, PTR_ERR(adsp->xo),
+ pas->xo = devm_clk_get(pas->dev, "xo");
+ if (IS_ERR(pas->xo))
+ return dev_err_probe(pas->dev, PTR_ERR(pas->xo),
"failed to get xo clock");
-
- adsp->aggre2_clk = devm_clk_get_optional(adsp->dev, "aggre2");
- if (IS_ERR(adsp->aggre2_clk))
- return dev_err_probe(adsp->dev, PTR_ERR(adsp->aggre2_clk),
+ pas->aggre2_clk = devm_clk_get_optional(pas->dev, "aggre2");
+ if (IS_ERR(pas->aggre2_clk))
+ return dev_err_probe(pas->dev, PTR_ERR(pas->aggre2_clk),
"failed to get aggre2 clock");
return 0;
}
-static int adsp_init_regulator(struct qcom_adsp *adsp)
+static int qcom_pas_init_regulator(struct qcom_pas *pas)
{
- adsp->cx_supply = devm_regulator_get_optional(adsp->dev, "cx");
- if (IS_ERR(adsp->cx_supply)) {
- if (PTR_ERR(adsp->cx_supply) == -ENODEV)
- adsp->cx_supply = NULL;
+ pas->cx_supply = devm_regulator_get_optional(pas->dev, "cx");
+ if (IS_ERR(pas->cx_supply)) {
+ if (PTR_ERR(pas->cx_supply) == -ENODEV)
+ pas->cx_supply = NULL;
else
- return PTR_ERR(adsp->cx_supply);
+ return PTR_ERR(pas->cx_supply);
}
- if (adsp->cx_supply)
- regulator_set_load(adsp->cx_supply, 100000);
+ if (pas->cx_supply)
+ regulator_set_load(pas->cx_supply, 100000);
- adsp->px_supply = devm_regulator_get_optional(adsp->dev, "px");
- if (IS_ERR(adsp->px_supply)) {
- if (PTR_ERR(adsp->px_supply) == -ENODEV)
- adsp->px_supply = NULL;
+ pas->px_supply = devm_regulator_get_optional(pas->dev, "px");
+ if (IS_ERR(pas->px_supply)) {
+ if (PTR_ERR(pas->px_supply) == -ENODEV)
+ pas->px_supply = NULL;
else
- return PTR_ERR(adsp->px_supply);
+ return PTR_ERR(pas->px_supply);
}
return 0;
}
-static int adsp_pds_attach(struct device *dev, struct device **devs,
- char **pd_names)
+static int qcom_pas_pds_attach(struct device *dev, struct device **devs, char **pd_names)
{
size_t num_pds = 0;
int ret;
@@ -526,10 +525,9 @@ static int adsp_pds_attach(struct device *dev, struct device **devs,
return ret;
};
-static void adsp_pds_detach(struct qcom_adsp *adsp, struct device **pds,
- size_t pd_count)
+static void qcom_pas_pds_detach(struct qcom_pas *pas, struct device **pds, size_t pd_count)
{
- struct device *dev = adsp->dev;
+ struct device *dev = pas->dev;
int i;
/* Handle single power domain */
@@ -542,62 +540,62 @@ static void adsp_pds_detach(struct qcom_adsp *adsp, struct device **pds,
dev_pm_domain_detach(pds[i], false);
}
-static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
+static int qcom_pas_alloc_memory_region(struct qcom_pas *pas)
{
struct reserved_mem *rmem;
struct device_node *node;
- node = of_parse_phandle(adsp->dev->of_node, "memory-region", 0);
+ node = of_parse_phandle(pas->dev->of_node, "memory-region", 0);
if (!node) {
- dev_err(adsp->dev, "no memory-region specified\n");
+ dev_err(pas->dev, "no memory-region specified\n");
return -EINVAL;
}
rmem = of_reserved_mem_lookup(node);
of_node_put(node);
if (!rmem) {
- dev_err(adsp->dev, "unable to resolve memory-region\n");
+ dev_err(pas->dev, "unable to resolve memory-region\n");
return -EINVAL;
}
- adsp->mem_phys = adsp->mem_reloc = rmem->base;
- adsp->mem_size = rmem->size;
- adsp->mem_region = devm_ioremap_wc(adsp->dev, adsp->mem_phys, adsp->mem_size);
- if (!adsp->mem_region) {
- dev_err(adsp->dev, "unable to map memory region: %pa+%zx\n",
- &rmem->base, adsp->mem_size);
+ pas->mem_phys = pas->mem_reloc = rmem->base;
+ pas->mem_size = rmem->size;
+ pas->mem_region = devm_ioremap_wc(pas->dev, pas->mem_phys, pas->mem_size);
+ if (!pas->mem_region) {
+ dev_err(pas->dev, "unable to map memory region: %pa+%zx\n",
+ &rmem->base, pas->mem_size);
return -EBUSY;
}
- if (!adsp->dtb_pas_id)
+ if (!pas->dtb_pas_id)
return 0;
- node = of_parse_phandle(adsp->dev->of_node, "memory-region", 1);
+ node = of_parse_phandle(pas->dev->of_node, "memory-region", 1);
if (!node) {
- dev_err(adsp->dev, "no dtb memory-region specified\n");
+ dev_err(pas->dev, "no dtb memory-region specified\n");
return -EINVAL;
}
rmem = of_reserved_mem_lookup(node);
of_node_put(node);
if (!rmem) {
- dev_err(adsp->dev, "unable to resolve dtb memory-region\n");
+ dev_err(pas->dev, "unable to resolve dtb memory-region\n");
return -EINVAL;
}
- adsp->dtb_mem_phys = adsp->dtb_mem_reloc = rmem->base;
- adsp->dtb_mem_size = rmem->size;
- adsp->dtb_mem_region = devm_ioremap_wc(adsp->dev, adsp->dtb_mem_phys, adsp->dtb_mem_size);
- if (!adsp->dtb_mem_region) {
- dev_err(adsp->dev, "unable to map dtb memory region: %pa+%zx\n",
- &rmem->base, adsp->dtb_mem_size);
+ pas->dtb_mem_phys = pas->dtb_mem_reloc = rmem->base;
+ pas->dtb_mem_size = rmem->size;
+ pas->dtb_mem_region = devm_ioremap_wc(pas->dev, pas->dtb_mem_phys, pas->dtb_mem_size);
+ if (!pas->dtb_mem_region) {
+ dev_err(pas->dev, "unable to map dtb memory region: %pa+%zx\n",
+ &rmem->base, pas->dtb_mem_size);
return -EBUSY;
}
return 0;
}
-static int adsp_assign_memory_region(struct qcom_adsp *adsp)
+static int qcom_pas_assign_memory_region(struct qcom_pas *pas)
{
struct qcom_scm_vmperm perm[MAX_ASSIGN_COUNT];
struct device_node *node;
@@ -605,45 +603,45 @@ static int adsp_assign_memory_region(struct qcom_adsp *adsp)
int offset;
int ret;
- if (!adsp->region_assign_idx)
+ if (!pas->region_assign_idx)
return 0;
- for (offset = 0; offset < adsp->region_assign_count; ++offset) {
+ for (offset = 0; offset < pas->region_assign_count; ++offset) {
struct reserved_mem *rmem = NULL;
- node = of_parse_phandle(adsp->dev->of_node, "memory-region",
- adsp->region_assign_idx + offset);
+ node = of_parse_phandle(pas->dev->of_node, "memory-region",
+ pas->region_assign_idx + offset);
if (node)
rmem = of_reserved_mem_lookup(node);
of_node_put(node);
if (!rmem) {
- dev_err(adsp->dev, "unable to resolve shareable memory-region index %d\n",
+ dev_err(pas->dev, "unable to resolve shareable memory-region index %d\n",
offset);
return -EINVAL;
}
- if (adsp->region_assign_shared) {
+ if (pas->region_assign_shared) {
perm[0].vmid = QCOM_SCM_VMID_HLOS;
perm[0].perm = QCOM_SCM_PERM_RW;
- perm[1].vmid = adsp->region_assign_vmid;
+ perm[1].vmid = pas->region_assign_vmid;
perm[1].perm = QCOM_SCM_PERM_RW;
perm_size = 2;
} else {
- perm[0].vmid = adsp->region_assign_vmid;
+ perm[0].vmid = pas->region_assign_vmid;
perm[0].perm = QCOM_SCM_PERM_RW;
perm_size = 1;
}
- adsp->region_assign_phys[offset] = rmem->base;
- adsp->region_assign_size[offset] = rmem->size;
- adsp->region_assign_owners[offset] = BIT(QCOM_SCM_VMID_HLOS);
+ pas->region_assign_phys[offset] = rmem->base;
+ pas->region_assign_size[offset] = rmem->size;
+ pas->region_assign_owners[offset] = BIT(QCOM_SCM_VMID_HLOS);
- ret = qcom_scm_assign_mem(adsp->region_assign_phys[offset],
- adsp->region_assign_size[offset],
- &adsp->region_assign_owners[offset],
+ ret = qcom_scm_assign_mem(pas->region_assign_phys[offset],
+ pas->region_assign_size[offset],
+ &pas->region_assign_owners[offset],
perm, perm_size);
if (ret < 0) {
- dev_err(adsp->dev, "assign memory %d failed\n", offset);
+ dev_err(pas->dev, "assign memory %d failed\n", offset);
return ret;
}
}
@@ -651,35 +649,35 @@ static int adsp_assign_memory_region(struct qcom_adsp *adsp)
return 0;
}
-static void adsp_unassign_memory_region(struct qcom_adsp *adsp)
+static void qcom_pas_unassign_memory_region(struct qcom_pas *pas)
{
struct qcom_scm_vmperm perm;
int offset;
int ret;
- if (!adsp->region_assign_idx || adsp->region_assign_shared)
+ if (!pas->region_assign_idx || pas->region_assign_shared)
return;
- for (offset = 0; offset < adsp->region_assign_count; ++offset) {
+ for (offset = 0; offset < pas->region_assign_count; ++offset) {
perm.vmid = QCOM_SCM_VMID_HLOS;
perm.perm = QCOM_SCM_PERM_RW;
- ret = qcom_scm_assign_mem(adsp->region_assign_phys[offset],
- adsp->region_assign_size[offset],
- &adsp->region_assign_owners[offset],
+ ret = qcom_scm_assign_mem(pas->region_assign_phys[offset],
+ pas->region_assign_size[offset],
+ &pas->region_assign_owners[offset],
&perm, 1);
if (ret < 0)
- dev_err(adsp->dev, "unassign memory %d failed\n", offset);
+ dev_err(pas->dev, "unassign memory %d failed\n", offset);
}
}
-static int adsp_probe(struct platform_device *pdev)
+static int qcom_pas_probe(struct platform_device *pdev)
{
- const struct adsp_data *desc;
- struct qcom_adsp *adsp;
+ const struct qcom_pas_data *desc;
+ struct qcom_pas *pas;
struct rproc *rproc;
const char *fw_name, *dtb_fw_name = NULL;
- const struct rproc_ops *ops = &adsp_ops;
+ const struct rproc_ops *ops = &qcom_pas_ops;
int ret;
desc = of_device_get_match_data(&pdev->dev);
@@ -704,9 +702,9 @@ static int adsp_probe(struct platform_device *pdev)
}
if (desc->minidump_id)
- ops = &adsp_minidump_ops;
+ ops = &qcom_pas_minidump_ops;
- rproc = devm_rproc_alloc(&pdev->dev, desc->sysmon_name, ops, fw_name, sizeof(*adsp));
+ rproc = devm_rproc_alloc(&pdev->dev, desc->sysmon_name, ops, fw_name, sizeof(*pas));
if (!rproc) {
dev_err(&pdev->dev, "unable to allocate remoteproc\n");
@@ -716,88 +714,85 @@ static int adsp_probe(struct platform_device *pdev)
rproc->auto_boot = desc->auto_boot;
rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
- adsp = rproc->priv;
- adsp->dev = &pdev->dev;
- adsp->rproc = rproc;
- adsp->minidump_id = desc->minidump_id;
- adsp->pas_id = desc->pas_id;
- adsp->lite_pas_id = desc->lite_pas_id;
- adsp->info_name = desc->sysmon_name;
- adsp->smem_host_id = desc->smem_host_id;
- adsp->decrypt_shutdown = desc->decrypt_shutdown;
- adsp->region_assign_idx = desc->region_assign_idx;
- adsp->region_assign_count = min_t(int, MAX_ASSIGN_COUNT, desc->region_assign_count);
- adsp->region_assign_vmid = desc->region_assign_vmid;
- adsp->region_assign_shared = desc->region_assign_shared;
+ pas = rproc->priv;
+ pas->dev = &pdev->dev;
+ pas->rproc = rproc;
+ pas->minidump_id = desc->minidump_id;
+ pas->pas_id = desc->pas_id;
+ pas->lite_pas_id = desc->lite_pas_id;
+ pas->info_name = desc->sysmon_name;
+ pas->smem_host_id = desc->smem_host_id;
+ pas->decrypt_shutdown = desc->decrypt_shutdown;
+ pas->region_assign_idx = desc->region_assign_idx;
+ pas->region_assign_count = min_t(int, MAX_ASSIGN_COUNT, desc->region_assign_count);
+ pas->region_assign_vmid = desc->region_assign_vmid;
+ pas->region_assign_shared = desc->region_assign_shared;
if (dtb_fw_name) {
- adsp->dtb_firmware_name = dtb_fw_name;
- adsp->dtb_pas_id = desc->dtb_pas_id;
+ pas->dtb_firmware_name = dtb_fw_name;
+ pas->dtb_pas_id = desc->dtb_pas_id;
}
- platform_set_drvdata(pdev, adsp);
+ platform_set_drvdata(pdev, pas);
- ret = device_init_wakeup(adsp->dev, true);
+ ret = device_init_wakeup(pas->dev, true);
if (ret)
goto free_rproc;
- ret = adsp_alloc_memory_region(adsp);
+ ret = qcom_pas_alloc_memory_region(pas);
if (ret)
goto free_rproc;
- ret = adsp_assign_memory_region(adsp);
+ ret = qcom_pas_assign_memory_region(pas);
if (ret)
goto free_rproc;
- ret = adsp_init_clock(adsp);
+ ret = qcom_pas_init_clock(pas);
if (ret)
goto unassign_mem;
- ret = adsp_init_regulator(adsp);
+ ret = qcom_pas_init_regulator(pas);
if (ret)
goto unassign_mem;
- ret = adsp_pds_attach(&pdev->dev, adsp->proxy_pds,
- desc->proxy_pd_names);
+ ret = qcom_pas_pds_attach(&pdev->dev, pas->proxy_pds, desc->proxy_pd_names);
if (ret < 0)
goto unassign_mem;
- adsp->proxy_pd_count = ret;
+ pas->proxy_pd_count = ret;
- ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem, desc->load_state,
- qcom_pas_handover);
+ ret = qcom_q6v5_init(&pas->q6v5, pdev, rproc, desc->crash_reason_smem,
+ desc->load_state, qcom_pas_handover);
if (ret)
goto detach_proxy_pds;
- qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name);
- qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
- qcom_add_pdm_subdev(rproc, &adsp->pdm_subdev);
- adsp->sysmon = qcom_add_sysmon_subdev(rproc,
- desc->sysmon_name,
- desc->ssctl_id);
- if (IS_ERR(adsp->sysmon)) {
- ret = PTR_ERR(adsp->sysmon);
+ qcom_add_glink_subdev(rproc, &pas->glink_subdev, desc->ssr_name);
+ qcom_add_smd_subdev(rproc, &pas->smd_subdev);
+ qcom_add_pdm_subdev(rproc, &pas->pdm_subdev);
+ pas->sysmon = qcom_add_sysmon_subdev(rproc, desc->sysmon_name, desc->ssctl_id);
+ if (IS_ERR(pas->sysmon)) {
+ ret = PTR_ERR(pas->sysmon);
goto deinit_remove_pdm_smd_glink;
}
- qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
+ qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name);
- adsp->pas_ctx = devm_kzalloc(adsp->dev, sizeof(*adsp->pas_ctx), GFP_KERNEL);
- if (!adsp->pas_ctx) {
+ pas->pas_ctx = devm_kzalloc(pas->dev, sizeof(*pas->pas_ctx), GFP_KERNEL);
+ if (!pas->pas_ctx) {
ret = -ENOMEM;
goto remove_ssr_sysmon;
}
- adsp->pas_ctx->dev = adsp->dev;
- adsp->pas_ctx->pas_id = adsp->pas_id;
- adsp->pas_ctx->mem_phys = adsp->mem_phys;
- adsp->pas_ctx->mem_size = adsp->mem_size;
+ pas->pas_ctx->dev = pas->dev;
+ pas->pas_ctx->pas_id = pas->pas_id;
+ pas->pas_ctx->mem_phys = pas->mem_phys;
+ pas->pas_ctx->mem_size = pas->mem_size;
- adsp->dtb_pas_ctx = devm_kzalloc(adsp->dev, sizeof(*adsp->dtb_pas_ctx), GFP_KERNEL);
- if (!adsp->dtb_pas_ctx) {
+ pas->dtb_pas_ctx = devm_kzalloc(pas->dev, sizeof(*pas->dtb_pas_ctx), GFP_KERNEL);
+ if (!pas->dtb_pas_ctx) {
ret = -ENOMEM;
goto remove_ssr_sysmon;
}
- adsp->dtb_pas_ctx->dev = adsp->dev;
- adsp->dtb_pas_ctx->pas_id = adsp->dtb_pas_id;
- adsp->dtb_pas_ctx->mem_phys = adsp->dtb_mem_phys;
- adsp->dtb_pas_ctx->mem_size = adsp->dtb_mem_size;
+ pas->dtb_pas_ctx->dev = pas->dev;
+ pas->dtb_pas_ctx->pas_id = pas->dtb_pas_id;
+ pas->dtb_pas_ctx->mem_phys = pas->dtb_mem_phys;
+ pas->dtb_pas_ctx->mem_size = pas->dtb_mem_size;
ret = rproc_add(rproc);
if (ret)
@@ -806,41 +801,41 @@ static int adsp_probe(struct platform_device *pdev)
return 0;
remove_ssr_sysmon:
- qcom_remove_ssr_subdev(rproc, &adsp->ssr_subdev);
- qcom_remove_sysmon_subdev(adsp->sysmon);
+ qcom_remove_ssr_subdev(rproc, &pas->ssr_subdev);
+ qcom_remove_sysmon_subdev(pas->sysmon);
deinit_remove_pdm_smd_glink:
- qcom_remove_pdm_subdev(rproc, &adsp->pdm_subdev);
- qcom_remove_smd_subdev(rproc, &adsp->smd_subdev);
- qcom_remove_glink_subdev(rproc, &adsp->glink_subdev);
- qcom_q6v5_deinit(&adsp->q6v5);
+ qcom_remove_pdm_subdev(rproc, &pas->pdm_subdev);
+ qcom_remove_smd_subdev(rproc, &pas->smd_subdev);
+ qcom_remove_glink_subdev(rproc, &pas->glink_subdev);
+ qcom_q6v5_deinit(&pas->q6v5);
detach_proxy_pds:
- adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
+ qcom_pas_pds_detach(pas, pas->proxy_pds, pas->proxy_pd_count);
unassign_mem:
- adsp_unassign_memory_region(adsp);
+ qcom_pas_unassign_memory_region(pas);
free_rproc:
- device_init_wakeup(adsp->dev, false);
+ device_init_wakeup(pas->dev, false);
return ret;
}
-static void adsp_remove(struct platform_device *pdev)
+static void qcom_pas_remove(struct platform_device *pdev)
{
- struct qcom_adsp *adsp = platform_get_drvdata(pdev);
-
- rproc_del(adsp->rproc);
-
- qcom_q6v5_deinit(&adsp->q6v5);
- adsp_unassign_memory_region(adsp);
- qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
- qcom_remove_sysmon_subdev(adsp->sysmon);
- qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev);
- qcom_remove_pdm_subdev(adsp->rproc, &adsp->pdm_subdev);
- qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
- adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
- device_init_wakeup(adsp->dev, false);
+ struct qcom_pas *pas = platform_get_drvdata(pdev);
+
+ rproc_del(pas->rproc);
+
+ qcom_q6v5_deinit(&pas->q6v5);
+ qcom_pas_unassign_memory_region(pas);
+ qcom_remove_glink_subdev(pas->rproc, &pas->glink_subdev);
+ qcom_remove_sysmon_subdev(pas->sysmon);
+ qcom_remove_smd_subdev(pas->rproc, &pas->smd_subdev);
+ qcom_remove_pdm_subdev(pas->rproc, &pas->pdm_subdev);
+ qcom_remove_ssr_subdev(pas->rproc, &pas->ssr_subdev);
+ qcom_pas_pds_detach(pas, pas->proxy_pds, pas->proxy_pd_count);
+ device_init_wakeup(pas->dev, false);
}
-static const struct adsp_data adsp_resource_init = {
+static const struct qcom_pas_data adsp_resource_init = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
@@ -850,7 +845,7 @@ static const struct adsp_data adsp_resource_init = {
.ssctl_id = 0x14,
};
-static const struct adsp_data sa8775p_adsp_resource = {
+static const struct qcom_pas_data sa8775p_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mbn",
.pas_id = 1,
@@ -867,7 +862,7 @@ static const struct adsp_data sa8775p_adsp_resource = {
.ssctl_id = 0x14,
};
-static const struct adsp_data sdm845_adsp_resource_init = {
+static const struct qcom_pas_data sdm845_adsp_resource_init = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
@@ -878,7 +873,7 @@ static const struct adsp_data sdm845_adsp_resource_init = {
.ssctl_id = 0x14,
};
-static const struct adsp_data sm6350_adsp_resource = {
+static const struct qcom_pas_data sm6350_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
@@ -894,7 +889,7 @@ static const struct adsp_data sm6350_adsp_resource = {
.ssctl_id = 0x14,
};
-static const struct adsp_data sm6375_mpss_resource = {
+static const struct qcom_pas_data sm6375_mpss_resource = {
.crash_reason_smem = 421,
.firmware_name = "modem.mdt",
.pas_id = 4,
@@ -909,7 +904,7 @@ static const struct adsp_data sm6375_mpss_resource = {
.ssctl_id = 0x12,
};
-static const struct adsp_data sm8150_adsp_resource = {
+static const struct qcom_pas_data sm8150_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
@@ -924,7 +919,7 @@ static const struct adsp_data sm8150_adsp_resource = {
.ssctl_id = 0x14,
};
-static const struct adsp_data sm8250_adsp_resource = {
+static const struct qcom_pas_data sm8250_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
@@ -941,7 +936,7 @@ static const struct adsp_data sm8250_adsp_resource = {
.ssctl_id = 0x14,
};
-static const struct adsp_data sm8350_adsp_resource = {
+static const struct qcom_pas_data sm8350_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
@@ -957,7 +952,7 @@ static const struct adsp_data sm8350_adsp_resource = {
.ssctl_id = 0x14,
};
-static const struct adsp_data msm8996_adsp_resource = {
+static const struct qcom_pas_data msm8996_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
@@ -971,7 +966,7 @@ static const struct adsp_data msm8996_adsp_resource = {
.ssctl_id = 0x14,
};
-static const struct adsp_data cdsp_resource_init = {
+static const struct qcom_pas_data cdsp_resource_init = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
@@ -981,7 +976,7 @@ static const struct adsp_data cdsp_resource_init = {
.ssctl_id = 0x17,
};
-static const struct adsp_data sa8775p_cdsp0_resource = {
+static const struct qcom_pas_data sa8775p_cdsp0_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp0.mbn",
.pas_id = 18,
@@ -999,7 +994,7 @@ static const struct adsp_data sa8775p_cdsp0_resource = {
.ssctl_id = 0x17,
};
-static const struct adsp_data sa8775p_cdsp1_resource = {
+static const struct qcom_pas_data sa8775p_cdsp1_resource = {
.crash_reason_smem = 633,
.firmware_name = "cdsp1.mbn",
.pas_id = 30,
@@ -1017,7 +1012,7 @@ static const struct adsp_data sa8775p_cdsp1_resource = {
.ssctl_id = 0x20,
};
-static const struct adsp_data sdm845_cdsp_resource_init = {
+static const struct qcom_pas_data sdm845_cdsp_resource_init = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
@@ -1028,7 +1023,7 @@ static const struct adsp_data sdm845_cdsp_resource_init = {
.ssctl_id = 0x17,
};
-static const struct adsp_data sm6350_cdsp_resource = {
+static const struct qcom_pas_data sm6350_cdsp_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
@@ -1044,7 +1039,7 @@ static const struct adsp_data sm6350_cdsp_resource = {
.ssctl_id = 0x17,
};
-static const struct adsp_data sm8150_cdsp_resource = {
+static const struct qcom_pas_data sm8150_cdsp_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
@@ -1059,7 +1054,7 @@ static const struct adsp_data sm8150_cdsp_resource = {
.ssctl_id = 0x17,
};
-static const struct adsp_data sm8250_cdsp_resource = {
+static const struct qcom_pas_data sm8250_cdsp_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
@@ -1074,7 +1069,7 @@ static const struct adsp_data sm8250_cdsp_resource = {
.ssctl_id = 0x17,
};
-static const struct adsp_data sc8280xp_nsp0_resource = {
+static const struct qcom_pas_data sc8280xp_nsp0_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
@@ -1088,7 +1083,7 @@ static const struct adsp_data sc8280xp_nsp0_resource = {
.ssctl_id = 0x17,
};
-static const struct adsp_data sc8280xp_nsp1_resource = {
+static const struct qcom_pas_data sc8280xp_nsp1_resource = {
.crash_reason_smem = 633,
.firmware_name = "cdsp.mdt",
.pas_id = 30,
@@ -1102,7 +1097,7 @@ static const struct adsp_data sc8280xp_nsp1_resource = {
.ssctl_id = 0x20,
};
-static const struct adsp_data x1e80100_adsp_resource = {
+static const struct qcom_pas_data x1e80100_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.dtb_firmware_name = "adsp_dtb.mdt",
@@ -1122,7 +1117,7 @@ static const struct adsp_data x1e80100_adsp_resource = {
.ssctl_id = 0x14,
};
-static const struct adsp_data x1e80100_cdsp_resource = {
+static const struct qcom_pas_data x1e80100_cdsp_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.dtb_firmware_name = "cdsp_dtb.mdt",
@@ -1142,7 +1137,7 @@ static const struct adsp_data x1e80100_cdsp_resource = {
.ssctl_id = 0x17,
};
-static const struct adsp_data sm8350_cdsp_resource = {
+static const struct qcom_pas_data sm8350_cdsp_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
@@ -1159,7 +1154,7 @@ static const struct adsp_data sm8350_cdsp_resource = {
.ssctl_id = 0x17,
};
-static const struct adsp_data sa8775p_gpdsp0_resource = {
+static const struct qcom_pas_data sa8775p_gpdsp0_resource = {
.crash_reason_smem = 640,
.firmware_name = "gpdsp0.mbn",
.pas_id = 39,
@@ -1176,7 +1171,7 @@ static const struct adsp_data sa8775p_gpdsp0_resource = {
.ssctl_id = 0x21,
};
-static const struct adsp_data sa8775p_gpdsp1_resource = {
+static const struct qcom_pas_data sa8775p_gpdsp1_resource = {
.crash_reason_smem = 641,
.firmware_name = "gpdsp1.mbn",
.pas_id = 40,
@@ -1193,7 +1188,7 @@ static const struct adsp_data sa8775p_gpdsp1_resource = {
.ssctl_id = 0x22,
};
-static const struct adsp_data mpss_resource_init = {
+static const struct qcom_pas_data mpss_resource_init = {
.crash_reason_smem = 421,
.firmware_name = "modem.mdt",
.pas_id = 4,
@@ -1210,7 +1205,7 @@ static const struct adsp_data mpss_resource_init = {
.ssctl_id = 0x12,
};
-static const struct adsp_data sc8180x_mpss_resource = {
+static const struct qcom_pas_data sc8180x_mpss_resource = {
.crash_reason_smem = 421,
.firmware_name = "modem.mdt",
.pas_id = 4,
@@ -1225,7 +1220,7 @@ static const struct adsp_data sc8180x_mpss_resource = {
.ssctl_id = 0x12,
};
-static const struct adsp_data msm8996_slpi_resource_init = {
+static const struct qcom_pas_data msm8996_slpi_resource_init = {
.crash_reason_smem = 424,
.firmware_name = "slpi.mdt",
.pas_id = 12,
@@ -1239,7 +1234,7 @@ static const struct adsp_data msm8996_slpi_resource_init = {
.ssctl_id = 0x16,
};
-static const struct adsp_data sdm845_slpi_resource_init = {
+static const struct qcom_pas_data sdm845_slpi_resource_init = {
.crash_reason_smem = 424,
.firmware_name = "slpi.mdt",
.pas_id = 12,
@@ -1255,7 +1250,7 @@ static const struct adsp_data sdm845_slpi_resource_init = {
.ssctl_id = 0x16,
};
-static const struct adsp_data wcss_resource_init = {
+static const struct qcom_pas_data wcss_resource_init = {
.crash_reason_smem = 421,
.firmware_name = "wcnss.mdt",
.pas_id = 6,
@@ -1265,7 +1260,7 @@ static const struct adsp_data wcss_resource_init = {
.ssctl_id = 0x12,
};
-static const struct adsp_data sdx55_mpss_resource = {
+static const struct qcom_pas_data sdx55_mpss_resource = {
.crash_reason_smem = 421,
.firmware_name = "modem.mdt",
.pas_id = 4,
@@ -1280,7 +1275,7 @@ static const struct adsp_data sdx55_mpss_resource = {
.ssctl_id = 0x22,
};
-static const struct adsp_data sm8450_mpss_resource = {
+static const struct qcom_pas_data sm8450_mpss_resource = {
.crash_reason_smem = 421,
.firmware_name = "modem.mdt",
.pas_id = 4,
@@ -1298,7 +1293,7 @@ static const struct adsp_data sm8450_mpss_resource = {
.ssctl_id = 0x12,
};
-static const struct adsp_data sm8550_adsp_resource = {
+static const struct qcom_pas_data sm8550_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.dtb_firmware_name = "adsp_dtb.mdt",
@@ -1318,7 +1313,7 @@ static const struct adsp_data sm8550_adsp_resource = {
.smem_host_id = 2,
};
-static const struct adsp_data sm8550_cdsp_resource = {
+static const struct qcom_pas_data sm8550_cdsp_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.dtb_firmware_name = "cdsp_dtb.mdt",
@@ -1339,7 +1334,7 @@ static const struct adsp_data sm8550_cdsp_resource = {
.smem_host_id = 5,
};
-static const struct adsp_data sm8550_mpss_resource = {
+static const struct qcom_pas_data sm8550_mpss_resource = {
.crash_reason_smem = 421,
.firmware_name = "modem.mdt",
.dtb_firmware_name = "modem_dtb.mdt",
@@ -1363,7 +1358,7 @@ static const struct adsp_data sm8550_mpss_resource = {
.region_assign_vmid = QCOM_SCM_VMID_MSS_MSA,
};
-static const struct adsp_data sc7280_wpss_resource = {
+static const struct qcom_pas_data sc7280_wpss_resource = {
.crash_reason_smem = 626,
.firmware_name = "wpss.mdt",
.pas_id = 6,
@@ -1380,7 +1375,7 @@ static const struct adsp_data sc7280_wpss_resource = {
.ssctl_id = 0x19,
};
-static const struct adsp_data sm8650_cdsp_resource = {
+static const struct qcom_pas_data sm8650_cdsp_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.dtb_firmware_name = "cdsp_dtb.mdt",
@@ -1405,7 +1400,7 @@ static const struct adsp_data sm8650_cdsp_resource = {
.region_assign_vmid = QCOM_SCM_VMID_CDSP,
};
-static const struct adsp_data sm8650_mpss_resource = {
+static const struct qcom_pas_data sm8650_mpss_resource = {
.crash_reason_smem = 421,
.firmware_name = "modem.mdt",
.dtb_firmware_name = "modem_dtb.mdt",
@@ -1429,7 +1424,7 @@ static const struct adsp_data sm8650_mpss_resource = {
.region_assign_vmid = QCOM_SCM_VMID_MSS_MSA,
};
-static const struct of_device_id adsp_of_match[] = {
+static const struct of_device_id qcom_pas_of_match[] = {
{ .compatible = "qcom,msm8226-adsp-pil", .data = &msm8996_adsp_resource},
{ .compatible = "qcom,msm8953-adsp-pil", .data = &msm8996_adsp_resource},
{ .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init},
@@ -1498,17 +1493,17 @@ static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,x1e80100-cdsp-pas", .data = &x1e80100_cdsp_resource},
{ },
};
-MODULE_DEVICE_TABLE(of, adsp_of_match);
+MODULE_DEVICE_TABLE(of, qcom_pas_of_match);
-static struct platform_driver adsp_driver = {
- .probe = adsp_probe,
- .remove = adsp_remove,
+static struct platform_driver qcom_pas_driver = {
+ .probe = qcom_pas_probe,
+ .remove = qcom_pas_remove,
.driver = {
.name = "qcom_q6v5_pas",
- .of_match_table = adsp_of_match,
+ .of_match_table = qcom_pas_of_match,
},
};
-module_platform_driver(adsp_driver);
-MODULE_DESCRIPTION("Qualcomm Hexagon v5 Peripheral Authentication Service driver");
+module_platform_driver(qcom_pas_driver);
+MODULE_DESCRIPTION("Qualcomm Peripheral Authentication Service remoteproc driver");
MODULE_LICENSE("GPL v2");
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 134/869] remoteproc: qcom: pas: Shutdown lite ADSP DTB on X1E
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (132 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 133/869] remoteproc: qcom: pas: Conclude the rename from adsp Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 135/869] scsi: ufs: core: Fix data race in CPU latency PM QoS request handling Greg Kroah-Hartman
` (735 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dmitry Baryshkov, Stephan Gerhold,
Bjorn Andersson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <stephan.gerhold@linaro.org>
[ Upstream commit 142964960c7c35de5c5f7bdd61c32699de693630 ]
The ADSP firmware on X1E has separate firmware binaries for the main
firmware and the DTB. The same applies for the "lite" firmware loaded by
the boot firmware.
When preparing to load the new ADSP firmware we shutdown the lite_pas_id
for the main firmware, but we don't shutdown the corresponding lite pas_id
for the DTB. The fact that we're leaving it "running" forever becomes
obvious if you try to reuse (or just access) the memory region used by the
"lite" firmware: The &adsp_boot_mem is accessible, but accessing the
&adsp_boot_dtb_mem results in a crash.
We don't support reusing the memory regions currently, but nevertheless we
should not keep part of the lite firmware running. Fix this by adding the
lite_dtb_pas_id and shutting it down as well.
We don't have a way to detect if the lite firmware is actually running yet,
so ignore the return status of qcom_scm_pas_shutdown() for now. This was
already the case before, the assignment to "ret" is not used anywhere.
Fixes: 62210f7509e1 ("remoteproc: qcom_q6v5_pas: Unload lite firmware on ADSP")
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Stephan Gerhold <stephan.gerhold@linaro.org>
Link: https://lore.kernel.org/r/20250820-rproc-qcom-q6v5-fixes-v2-3-910b1a3aff71@linaro.org
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/remoteproc/qcom_q6v5_pas.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index 001ac642c63b1..bf4f242f1995e 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -42,6 +42,7 @@ struct qcom_pas_data {
int pas_id;
int dtb_pas_id;
int lite_pas_id;
+ int lite_dtb_pas_id;
unsigned int minidump_id;
bool auto_boot;
bool decrypt_shutdown;
@@ -80,6 +81,7 @@ struct qcom_pas {
int pas_id;
int dtb_pas_id;
int lite_pas_id;
+ int lite_dtb_pas_id;
unsigned int minidump_id;
int crash_reason_smem;
unsigned int smem_host_id;
@@ -226,6 +228,8 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw)
if (pas->lite_pas_id)
ret = qcom_scm_pas_shutdown(pas->lite_pas_id);
+ if (pas->lite_dtb_pas_id)
+ qcom_scm_pas_shutdown(pas->lite_dtb_pas_id);
if (pas->dtb_pas_id) {
ret = request_firmware(&pas->dtb_firmware, pas->dtb_firmware_name, pas->dev);
@@ -720,6 +724,7 @@ static int qcom_pas_probe(struct platform_device *pdev)
pas->minidump_id = desc->minidump_id;
pas->pas_id = desc->pas_id;
pas->lite_pas_id = desc->lite_pas_id;
+ pas->lite_dtb_pas_id = desc->lite_dtb_pas_id;
pas->info_name = desc->sysmon_name;
pas->smem_host_id = desc->smem_host_id;
pas->decrypt_shutdown = desc->decrypt_shutdown;
@@ -1104,6 +1109,7 @@ static const struct qcom_pas_data x1e80100_adsp_resource = {
.pas_id = 1,
.dtb_pas_id = 0x24,
.lite_pas_id = 0x1f,
+ .lite_dtb_pas_id = 0x29,
.minidump_id = 5,
.auto_boot = true,
.proxy_pd_names = (char*[]){
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 135/869] scsi: ufs: core: Fix data race in CPU latency PM QoS request handling
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (133 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 134/869] remoteproc: qcom: pas: Shutdown lite ADSP DTB on X1E Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 136/869] crypto: hisilicon/hpre - enable all clusters clock gating Greg Kroah-Hartman
` (734 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Zhongqiu Han, Bart Van Assche,
Huan Tang, Martin K. Petersen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
[ Upstream commit 79dde5f7dc7c038eec903745dc1550cd4139980e ]
The cpu_latency_qos_add/remove/update_request interfaces lack internal
synchronization by design, requiring the caller to ensure thread safety.
The current implementation relies on the 'pm_qos_enabled' flag, which is
insufficient to prevent concurrent access and cannot serve as a proper
synchronization mechanism. This has led to data races and list
corruption issues.
A typical race condition call trace is:
[Thread A]
ufshcd_pm_qos_exit()
--> cpu_latency_qos_remove_request()
--> cpu_latency_qos_apply();
--> pm_qos_update_target()
--> plist_del <--(1) delete plist node
--> memset(req, 0, sizeof(*req));
--> hba->pm_qos_enabled = false;
[Thread B]
ufshcd_devfreq_target
--> ufshcd_devfreq_scale
--> ufshcd_scale_clks
--> ufshcd_pm_qos_update <--(2) pm_qos_enabled is true
--> cpu_latency_qos_update_request
--> pm_qos_update_target
--> plist_del <--(3) plist node use-after-free
Introduces a dedicated mutex to serialize PM QoS operations, preventing
data races and ensuring safe access to PM QoS resources, including sysfs
interface reads.
Fixes: 2777e73fc154 ("scsi: ufs: core: Add CPU latency QoS support for UFS driver")
Signed-off-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Tested-by: Huan Tang <tanghuan@vivo.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ufs/core/ufs-sysfs.c | 2 ++
drivers/ufs/core/ufshcd.c | 9 +++++++++
include/ufs/ufshcd.h | 3 +++
3 files changed, 14 insertions(+)
diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c
index f8397ef3cf8df..5d4f23bb6ab10 100644
--- a/drivers/ufs/core/ufs-sysfs.c
+++ b/drivers/ufs/core/ufs-sysfs.c
@@ -426,6 +426,8 @@ static ssize_t pm_qos_enable_show(struct device *dev,
{
struct ufs_hba *hba = dev_get_drvdata(dev);
+ guard(mutex)(&hba->pm_qos_mutex);
+
return sysfs_emit(buf, "%d\n", hba->pm_qos_enabled);
}
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 9c2f407da28a1..44c84090496d6 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -1023,6 +1023,7 @@ EXPORT_SYMBOL_GPL(ufshcd_is_hba_active);
*/
void ufshcd_pm_qos_init(struct ufs_hba *hba)
{
+ guard(mutex)(&hba->pm_qos_mutex);
if (hba->pm_qos_enabled)
return;
@@ -1039,6 +1040,8 @@ void ufshcd_pm_qos_init(struct ufs_hba *hba)
*/
void ufshcd_pm_qos_exit(struct ufs_hba *hba)
{
+ guard(mutex)(&hba->pm_qos_mutex);
+
if (!hba->pm_qos_enabled)
return;
@@ -1053,6 +1056,8 @@ void ufshcd_pm_qos_exit(struct ufs_hba *hba)
*/
static void ufshcd_pm_qos_update(struct ufs_hba *hba, bool on)
{
+ guard(mutex)(&hba->pm_qos_mutex);
+
if (!hba->pm_qos_enabled)
return;
@@ -10545,6 +10550,9 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
*/
spin_lock_init(&hba->clk_gating.lock);
+ /* Initialize mutex for PM QoS request synchronization */
+ mutex_init(&hba->pm_qos_mutex);
+
/*
* Set the default power management level for runtime and system PM.
* Host controller drivers can override them in their
@@ -10630,6 +10638,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
mutex_init(&hba->ee_ctrl_mutex);
mutex_init(&hba->wb_mutex);
+
init_rwsem(&hba->clk_scaling_lock);
ufshcd_init_clk_gating(hba);
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index e68ce42eaff4d..175ce70758bbc 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -968,6 +968,7 @@ enum ufshcd_mcq_opr {
* @ufs_rtc_update_work: A work for UFS RTC periodic update
* @pm_qos_req: PM QoS request handle
* @pm_qos_enabled: flag to check if pm qos is enabled
+ * @pm_qos_mutex: synchronizes PM QoS request and status updates
*/
struct ufs_hba {
void __iomem *mmio_base;
@@ -1138,6 +1139,8 @@ struct ufs_hba {
struct delayed_work ufs_rtc_update_work;
struct pm_qos_request pm_qos_req;
bool pm_qos_enabled;
+ /* synchronizes PM QoS request and status updates */
+ struct mutex pm_qos_mutex;
};
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 136/869] crypto: hisilicon/hpre - enable all clusters clock gating
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (134 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 135/869] scsi: ufs: core: Fix data race in CPU latency PM QoS request handling Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 137/869] crypto: hisilicon/qm - request reserved interrupt for virtual function Greg Kroah-Hartman
` (733 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Weili Qian, Herbert Xu, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weili Qian <qianweili@huawei.com>
[ Upstream commit c62db61a416ff832481bccdfdee146f5272864b3 ]
Currently, the driver enables clock gating for only one cluster.
However, the new hardware has three clusters. Therefore, clock
gating needs to be enabled based on the number of clusters on the
current hardware.
Signed-off-by: Weili Qian <qianweili@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Stable-dep-of: 9228facb3081 ("crypto: hisilicon/qm - request reserved interrupt for virtual function")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/crypto/hisilicon/hpre/hpre_main.c | 40 +++++++++++++++--------
1 file changed, 26 insertions(+), 14 deletions(-)
diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c
index a11fe5e276773..6eeaa00e07b25 100644
--- a/drivers/crypto/hisilicon/hpre/hpre_main.c
+++ b/drivers/crypto/hisilicon/hpre/hpre_main.c
@@ -593,6 +593,8 @@ static void hpre_close_sva_prefetch(struct hisi_qm *qm)
static void hpre_enable_clock_gate(struct hisi_qm *qm)
{
+ unsigned long offset;
+ u8 clusters_num, i;
u32 val;
if (qm->ver < QM_HW_V3)
@@ -606,17 +608,23 @@ static void hpre_enable_clock_gate(struct hisi_qm *qm)
val |= HPRE_PEH_CFG_AUTO_GATE_EN;
writel(val, qm->io_base + HPRE_PEH_CFG_AUTO_GATE);
- val = readl(qm->io_base + HPRE_CLUSTER_DYN_CTL);
- val |= HPRE_CLUSTER_DYN_CTL_EN;
- writel(val, qm->io_base + HPRE_CLUSTER_DYN_CTL);
-
- val = readl_relaxed(qm->io_base + HPRE_CORE_SHB_CFG);
- val |= HPRE_CORE_GATE_EN;
- writel(val, qm->io_base + HPRE_CORE_SHB_CFG);
+ clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val;
+ for (i = 0; i < clusters_num; i++) {
+ offset = (unsigned long)i * HPRE_CLSTR_ADDR_INTRVL;
+ val = readl(qm->io_base + offset + HPRE_CLUSTER_DYN_CTL);
+ val |= HPRE_CLUSTER_DYN_CTL_EN;
+ writel(val, qm->io_base + offset + HPRE_CLUSTER_DYN_CTL);
+
+ val = readl(qm->io_base + offset + HPRE_CORE_SHB_CFG);
+ val |= HPRE_CORE_GATE_EN;
+ writel(val, qm->io_base + offset + HPRE_CORE_SHB_CFG);
+ }
}
static void hpre_disable_clock_gate(struct hisi_qm *qm)
{
+ unsigned long offset;
+ u8 clusters_num, i;
u32 val;
if (qm->ver < QM_HW_V3)
@@ -630,13 +638,17 @@ static void hpre_disable_clock_gate(struct hisi_qm *qm)
val &= ~HPRE_PEH_CFG_AUTO_GATE_EN;
writel(val, qm->io_base + HPRE_PEH_CFG_AUTO_GATE);
- val = readl(qm->io_base + HPRE_CLUSTER_DYN_CTL);
- val &= ~HPRE_CLUSTER_DYN_CTL_EN;
- writel(val, qm->io_base + HPRE_CLUSTER_DYN_CTL);
-
- val = readl_relaxed(qm->io_base + HPRE_CORE_SHB_CFG);
- val &= ~HPRE_CORE_GATE_EN;
- writel(val, qm->io_base + HPRE_CORE_SHB_CFG);
+ clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val;
+ for (i = 0; i < clusters_num; i++) {
+ offset = (unsigned long)i * HPRE_CLSTR_ADDR_INTRVL;
+ val = readl(qm->io_base + offset + HPRE_CLUSTER_DYN_CTL);
+ val &= ~HPRE_CLUSTER_DYN_CTL_EN;
+ writel(val, qm->io_base + offset + HPRE_CLUSTER_DYN_CTL);
+
+ val = readl(qm->io_base + offset + HPRE_CORE_SHB_CFG);
+ val &= ~HPRE_CORE_GATE_EN;
+ writel(val, qm->io_base + offset + HPRE_CORE_SHB_CFG);
+ }
}
static int hpre_set_user_domain_and_cache(struct hisi_qm *qm)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 137/869] crypto: hisilicon/qm - request reserved interrupt for virtual function
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (135 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 136/869] crypto: hisilicon/hpre - enable all clusters clock gating Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 138/869] ASoC: Intel: avs: Use topology information for endpoint numbers Greg Kroah-Hartman
` (732 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Weili Qian, Chenghai Huang,
Herbert Xu, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weili Qian <qianweili@huawei.com>
[ Upstream commit 9228facb308157ac0bdd264b873187896f7a9c7a ]
The device interrupt vector 3 is an error interrupt for
physical function and a reserved interrupt for virtual function.
However, the driver has not registered the reserved interrupt for
virtual function. When allocating interrupts, the number of interrupts
is allocated based on powers of two, which includes this interrupt.
When the system enables GICv4 and the virtual function passthrough
to the virtual machine, releasing the interrupt in the driver
triggers a warning.
The WARNING report is:
WARNING: CPU: 62 PID: 14889 at arch/arm64/kvm/vgic/vgic-its.c:852 its_free_ite+0x94/0xb4
Therefore, register a reserved interrupt for VF and set the
IRQF_NO_AUTOEN flag to avoid that warning.
Fixes: 3536cc55cada ("crypto: hisilicon/qm - support get device irq information from hardware registers")
Signed-off-by: Weili Qian <qianweili@huawei.com>
Signed-off-by: Chenghai Huang <huangchenghai2@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/crypto/hisilicon/qm.c | 38 +++++++++++++++++++++++++++++------
1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c
index 38c9d633db5f4..32882cc9b18e3 100644
--- a/drivers/crypto/hisilicon/qm.c
+++ b/drivers/crypto/hisilicon/qm.c
@@ -4603,6 +4603,15 @@ void hisi_qm_reset_done(struct pci_dev *pdev)
}
EXPORT_SYMBOL_GPL(hisi_qm_reset_done);
+static irqreturn_t qm_rsvd_irq(int irq, void *data)
+{
+ struct hisi_qm *qm = data;
+
+ dev_info(&qm->pdev->dev, "Reserved interrupt, ignore!\n");
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t qm_abnormal_irq(int irq, void *data)
{
struct hisi_qm *qm = data;
@@ -4887,7 +4896,7 @@ static void qm_unregister_abnormal_irq(struct hisi_qm *qm)
struct pci_dev *pdev = qm->pdev;
u32 irq_vector, val;
- if (qm->fun_type == QM_HW_VF)
+ if (qm->fun_type == QM_HW_VF && qm->ver < QM_HW_V3)
return;
val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val;
@@ -4904,17 +4913,28 @@ static int qm_register_abnormal_irq(struct hisi_qm *qm)
u32 irq_vector, val;
int ret;
- if (qm->fun_type == QM_HW_VF)
- return 0;
-
val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val;
if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK))
return 0;
-
irq_vector = val & QM_IRQ_VECTOR_MASK;
+
+ /* For VF, this is a reserved interrupt in V3 version. */
+ if (qm->fun_type == QM_HW_VF) {
+ if (qm->ver < QM_HW_V3)
+ return 0;
+
+ ret = request_irq(pci_irq_vector(pdev, irq_vector), qm_rsvd_irq,
+ IRQF_NO_AUTOEN, qm->dev_name, qm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request reserved irq, ret = %d!\n", ret);
+ return ret;
+ }
+ return 0;
+ }
+
ret = request_irq(pci_irq_vector(pdev, irq_vector), qm_abnormal_irq, 0, qm->dev_name, qm);
if (ret)
- dev_err(&qm->pdev->dev, "failed to request abnormal irq, ret = %d", ret);
+ dev_err(&qm->pdev->dev, "failed to request abnormal irq, ret = %d!\n", ret);
return ret;
}
@@ -5253,6 +5273,12 @@ static int hisi_qm_pci_init(struct hisi_qm *qm)
pci_set_master(pdev);
num_vec = qm_get_irq_num(qm);
+ if (!num_vec) {
+ dev_err(dev, "Device irq num is zero!\n");
+ ret = -EINVAL;
+ goto err_get_pci_res;
+ }
+ num_vec = roundup_pow_of_two(num_vec);
ret = pci_alloc_irq_vectors(pdev, num_vec, num_vec, PCI_IRQ_MSI);
if (ret < 0) {
dev_err(dev, "Failed to enable MSI vectors!\n");
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 138/869] ASoC: Intel: avs: Use topology information for endpoint numbers
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (136 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 137/869] crypto: hisilicon/qm - request reserved interrupt for virtual function Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 139/869] ASoC: Intel: avs: Do not share the name pointer between components Greg Kroah-Hartman
` (731 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Amadeusz Sławiński,
Jaroslav Kysela, Cezary Rojewski, Mark Brown, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
[ Upstream commit e3dc0351d7a0fdcde18ed1719c9149b1a656e7ec ]
Use DAI PCM ID from topology as Front End device endpoint number. This
allows devices to be more naturally enumerated starting from 0, like
most cards, instead of values like 1 or 2.
Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Acked-by: Jaroslav Kysela <perex@perex.cz>
Link: https://patch.msgid.link/20250407124154.1713039-3-amadeuszx.slawinski@linux.intel.com
Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Keep the compatibility parameter local to PCM registration, defaulting
to topology endpoint numbers. The card-name compatibility option and
machine-data conversion are not present, so omit those prerequisites
and describe the parameter in terms of PCM device numbering.
Retain the registration changes needed for the component-name lifetime
fix to apply without conflicts.
Stable-dep-of: 4dee5c1cc439 ("ASoC: Intel: avs: Do not share the name pointer between components")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/soc/intel/avs/avs.h | 2 +-
sound/soc/intel/avs/pcm.c | 13 ++++++++++---
sound/soc/intel/avs/probes.c | 2 +-
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index eca6ec0428bbb..bd63676aa7aa5 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -339,7 +339,7 @@ struct avs_soc_component {
extern const struct snd_soc_dai_ops avs_dai_fe_ops;
int avs_soc_component_register(struct device *dev, const char *name,
- const struct snd_soc_component_driver *drv,
+ struct snd_soc_component_driver *drv,
struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais);
int avs_dmic_platform_register(struct avs_dev *adev, const char *name);
int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index b63a537c3faeb..8889fa7ddd908 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -9,6 +9,7 @@
#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/device.h>
+#include <linux/module.h>
#include <sound/hda_register.h>
#include <sound/hdaudio_ext.h>
#include <sound/pcm_params.h>
@@ -21,6 +22,10 @@
#include "topology.h"
#include "../../codecs/hda.h"
+static bool obsolete_card_names;
+module_param_named(obsolete_card_names, obsolete_card_names, bool, 0444);
+MODULE_PARM_DESC(obsolete_card_names, "Use obsolete PCM device numbering 0=no, 1=yes");
+
struct avs_dma_data {
struct avs_tplg_path_template *template;
struct avs_path *path;
@@ -1274,7 +1279,7 @@ static int avs_component_construct(struct snd_soc_component *component,
return 0;
}
-static const struct snd_soc_component_driver avs_component_driver = {
+static struct snd_soc_component_driver avs_component_driver = {
.name = "avs-pcm",
.probe = avs_component_probe,
.remove = avs_component_remove,
@@ -1289,7 +1294,7 @@ static const struct snd_soc_component_driver avs_component_driver = {
};
int avs_soc_component_register(struct device *dev, const char *name,
- const struct snd_soc_component_driver *drv,
+ struct snd_soc_component_driver *drv,
struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
{
struct avs_soc_component *acomp;
@@ -1307,6 +1312,8 @@ int avs_soc_component_register(struct device *dev, const char *name,
acomp->base.name = name;
INIT_LIST_HEAD(&acomp->node);
+ drv->use_dai_pcm_id = !obsolete_card_names;
+
return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais);
}
@@ -1630,7 +1637,7 @@ static int avs_component_hda_open(struct snd_soc_component *component,
return 0;
}
-static const struct snd_soc_component_driver avs_hda_component_driver = {
+static struct snd_soc_component_driver avs_hda_component_driver = {
.name = "avs-hda-pcm",
.probe = avs_component_hda_probe,
.remove = avs_component_hda_remove,
diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c
index f0b0109563038..a42736b9aa55b 100644
--- a/sound/soc/intel/avs/probes.c
+++ b/sound/soc/intel/avs/probes.c
@@ -284,7 +284,7 @@ static struct snd_soc_dai_driver probe_cpu_dais[] = {
},
};
-static const struct snd_soc_component_driver avs_probe_component_driver = {
+static struct snd_soc_component_driver avs_probe_component_driver = {
.name = "avs-probe-compr",
.compress_ops = &avs_probe_compress_ops,
.module_get_upon_open = 1, /* increment refcount when a stream is opened */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 139/869] ASoC: Intel: avs: Do not share the name pointer between components
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (137 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 138/869] ASoC: Intel: avs: Use topology information for endpoint numbers Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 140/869] sysfs: check visibility before changing group attribute ownership Greg Kroah-Hartman
` (730 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Amadeusz Sławiński,
Cezary Rojewski, Mark Brown, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cezary Rojewski <cezary.rojewski@intel.com>
[ Upstream commit 4dee5c1cc439b0d5ef87f741518268ad6a95b23d ]
By sharing 'name' directly, tearing down components may lead to
use-after-free errors. Duplicate the name to avoid that.
At the same time, update the order of operations - since commit
cee28113db17 ("ASoC: dmaengine_pcm: Allow passing component name via
config") the framework does not override component->name if set before
invoking the initializer.
Reviewed-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
Link: https://patch.msgid.link/20250818104126.526442-4-cezary.rojewski@intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/soc/intel/avs/pcm.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 8889fa7ddd908..81fe4f0218c1a 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -1304,16 +1304,18 @@ int avs_soc_component_register(struct device *dev, const char *name,
if (!acomp)
return -ENOMEM;
- ret = snd_soc_component_initialize(&acomp->base, drv, dev);
- if (ret < 0)
- return ret;
+ acomp->base.name = devm_kstrdup(dev, name, GFP_KERNEL);
+ if (!acomp->base.name)
+ return -ENOMEM;
- /* force name change after ASoC is done with its init */
- acomp->base.name = name;
INIT_LIST_HEAD(&acomp->node);
drv->use_dai_pcm_id = !obsolete_card_names;
+ ret = snd_soc_component_initialize(&acomp->base, drv, dev);
+ if (ret < 0)
+ return ret;
+
return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 140/869] sysfs: check visibility before changing group attribute ownership
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (138 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 139/869] ASoC: Intel: avs: Do not share the name pointer between components Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 141/869] amd/amdkfd: enhance kfd process check in switch partition Greg Kroah-Hartman
` (729 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Cynthia, Fernando Fernandez Mancera,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <fmancera@suse.de>
[ Upstream commit c7fbb8218b4ad35fec0bd2256d2b9c8d60331f33 ]
Since commit 0c17270f9b92 ("net: sysfs: Implement is_visible for
phys_(port_id, port_name, switch_id)"), __dev_change_net_namespace() can
hit WARN_ON() when trying to change owner of a file that isn't visible.
See the trace below:
WARNING: CPU: 6 PID: 2938 at net/core/dev.c:12410 __dev_change_net_namespace+0xb89/0xc30
CPU: 6 UID: 0 PID: 2938 Comm: incusd Not tainted 6.17.1-1-mainline #1 PREEMPT(full) 4b783b4a638669fb644857f484487d17cb45ed1f
Hardware name: Framework Laptop 13 (AMD Ryzen 7040Series)/FRANMDCP07, BIOS 03.07 02/19/2025
RIP: 0010:__dev_change_net_namespace+0xb89/0xc30
[...]
Call Trace:
<TASK>
? if6_seq_show+0x30/0x50
do_setlink.isra.0+0xc7/0x1270
? __nla_validate_parse+0x5c/0xcc0
? security_capable+0x94/0x1a0
rtnl_newlink+0x858/0xc20
? update_curr+0x8e/0x1c0
? update_entity_lag+0x71/0x80
? sched_balance_newidle+0x358/0x450
? psi_task_switch+0x113/0x2a0
? __pfx_rtnl_newlink+0x10/0x10
rtnetlink_rcv_msg+0x346/0x3e0
? sched_clock+0x10/0x30
? __pfx_rtnetlink_rcv_msg+0x10/0x10
netlink_rcv_skb+0x59/0x110
netlink_unicast+0x285/0x3c0
? __alloc_skb+0xdb/0x1a0
netlink_sendmsg+0x20d/0x430
____sys_sendmsg+0x39f/0x3d0
? import_iovec+0x2f/0x40
___sys_sendmsg+0x99/0xe0
__sys_sendmsg+0x8a/0xf0
do_syscall_64+0x81/0x970
? __sys_bind+0xe3/0x110
? syscall_exit_work+0x143/0x1b0
? do_syscall_64+0x244/0x970
? sock_alloc_file+0x63/0xc0
? syscall_exit_work+0x143/0x1b0
? do_syscall_64+0x244/0x970
? alloc_fd+0x12e/0x190
? put_unused_fd+0x2a/0x70
? do_sys_openat2+0xa2/0xe0
? syscall_exit_work+0x143/0x1b0
? do_syscall_64+0x244/0x970
? exc_page_fault+0x7e/0x1a0
entry_SYSCALL_64_after_hwframe+0x76/0x7e
[...]
</TASK>
Fix this by checking is_visible() before trying to touch the attribute.
Fixes: 303a42769c4c ("sysfs: add sysfs_group{s}_change_owner()")
Fixes: 0c17270f9b92 ("net: sysfs: Implement is_visible for phys_(port_id, port_name, switch_id)")
Reported-by: Cynthia <cynthia@kosmx.dev>
Closes: https://lore.kernel.org/netdev/01070199e22de7f8-28f711ab-d3f1-46d9-b9a0-048ab05eb09b-000000@eu-central-1.amazonses.com/
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Reviewed-by: Jakub Kicinski <kuba@kernel.org>
Link: https://lore.kernel.org/r/20251016101456.4087-1-fmancera@suse.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/sysfs/group.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index f2b7283e6fa0a..e1b6c38285f7a 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -495,17 +495,26 @@ int compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj,
}
EXPORT_SYMBOL_GPL(compat_only_sysfs_link_entry_to_kobj);
-static int sysfs_group_attrs_change_owner(struct kernfs_node *grp_kn,
+static int sysfs_group_attrs_change_owner(struct kobject *kobj,
+ struct kernfs_node *grp_kn,
const struct attribute_group *grp,
struct iattr *newattrs)
{
struct kernfs_node *kn;
- int error;
+ int error, i;
+ umode_t mode;
if (grp->attrs) {
struct attribute *const *attr;
- for (attr = grp->attrs; *attr; attr++) {
+ for (i = 0, attr = grp->attrs; *attr; i++, attr++) {
+ if (grp->is_visible) {
+ mode = grp->is_visible(kobj, *attr, i);
+ if (mode & SYSFS_GROUP_INVISIBLE)
+ break;
+ if (!mode)
+ continue;
+ }
kn = kernfs_find_and_get(grp_kn, (*attr)->name);
if (!kn)
return -ENOENT;
@@ -520,7 +529,14 @@ static int sysfs_group_attrs_change_owner(struct kernfs_node *grp_kn,
if (grp->bin_attrs) {
struct bin_attribute *const *bin_attr;
- for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
+ for (i = 0, bin_attr = grp->bin_attrs; *bin_attr; i++, bin_attr++) {
+ if (grp->is_bin_visible) {
+ mode = grp->is_bin_visible(kobj, *bin_attr, i);
+ if (mode & SYSFS_GROUP_INVISIBLE)
+ break;
+ if (!mode)
+ continue;
+ }
kn = kernfs_find_and_get(grp_kn, (*bin_attr)->attr.name);
if (!kn)
return -ENOENT;
@@ -570,7 +586,7 @@ int sysfs_group_change_owner(struct kobject *kobj,
error = kernfs_setattr(grp_kn, &newattrs);
if (!error)
- error = sysfs_group_attrs_change_owner(grp_kn, grp, &newattrs);
+ error = sysfs_group_attrs_change_owner(kobj, grp_kn, grp, &newattrs);
kernfs_put(grp_kn);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 141/869] amd/amdkfd: enhance kfd process check in switch partition
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (139 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 140/869] sysfs: check visibility before changing group attribute ownership Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 142/869] drm/xe/guc: Add devm release action to safely tear down CT Greg Kroah-Hartman
` (728 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yifan Zhang, Philip.Yang,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yifan Zhang <yifan1.zhang@amd.com>
[ Upstream commit 45da20e00d5da842e17dfc633072b127504f0d0e ]
current switch partition only check if kfd_processes_table is empty.
kfd_prcesses_table entry is deleted in kfd_process_notifier_release, but
kfd_process tear down is in kfd_process_wq_release.
consider two processes:
Process A (workqueue) -> kfd_process_wq_release -> Access kfd_node member
Process B switch partition -> amdgpu_xcp_pre_partition_switch -> amdgpu_amdkfd_device_fini_sw
-> kfd_node tear down.
Process A and B may trigger a race as shown in dmesg log.
This patch is to resolve the race by adding an atomic kfd_process counter
kfd_processes_count, it increment as create kfd process, decrement as
finish kfd_process_wq_release.
v2: Put kfd_processes_count per kfd_dev, move decrement to kfd_process_destroy_pdds
and bug fix. (Philip Yang)
[3966658.307702] divide error: 0000 [#1] SMP NOPTI
[3966658.350818] i10nm_edac
[3966658.356318] CPU: 124 PID: 38435 Comm: kworker/124:0 Kdump: loaded Tainted
[3966658.356890] Workqueue: kfd_process_wq kfd_process_wq_release [amdgpu]
[3966658.362839] nfit
[3966658.366457] RIP: 0010:kfd_get_num_sdma_engines+0x17/0x40 [amdgpu]
[3966658.366460] Code: 00 00 e9 ac 81 02 00 66 66 2e 0f 1f 84 00 00 00 00 00 90 0f 1f 44 00 00 48 8b 4f 08 48 8b b7 00 01 00 00 8b 81 58 26 03 00 99 <f7> be b8 01 00 00 80 b9 70 2e 00 00 00 74 0b 83 f8 02 ba 02 00 00
[3966658.380967] x86_pkg_temp_thermal
[3966658.391529] RSP: 0018:ffffc900a0edfdd8 EFLAGS: 00010246
[3966658.391531] RAX: 0000000000000008 RBX: ffff8974e593b800 RCX: ffff888645900000
[3966658.391531] RDX: 0000000000000000 RSI: ffff888129154400 RDI: ffff888129151c00
[3966658.391532] RBP: ffff8883ad79d400 R08: 0000000000000000 R09: ffff8890d2750af4
[3966658.391532] R10: 0000000000000018 R11: 0000000000000018 R12: 0000000000000000
[3966658.391533] R13: ffff8883ad79d400 R14: ffffe87ff662ba00 R15: ffff8974e593b800
[3966658.391533] FS: 0000000000000000(0000) GS:ffff88fe7f600000(0000) knlGS:0000000000000000
[3966658.391534] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[3966658.391534] CR2: 0000000000d71000 CR3: 000000dd0e970004 CR4: 0000000002770ee0
[3966658.391535] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[3966658.391535] DR3: 0000000000000000 DR6: 00000000fffe07f0 DR7: 0000000000000400
[3966658.391536] PKRU: 55555554
[3966658.391536] Call Trace:
[3966658.391674] deallocate_sdma_queue+0x38/0xa0 [amdgpu]
[3966658.391762] process_termination_cpsch+0x1ed/0x480 [amdgpu]
[3966658.399754] intel_powerclamp
[3966658.402831] kfd_process_dequeue_from_all_devices+0x5b/0xc0 [amdgpu]
[3966658.402908] kfd_process_wq_release+0x1a/0x1a0 [amdgpu]
[3966658.410516] coretemp
[3966658.434016] process_one_work+0x1ad/0x380
[3966658.434021] worker_thread+0x49/0x310
[3966658.438963] kvm_intel
[3966658.446041] ? process_one_work+0x380/0x380
[3966658.446045] kthread+0x118/0x140
[3966658.446047] ? __kthread_bind_mask+0x60/0x60
[3966658.446050] ret_from_fork+0x1f/0x30
[3966658.446053] Modules linked in: kpatch_20765354(OEK)
[3966658.455310] kvm
[3966658.464534] mptcp_diag xsk_diag raw_diag unix_diag af_packet_diag netlink_diag udp_diag act_pedit act_mirred act_vlan cls_flower kpatch_21951273(OEK) kpatch_18424469(OEK) kpatch_19749756(OEK)
[3966658.473462] idxd_mdev
[3966658.482306] kpatch_17971294(OEK) sch_ingress xt_conntrack amdgpu(OE) amdxcp(OE) amddrm_buddy(OE) amd_sched(OE) amdttm(OE) amdkcl(OE) intel_ifs iptable_mangle tcm_loop target_core_pscsi tcp_diag target_core_file inet_diag target_core_iblock target_core_user target_core_mod coldpgs kpatch_18383292(OEK) ip6table_nat ip6table_filter ip6_tables ip_set_hash_ipportip ip_set_hash_ipportnet ip_set_hash_ipport ip_set_bitmap_port xt_comment iptable_nat nf_nat iptable_filter ip_tables ip_set ip_vs_sh ip_vs_wrr ip_vs_rr ip_vs nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 sn_core_odd(OE) i40e overlay binfmt_misc tun bonding(OE) aisqos(OE) aisqos_hotfixes(OE) rfkill uio_pci_generic uio cuse fuse nf_tables nfnetlink intel_rapl_msr intel_rapl_common intel_uncore_frequency intel_uncore_frequency_common i10nm_edac nfit x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel kvm idxd_mdev
[3966658.491237] vfio_pci
[3966658.501196] vfio_pci vfio_virqfd mdev vfio_iommu_type1 vfio iax_crypto intel_pmt_telemetry iTCO_wdt intel_pmt_class iTCO_vendor_support irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel rapl intel_cstate snd_hda_intel snd_intel_dspcfg snd_hda_codec snd_hda_core snd_hwdep snd_seq
[3966658.508537] vfio_virqfd
[3966658.517569] snd_seq_device ipmi_ssif isst_if_mbox_pci isst_if_mmio pcspkr snd_pcm idxd intel_uncore ses isst_if_common intel_vsec idxd_bus enclosure snd_timer mei_me snd i2c_i801 i2c_smbus mei i2c_ismt soundcore joydev acpi_ipmi ipmi_si ipmi_devintf ipmi_msghandler acpi_power_meter acpi_pad vfat fat
[3966658.526851] mdev
[3966658.536096] nfsd auth_rpcgss nfs_acl lockd grace slb_vtoa(OE) sunrpc dm_mod hookers mlx5_ib(OE) ast i2c_algo_bit drm_vram_helper drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops drm_ttm_helper ttm mlx5_core(OE) mlxfw(OE)
[3966658.540381] vfio_iommu_type1
[3966658.544341] nvme mpt3sas tls drm nvme_core pci_hyperv_intf raid_class psample libcrc32c crc32c_intel mlxdevm(OE) i2c_core
[3966658.551254] vfio
[3966658.558742] scsi_transport_sas wmi pinctrl_emmitsburg sd_mod t10_pi sg ahci libahci libata rdma_ucm(OE) ib_uverbs(OE) rdma_cm(OE) iw_cm(OE) ib_cm(OE) ib_umad(OE) ib_core(OE) ib_ucm(OE) mlx_compat(OE)
[3966658.563004] iax_crypto
[3966658.570988] [last unloaded: diagnose]
[3966658.571027] ---[ end trace cc9dbb180f9ae537 ]---
Signed-off-by: Yifan Zhang <yifan1.zhang@amd.com>
Reviewed-by: Philip.Yang<Philip.Yang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 4 ++--
drivers/gpu/drm/amd/amdkfd/kfd_device.c | 13 ++++++++++++-
drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 2 ++
drivers/gpu/drm/amd/amdkfd/kfd_process.c | 4 ++++
5 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index a89172a696e4c..1a92f04c63ace 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -805,7 +805,7 @@ int amdgpu_amdkfd_send_close_event_drain_irq(struct amdgpu_device *adev,
int amdgpu_amdkfd_check_and_lock_kfd(struct amdgpu_device *adev)
{
- return kgd2kfd_check_and_lock_kfd();
+ return kgd2kfd_check_and_lock_kfd(adev->kfd.dev);
}
void amdgpu_amdkfd_unlock_kfd(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index d7de6fe404940..d79c431de2234 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -423,7 +423,7 @@ int kgd2kfd_post_reset(struct kfd_dev *kfd);
void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry);
void kgd2kfd_set_sram_ecc_flag(struct kfd_dev *kfd);
void kgd2kfd_smi_event_throttle(struct kfd_dev *kfd, uint64_t throttle_bitmask);
-int kgd2kfd_check_and_lock_kfd(void);
+int kgd2kfd_check_and_lock_kfd(struct kfd_dev *kfd);
void kgd2kfd_unlock_kfd(void);
int kgd2kfd_start_sched(struct kfd_dev *kfd, uint32_t node_id);
int kgd2kfd_stop_sched(struct kfd_dev *kfd, uint32_t node_id);
@@ -489,7 +489,7 @@ void kgd2kfd_smi_event_throttle(struct kfd_dev *kfd, uint64_t throttle_bitmask)
{
}
-static inline int kgd2kfd_check_and_lock_kfd(void)
+static inline int kgd2kfd_check_and_lock_kfd(struct kfd_dev *kfd)
{
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
index b536ec72cffb7..fa95bde45f3c3 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -487,6 +487,7 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
mutex_init(&kfd->doorbell_mutex);
ida_init(&kfd->doorbell_ida);
+ atomic_set(&kfd->kfd_processes_count, 0);
return kfd;
}
@@ -1430,9 +1431,19 @@ unsigned int kfd_get_num_xgmi_sdma_engines(struct kfd_node *node)
kfd_get_num_sdma_engines(node);
}
-int kgd2kfd_check_and_lock_kfd(void)
+int kgd2kfd_check_and_lock_kfd(struct kfd_dev *kfd)
{
mutex_lock(&kfd_processes_mutex);
+
+ /* kfd_processes_count is per kfd_dev, return -EBUSY without
+ * further check
+ */
+ if (!!atomic_read(&kfd->kfd_processes_count)) {
+ pr_debug("process_wq_release not finished\n");
+ mutex_unlock(&kfd_processes_mutex);
+ return -EBUSY;
+ }
+
if (!hash_empty(kfd_processes_table) || kfd_is_locked()) {
mutex_unlock(&kfd_processes_mutex);
return -EBUSY;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 74bd33a9bd092..8f7e44afba635 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -386,6 +386,8 @@ struct kfd_dev {
/* bitmap for dynamic doorbell allocation from doorbell object */
unsigned long *doorbell_bitmap;
+
+ atomic_t kfd_processes_count;
};
enum kfd_mempool {
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 64f3a0687f8a2..b9f00b756c509 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -1091,6 +1091,8 @@ static void kfd_process_destroy_pdds(struct kfd_process *p)
pdd->runtime_inuse = false;
}
+ atomic_dec(&pdd->dev->kfd->kfd_processes_count);
+
kfree(pdd);
p->pdds[i] = NULL;
}
@@ -1662,6 +1664,8 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev,
/* Init idr used for memory handle translation */
idr_init(&pdd->alloc_idr);
+ atomic_inc(&dev->kfd->kfd_processes_count);
+
return pdd;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 142/869] drm/xe/guc: Add devm release action to safely tear down CT
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (140 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 141/869] amd/amdkfd: enhance kfd process check in switch partition Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 143/869] RDMA/mlx5: Remove the redundant MLX5_IB_STAGE_UAR stage Greg Kroah-Hartman
` (727 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Satyanarayana K V P,
Michal Wajdeczko, Matthew Brost, Matthew Auld, Summers Stuart,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Satyanarayana K V P <satyanarayana.k.v.p@intel.com>
[ Upstream commit ee4b32220a6b41e71512e8804585325e685456ba ]
When a buffer object (BO) is allocated with the XE_BO_FLAG_GGTT_INVALIDATE
flag, the driver initiates TLB invalidation requests via the CTB mechanism
while releasing the BO. However a premature release of the CTB BO can lead
to system crashes, as observed in:
Oops: Oops: 0000 [#1] SMP NOPTI
RIP: 0010:h2g_write+0x2f3/0x7c0 [xe]
Call Trace:
guc_ct_send_locked+0x8b/0x670 [xe]
xe_guc_ct_send_locked+0x19/0x60 [xe]
send_tlb_invalidation+0xb4/0x460 [xe]
xe_gt_tlb_invalidation_ggtt+0x15e/0x2e0 [xe]
ggtt_invalidate_gt_tlb.part.0+0x16/0x90 [xe]
ggtt_node_remove+0x110/0x140 [xe]
xe_ggtt_node_remove+0x40/0xa0 [xe]
xe_ggtt_remove_bo+0x87/0x250 [xe]
Introduce a devm-managed release action during xe_guc_ct_init() and
xe_guc_ct_init_post_hwconfig() to ensure proper CTB disablement before
resource deallocation, preventing the use-after-free scenario.
Signed-off-by: Satyanarayana K V P <satyanarayana.k.v.p@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Matthew Auld <matthew.auld@intel.com>
Cc: Summers Stuart <stuart.summers@intel.com>
Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Link: https://lore.kernel.org/r/20250901072541.31461-1-satyanarayana.k.v.p@intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/xe/xe_guc.c | 8 +++----
drivers/gpu/drm/xe/xe_guc_ct.c | 41 +++++++++++++++++++++++++++++++++-
drivers/gpu/drm/xe/xe_guc_ct.h | 1 +
3 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c
index bedd9894e182e..d4c8a782e7e56 100644
--- a/drivers/gpu/drm/xe/xe_guc.c
+++ b/drivers/gpu/drm/xe/xe_guc.c
@@ -289,10 +289,6 @@ static int xe_guc_realloc_post_hwconfig(struct xe_guc *guc)
if (ret)
return ret;
- ret = xe_managed_bo_reinit_in_vram(xe, tile, &guc->ct.bo);
- if (ret)
- return ret;
-
return 0;
}
@@ -397,6 +393,10 @@ int xe_guc_init_post_hwconfig(struct xe_guc *guc)
if (ret)
return ret;
+ ret = xe_guc_ct_init_post_hwconfig(&guc->ct);
+ if (ret)
+ return ret;
+
guc_init_params_post_hwconfig(guc);
ret = xe_guc_submit_init(guc, ~0);
diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c
index 7619b48dbfe43..e9da1b478cb3d 100644
--- a/drivers/gpu/drm/xe/xe_guc_ct.c
+++ b/drivers/gpu/drm/xe/xe_guc_ct.c
@@ -36,6 +36,8 @@ static void receive_g2h(struct xe_guc_ct *ct);
static void g2h_worker_func(struct work_struct *w);
static void safe_mode_worker_func(struct work_struct *w);
static void ct_exit_safe_mode(struct xe_guc_ct *ct);
+static void xe_guc_ct_set_state(struct xe_guc_ct *ct,
+ enum xe_guc_ct_state state);
#if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
enum {
@@ -206,6 +208,13 @@ static void primelockdep(struct xe_guc_ct *ct)
fs_reclaim_release(GFP_KERNEL);
}
+static void guc_action_disable_ct(void *arg)
+{
+ struct xe_guc_ct *ct = arg;
+
+ xe_guc_ct_set_state(ct, XE_GUC_CT_STATE_DISABLED);
+}
+
int xe_guc_ct_init(struct xe_guc_ct *ct)
{
struct xe_device *xe = ct_to_xe(ct);
@@ -252,7 +261,37 @@ int xe_guc_ct_init(struct xe_guc_ct *ct)
xe_gt_assert(gt, ct->state == XE_GUC_CT_STATE_NOT_INITIALIZED);
ct->state = XE_GUC_CT_STATE_DISABLED;
- return 0;
+
+ return devm_add_action_or_reset(xe->drm.dev, guc_action_disable_ct, ct);
+}
+
+/**
+ * xe_guc_ct_init_post_hwconfig - Reinitialize the GuC CTB in VRAM
+ * @ct: the &xe_guc_ct
+ *
+ * Allocate a new BO in VRAM and free the previous BO that was allocated
+ * in system memory (SMEM). Applicable only for DGFX products.
+ *
+ * Return: 0 on success, or a negative errno on failure.
+ */
+int xe_guc_ct_init_post_hwconfig(struct xe_guc_ct *ct)
+{
+ struct xe_device *xe = ct_to_xe(ct);
+ struct xe_gt *gt = ct_to_gt(ct);
+ struct xe_tile *tile = gt_to_tile(gt);
+ int ret;
+
+ xe_assert(xe, !xe_guc_ct_enabled(ct));
+
+ if (!IS_DGFX(xe))
+ return 0;
+
+ ret = xe_managed_bo_reinit_in_vram(xe, tile, &ct->bo);
+ if (ret)
+ return ret;
+
+ devm_release_action(xe->drm.dev, guc_action_disable_ct, ct);
+ return devm_add_action_or_reset(xe->drm.dev, guc_action_disable_ct, ct);
}
#define desc_read(xe_, guc_ctb__, field_) \
diff --git a/drivers/gpu/drm/xe/xe_guc_ct.h b/drivers/gpu/drm/xe/xe_guc_ct.h
index c7ac9407b861e..398e3adf49c73 100644
--- a/drivers/gpu/drm/xe/xe_guc_ct.h
+++ b/drivers/gpu/drm/xe/xe_guc_ct.h
@@ -11,6 +11,7 @@
struct drm_printer;
int xe_guc_ct_init(struct xe_guc_ct *ct);
+int xe_guc_ct_init_post_hwconfig(struct xe_guc_ct *ct);
int xe_guc_ct_enable(struct xe_guc_ct *ct);
void xe_guc_ct_disable(struct xe_guc_ct *ct);
void xe_guc_ct_stop(struct xe_guc_ct *ct);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 143/869] RDMA/mlx5: Remove the redundant MLX5_IB_STAGE_UAR stage
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (141 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 142/869] drm/xe/guc: Add devm release action to safely tear down CT Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 144/869] net/mlx5: HWS, fix bad parameter in CQ creation Greg Kroah-Hartman
` (726 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yishai Hadas, Fan Li,
Leon Romanovsky, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yishai Hadas <yishaih@nvidia.com>
[ Upstream commit 972db388d40ded1a5ef8ce09d92ef1e2b9e40f07 ]
The MLX5_IB_STAGE_UAR stage in the RDMA driver is redundant and should
be removed.
Responsibility for initializing the device's UAR pointer
(mdev->priv.uar) lies with mlx5_core, which already sets it during the
mlx5_load() process.
At present, the RDMA UAR stage overwrites this pointer, which was
correctly initialized by mlx5_core, creating the risk of inconsistency.
Ownership and management of the UAR pointer should remain exclusively
within mlx5_core.
In the current upstream code, we luckily receive the same pointer, since
mlx5_get_uars_page() still finds available BF registers for that UAR,
allowing it to be shared.
However, future changes in mlx5_core may expose this flaw.
For instance, if mlx5_alloc_bfreg() is invoked twice before the RDMA UAR
stage runs, the RDMA driver may overwrite the UAR allocated by
mlx5_core.
This could lead to real bugs. For example, if mlx5_ib is unloaded
(rmmod), it might free the UAR, leaving mlx5_core with a dangling
reference to an invalid UAR.
Signed-off-by: Yishai Hadas <yishaih@nvidia.com>
Reviewed-by: Fan Li <fanl@nvidia.com>
Link: https://patch.msgid.link/feaa84ec6f20468b4935c439923e9266122a93d0.1747134130.git.leon@kernel.org
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Stable-dep-of: e5eba42f0134 ("mlx5: Fix default values in create CQ")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/mlx5/main.c | 17 -----------------
drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 -
2 files changed, 18 deletions(-)
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 2d1cb516d8450..42a917c2d0d7f 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -4502,17 +4502,6 @@ static void mlx5_ib_stage_cong_debugfs_cleanup(struct mlx5_ib_dev *dev)
mlx5_core_native_port_num(dev->mdev) - 1);
}
-static int mlx5_ib_stage_uar_init(struct mlx5_ib_dev *dev)
-{
- dev->mdev->priv.uar = mlx5_get_uars_page(dev->mdev);
- return PTR_ERR_OR_ZERO(dev->mdev->priv.uar);
-}
-
-static void mlx5_ib_stage_uar_cleanup(struct mlx5_ib_dev *dev)
-{
- mlx5_put_uars_page(dev->mdev, dev->mdev->priv.uar);
-}
-
static int mlx5_ib_stage_bfrag_init(struct mlx5_ib_dev *dev)
{
int err;
@@ -4742,9 +4731,6 @@ static const struct mlx5_ib_profile pf_profile = {
STAGE_CREATE(MLX5_IB_STAGE_CONG_DEBUGFS,
mlx5_ib_stage_cong_debugfs_init,
mlx5_ib_stage_cong_debugfs_cleanup),
- STAGE_CREATE(MLX5_IB_STAGE_UAR,
- mlx5_ib_stage_uar_init,
- mlx5_ib_stage_uar_cleanup),
STAGE_CREATE(MLX5_IB_STAGE_BFREG,
mlx5_ib_stage_bfrag_init,
mlx5_ib_stage_bfrag_cleanup),
@@ -4805,9 +4791,6 @@ const struct mlx5_ib_profile raw_eth_profile = {
STAGE_CREATE(MLX5_IB_STAGE_CONG_DEBUGFS,
mlx5_ib_stage_cong_debugfs_init,
mlx5_ib_stage_cong_debugfs_cleanup),
- STAGE_CREATE(MLX5_IB_STAGE_UAR,
- mlx5_ib_stage_uar_init,
- mlx5_ib_stage_uar_cleanup),
STAGE_CREATE(MLX5_IB_STAGE_BFREG,
mlx5_ib_stage_bfrag_init,
mlx5_ib_stage_bfrag_cleanup),
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index 3135519f1cfdf..5c0efac217eac 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -975,7 +975,6 @@ enum mlx5_ib_stages {
MLX5_IB_STAGE_ODP,
MLX5_IB_STAGE_COUNTERS,
MLX5_IB_STAGE_CONG_DEBUGFS,
- MLX5_IB_STAGE_UAR,
MLX5_IB_STAGE_BFREG,
MLX5_IB_STAGE_PRE_IB_REG_UMR,
MLX5_IB_STAGE_WHITELIST_UID,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 144/869] net/mlx5: HWS, fix bad parameter in CQ creation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (142 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 143/869] RDMA/mlx5: Remove the redundant MLX5_IB_STAGE_UAR stage Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 145/869] net/mlx5: Fix typo of MLX5_EQ_DOORBEL_OFFSET Greg Kroah-Hartman
` (725 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yevgeny Kliteynik, Vlad Dogaru,
Mark Bloch, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yevgeny Kliteynik <kliteyn@nvidia.com>
[ Upstream commit 2462c1b9217246a889ec318b3894d84e4dd709c6 ]
'cqe_sz' valid value should be 0 for 64-byte CQE.
Fixes: 2ca62599aa0b ("net/mlx5: HWS, added send engine and context handling")
Signed-off-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Vlad Dogaru <vdogaru@nvidia.com>
Signed-off-by: Mark Bloch <mbloch@nvidia.com>
Link: https://patch.msgid.link/20250817202323.308604-2-mbloch@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: e5eba42f0134 ("mlx5: Fix default values in create CQ")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c
index 08be034bd1e16..ad766451cd6ef 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c
@@ -839,7 +839,6 @@ static int hws_send_ring_open_cq(struct mlx5_core_dev *mdev,
return -ENOMEM;
MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.uar->index);
- MLX5_SET(cqc, cqc_data, cqe_sz, queue->num_entries);
MLX5_SET(cqc, cqc_data, log_cq_size, ilog2(queue->num_entries));
err = hws_send_ring_alloc_cq(mdev, numa_node, queue, cqc_data, cq);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 145/869] net/mlx5: Fix typo of MLX5_EQ_DOORBEL_OFFSET
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (143 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 144/869] net/mlx5: HWS, fix bad parameter in CQ creation Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 146/869] net/mlx5: Store the global doorbell in mlx5_priv Greg Kroah-Hartman
` (724 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Cosmin Ratiu, Dragos Tatulea,
Tariq Toukan, Simon Horman, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cosmin Ratiu <cratiu@nvidia.com>
[ Upstream commit 917449e7c3cdc7a0dfe429de997e39098d9cdd20 ]
Also convert it to a simple define.
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: e5eba42f0134 ("mlx5: Fix default values in create CQ")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/mellanox/mlx5/core/eq.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 4241cf07a0306..c53efb0711e16 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -32,9 +32,7 @@ enum {
MLX5_EQ_STATE_ALWAYS_ARMED = 0xb,
};
-enum {
- MLX5_EQ_DOORBEL_OFFSET = 0x40,
-};
+#define MLX5_EQ_DOORBELL_OFFSET 0x40
/* budget must be smaller than MLX5_NUM_SPARE_EQE to guarantee that we update
* the ci before we polled all the entries in the EQ. MLX5_NUM_SPARE_EQE is
@@ -331,7 +329,7 @@ create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
eq->eqn = MLX5_GET(create_eq_out, out, eq_number);
eq->irqn = pci_irq_vector(dev->pdev, vecidx);
eq->dev = dev;
- eq->doorbell = priv->uar->map + MLX5_EQ_DOORBEL_OFFSET;
+ eq->doorbell = priv->uar->map + MLX5_EQ_DOORBELL_OFFSET;
err = mlx5_debug_eq_add(dev, eq);
if (err)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 146/869] net/mlx5: Store the global doorbell in mlx5_priv
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (144 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 145/869] net/mlx5: Fix typo of MLX5_EQ_DOORBEL_OFFSET Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 147/869] net/mlx5e: Prepare for using different CQ doorbells Greg Kroah-Hartman
` (723 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Cosmin Ratiu, Dragos Tatulea,
Tariq Toukan, Simon Horman, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cosmin Ratiu <cratiu@nvidia.com>
[ Upstream commit aa4595d0ada65d5d44fa924a42a87c175d9d88e3 ]
The global doorbell is used for more than just Ethernet resources, so
move it out of mlx5e_hw_objs into a common place (mlx5_priv), to avoid
non-Ethernet modules (e.g. HWS, ASO) depending on Ethernet structs.
Use this opportunity to consolidate it with the 'uar' pointer already
there, which was used as an RX doorbell. Underneath the 'uar' pointer is
identical to 'bfreg->up', so store a single resource and use that
instead.
For CQ doorbells, care is taken to always use bfreg->up->index instead
of bfreg->index, which may refer to a subsequent UAR page from the same
ALLOC_UAR batch on some NICs.
This paves the way for cleanly supporting multiple doorbells in the
Ethernet driver.
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: e5eba42f0134 ("mlx5: Fix default values in create CQ")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/mlx5/cq.c | 4 ++--
drivers/net/ethernet/mellanox/mlx5/core/cq.c | 2 +-
drivers/net/ethernet/mellanox/mlx5/core/en/params.c | 2 +-
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c | 2 +-
drivers/net/ethernet/mellanox/mlx5/core/en_common.c | 11 +----------
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 10 +++++-----
drivers/net/ethernet/mellanox/mlx5/core/eq.c | 4 ++--
drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c | 8 ++++----
drivers/net/ethernet/mellanox/mlx5/core/main.c | 11 +++++------
.../mellanox/mlx5/core/steering/hws/mlx5hws_send.c | 8 ++++----
drivers/net/ethernet/mellanox/mlx5/core/wc.c | 4 ++--
include/linux/mlx5/driver.h | 3 +--
12 files changed, 29 insertions(+), 40 deletions(-)
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
index 9e04b595c77fd..3387f218104aa 100644
--- a/drivers/infiniband/hw/mlx5/cq.c
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -649,7 +649,7 @@ int mlx5_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
{
struct mlx5_core_dev *mdev = to_mdev(ibcq->device)->mdev;
struct mlx5_ib_cq *cq = to_mcq(ibcq);
- void __iomem *uar_page = mdev->priv.uar->map;
+ void __iomem *uar_page = mdev->priv.bfreg.up->map;
unsigned long irq_flags;
int ret = 0;
@@ -924,7 +924,7 @@ static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
cq->buf.frag_buf.page_shift -
MLX5_ADAPTER_PAGE_SHIFT);
- *index = dev->mdev->priv.uar->index;
+ *index = dev->mdev->priv.bfreg.up->index;
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
index 4caa1b6f40ba4..7dadf4cde9e5d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
@@ -134,7 +134,7 @@ int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
mlx5_core_dbg(dev, "failed adding CP 0x%x to debug file system\n",
cq->cqn);
- cq->uar = dev->priv.uar;
+ cq->uar = dev->priv.bfreg.up;
cq->irqn = eq->core.irqn;
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
index 3dac708c0d75a..121c836acdf30 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
@@ -825,7 +825,7 @@ static void mlx5e_build_common_cq_param(struct mlx5_core_dev *mdev,
{
void *cqc = param->cqc;
- MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index);
+ MLX5_SET(cqc, cqc, uar_page, mdev->priv.bfreg.up->index);
if (MLX5_CAP_GEN(mdev, cqe_128_always) && cache_line_size() >= 128)
MLX5_SET(cqc, cqc, cqe_sz, CQE_STRIDE_128_PAD);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
index afd654583b6b1..ff7074310b6c3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
@@ -333,7 +333,7 @@ static int mlx5e_ptp_alloc_txqsq(struct mlx5e_ptp *c, int txq_ix,
sq->mdev = mdev;
sq->ch_ix = MLX5E_PTP_CHANNEL_IX;
sq->txq_ix = txq_ix;
- sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
+ sq->uar_map = mdev->priv.bfreg.map;
sq->min_inline_mode = params->tx_min_inline_mode;
sq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
sq->stats = &c->priv->ptp_stats.sq[tc];
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
index 6ed3a32b7e226..e9e36358c39d1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
@@ -163,17 +163,11 @@ int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev, bool create_tises)
goto err_dealloc_transport_domain;
}
- err = mlx5_alloc_bfreg(mdev, &res->bfreg, false, false);
- if (err) {
- mlx5_core_err(mdev, "alloc bfreg failed, %d\n", err);
- goto err_destroy_mkey;
- }
-
if (create_tises) {
err = mlx5e_create_tises(mdev, res->tisn);
if (err) {
mlx5_core_err(mdev, "alloc tises failed, %d\n", err);
- goto err_destroy_bfreg;
+ goto err_destroy_mkey;
}
res->tisn_valid = true;
}
@@ -190,8 +184,6 @@ int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev, bool create_tises)
return 0;
-err_destroy_bfreg:
- mlx5_free_bfreg(mdev, &res->bfreg);
err_destroy_mkey:
mlx5_core_destroy_mkey(mdev, res->mkey);
err_dealloc_transport_domain:
@@ -209,7 +201,6 @@ void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev)
mdev->mlx5e_res.dek_priv = NULL;
if (res->tisn_valid)
mlx5e_destroy_tises(mdev, res->tisn);
- mlx5_free_bfreg(mdev, &res->bfreg);
mlx5_core_destroy_mkey(mdev, res->mkey);
mlx5_core_dealloc_transport_domain(mdev, res->td.tdn);
mlx5_core_dealloc_pd(mdev, res->pdn);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index c5a2fa4152276..c34bf77d72226 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -1460,7 +1460,7 @@ static int mlx5e_alloc_xdpsq(struct mlx5e_channel *c,
sq->pdev = c->pdev;
sq->mkey_be = c->mkey_be;
sq->channel = c;
- sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
+ sq->uar_map = mdev->priv.bfreg.map;
sq->min_inline_mode = params->tx_min_inline_mode;
sq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu) - ETH_FCS_LEN;
sq->xsk_pool = xsk_pool;
@@ -1545,7 +1545,7 @@ static int mlx5e_alloc_icosq(struct mlx5e_channel *c,
int err;
sq->channel = c;
- sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
+ sq->uar_map = mdev->priv.bfreg.map;
sq->reserved_room = param->stop_room;
param->wq.db_numa_node = cpu_to_node(c->cpu);
@@ -1630,7 +1630,7 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
sq->priv = c->priv;
sq->ch_ix = c->ix;
sq->txq_ix = txq_ix;
- sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
+ sq->uar_map = mdev->priv.bfreg.map;
sq->min_inline_mode = params->tx_min_inline_mode;
sq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
sq->max_sq_mpw_wqebbs = mlx5e_get_max_sq_aligned_wqebbs(mdev);
@@ -1708,7 +1708,7 @@ static int mlx5e_create_sq(struct mlx5_core_dev *mdev,
MLX5_SET(sqc, sqc, flush_in_error_en, 1);
MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
- MLX5_SET(wq, wq, uar_page, mdev->mlx5e_res.hw_objs.bfreg.index);
+ MLX5_SET(wq, wq, uar_page, mdev->priv.bfreg.index);
MLX5_SET(wq, wq, log_wq_pg_sz, csp->wq_ctrl->buf.page_shift -
MLX5_ADAPTER_PAGE_SHIFT);
MLX5_SET64(wq, wq, dbr_addr, csp->wq_ctrl->db.dma);
@@ -2152,7 +2152,7 @@ static int mlx5e_create_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
MLX5_SET(cqc, cqc, cq_period_mode, mlx5e_cq_period_mode(param->cq_period_mode));
MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn);
- MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index);
+ MLX5_SET(cqc, cqc, uar_page, mdev->priv.bfreg.up->index);
MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
MLX5_ADAPTER_PAGE_SHIFT);
MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index c53efb0711e16..78a6d11713c95 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -316,7 +316,7 @@ create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
eqc = MLX5_ADDR_OF(create_eq_in, in, eq_context_entry);
MLX5_SET(eqc, eqc, log_eq_size, eq->fbc.log_sz);
- MLX5_SET(eqc, eqc, uar_page, priv->uar->index);
+ MLX5_SET(eqc, eqc, uar_page, priv->bfreg.up->index);
MLX5_SET(eqc, eqc, intr, vecidx);
MLX5_SET(eqc, eqc, log_page_size,
eq->frag_buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT);
@@ -329,7 +329,7 @@ create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
eq->eqn = MLX5_GET(create_eq_out, out, eq_number);
eq->irqn = pci_irq_vector(dev->pdev, vecidx);
eq->dev = dev;
- eq->doorbell = priv->uar->map + MLX5_EQ_DOORBELL_OFFSET;
+ eq->doorbell = priv->bfreg.up->map + MLX5_EQ_DOORBELL_OFFSET;
err = mlx5_debug_eq_add(dev, eq);
if (err)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c
index 58bd749b5e4de..129725159a935 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c
@@ -100,7 +100,7 @@ static int create_aso_cq(struct mlx5_aso_cq *cq, void *cqc_data)
MLX5_SET(cqc, cqc, cq_period_mode, MLX5_CQ_PERIOD_MODE_START_FROM_EQE);
MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn);
- MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index);
+ MLX5_SET(cqc, cqc, uar_page, mdev->priv.bfreg.up->index);
MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
MLX5_ADAPTER_PAGE_SHIFT);
MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma);
@@ -129,7 +129,7 @@ static int mlx5_aso_create_cq(struct mlx5_core_dev *mdev, int numa_node,
return -ENOMEM;
MLX5_SET(cqc, cqc_data, log_cq_size, 1);
- MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.uar->index);
+ MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.bfreg.up->index);
if (MLX5_CAP_GEN(mdev, cqe_128_always) && cache_line_size() >= 128)
MLX5_SET(cqc, cqc_data, cqe_sz, CQE_STRIDE_128_PAD);
@@ -163,7 +163,7 @@ static int mlx5_aso_alloc_sq(struct mlx5_core_dev *mdev, int numa_node,
struct mlx5_wq_param param;
int err;
- sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
+ sq->uar_map = mdev->priv.bfreg.map;
param.db_numa_node = numa_node;
param.buf_numa_node = numa_node;
@@ -203,7 +203,7 @@ static int create_aso_sq(struct mlx5_core_dev *mdev, int pdn,
MLX5_SET(sqc, sqc, ts_format, ts_format);
MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
- MLX5_SET(wq, wq, uar_page, mdev->mlx5e_res.hw_objs.bfreg.index);
+ MLX5_SET(wq, wq, uar_page, mdev->priv.bfreg.index);
MLX5_SET(wq, wq, log_wq_pg_sz, sq->wq_ctrl.buf.page_shift -
MLX5_ADAPTER_PAGE_SHIFT);
MLX5_SET64(wq, wq, dbr_addr, sq->wq_ctrl.db.dma);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index fd5676dfda4af..0496f2e3f2a23 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -1321,10 +1321,9 @@ static int mlx5_load(struct mlx5_core_dev *dev)
{
int err;
- dev->priv.uar = mlx5_get_uars_page(dev);
- if (IS_ERR(dev->priv.uar)) {
- mlx5_core_err(dev, "Failed allocating uar, aborting\n");
- err = PTR_ERR(dev->priv.uar);
+ err = mlx5_alloc_bfreg(dev, &dev->priv.bfreg, false, false);
+ if (err) {
+ mlx5_core_err(dev, "Failed allocating bfreg, %d\n", err);
return err;
}
@@ -1432,7 +1431,7 @@ static int mlx5_load(struct mlx5_core_dev *dev)
err_irq_table:
mlx5_pagealloc_stop(dev);
mlx5_events_stop(dev);
- mlx5_put_uars_page(dev, dev->priv.uar);
+ mlx5_free_bfreg(dev, &dev->priv.bfreg);
return err;
}
@@ -1455,7 +1454,7 @@ static void mlx5_unload(struct mlx5_core_dev *dev)
mlx5_irq_table_destroy(dev);
mlx5_pagealloc_stop(dev);
mlx5_events_stop(dev);
- mlx5_put_uars_page(dev, dev->priv.uar);
+ mlx5_free_bfreg(dev, &dev->priv.bfreg);
}
int mlx5_init_one_devl_locked(struct mlx5_core_dev *dev)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c
index ad766451cd6ef..7312f042d41eb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c
@@ -566,7 +566,7 @@ static int hws_send_ring_alloc_sq(struct mlx5_core_dev *mdev,
size_t buf_sz;
int err;
- sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
+ sq->uar_map = mdev->priv.bfreg.map;
sq->mdev = mdev;
param.db_numa_node = numa_node;
@@ -639,7 +639,7 @@ static int hws_send_ring_create_sq(struct mlx5_core_dev *mdev, u32 pdn,
MLX5_SET(sqc, sqc, ts_format, ts_format);
MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
- MLX5_SET(wq, wq, uar_page, mdev->mlx5e_res.hw_objs.bfreg.index);
+ MLX5_SET(wq, wq, uar_page, mdev->priv.bfreg.index);
MLX5_SET(wq, wq, log_wq_pg_sz, sq->wq_ctrl.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT);
MLX5_SET64(wq, wq, dbr_addr, sq->wq_ctrl.db.dma);
@@ -815,7 +815,7 @@ static int hws_send_ring_create_cq(struct mlx5_core_dev *mdev,
(__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas));
MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn);
- MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index);
+ MLX5_SET(cqc, cqc, uar_page, mdev->priv.bfreg.up->index);
MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT);
MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma);
@@ -838,7 +838,7 @@ static int hws_send_ring_open_cq(struct mlx5_core_dev *mdev,
if (!cqc_data)
return -ENOMEM;
- MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.uar->index);
+ MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.bfreg.up->index);
MLX5_SET(cqc, cqc_data, log_cq_size, ilog2(queue->num_entries));
err = hws_send_ring_alloc_cq(mdev, numa_node, queue, cqc_data, cq);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wc.c b/drivers/net/ethernet/mellanox/mlx5/core/wc.c
index 740b719e7072d..089f7d3712b50 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/wc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/wc.c
@@ -94,7 +94,7 @@ static int create_wc_cq(struct mlx5_wc_cq *cq, void *cqc_data)
MLX5_SET(cqc, cqc, cq_period_mode, MLX5_CQ_PERIOD_MODE_START_FROM_EQE);
MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn);
- MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index);
+ MLX5_SET(cqc, cqc, uar_page, mdev->priv.bfreg.up->index);
MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
MLX5_ADAPTER_PAGE_SHIFT);
MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma);
@@ -116,7 +116,7 @@ static int mlx5_wc_create_cq(struct mlx5_core_dev *mdev, struct mlx5_wc_cq *cq)
return -ENOMEM;
MLX5_SET(cqc, cqc, log_cq_size, TEST_WC_LOG_CQ_SZ);
- MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index);
+ MLX5_SET(cqc, cqc, uar_page, mdev->priv.bfreg.up->index);
if (MLX5_CAP_GEN(mdev, cqe_128_always) && cache_line_size() >= 128)
MLX5_SET(cqc, cqc, cqe_sz, CQE_STRIDE_128_PAD);
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index 2e3324578f2ea..aa38f0f281503 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -637,7 +637,7 @@ struct mlx5_priv {
struct mlx5_ft_pool *ft_pool;
struct mlx5_bfreg_data bfregs;
- struct mlx5_uars_page *uar;
+ struct mlx5_sq_bfreg bfreg;
#ifdef CONFIG_MLX5_SF
struct mlx5_vhca_state_notifier *vhca_state_notifier;
struct mlx5_sf_dev_table *sf_dev_table;
@@ -683,7 +683,6 @@ struct mlx5e_resources {
u32 pdn;
struct mlx5_td td;
u32 mkey;
- struct mlx5_sq_bfreg bfreg;
#define MLX5_MAX_NUM_TC 8
u32 tisn[MLX5_MAX_PORTS][MLX5_MAX_NUM_TC];
bool tisn_valid;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 147/869] net/mlx5e: Prepare for using different CQ doorbells
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (145 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 146/869] net/mlx5: Store the global doorbell in mlx5_priv Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 148/869] mlx5: Fix default values in create CQ Greg Kroah-Hartman
` (722 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Cosmin Ratiu, Dragos Tatulea,
Tariq Toukan, Simon Horman, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cosmin Ratiu <cratiu@nvidia.com>
[ Upstream commit a315b723e87ba4e4573e1e5c759d512f38bdc0b3 ]
Completion queues (CQs) in mlx5 use the same global doorbell, which may
become contended when accessed concurrently from many cores.
This patch prepares the CQ management code for supporting different
doorbells per CQ. This will be used in downstream patches to allow
separate doorbells to be used by channels CQs.
The main change is moving the 'uar' pointer from struct mlx5_core_cq to
struct mlx5e_cq, as the uar page to be used is better off stored
directly there. Other users of mlx5_core_cq also store the UAR to be
used separately and therefore the pointer being removed is dead weight
for them. As evidence, in this patch there are two users which set the
mcq.uar pointer but didn't use it, Software Steering and old Innova CQ
creation code. Instead, they rang the doorbell directly from another
pointer.
The 'uar' pointer added to struct mlx5e_cq remains in a hot cacheline
(as before), because it may get accessed for each packet.
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: e5eba42f0134 ("mlx5: Fix default values in create CQ")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/mellanox/mlx5/core/cq.c | 1 -
drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 +
drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h | 5 +----
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 10 +++++++---
drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c | 1 -
.../net/ethernet/mellanox/mlx5/core/steering/dr_send.c | 1 -
include/linux/mlx5/cq.h | 1 -
7 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
index 7dadf4cde9e5d..ba52e52e98863 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
@@ -134,7 +134,6 @@ int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
mlx5_core_dbg(dev, "failed adding CP 0x%x to debug file system\n",
cq->cqn);
- cq->uar = dev->priv.bfreg.up;
cq->irqn = eq->core.irqn;
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 0e18906168313..a0a9a11b0fb92 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -341,6 +341,7 @@ struct mlx5e_cq {
/* data path - accessed per napi poll */
u16 event_ctr;
struct napi_struct *napi;
+ struct mlx5_uars_page *uar;
struct mlx5_core_cq mcq;
struct mlx5e_ch_stats *ch_stats;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
index 5ec468268d1aa..ee1267e0023a3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
@@ -296,10 +296,7 @@ mlx5e_notify_hw(struct mlx5_wq_cyc *wq, u16 pc, void __iomem *uar_map,
static inline void mlx5e_cq_arm(struct mlx5e_cq *cq)
{
- struct mlx5_core_cq *mcq;
-
- mcq = &cq->mcq;
- mlx5_cq_arm(mcq, MLX5_CQ_DB_REQ_NOT, mcq->uar->map, cq->wq.cc);
+ mlx5_cq_arm(&cq->mcq, MLX5_CQ_DB_REQ_NOT, cq->uar->map, cq->wq.cc);
}
static inline struct mlx5e_sq_dma *
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index c34bf77d72226..573a9d1ea3765 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -2061,6 +2061,7 @@ void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq)
static int mlx5e_alloc_cq_common(struct mlx5_core_dev *mdev,
struct net_device *netdev,
struct workqueue_struct *workqueue,
+ struct mlx5_uars_page *uar,
struct mlx5e_cq_param *param,
struct mlx5e_cq *cq)
{
@@ -2092,6 +2093,7 @@ static int mlx5e_alloc_cq_common(struct mlx5_core_dev *mdev,
cq->mdev = mdev;
cq->netdev = netdev;
cq->workqueue = workqueue;
+ cq->uar = uar;
return 0;
}
@@ -2107,7 +2109,8 @@ static int mlx5e_alloc_cq(struct mlx5_core_dev *mdev,
param->wq.db_numa_node = ccp->node;
param->eq_ix = ccp->ix;
- err = mlx5e_alloc_cq_common(mdev, ccp->netdev, ccp->wq, param, cq);
+ err = mlx5e_alloc_cq_common(mdev, ccp->netdev, ccp->wq,
+ mdev->priv.bfreg.up, param, cq);
cq->napi = ccp->napi;
cq->ch_stats = ccp->ch_stats;
@@ -2152,7 +2155,7 @@ static int mlx5e_create_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
MLX5_SET(cqc, cqc, cq_period_mode, mlx5e_cq_period_mode(param->cq_period_mode));
MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn);
- MLX5_SET(cqc, cqc, uar_page, mdev->priv.bfreg.up->index);
+ MLX5_SET(cqc, cqc, uar_page, cq->uar->index);
MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
MLX5_ADAPTER_PAGE_SHIFT);
MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma);
@@ -3447,7 +3450,8 @@ static int mlx5e_alloc_drop_cq(struct mlx5e_priv *priv,
param->wq.buf_numa_node = dev_to_node(mlx5_core_dma_dev(mdev));
param->wq.db_numa_node = dev_to_node(mlx5_core_dma_dev(mdev));
- return mlx5e_alloc_cq_common(priv->mdev, priv->netdev, priv->wq, param, cq);
+ return mlx5e_alloc_cq_common(priv->mdev, priv->netdev, priv->wq,
+ mdev->priv.bfreg.up, param, cq);
}
int mlx5e_open_drop_rq(struct mlx5e_priv *priv,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
index c4de6bf8d1b65..cb1319974f83f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
@@ -475,7 +475,6 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
*conn->cq.mcq.arm_db = 0;
conn->cq.mcq.vector = 0;
conn->cq.mcq.comp = mlx5_fpga_conn_cq_complete;
- conn->cq.mcq.uar = fdev->conn_res.uar;
tasklet_setup(&conn->cq.tasklet, mlx5_fpga_conn_cq_tasklet);
mlx5_fpga_dbg(fdev, "Created CQ #0x%x\n", conn->cq.mcq.cqn);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
index f57c84e5128bc..34e64c1d11437 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
@@ -1131,7 +1131,6 @@ static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
*cq->mcq.arm_db = cpu_to_be32(2 << 28);
cq->mcq.vector = 0;
- cq->mcq.uar = uar;
cq->mdev = mdev;
return cq;
diff --git a/include/linux/mlx5/cq.h b/include/linux/mlx5/cq.h
index 991526039ccbd..7ef2c7c7d803d 100644
--- a/include/linux/mlx5/cq.h
+++ b/include/linux/mlx5/cq.h
@@ -41,7 +41,6 @@ struct mlx5_core_cq {
int cqe_sz;
__be32 *set_ci_db;
__be32 *arm_db;
- struct mlx5_uars_page *uar;
refcount_t refcount;
struct completion free;
unsigned vector;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 148/869] mlx5: Fix default values in create CQ
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (146 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 147/869] net/mlx5e: Prepare for using different CQ doorbells Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 149/869] scsi: ufs: qcom : Refactor phy_power_on/off calls Greg Kroah-Hartman
` (721 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Akiva Goldberger, Moshe Shemesh,
Tariq Toukan, Leon Romanovsky, Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Akiva Goldberger <agoldberger@nvidia.com>
[ Upstream commit e5eba42f01340f73888dfe560be2806057c25913 ]
Currently, CQs without a completion function are assigned the
mlx5_add_cq_to_tasklet function by default. This is problematic since
only user CQs created through the mlx5_ib driver are intended to use
this function.
Additionally, all CQs that will use doorbells instead of polling for
completions must call mlx5_cq_arm. However, the default CQ creation flow
leaves a valid value in the CQ's arm_db field, allowing FW to send
interrupts to polling-only CQs in certain corner cases.
These two factors would allow a polling-only kernel CQ to be triggered
by an EQ interrupt and call a completion function intended only for user
CQs, causing a null pointer exception.
Some areas in the driver have prevented this issue with one-off fixes
but did not address the root cause.
This patch fixes the described issue by adding defaults to the create CQ
flow. It adds a default dummy completion function to protect against
null pointer exceptions, and it sets an invalid command sequence number
by default in kernel CQs to prevent the FW from sending an interrupt to
the CQ until it is armed. User CQs are responsible for their own
initialization values.
Callers of mlx5_core_create_cq are responsible for changing the
completion function and arming the CQ per their needs.
Fixes: cdd04f4d4d71 ("net/mlx5: Add support to create SQ and CQ for ASO")
Signed-off-by: Akiva Goldberger <agoldberger@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Acked-by: Leon Romanovsky <leon@kernel.org>
Link: https://patch.msgid.link/1762681743-1084694-1-git-send-email-tariqt@nvidia.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/mlx5/cq.c | 11 +++++---
drivers/net/ethernet/mellanox/mlx5/core/cq.c | 23 +++++++++++++--
.../net/ethernet/mellanox/mlx5/core/en_main.c | 1 -
.../ethernet/mellanox/mlx5/core/fpga/conn.c | 15 +++++-----
.../mellanox/mlx5/core/steering/dr_send.c | 28 +++++--------------
.../mlx5/core/steering/hws/mlx5hws_send.c | 7 -----
drivers/vdpa/mlx5/net/mlx5_vnet.c | 6 ++--
include/linux/mlx5/cq.h | 1 +
8 files changed, 44 insertions(+), 48 deletions(-)
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
index 3387f218104aa..b0b10b8bedfb4 100644
--- a/drivers/infiniband/hw/mlx5/cq.c
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -1021,15 +1021,18 @@ int mlx5_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
if (cq->create_flags & IB_UVERBS_CQ_FLAGS_IGNORE_OVERRUN)
MLX5_SET(cqc, cqc, oi, 1);
+ if (udata) {
+ cq->mcq.comp = mlx5_add_cq_to_tasklet;
+ cq->mcq.tasklet_ctx.comp = mlx5_ib_cq_comp;
+ } else {
+ cq->mcq.comp = mlx5_ib_cq_comp;
+ }
+
err = mlx5_core_create_cq(dev->mdev, &cq->mcq, cqb, inlen, out, sizeof(out));
if (err)
goto err_cqb;
mlx5_ib_dbg(dev, "cqn 0x%x\n", cq->mcq.cqn);
- if (udata)
- cq->mcq.tasklet_ctx.comp = mlx5_ib_cq_comp;
- else
- cq->mcq.comp = mlx5_ib_cq_comp;
cq->mcq.event = mlx5_ib_cq_event;
INIT_LIST_HEAD(&cq->wc_list);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
index ba52e52e98863..24dd6318964a9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
@@ -66,8 +66,8 @@ void mlx5_cq_tasklet_cb(struct tasklet_struct *t)
tasklet_schedule(&ctx->task);
}
-static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
- struct mlx5_eqe *eqe)
+void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
+ struct mlx5_eqe *eqe)
{
unsigned long flags;
struct mlx5_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv;
@@ -84,7 +84,15 @@ static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
}
spin_unlock_irqrestore(&tasklet_ctx->lock, flags);
}
+EXPORT_SYMBOL(mlx5_add_cq_to_tasklet);
+static void mlx5_core_cq_dummy_cb(struct mlx5_core_cq *cq, struct mlx5_eqe *eqe)
+{
+ mlx5_core_err(cq->eq->core.dev,
+ "CQ default completion callback, CQ #%u\n", cq->cqn);
+}
+
+#define MLX5_CQ_INIT_CMD_SN cpu_to_be32(2 << 28)
/* Callers must verify outbox status in case of err */
int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
u32 *in, int inlen, u32 *out, int outlen)
@@ -110,10 +118,19 @@ int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
cq->arm_sn = 0;
cq->eq = eq;
cq->uid = MLX5_GET(create_cq_in, in, uid);
+
+ /* Kernel CQs must set the arm_db address prior to calling
+ * this function, allowing for the proper value to be
+ * initialized. User CQs are responsible for their own
+ * initialization since they do not use the arm_db field.
+ */
+ if (cq->arm_db)
+ *cq->arm_db = MLX5_CQ_INIT_CMD_SN;
+
refcount_set(&cq->refcount, 1);
init_completion(&cq->free);
if (!cq->comp)
- cq->comp = mlx5_add_cq_to_tasklet;
+ cq->comp = mlx5_core_cq_dummy_cb;
/* assuming CQ will be deleted before the EQ */
cq->tasklet_ctx.priv = &eq->tasklet_ctx;
INIT_LIST_HEAD(&cq->tasklet_ctx.list);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 573a9d1ea3765..f6c15fce4a025 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -2078,7 +2078,6 @@ static int mlx5e_alloc_cq_common(struct mlx5_core_dev *mdev,
mcq->set_ci_db = cq->wq_ctrl.db.db;
mcq->arm_db = cq->wq_ctrl.db.db + 1;
*mcq->set_ci_db = 0;
- *mcq->arm_db = 0;
mcq->vector = param->eq_ix;
mcq->comp = mlx5e_completion_event;
mcq->event = mlx5e_cq_error_event;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
index cb1319974f83f..ccef64fb40b66 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
@@ -421,6 +421,13 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
__be64 *pas;
u32 i;
+ conn->cq.mcq.cqe_sz = 64;
+ conn->cq.mcq.set_ci_db = conn->cq.wq_ctrl.db.db;
+ conn->cq.mcq.arm_db = conn->cq.wq_ctrl.db.db + 1;
+ *conn->cq.mcq.set_ci_db = 0;
+ conn->cq.mcq.vector = 0;
+ conn->cq.mcq.comp = mlx5_fpga_conn_cq_complete;
+
cq_size = roundup_pow_of_two(cq_size);
MLX5_SET(cqc, temp_cqc, log_cq_size, ilog2(cq_size));
@@ -468,15 +475,7 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
if (err)
goto err_cqwq;
- conn->cq.mcq.cqe_sz = 64;
- conn->cq.mcq.set_ci_db = conn->cq.wq_ctrl.db.db;
- conn->cq.mcq.arm_db = conn->cq.wq_ctrl.db.db + 1;
- *conn->cq.mcq.set_ci_db = 0;
- *conn->cq.mcq.arm_db = 0;
- conn->cq.mcq.vector = 0;
- conn->cq.mcq.comp = mlx5_fpga_conn_cq_complete;
tasklet_setup(&conn->cq.tasklet, mlx5_fpga_conn_cq_tasklet);
-
mlx5_fpga_dbg(fdev, "Created CQ #0x%x\n", conn->cq.mcq.cqn);
goto out;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
index 34e64c1d11437..645d329367760 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
@@ -1049,12 +1049,6 @@ static int dr_prepare_qp_to_rts(struct mlx5dr_domain *dmn)
return 0;
}
-static void dr_cq_complete(struct mlx5_core_cq *mcq,
- struct mlx5_eqe *eqe)
-{
- pr_err("CQ completion CQ: #%u\n", mcq->cqn);
-}
-
static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
struct mlx5_uars_page *uar,
size_t ncqe)
@@ -1089,6 +1083,13 @@ static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
cqe->op_own = MLX5_CQE_INVALID << 4 | MLX5_CQE_OWNER_MASK;
}
+ cq->mcq.cqe_sz = 64;
+ cq->mcq.set_ci_db = cq->wq_ctrl.db.db;
+ cq->mcq.arm_db = cq->wq_ctrl.db.db + 1;
+ *cq->mcq.set_ci_db = 0;
+ cq->mcq.vector = 0;
+ cq->mdev = mdev;
+
inlen = MLX5_ST_SZ_BYTES(create_cq_in) +
sizeof(u64) * cq->wq_ctrl.buf.npages;
in = kvzalloc(inlen, GFP_KERNEL);
@@ -1112,27 +1113,12 @@ static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas);
mlx5_fill_page_frag_array(&cq->wq_ctrl.buf, pas);
- cq->mcq.comp = dr_cq_complete;
-
err = mlx5_core_create_cq(mdev, &cq->mcq, in, inlen, out, sizeof(out));
kvfree(in);
if (err)
goto err_cqwq;
- cq->mcq.cqe_sz = 64;
- cq->mcq.set_ci_db = cq->wq_ctrl.db.db;
- cq->mcq.arm_db = cq->wq_ctrl.db.db + 1;
- *cq->mcq.set_ci_db = 0;
-
- /* set no-zero value, in order to avoid the HW to run db-recovery on
- * CQ that used in polling mode.
- */
- *cq->mcq.arm_db = cpu_to_be32(2 << 28);
-
- cq->mcq.vector = 0;
- cq->mdev = mdev;
-
return cq;
err_cqwq:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c
index 7312f042d41eb..6911ce4138836 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c
@@ -748,12 +748,6 @@ static int hws_send_ring_open_sq(struct mlx5hws_context *ctx,
return err;
}
-static void hws_cq_complete(struct mlx5_core_cq *mcq,
- struct mlx5_eqe *eqe)
-{
- pr_err("CQ completion CQ: #%u\n", mcq->cqn);
-}
-
static int hws_send_ring_alloc_cq(struct mlx5_core_dev *mdev,
int numa_node,
struct mlx5hws_send_engine *queue,
@@ -776,7 +770,6 @@ static int hws_send_ring_alloc_cq(struct mlx5_core_dev *mdev,
mcq->cqe_sz = 64;
mcq->set_ci_db = cq->wq_ctrl.db.db;
mcq->arm_db = cq->wq_ctrl.db.db + 1;
- mcq->comp = hws_cq_complete;
for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) {
cqe = mlx5_cqwq_get_wqe(&cq->wq, i);
diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
index 6b8e9da15ed0b..ac4aa2e29fcc0 100644
--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
+++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
@@ -573,6 +573,8 @@ static int cq_create(struct mlx5_vdpa_net *ndev, u16 idx, u32 num_ent)
vcq->mcq.set_ci_db = vcq->db.db;
vcq->mcq.arm_db = vcq->db.db + 1;
vcq->mcq.cqe_sz = 64;
+ vcq->mcq.comp = mlx5_vdpa_cq_comp;
+ vcq->cqe = num_ent;
err = cq_frag_buf_alloc(ndev, &vcq->buf, num_ent);
if (err)
@@ -612,10 +614,6 @@ static int cq_create(struct mlx5_vdpa_net *ndev, u16 idx, u32 num_ent)
if (err)
goto err_vec;
- vcq->mcq.comp = mlx5_vdpa_cq_comp;
- vcq->cqe = num_ent;
- vcq->mcq.set_ci_db = vcq->db.db;
- vcq->mcq.arm_db = vcq->db.db + 1;
mlx5_cq_arm(&mvq->cq.mcq, MLX5_CQ_DB_REQ_NOT, uar_page, mvq->cq.mcq.cons_index);
kfree(in);
return 0;
diff --git a/include/linux/mlx5/cq.h b/include/linux/mlx5/cq.h
index 7ef2c7c7d803d..9d47cdc727ad0 100644
--- a/include/linux/mlx5/cq.h
+++ b/include/linux/mlx5/cq.h
@@ -183,6 +183,7 @@ static inline void mlx5_cq_put(struct mlx5_core_cq *cq)
complete(&cq->free);
}
+void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq, struct mlx5_eqe *eqe);
int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
u32 *in, int inlen, u32 *out, int outlen);
int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 149/869] scsi: ufs: qcom : Refactor phy_power_on/off calls
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (147 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 148/869] mlx5: Fix default values in create CQ Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 150/869] scsi: ufs: ufs-qcom: Fix UFS OCP issue during UFS power down (PC=3) Greg Kroah-Hartman
` (720 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Can Guo, Nitin Rawat, Vinod Koul,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nitin Rawat <quic_nitirawa@quicinc.com>
[ Upstream commit 77d2fa54a94574f767d5fb296b6b8e011eba0c8e ]
Commit 3f6d1767b1a0 ("phy: ufs-qcom: Refactor all init steps into
phy_poweron") moved the phy_power_on/off from ufs_qcom_setup_clocks
to suspend/resume func.
To have a better power saving, remove the phy_power_on/off calls from
resume/suspend path and put them back to ufs_qcom_setup_clocks, so that
PHY regulators & clks can be turned on/off along with UFS's clocks.
Since phy phy_power_on is separated out from phy calibrate, make
separate calls to phy_power_on calls from ufs qcom driver.
Co-developed-by: Can Guo <quic_cang@quicinc.com>
Signed-off-by: Can Guo <quic_cang@quicinc.com>
Signed-off-by: Nitin Rawat <quic_nitirawa@quicinc.com>
Link: https://lore.kernel.org/r/20250526153821.7918-11-quic_nitirawa@quicinc.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Stable-dep-of: 5127be409c6c ("scsi: ufs: ufs-qcom: Fix UFS OCP issue during UFS power down (PC=3)")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ufs/host/ufs-qcom.c | 58 +++++++++++++++++--------------------
1 file changed, 27 insertions(+), 31 deletions(-)
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index a715f377d0a80..5d93aa7067a68 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -561,26 +561,17 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
enum ufs_notify_change_status status)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct phy *phy = host->generic_phy;
if (status == PRE_CHANGE)
return 0;
- if (ufs_qcom_is_link_off(hba)) {
- /*
- * Disable the tx/rx lane symbol clocks before PHY is
- * powered down as the PLL source should be disabled
- * after downstream clocks are disabled.
- */
+ if (!ufs_qcom_is_link_active(hba))
ufs_qcom_disable_lane_clks(host);
- phy_power_off(phy);
- /* reset the connected UFS device during power down */
- ufs_qcom_device_reset_ctrl(hba, true);
- } else if (!ufs_qcom_is_link_active(hba)) {
- ufs_qcom_disable_lane_clks(host);
- }
+ /* reset the connected UFS device during power down */
+ if (ufs_qcom_is_link_off(hba) && host->device_reset)
+ ufs_qcom_device_reset_ctrl(hba, true);
return ufs_qcom_ice_suspend(host);
}
@@ -588,26 +579,11 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct phy *phy = host->generic_phy;
int err;
- if (ufs_qcom_is_link_off(hba)) {
- err = phy_power_on(phy);
- if (err) {
- dev_err(hba->dev, "%s: failed PHY power on: %d\n",
- __func__, err);
- return err;
- }
-
- err = ufs_qcom_enable_lane_clks(host);
- if (err)
- return err;
-
- } else if (!ufs_qcom_is_link_active(hba)) {
- err = ufs_qcom_enable_lane_clks(host);
- if (err)
- return err;
- }
+ err = ufs_qcom_enable_lane_clks(host);
+ if (err)
+ return err;
return ufs_qcom_ice_resume(host);
}
@@ -933,12 +909,20 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba)
* @on: If true, enable clocks else disable them.
* @status: PRE_CHANGE or POST_CHANGE notify
*
+ * There are certain clocks which comes from the PHY so it needs
+ * to be managed together along with controller clocks which also
+ * provides a better power saving. Hence keep phy_power_off/on calls
+ * in ufs_qcom_setup_clocks, so that PHY's regulators & clks can be
+ * turned on/off along with UFS's clocks.
+ *
* Return: 0 on success, non-zero on failure.
*/
static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
enum ufs_notify_change_status status)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ struct phy *phy = host->generic_phy;
+ int err;
/*
* In case ufs_qcom_init() is not yet done, simply ignore.
@@ -957,10 +941,22 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
/* disable device ref_clk */
ufs_qcom_dev_ref_clk_ctrl(host, false);
}
+
+ err = phy_power_off(phy);
+ if (err) {
+ dev_err(hba->dev, "phy power off failed, ret=%d\n", err);
+ return err;
+ }
}
break;
case POST_CHANGE:
if (on) {
+ err = phy_power_on(phy);
+ if (err) {
+ dev_err(hba->dev, "phy power on failed, ret = %d\n", err);
+ return err;
+ }
+
/* enable the device ref clock for HS mode*/
if (ufshcd_is_hs_mode(&hba->pwr_info))
ufs_qcom_dev_ref_clk_ctrl(host, true);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 150/869] scsi: ufs: ufs-qcom: Fix UFS OCP issue during UFS power down (PC=3)
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (148 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 149/869] scsi: ufs: qcom : Refactor phy_power_on/off calls Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 151/869] clk: thead: th1520-ap: set all AXI clocks to CLK_IS_CRITICAL Greg Kroah-Hartman
` (719 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nitin Rawat, Manivannan Sadhasivam,
Martin K. Petersen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nitin Rawat <nitin.rawat@oss.qualcomm.com>
[ Upstream commit 5127be409c6c3815c4a7d8f6d88043e44f9b9543 ]
According to UFS specifications, the power-off sequence for a UFS device
includes:
- Sending an SSU command with Power_Condition=3 and await a response.
- Asserting RST_N low.
- Turning off REF_CLK.
- Turning off VCC.
- Turning off VCCQ/VCCQ2.
As part of ufs shutdown, after the SSU command completion, asserting
hardware reset (HWRST) triggers the device firmware to wake up and
execute its reset routine. This routine initializes hardware blocks and
takes a few milliseconds to complete. During this time, the ICCQ draws a
large current.
This large ICCQ current may cause issues for the regulator which is
supplying power to UFS, because the turn off request from UFS driver to
the regulator framework will be immediately followed by low power
mode(LPM) request by regulator framework. This is done by framework
because UFS which is the only client is requesting for disable. So if
the rail is still in the process of shutting down while ICCQ exceeds LPM
current thresholds, and LPM mode is activated in hardware during this
state, it may trigger an overcurrent protection (OCP) fault in the
regulator.
To prevent this, a 10ms delay is added after asserting HWRST. This
allows the reset operation to complete while power rails remain active
and in high-power mode.
Currently there is no way for Host to query whether the reset is
completed or not and hence this the delay is based on experiments with
Qualcomm UFS controllers across multiple UFS vendors.
Signed-off-by: Nitin Rawat <nitin.rawat@oss.qualcomm.com>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20251012173828.9880-1-nitin.rawat@oss.qualcomm.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ufs/host/ufs-qcom.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 5d93aa7067a68..5fbcc234131f1 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -570,8 +570,21 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
/* reset the connected UFS device during power down */
- if (ufs_qcom_is_link_off(hba) && host->device_reset)
+ if (ufs_qcom_is_link_off(hba) && host->device_reset) {
ufs_qcom_device_reset_ctrl(hba, true);
+ /*
+ * After sending the SSU command, asserting the rst_n
+ * line causes the device firmware to wake up and
+ * execute its reset routine.
+ *
+ * During this process, the device may draw current
+ * beyond the permissible limit for low-power mode (LPM).
+ * A 10ms delay, based on experimental observations,
+ * allows the UFS device to complete its hardware reset
+ * before transitioning the power rail to LPM.
+ */
+ usleep_range(10000, 11000);
+ }
return ufs_qcom_ice_suspend(host);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 151/869] clk: thead: th1520-ap: set all AXI clocks to CLK_IS_CRITICAL
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (149 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 150/869] scsi: ufs: ufs-qcom: Fix UFS OCP issue during UFS power down (PC=3) Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 152/869] netconsole: Acquire su_mutex before navigating configs hierarchy Greg Kroah-Hartman
` (718 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Icenowy Zheng, Drew Fustini,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Icenowy Zheng <uwu@icenowy.me>
[ Upstream commit c567bc5fc68c4388c00e11fc65fd14fe86b52070 ]
The AXI crossbar of TH1520 has no proper timeout handling, which means
gating AXI clocks can easily lead to bus timeout and thus system hang.
Set all AXI clock gates to CLK_IS_CRITICAL. All these clock gates are
ungated by default on system reset.
In addition, convert all current CLK_IGNORE_UNUSED usage to
CLK_IS_CRITICAL to prevent unwanted clock gating.
Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Drew Fustini <fustini@kernel.org>
Signed-off-by: Drew Fustini <fustini@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/clk/thead/clk-th1520-ap.c | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c
index c8ebacc6934ab..510670b9c983e 100644
--- a/drivers/clk/thead/clk-th1520-ap.c
+++ b/drivers/clk/thead/clk-th1520-ap.c
@@ -493,7 +493,7 @@ static struct ccu_div axi4_cpusys2_aclk = {
.hw.init = CLK_HW_INIT_PARENTS_HW("axi4-cpusys2-aclk",
gmac_pll_clk_parent,
&ccu_div_ops,
- 0),
+ CLK_IS_CRITICAL),
},
};
@@ -515,7 +515,7 @@ static struct ccu_div axi_aclk = {
.hw.init = CLK_HW_INIT_PARENTS_DATA("axi-aclk",
axi_parents,
&ccu_div_ops,
- 0),
+ CLK_IS_CRITICAL),
},
};
@@ -664,7 +664,7 @@ static struct ccu_div apb_pclk = {
.hw.init = CLK_HW_INIT_PARENTS_DATA("apb-pclk",
apb_parents,
&ccu_div_ops,
- CLK_IGNORE_UNUSED),
+ CLK_IS_CRITICAL),
},
};
@@ -695,7 +695,7 @@ static struct ccu_div vi_clk = {
.hw.init = CLK_HW_INIT_PARENTS_HW("vi",
video_pll_clk_parent,
&ccu_div_ops,
- 0),
+ CLK_IS_CRITICAL),
},
};
@@ -720,7 +720,7 @@ static struct ccu_div vo_axi_clk = {
.hw.init = CLK_HW_INIT_PARENTS_HW("vo-axi",
video_pll_clk_parent,
&ccu_div_ops,
- 0),
+ CLK_IS_CRITICAL),
},
};
@@ -745,7 +745,7 @@ static struct ccu_div vp_axi_clk = {
.hw.init = CLK_HW_INIT_PARENTS_HW("vp-axi",
video_pll_clk_parent,
&ccu_div_ops,
- CLK_IGNORE_UNUSED),
+ CLK_IS_CRITICAL),
},
};
@@ -796,23 +796,23 @@ static const struct clk_parent_data emmc_sdio_ref_clk_pd[] = {
static CCU_GATE(CLK_BROM, brom_clk, "brom", ahb2_cpusys_hclk_pd, 0x100, BIT(4), 0);
static CCU_GATE(CLK_BMU, bmu_clk, "bmu", axi4_cpusys2_aclk_pd, 0x100, BIT(5), 0);
static CCU_GATE(CLK_AON2CPU_A2X, aon2cpu_a2x_clk, "aon2cpu-a2x", axi4_cpusys2_aclk_pd,
- 0x134, BIT(8), 0);
+ 0x134, BIT(8), CLK_IS_CRITICAL);
static CCU_GATE(CLK_X2X_CPUSYS, x2x_cpusys_clk, "x2x-cpusys", axi4_cpusys2_aclk_pd,
- 0x134, BIT(7), 0);
+ 0x134, BIT(7), CLK_IS_CRITICAL);
static CCU_GATE(CLK_CPU2AON_X2H, cpu2aon_x2h_clk, "cpu2aon-x2h", axi_aclk_pd,
- 0x138, BIT(8), CLK_IGNORE_UNUSED);
+ 0x138, BIT(8), CLK_IS_CRITICAL);
static CCU_GATE(CLK_CPU2PERI_X2H, cpu2peri_x2h_clk, "cpu2peri-x2h", axi4_cpusys2_aclk_pd,
- 0x140, BIT(9), CLK_IGNORE_UNUSED);
+ 0x140, BIT(9), CLK_IS_CRITICAL);
static CCU_GATE(CLK_PERISYS_APB1_HCLK, perisys_apb1_hclk, "perisys-apb1-hclk", perisys_ahb_hclk_pd,
- 0x150, BIT(9), CLK_IGNORE_UNUSED);
+ 0x150, BIT(9), CLK_IS_CRITICAL);
static CCU_GATE(CLK_PERISYS_APB2_HCLK, perisys_apb2_hclk, "perisys-apb2-hclk", perisys_ahb_hclk_pd,
- 0x150, BIT(10), CLK_IGNORE_UNUSED);
+ 0x150, BIT(10), CLK_IS_CRITICAL);
static CCU_GATE(CLK_PERISYS_APB3_HCLK, perisys_apb3_hclk, "perisys-apb3-hclk", perisys_ahb_hclk_pd,
- 0x150, BIT(11), CLK_IGNORE_UNUSED);
+ 0x150, BIT(11), CLK_IS_CRITICAL);
static CCU_GATE(CLK_PERISYS_APB4_HCLK, perisys_apb4_hclk, "perisys-apb4-hclk", perisys_ahb_hclk_pd,
0x150, BIT(12), 0);
-static CCU_GATE(CLK_NPU_AXI, npu_axi_clk, "npu-axi", axi_aclk_pd, 0x1c8, BIT(5), 0);
-static CCU_GATE(CLK_CPU2VP, cpu2vp_clk, "cpu2vp", axi_aclk_pd, 0x1e0, BIT(13), 0);
+static CCU_GATE(CLK_NPU_AXI, npu_axi_clk, "npu-axi", axi_aclk_pd, 0x1c8, BIT(5), CLK_IS_CRITICAL);
+static CCU_GATE(CLK_CPU2VP, cpu2vp_clk, "cpu2vp", axi_aclk_pd, 0x1e0, BIT(13), CLK_IS_CRITICAL);
static CCU_GATE(CLK_EMMC_SDIO, emmc_sdio_clk, "emmc-sdio", emmc_sdio_ref_clk_pd, 0x204, BIT(30), 0);
static CCU_GATE(CLK_GMAC1, gmac1_clk, "gmac1", gmac_pll_clk_pd, 0x204, BIT(26), 0);
static CCU_GATE(CLK_PADCTRL1, padctrl1_clk, "padctrl1", perisys_apb_pclk_pd, 0x204, BIT(24), 0);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 152/869] netconsole: Acquire su_mutex before navigating configs hierarchy
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (150 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 151/869] clk: thead: th1520-ap: set all AXI clocks to CLK_IS_CRITICAL Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 153/869] net: vxlan: prevent NULL deref in vxlan_xmit_one Greg Kroah-Hartman
` (717 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Gustavo Luiz Duarte, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gustavo Luiz Duarte <gustavold@gmail.com>
[ Upstream commit d7d2fcf7ae31471b4e08b7e448b8fd0ec2e06a1b ]
There is a race between operations that iterate over the userdata
cg_children list and concurrent add/remove of userdata items through
configfs. The update_userdata() function iterates over the
nt->userdata_group.cg_children list, and count_extradata_entries() also
iterates over this same list to count nodes.
Quoting from Documentation/filesystems/configfs.rst:
> A subsystem can navigate the cg_children list and the ci_parent pointer
> to see the tree created by the subsystem. This can race with configfs'
> management of the hierarchy, so configfs uses the subsystem mutex to
> protect modifications. Whenever a subsystem wants to navigate the
> hierarchy, it must do so under the protection of the subsystem
> mutex.
Without proper locking, if a userdata item is added or removed
concurrently while these functions are iterating, the list can be
accessed in an inconsistent state. For example, the list_for_each() loop
can reach a node that is being removed from the list by list_del_init()
which sets the nodes' .next pointer to point to itself, so the loop will
never end (or reach the WARN_ON_ONCE in update_userdata() ).
Fix this by holding the configfs subsystem mutex (su_mutex) during all
operations that iterate over cg_children.
This includes:
- userdatum_value_store() which calls update_userdata() to iterate over
cg_children
- All sysdata_*_enabled_store() functions which call
count_extradata_entries() to iterate over cg_children
The su_mutex must be acquired before dynamic_netconsole_mutex to avoid
potential lock ordering issues, as configfs operations may already hold
su_mutex when calling into our code.
Fixes: df03f830d099 ("net: netconsole: cache userdata formatted string in netconsole_target")
Signed-off-by: Gustavo Luiz Duarte <gustavold@gmail.com>
Link: https://patch.msgid.link/20251029-netconsole-fix-warn-v1-1-0d0dd4622f48@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/netconsole.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 0c47713b6adbc..68df8a9e1ecc8 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -748,6 +748,7 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf,
if (count > MAX_USERDATA_VALUE_LENGTH)
return -EMSGSIZE;
+ mutex_lock(&netconsole_subsys.su_mutex);
mutex_lock(&dynamic_netconsole_mutex);
ret = strscpy(udm->value, buf, sizeof(udm->value));
@@ -761,6 +762,7 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf,
ret = count;
out_unlock:
mutex_unlock(&dynamic_netconsole_mutex);
+ mutex_unlock(&netconsole_subsys.su_mutex);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 153/869] net: vxlan: prevent NULL deref in vxlan_xmit_one
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (151 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 152/869] netconsole: Acquire su_mutex before navigating configs hierarchy Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 154/869] btrfs: fix double free of qgroup record after failure to add delayed ref head Greg Kroah-Hartman
` (716 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Liang Li, Beniamino Galvani,
Antoine Tenart, Ido Schimmel, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Antoine Tenart <atenart@kernel.org>
[ Upstream commit 1f73a56f986005f0bc64ed23873930e2ee4f5911 ]
Neither sock4 nor sock6 pointers are guaranteed to be non-NULL in
vxlan_xmit_one, e.g. if the iface is brought down. This can lead to the
following NULL dereference:
BUG: kernel NULL pointer dereference, address: 0000000000000010
Oops: Oops: 0000 [#1] SMP NOPTI
RIP: 0010:vxlan_xmit_one+0xbb3/0x1580
Call Trace:
vxlan_xmit+0x429/0x610
dev_hard_start_xmit+0x55/0xa0
__dev_queue_xmit+0x6d0/0x7f0
ip_finish_output2+0x24b/0x590
ip_output+0x63/0x110
Mentioned commits changed the code path in vxlan_xmit_one and as a side
effect the sock4/6 pointer validity checks in vxlan(6)_get_route were
lost. Fix this by adding back checks.
Since both commits being fixed were released in the same version (v6.7)
and are strongly related, bundle the fixes in a single commit.
Reported-by: Liang Li <liali@redhat.com>
Fixes: 6f19b2c136d9 ("vxlan: use generic function for tunnel IPv4 route lookup")
Fixes: 2aceb896ee18 ("vxlan: use generic function for tunnel IPv6 route lookup")
Cc: Beniamino Galvani <b.galvani@gmail.com>
Signed-off-by: Antoine Tenart <atenart@kernel.org>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Tested-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20251126102627.74223-1-atenart@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/vxlan/vxlan_core.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index f612def46c3c4..567793aea4a21 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2402,7 +2402,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
int addr_family;
__u8 tos, ttl;
int ifindex;
- int err;
+ int err = 0;
u32 flags = vxlan->cfg.flags;
bool use_cache;
bool udp_sum = false;
@@ -2504,11 +2504,16 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
rcu_read_lock();
if (addr_family == AF_INET) {
- struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock);
+ struct vxlan_sock *sock4;
struct rtable *rt;
__be16 df = 0;
__be32 saddr;
+ sock4 = rcu_dereference(vxlan->vn4_sock);
+ if (unlikely(!sock4)) {
+ goto tx_error;
+ }
+
if (!ifindex)
ifindex = sock4->sock->sk->sk_bound_dev_if;
@@ -2576,9 +2581,14 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
src_port, dst_port, xnet, !udp_sum);
#if IS_ENABLED(CONFIG_IPV6)
} else {
- struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock);
+ struct vxlan_sock *sock6;
struct in6_addr saddr;
+ sock6 = rcu_dereference(vxlan->vn6_sock);
+ if (unlikely(!sock6)) {
+ goto tx_error;
+ }
+
if (!ifindex)
ifindex = sock6->sock->sk->sk_bound_dev_if;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 154/869] btrfs: fix double free of qgroup record after failure to add delayed ref head
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (152 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 153/869] net: vxlan: prevent NULL deref in vxlan_xmit_one Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 155/869] wifi: mt76: wed: use proper wed reference in mt76 wed driver callabacks Greg Kroah-Hartman
` (715 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Filipe Manana,
Miquel Sabaté Solà, David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miquel Sabaté Solà <mssola@mssola.com>
[ Upstream commit 725e46298876a2cc1f1c3fb22ba69d29102c3ddf ]
In the previous code it was possible to incur into a double kfree()
scenario when calling add_delayed_ref_head(). This could happen if the
record was reported to already exist in the
btrfs_qgroup_trace_extent_nolock() call, but then there was an error
later on add_delayed_ref_head(). In this case, since
add_delayed_ref_head() returned an error, the caller went to free the
record. Since add_delayed_ref_head() couldn't set this kfree'd pointer
to NULL, then kfree() would have acted on a non-NULL 'record' object
which was pointing to memory already freed by the callee.
The problem comes from the fact that the responsibility to kfree the
object is on both the caller and the callee at the same time. Hence, the
fix for this is to shift the ownership of the 'qrecord' object out of
the add_delayed_ref_head(). That is, we will never attempt to kfree()
the given object inside of this function, and will expect the caller to
act on the 'qrecord' object on its own. The only exception where the
'qrecord' object cannot be kfree'd is if it was inserted into the
tracing logic, for which we already have the 'qrecord_inserted_ret'
boolean to account for this. Hence, the caller has to kfree the object
only if add_delayed_ref_head() reports not to have inserted it on the
tracing logic.
As a side-effect of the above, we must guarantee that
'qrecord_inserted_ret' is properly initialized at the start of the
function, not at the end, and then set when an actual insert
happens. This way we avoid 'qrecord_inserted_ret' having an invalid
value on an early exit.
The documentation from the add_delayed_ref_head() has also been updated
to reflect on the exact ownership of the 'qrecord' object.
Fixes: 6ef8fbce0104 ("btrfs: fix missing error handling when adding delayed ref with qgroups enabled")
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/delayed-ref.c | 35 +++++++++++++++++++++++++----------
1 file changed, 25 insertions(+), 10 deletions(-)
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
index cab94d141f662..55d2a3089ac1a 100644
--- a/fs/btrfs/delayed-ref.c
+++ b/fs/btrfs/delayed-ref.c
@@ -837,9 +837,13 @@ static void init_delayed_ref_head(struct btrfs_delayed_ref_head *head_ref,
}
/*
- * helper function to actually insert a head node into the rbtree.
- * this does all the dirty work in terms of maintaining the correct
- * overall modification count.
+ * Helper function to actually insert a head node into the rbtree. This does all
+ * the dirty work in terms of maintaining the correct overall modification
+ * count.
+ *
+ * The caller is responsible for calling kfree() on @qrecord. More specifically,
+ * if this function reports that it did not insert it as noted in
+ * @qrecord_inserted_ret, then it's safe to call kfree() on it.
*
* Returns an error pointer in case of an error.
*/
@@ -852,12 +856,25 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_delayed_ref_head *existing;
struct btrfs_delayed_ref_root *delayed_refs;
- bool qrecord_inserted = false;
+
+ /*
+ * If 'qrecord_inserted_ret' is provided, then the first thing we need
+ * to do is to initialize it to false just in case we have an exit
+ * before trying to insert the record.
+ */
+ if (qrecord_inserted_ret)
+ *qrecord_inserted_ret = false;
delayed_refs = &trans->transaction->delayed_refs;
/* Record qgroup extent info if provided */
if (qrecord) {
+ /*
+ * Setting 'qrecord' but not 'qrecord_inserted_ret' will likely
+ * result in a memory leakage.
+ */
+ ASSERT(qrecord_inserted_ret != NULL);
+
int ret;
ret = btrfs_qgroup_trace_extent_nolock(fs_info, delayed_refs, qrecord);
@@ -865,12 +882,10 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans,
/* Clean up if insertion fails or item exists. */
xa_release(&delayed_refs->dirty_extents,
qrecord->bytenr >> fs_info->sectorsize_bits);
- /* Caller responsible for freeing qrecord on error. */
if (ret < 0)
return ERR_PTR(ret);
- kfree(qrecord);
- } else {
- qrecord_inserted = true;
+ } else if (qrecord_inserted_ret) {
+ *qrecord_inserted_ret = true;
}
}
@@ -902,8 +917,6 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans,
delayed_refs->num_heads_ready++;
atomic_inc(&delayed_refs->num_entries);
}
- if (qrecord_inserted_ret)
- *qrecord_inserted_ret = qrecord_inserted;
return head_ref;
}
@@ -1075,6 +1088,8 @@ static int add_delayed_ref(struct btrfs_trans_handle *trans,
if (qrecord_inserted)
return btrfs_qgroup_trace_extent_post(trans, record);
+
+ kfree(record);
return 0;
free_record:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 155/869] wifi: mt76: wed: use proper wed reference in mt76 wed driver callabacks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (153 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 154/869] btrfs: fix double free of qgroup record after failure to add delayed ref head Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 156/869] md: init bioset in mddev_init Greg Kroah-Hartman
` (714 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Daniel Pawlik, Matteo Croce,
Lorenzo Bianconi, Felix Fietkau, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <lorenzo@kernel.org>
[ Upstream commit 385aab8fccd7a8746b9f1a17f3c1e38498a14bc7 ]
MT7996 driver can use both wed and wed_hif2 devices to offload traffic
from/to the wireless NIC. In the current codebase we assume to always
use the primary wed device in wed callbacks resulting in the following
crash if the hw runs wed_hif2 (e.g. 6GHz link).
[ 297.455876] Unable to handle kernel read from unreadable memory at virtual address 000000000000080a
[ 297.464928] Mem abort info:
[ 297.467722] ESR = 0x0000000096000005
[ 297.471461] EC = 0x25: DABT (current EL), IL = 32 bits
[ 297.476766] SET = 0, FnV = 0
[ 297.479809] EA = 0, S1PTW = 0
[ 297.482940] FSC = 0x05: level 1 translation fault
[ 297.487809] Data abort info:
[ 297.490679] ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000
[ 297.496156] CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[ 297.501196] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[ 297.506500] user pgtable: 4k pages, 39-bit VAs, pgdp=0000000107480000
[ 297.512927] [000000000000080a] pgd=08000001097fb003, p4d=08000001097fb003, pud=08000001097fb003, pmd=0000000000000000
[ 297.523532] Internal error: Oops: 0000000096000005 [#1] SMP
[ 297.715393] CPU: 2 UID: 0 PID: 45 Comm: kworker/u16:2 Tainted: G O 6.12.50 #0
[ 297.723908] Tainted: [O]=OOT_MODULE
[ 297.727384] Hardware name: Banana Pi BPI-R4 (2x SFP+) (DT)
[ 297.732857] Workqueue: nf_ft_offload_del nf_flow_rule_route_ipv6 [nf_flow_table]
[ 297.740254] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 297.747205] pc : mt76_wed_offload_disable+0x64/0xa0 [mt76]
[ 297.752688] lr : mtk_wed_flow_remove+0x58/0x80
[ 297.757126] sp : ffffffc080fe3ae0
[ 297.760430] x29: ffffffc080fe3ae0 x28: ffffffc080fe3be0 x27: 00000000deadbef7
[ 297.767557] x26: ffffff80c5ebca00 x25: 0000000000000001 x24: ffffff80c85f4c00
[ 297.774683] x23: ffffff80c1875b78 x22: ffffffc080d42cd0 x21: ffffffc080660018
[ 297.781809] x20: ffffff80c6a076d0 x19: ffffff80c6a043c8 x18: 0000000000000000
[ 297.788935] x17: 0000000000000000 x16: 0000000000000001 x15: 0000000000000000
[ 297.796060] x14: 0000000000000019 x13: ffffff80c0ad8ec0 x12: 00000000fa83b2da
[ 297.803185] x11: ffffff80c02700c0 x10: ffffff80c0ad8ec0 x9 : ffffff81fef96200
[ 297.810311] x8 : ffffff80c02700c0 x7 : ffffff80c02700d0 x6 : 0000000000000002
[ 297.817435] x5 : 0000000000000400 x4 : 0000000000000000 x3 : 0000000000000000
[ 297.824561] x2 : 0000000000000001 x1 : 0000000000000800 x0 : ffffff80c6a063c8
[ 297.831686] Call trace:
[ 297.834123] mt76_wed_offload_disable+0x64/0xa0 [mt76]
[ 297.839254] mtk_wed_flow_remove+0x58/0x80
[ 297.843342] mtk_flow_offload_cmd+0x434/0x574
[ 297.847689] mtk_wed_setup_tc_block_cb+0x30/0x40
[ 297.852295] nf_flow_offload_ipv6_hook+0x7f4/0x964 [nf_flow_table]
[ 297.858466] nf_flow_rule_route_ipv6+0x438/0x4a4 [nf_flow_table]
[ 297.864463] process_one_work+0x174/0x300
[ 297.868465] worker_thread+0x278/0x430
[ 297.872204] kthread+0xd8/0xdc
[ 297.875251] ret_from_fork+0x10/0x20
[ 297.878820] Code: 928b5ae0 8b000273 91400a60 f943fa61 (79401421)
[ 297.884901] ---[ end trace 0000000000000000 ]---
Fix the issue detecting the proper wed reference to use running wed
callabacks.
Fixes: 83eafc9251d6 ("wifi: mt76: mt7996: add wed tx support")
Tested-by: Daniel Pawlik <pawlik.dan@gmail.com>
Tested-by: Matteo Croce <teknoraver@meta.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20251008-wed-fixes-v1-1-8f7678583385@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mt76.h | 9 +++++++++
drivers/net/wireless/mediatek/mt76/mt7996/mmio.c | 1 +
drivers/net/wireless/mediatek/mt76/wed.c | 10 +++++-----
include/linux/soc/mediatek/mtk_wed.h | 1 +
4 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index ffcd4509dfcae..8addbffa97c55 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -1161,6 +1161,15 @@ static inline int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q,
for (i = 0; i < ARRAY_SIZE((dev)->q_rx); i++) \
if ((dev)->q_rx[i].ndesc)
+static inline struct mt76_dev *mt76_wed_to_dev(struct mtk_wed_device *wed)
+{
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ if (wed->wlan.hif2)
+ return container_of(wed, struct mt76_dev, mmio.wed_hif2);
+#endif /* CONFIG_NET_MEDIATEK_SOC_WED */
+ return container_of(wed, struct mt76_dev, mmio.wed);
+}
+
struct mt76_dev *mt76_alloc_device(struct device *pdev, unsigned int size,
const struct ieee80211_ops *ops,
const struct mt76_driver_ops *drv_ops);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
index 01d4b54a1acc6..11e9c71e9b17a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
@@ -410,6 +410,7 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE;
wed->wlan.token_start = MT7996_TOKEN_SIZE - wed->wlan.nbuf;
+ wed->wlan.hif2 = hif2;
wed->wlan.amsdu_max_subframes = 8;
wed->wlan.amsdu_max_len = 1536;
diff --git a/drivers/net/wireless/mediatek/mt76/wed.c b/drivers/net/wireless/mediatek/mt76/wed.c
index f89e4537555c5..6798b56bc5554 100644
--- a/drivers/net/wireless/mediatek/mt76/wed.c
+++ b/drivers/net/wireless/mediatek/mt76/wed.c
@@ -8,7 +8,7 @@
void mt76_wed_release_rx_buf(struct mtk_wed_device *wed)
{
- struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
+ struct mt76_dev *dev = mt76_wed_to_dev(wed);
int i;
for (i = 0; i < dev->rx_token_size; i++) {
@@ -31,8 +31,8 @@ EXPORT_SYMBOL_GPL(mt76_wed_release_rx_buf);
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
{
- struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc;
+ struct mt76_dev *dev = mt76_wed_to_dev(wed);
struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
int i, len = SKB_WITH_OVERHEAD(q->buf_size);
struct mt76_txwi_cache *t = NULL;
@@ -84,7 +84,7 @@ EXPORT_SYMBOL_GPL(mt76_wed_init_rx_buf);
int mt76_wed_offload_enable(struct mtk_wed_device *wed)
{
- struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
+ struct mt76_dev *dev = mt76_wed_to_dev(wed);
spin_lock_bh(&dev->token_lock);
dev->token_size = wed->wlan.token_start;
@@ -168,7 +168,7 @@ EXPORT_SYMBOL_GPL(mt76_wed_dma_setup);
void mt76_wed_offload_disable(struct mtk_wed_device *wed)
{
- struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
+ struct mt76_dev *dev = mt76_wed_to_dev(wed);
spin_lock_bh(&dev->token_lock);
dev->token_size = dev->drv->token_size;
@@ -178,7 +178,7 @@ EXPORT_SYMBOL_GPL(mt76_wed_offload_disable);
void mt76_wed_reset_complete(struct mtk_wed_device *wed)
{
- struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
+ struct mt76_dev *dev = mt76_wed_to_dev(wed);
complete(&dev->mmio.wed_reset_complete);
}
diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
index a476648858a66..9b569b1300b93 100644
--- a/include/linux/soc/mediatek/mtk_wed.h
+++ b/include/linux/soc/mediatek/mtk_wed.h
@@ -154,6 +154,7 @@ struct mtk_wed_device {
bool wcid_512;
bool hw_rro;
bool msi;
+ bool hif2;
u16 token_start;
unsigned int nbuf;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 156/869] md: init bioset in mddev_init
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (154 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 155/869] wifi: mt76: wed: use proper wed reference in mt76 wed driver callabacks Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 157/869] coresight-tmc: change tmc_drvdata spinlocks type to raw_spinlock_t Greg Kroah-Hartman
` (713 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Li Nan, Xiao Ni, Yu Kuai,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Nan <linan122@huawei.com>
[ Upstream commit 381a3ce1c0ffed647c9b913e142b099c7e9d5afc ]
IO operations may be needed before md_run(), such as updating metadata
after writing sysfs. Without bioset, this triggers a NULL pointer
dereference as below:
BUG: kernel NULL pointer dereference, address: 0000000000000020
Call Trace:
md_update_sb+0x658/0xe00
new_level_store+0xc5/0x120
md_attr_store+0xc9/0x1e0
sysfs_kf_write+0x6f/0xa0
kernfs_fop_write_iter+0x141/0x2a0
vfs_write+0x1fc/0x5a0
ksys_write+0x79/0x180
__x64_sys_write+0x1d/0x30
x64_sys_call+0x2818/0x2880
do_syscall_64+0xa9/0x580
entry_SYSCALL_64_after_hwframe+0x4b/0x53
Reproducer
```
mdadm -CR /dev/md0 -l1 -n2 /dev/sd[cd]
echo inactive > /sys/block/md0/md/array_state
echo 10 > /sys/block/md0/md/new_level
```
mddev_init() can only be called once per mddev, no need to test if bioset
has been initialized anymore.
Link: https://lore.kernel.org/linux-raid/20251103125757.1405796-3-linan666@huaweicloud.com
Fixes: d981ed841930 ("md: Add new_level sysfs interface")
Signed-off-by: Li Nan <linan122@huawei.com>
Reviewed-by: Xiao Ni <xni@redhat.com>
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/md.c | 66 +++++++++++++++++++++++--------------------------
1 file changed, 31 insertions(+), 35 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index b3ba51d7da60f..a6f71253511cf 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -665,6 +665,7 @@ static void no_op(struct percpu_ref *r) {}
int mddev_init(struct mddev *mddev)
{
+ int err = 0;
if (percpu_ref_init(&mddev->active_io, active_io_release,
PERCPU_REF_ALLOW_REINIT, GFP_KERNEL))
@@ -672,10 +673,23 @@ int mddev_init(struct mddev *mddev)
if (percpu_ref_init(&mddev->writes_pending, no_op,
PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) {
- percpu_ref_exit(&mddev->active_io);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto exit_acitve_io;
}
+ err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
+ if (err)
+ goto exit_writes_pending;
+
+ err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
+ if (err)
+ goto exit_bio_set;
+
+ err = bioset_init(&mddev->io_clone_set, BIO_POOL_SIZE,
+ offsetof(struct md_io_clone, bio_clone), 0);
+ if (err)
+ goto exit_sync_set;
+
/* We want to start with the refcount at zero */
percpu_ref_put(&mddev->writes_pending);
@@ -705,11 +719,24 @@ int mddev_init(struct mddev *mddev)
INIT_WORK(&mddev->del_work, mddev_delayed_delete);
return 0;
+
+exit_sync_set:
+ bioset_exit(&mddev->sync_set);
+exit_bio_set:
+ bioset_exit(&mddev->bio_set);
+exit_writes_pending:
+ percpu_ref_exit(&mddev->writes_pending);
+exit_acitve_io:
+ percpu_ref_exit(&mddev->active_io);
+ return err;
}
EXPORT_SYMBOL_GPL(mddev_init);
void mddev_destroy(struct mddev *mddev)
{
+ bioset_exit(&mddev->bio_set);
+ bioset_exit(&mddev->sync_set);
+ bioset_exit(&mddev->io_clone_set);
percpu_ref_exit(&mddev->active_io);
percpu_ref_exit(&mddev->writes_pending);
}
@@ -6152,25 +6179,6 @@ int md_run(struct mddev *mddev)
sysfs_notify_dirent_safe(rdev->sysfs_state);
nowait = nowait && bdev_nowait(rdev->bdev);
}
-
- if (!bioset_initialized(&mddev->bio_set)) {
- err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
- if (err)
- return err;
- }
- if (!bioset_initialized(&mddev->sync_set)) {
- err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
- if (err)
- goto exit_bio_set;
- }
-
- if (!bioset_initialized(&mddev->io_clone_set)) {
- err = bioset_init(&mddev->io_clone_set, BIO_POOL_SIZE,
- offsetof(struct md_io_clone, bio_clone), 0);
- if (err)
- goto exit_sync_set;
- }
-
spin_lock(&pers_lock);
pers = find_pers(mddev->level, mddev->clevel);
if (!pers || !try_module_get(pers->owner)) {
@@ -6181,8 +6189,7 @@ int md_run(struct mddev *mddev)
else
pr_warn("md: personality for level %s is not loaded!\n",
mddev->clevel);
- err = -EINVAL;
- goto abort;
+ return -EINVAL;
}
spin_unlock(&pers_lock);
if (mddev->level != pers->level) {
@@ -6195,8 +6202,7 @@ int md_run(struct mddev *mddev)
pers->start_reshape == NULL) {
/* This personality cannot handle reshaping... */
module_put(pers->owner);
- err = -EINVAL;
- goto abort;
+ return -EINVAL;
}
if (pers->sync_request) {
@@ -6323,12 +6329,6 @@ int md_run(struct mddev *mddev)
mddev->private = NULL;
module_put(pers->owner);
mddev->bitmap_ops->destroy(mddev);
-abort:
- bioset_exit(&mddev->io_clone_set);
-exit_sync_set:
- bioset_exit(&mddev->sync_set);
-exit_bio_set:
- bioset_exit(&mddev->bio_set);
return err;
}
EXPORT_SYMBOL_GPL(md_run);
@@ -6544,10 +6544,6 @@ static void __md_stop(struct mddev *mddev)
mddev->to_remove = &md_redundancy_group;
module_put(pers->owner);
clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
-
- bioset_exit(&mddev->bio_set);
- bioset_exit(&mddev->sync_set);
- bioset_exit(&mddev->io_clone_set);
}
void md_stop(struct mddev *mddev)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 157/869] coresight-tmc: change tmc_drvdata spinlocks type to raw_spinlock_t
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (155 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 156/869] md: init bioset in mddev_init Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 158/869] coresight: ETR: Fix ETR buffer use-after-free issue Greg Kroah-Hartman
` (712 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, James Clark, Mike Leach, Yeoreum Yun,
Suzuki K Poulose, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yeoreum Yun <yeoreum.yun@arm.com>
[ Upstream commit db11f75bc29c843a70d4af1921f05d50fc72f49b ]
In coresight-tmc drivers, tmc_drvdata->spinlock can be held
during __schedule() by perf_event_task_sched_out()/in().
Since tmc_drvdata->spinlock type is spinlock_t and
perf_event_task_sched_out()/in() is called after acquiring rq_lock,
which is raw_spinlock_t (an unsleepable lock),
this poses an issue in PREEMPT_RT kernel where spinlock_t is sleepable.
To address this, change type tmc_drvdata->spinlock in coresight-tmc drivers,
which can be called by perf_event_task_sched_out()/in(),
from spinlock_t to raw_spinlock_t.
Reviewed-by: James Clark <james.clark@linaro.org>
Reviewed-by: Mike Leach <mike.leach@linaro.org>
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20250306121110.1647948-9-yeoreum.yun@arm.com
Stable-dep-of: 35501ac3c7d4 ("coresight: ETR: Fix ETR buffer use-after-free issue")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../hwtracing/coresight/coresight-tmc-core.c | 6 +--
.../hwtracing/coresight/coresight-tmc-etf.c | 48 +++++++++----------
.../hwtracing/coresight/coresight-tmc-etr.c | 40 ++++++++--------
drivers/hwtracing/coresight/coresight-tmc.h | 2 +-
4 files changed, 48 insertions(+), 48 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 96ef2517dd439..6e503ca892027 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -496,7 +496,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
drvdata->base = base;
desc.access = CSDEV_ACCESS_IOMEM(base);
- spin_lock_init(&drvdata->spinlock);
+ raw_spin_lock_init(&drvdata->spinlock);
devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
drvdata->config_type = BMVAL(devid, 6, 7);
@@ -600,7 +600,7 @@ static void tmc_shutdown(struct amba_device *adev)
unsigned long flags;
struct tmc_drvdata *drvdata = amba_get_drvdata(adev);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED)
goto out;
@@ -614,7 +614,7 @@ static void tmc_shutdown(struct amba_device *adev)
* the system is going down after this.
*/
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
}
static void __tmc_remove(struct device *dev)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index d4f641cd9de69..fca8e9ffb3cfb 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -182,9 +182,9 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
* If we don't have a buffer release the lock and allocate memory.
* Otherwise keep the lock and move along.
*/
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (!drvdata->buf) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Allocating the memory here while outside of the spinlock */
buf = kzalloc(drvdata->size, GFP_KERNEL);
@@ -192,7 +192,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
return -ENOMEM;
/* Let's try again */
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
}
if (drvdata->reading) {
@@ -235,7 +235,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
used = false;
}
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Free memory outside the spinlock if need be */
if (!used)
@@ -253,7 +253,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
struct perf_output_handle *handle = data;
struct cs_buffers *buf = etm_perf_sink_config(handle);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
do {
ret = -EINVAL;
if (drvdata->reading)
@@ -296,7 +296,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
csdev->refcnt++;
}
} while (0);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret;
}
@@ -331,16 +331,16 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
csdev->refcnt--;
if (csdev->refcnt) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
@@ -351,7 +351,7 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
drvdata->pid = -1;
coresight_set_mode(csdev, CS_MODE_DISABLED);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_dbg(&csdev->dev, "TMC-ETB/ETF disabled\n");
return 0;
@@ -366,9 +366,9 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
bool first_enable = false;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
@@ -381,7 +381,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
}
if (!ret)
csdev->refcnt++;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (first_enable)
dev_dbg(&csdev->dev, "TMC-ETF enabled\n");
@@ -396,9 +396,9 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
bool last_disable = false;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return;
}
@@ -408,7 +408,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
coresight_set_mode(csdev, CS_MODE_DISABLED);
last_disable = true;
}
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (last_disable)
dev_dbg(&csdev->dev, "TMC-ETF disabled\n");
@@ -488,7 +488,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
if (WARN_ON_ONCE(coresight_get_mode(csdev) != CS_MODE_PERF))
return 0;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't do anything if another tracer is using this sink */
if (csdev->refcnt != 1)
@@ -585,7 +585,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
*/
CS_LOCK(drvdata->base);
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return to_read;
}
@@ -623,7 +623,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
drvdata->config_type != TMC_CONFIG_TYPE_ETF))
return -EINVAL;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
ret = -EBUSY;
@@ -655,7 +655,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
drvdata->reading = true;
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret;
}
@@ -672,14 +672,14 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
drvdata->config_type != TMC_CONFIG_TYPE_ETF))
return -EINVAL;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* Re-enable the TMC if need be */
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
/* There is no point in reading a TMC in HW FIFO mode */
mode = readl_relaxed(drvdata->base + TMC_MODE);
if (mode != TMC_MODE_CIRCULAR_BUFFER) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EINVAL;
}
/*
@@ -693,7 +693,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
memset(drvdata->buf, 0, drvdata->size);
rc = __tmc_etb_enable_hw(drvdata);
if (rc) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return rc;
}
} else {
@@ -706,7 +706,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
}
drvdata->reading = false;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/*
* Free allocated memory outside of the spinlock. There is no need
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index a48bb85d0e7f4..a0a90ce7333e9 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1176,10 +1176,10 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
* buffer, provided the size matches. Any allocation has to be done
* with the lock released.
*/
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
sysfs_buf = READ_ONCE(drvdata->sysfs_buf);
if (!sysfs_buf || (sysfs_buf->size != drvdata->size)) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Allocate memory with the locks released */
free_buf = new_buf = tmc_etr_setup_sysfs_buf(drvdata);
@@ -1187,7 +1187,7 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
return new_buf;
/* Let's try again */
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
}
if (drvdata->reading || coresight_get_mode(csdev) == CS_MODE_PERF) {
@@ -1206,7 +1206,7 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
}
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Free memory outside the spinlock if need be */
if (free_buf)
@@ -1224,7 +1224,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
if (IS_ERR(sysfs_buf))
return PTR_ERR(sysfs_buf);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/*
* In sysFS mode we can have multiple writers per sink. Since this
@@ -1243,7 +1243,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
}
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (!ret)
dev_dbg(&csdev->dev, "TMC-ETR enabled\n");
@@ -1562,17 +1562,17 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
struct etr_perf_buffer *etr_perf = config;
struct etr_buf *etr_buf = etr_perf->etr_buf;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't do anything if another tracer is using this sink */
if (csdev->refcnt != 1) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
goto out;
}
if (WARN_ON(drvdata->perf_buf != etr_buf)) {
lost = true;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
goto out;
}
@@ -1582,7 +1582,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
tmc_sync_etr_buf(drvdata);
CS_LOCK(drvdata->base);
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
lost = etr_buf->full;
offset = etr_buf->offset;
@@ -1651,7 +1651,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
struct perf_output_handle *handle = data;
struct etr_perf_buffer *etr_perf = etm_perf_sink_config(handle);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't use this sink if it is already claimed by sysFS */
if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
rc = -EBUSY;
@@ -1691,7 +1691,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
}
unlock_out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return rc;
}
@@ -1713,16 +1713,16 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
csdev->refcnt--;
if (csdev->refcnt) {
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY;
}
@@ -1735,7 +1735,7 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
/* Reset perf specific data */
drvdata->perf_buf = NULL;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_dbg(&csdev->dev, "TMC-ETR disabled\n");
return 0;
@@ -1762,7 +1762,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
return -EINVAL;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
ret = -EBUSY;
goto out;
@@ -1784,7 +1784,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
drvdata->reading = true;
out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret;
}
@@ -1798,7 +1798,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
return -EINVAL;
- spin_lock_irqsave(&drvdata->spinlock, flags);
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
/* RE-enable the TMC if need be */
if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
@@ -1818,7 +1818,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
}
drvdata->reading = false;
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Free allocated memory out side of the spinlock */
if (sysfs_buf)
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 2a53acbb5990b..a9fccc3eb423e 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -197,7 +197,7 @@ struct tmc_drvdata {
void __iomem *base;
struct coresight_device *csdev;
struct miscdevice miscdev;
- spinlock_t spinlock;
+ raw_spinlock_t spinlock;
pid_t pid;
bool reading;
union {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 158/869] coresight: ETR: Fix ETR buffer use-after-free issue
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (156 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 157/869] coresight-tmc: change tmc_drvdata spinlocks type to raw_spinlock_t Greg Kroah-Hartman
@ 2026-10-17 15:49 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 159/869] wifi: ath12k: Fix MSDU buffer types handling in RX error path Greg Kroah-Hartman
` (711 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:49 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Xiaoqi Zhuang, Suzuki K Poulose,
Leo Yan, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiaoqi Zhuang <xiaoqi.zhuang@oss.qualcomm.com>
[ Upstream commit 35501ac3c7d40a7bb9568c2f89d6b56beaf9bed3 ]
When ETR is enabled as CS_MODE_SYSFS, if the buffer size is changed
and enabled again, currently sysfs_buf will point to the newly
allocated memory(buf_new) and free the old memory(buf_old). But the
etr_buf that is being used by the ETR remains pointed to buf_old, not
updated to buf_new. In this case, it will result in a memory
use-after-free issue.
Fix this by checking ETR's mode before updating and releasing buf_old,
if the mode is CS_MODE_SYSFS, then skip updating and releasing it.
Fixes: bd2767ec3df2 ("coresight: Fix run time warnings while reusing ETR buffer")
Signed-off-by: Xiaoqi Zhuang <xiaoqi.zhuang@oss.qualcomm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Tested-by: Leo Yan <leo.yan@arm.com>
Link: https://lore.kernel.org/r/20251021-fix_etr_issue-v3-1-99a2d066fee2@oss.qualcomm.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hwtracing/coresight/coresight-tmc-etr.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index a0a90ce7333e9..25f0335e2db05 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1177,6 +1177,13 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
* with the lock released.
*/
raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+
+ /*
+ * If the ETR is already enabled, continue with the existing buffer.
+ */
+ if (coresight_get_mode(csdev) == CS_MODE_SYSFS)
+ goto out;
+
sysfs_buf = READ_ONCE(drvdata->sysfs_buf);
if (!sysfs_buf || (sysfs_buf->size != drvdata->size)) {
raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 159/869] wifi: ath12k: Fix MSDU buffer types handling in RX error path
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (157 preceding siblings ...)
2026-10-17 15:49 ` [PATCH 6.12 158/869] coresight: ETR: Fix ETR buffer use-after-free issue Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 160/869] accel/ivpu: Allow to import single buffer into multiple contexts Greg Kroah-Hartman
` (710 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sarika Sharma, Baochen Qiang,
Vasanthakumar Thiagarajan, Jeff Johnson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sarika Sharma <sarika.sharma@oss.qualcomm.com>
[ Upstream commit 36f9edbb9d0fc36c865c74f3c1ad8e1261ad3981 ]
Currently, packets received on the REO exception ring from
unassociated peers are of MSDU buffer type, while the driver expects
link descriptor type packets. These packets are not parsed further due
to a return check on packet type in ath12k_hal_desc_reo_parse_err(),
but the associated skb is not freed. This may lead to kernel
crashes and buffer leaks.
Hence to fix, update the RX error handler to explicitly drop
MSDU buffer type packets received on the REO exception ring.
This prevents further processing of invalid packets and ensures
stability in the RX error handling path.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1
Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
Signed-off-by: Sarika Sharma <sarika.sharma@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250930091551.3305312-2-sarika.sharma@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath12k/dp_rx.c | 58 +++++++++++++++++++++++-
drivers/net/wireless/ath/ath12k/hal_rx.c | 10 +---
2 files changed, 59 insertions(+), 9 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index 1c0d796ffc7ad..d1248b98573ef 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/ieee80211.h>
@@ -3441,6 +3441,48 @@ ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc,
return 0;
}
+static int ath12k_dp_h_msdu_buffer_type(struct ath12k_base *ab,
+ struct list_head *list,
+ struct hal_reo_dest_ring *desc)
+{
+ struct ath12k_rx_desc_info *desc_info;
+ struct ath12k_skb_rxcb *rxcb;
+ struct sk_buff *msdu;
+ u64 desc_va;
+
+ desc_va = (u64)le32_to_cpu(desc->buf_va_hi) << 32 |
+ le32_to_cpu(desc->buf_va_lo);
+ desc_info = (struct ath12k_rx_desc_info *)(uintptr_t)desc_va;
+ if (!desc_info) {
+ u32 cookie;
+
+ cookie = le32_get_bits(desc->buf_addr_info.info1,
+ BUFFER_ADDR_INFO1_SW_COOKIE);
+ desc_info = ath12k_dp_get_rx_desc(ab, cookie);
+ if (!desc_info) {
+ ath12k_warn(ab, "Invalid cookie in manual descriptor retrieval: 0x%x\n",
+ cookie);
+ return -EINVAL;
+ }
+ }
+
+ if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC) {
+ ath12k_warn(ab, "rx exception, magic check failed with value: %u\n",
+ desc_info->magic);
+ return -EINVAL;
+ }
+
+ msdu = desc_info->skb;
+ desc_info->skb = NULL;
+ list_add_tail(&desc_info->list, list);
+ rxcb = ATH12K_SKB_RXCB(msdu);
+ dma_unmap_single(ab->dev, rxcb->paddr, msdu->len + skb_tailroom(msdu),
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(msdu);
+
+ return 0;
+}
+
int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi,
int budget)
{
@@ -3481,6 +3523,19 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi,
drop = false;
ab->soc_stats.err_ring_pkts++;
+ /* Below case is added to handle data packet from un-associated clients.
+ * As it is expected that AST lookup will fail for
+ * un-associated station's data packets.
+ */
+ if (le32_get_bits(reo_desc->info0, HAL_REO_DEST_RING_INFO0_BUFFER_TYPE) ==
+ HAL_REO_DEST_RING_BUFFER_TYPE_MSDU) {
+ if (!ath12k_dp_h_msdu_buffer_type(ab,
+ &rx_desc_used_list,
+ reo_desc))
+ tot_n_bufs_reaped++;
+ goto next_desc;
+ }
+
ret = ath12k_hal_desc_reo_parse_err(ab, reo_desc, &paddr,
&desc_bank);
if (ret) {
@@ -3529,6 +3584,7 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi,
tot_n_bufs_reaped++;
}
+next_desc:
if (tot_n_bufs_reaped >= quota) {
tot_n_bufs_reaped = quota;
goto exit;
diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.c b/drivers/net/wireless/ath/ath12k/hal_rx.c
index f7c1aaa3b5d47..ac820333047ff 100644
--- a/drivers/net/wireless/ath/ath12k/hal_rx.c
+++ b/drivers/net/wireless/ath/ath12k/hal_rx.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "debug.h"
@@ -320,7 +320,7 @@ int ath12k_hal_desc_reo_parse_err(struct ath12k_base *ab,
{
enum hal_reo_dest_ring_push_reason push_reason;
enum hal_reo_dest_ring_error_code err_code;
- u32 cookie, val;
+ u32 cookie;
push_reason = le32_get_bits(desc->info0,
HAL_REO_DEST_RING_INFO0_PUSH_REASON);
@@ -335,12 +335,6 @@ int ath12k_hal_desc_reo_parse_err(struct ath12k_base *ab,
return -EINVAL;
}
- val = le32_get_bits(desc->info0, HAL_REO_DEST_RING_INFO0_BUFFER_TYPE);
- if (val != HAL_REO_DEST_RING_BUFFER_TYPE_LINK_DESC) {
- ath12k_warn(ab, "expected buffer type link_desc");
- return -EINVAL;
- }
-
ath12k_hal_rx_reo_ent_paddr_get(ab, &desc->buf_addr_info, paddr, &cookie);
*desc_bank = u32_get_bits(cookie, DP_LINK_DESC_BANK_MASK);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 160/869] accel/ivpu: Allow to import single buffer into multiple contexts
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (158 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 159/869] wifi: ath12k: Fix MSDU buffer types handling in RX error path Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 161/869] accel/ivpu: Rework bind/unbind of imported buffers Greg Kroah-Hartman
` (709 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jacek Lawrynowicz, Tomasz Rusinowicz,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tomasz Rusinowicz <tomasz.rusinowicz@intel.com>
[ Upstream commit 67725f5e8d844e27db4514a76699ec6a7000c627 ]
Use ivpu_gem_prime_import() based on drm_gem_prime_import_dev()
for importing buffers, removing optimization for same device
imports. This optimization reused the same ivpu_bo object in multiple
contexts but a single buffer can be MMU-mapped only to a single context.
Each import now creates a new instance of ivpu_bo object that shares
the same sg_table but have separate MMU mappings.
Reviewed-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Signed-off-by: Tomasz Rusinowicz <tomasz.rusinowicz@intel.com>
Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250204084622.2422544-5-jacek.lawrynowicz@linux.intel.com
Stable-dep-of: 8b694b405a84 ("accel/ivpu: Fix page fault in ivpu_bo_unbind_all_bos_from_context()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/accel/ivpu/ivpu_drv.c | 2 +-
drivers/accel/ivpu/ivpu_gem.c | 45 ++++++++++++++++++++++++++++++++++-
drivers/accel/ivpu/ivpu_gem.h | 1 +
3 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c
index ea2909c4745ab..a811da0634e71 100644
--- a/drivers/accel/ivpu/ivpu_drv.c
+++ b/drivers/accel/ivpu/ivpu_drv.c
@@ -446,7 +446,7 @@ static const struct drm_driver driver = {
.postclose = ivpu_postclose,
.gem_create_object = ivpu_gem_create_object,
- .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table,
+ .gem_prime_import = ivpu_gem_prime_import,
.ioctls = ivpu_drm_ioctls,
.num_ioctls = ARRAY_SIZE(ivpu_drm_ioctls),
diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c
index b4213e63afb43..6f07c1d022b27 100644
--- a/drivers/accel/ivpu/ivpu_gem.c
+++ b/drivers/accel/ivpu/ivpu_gem.c
@@ -20,6 +20,8 @@
#include "ivpu_mmu.h"
#include "ivpu_mmu_context.h"
+MODULE_IMPORT_NS(DMA_BUF);
+
static const struct drm_gem_object_funcs ivpu_gem_funcs;
static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, const char *action)
@@ -177,6 +179,47 @@ struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t siz
return &bo->base.base;
}
+struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct device *attach_dev = dev->dev;
+ struct dma_buf_attachment *attach;
+ struct sg_table *sgt;
+ struct drm_gem_object *obj;
+ int ret;
+
+ attach = dma_buf_attach(dma_buf, attach_dev);
+ if (IS_ERR(attach))
+ return ERR_CAST(attach);
+
+ get_dma_buf(dma_buf);
+
+ sgt = dma_buf_map_attachment_unlocked(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sgt)) {
+ ret = PTR_ERR(sgt);
+ goto fail_detach;
+ }
+
+ obj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt);
+ if (IS_ERR(obj)) {
+ ret = PTR_ERR(obj);
+ goto fail_unmap;
+ }
+
+ obj->import_attach = attach;
+ obj->resv = dma_buf->resv;
+
+ return obj;
+
+fail_unmap:
+ dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_BIDIRECTIONAL);
+fail_detach:
+ dma_buf_detach(dma_buf, attach);
+ dma_buf_put(dma_buf);
+
+ return ERR_PTR(ret);
+}
+
static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, u32 ctx_id)
{
struct drm_gem_shmem_object *shmem;
@@ -203,7 +246,7 @@ static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 fla
list_add_tail(&bo->bo_list_node, &vdev->bo_list);
mutex_unlock(&vdev->bo_list_lock);
- ivpu_dbg_bo(vdev, bo, "alloc");
+ ivpu_dbg(vdev, BO, " alloc: bo %8p size %9llu\n", bo, size);
return bo;
}
diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h
index df8e65b77ec41..efca279758c8b 100644
--- a/drivers/accel/ivpu/ivpu_gem.h
+++ b/drivers/accel/ivpu/ivpu_gem.h
@@ -28,6 +28,7 @@ int ivpu_bo_pin(struct ivpu_bo *bo);
void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx);
struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size);
+struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf);
struct ivpu_bo *ivpu_bo_create(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
struct ivpu_addr_range *range, u64 size, u32 flags);
struct ivpu_bo *ivpu_bo_create_global(struct ivpu_device *vdev, u64 size, u32 flags);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 161/869] accel/ivpu: Rework bind/unbind of imported buffers
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (159 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 160/869] accel/ivpu: Allow to import single buffer into multiple contexts Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 162/869] accel/ivpu: Fix page fault in ivpu_bo_unbind_all_bos_from_context() Greg Kroah-Hartman
` (708 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jacek Lawrynowicz, Maciej Falkowski,
Karol Wachowski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
[ Upstream commit e0c0891cd63bf8338c25c423e28a5a93aed3d74c ]
Ensure that imported buffers are properly mapped and unmapped in
the same way as regular buffers to properly handle buffers during
device's bind and unbind operations to prevent resource leaks and
inconsistent buffer states.
Imported buffers are now dma_mapped before submission and
dma_unmapped in ivpu_bo_unbind(), guaranteeing they are unmapped
when the device is unbound.
Add also imported buffers to vdev->bo_list for consistent unmapping
on device unbind. The bo->ctx_id is set in open() so imported
buffers have a valid context ID.
Debug logs have been updated to match the new code structure.
The function ivpu_bo_pin() has been renamed to ivpu_bo_bind()
to better reflect its purpose, and unbind tests have been refactored
for improved coverage and clarity.
Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Signed-off-by: Maciej Falkowski <maciej.falkowski@linux.intel.com>
Reviewed-by: Karol Wachowski <karol.wachowski@linux.intel.com>
Signed-off-by: Karol Wachowski <karol.wachowski@linux.intel.com>
Link: https://lore.kernel.org/r/20250925145059.1446243-1-maciej.falkowski@linux.intel.com
Stable-dep-of: 8b694b405a84 ("accel/ivpu: Fix page fault in ivpu_bo_unbind_all_bos_from_context()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/accel/ivpu/ivpu_gem.c | 89 ++++++++++++++++++++++-------------
drivers/accel/ivpu/ivpu_gem.h | 2 +-
drivers/accel/ivpu/ivpu_job.c | 2 +-
3 files changed, 59 insertions(+), 34 deletions(-)
diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c
index 6f07c1d022b27..b236a2e32bc0a 100644
--- a/drivers/accel/ivpu/ivpu_gem.c
+++ b/drivers/accel/ivpu/ivpu_gem.c
@@ -27,8 +27,8 @@ static const struct drm_gem_object_funcs ivpu_gem_funcs;
static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, const char *action)
{
ivpu_dbg(vdev, BO,
- "%6s: bo %8p vpu_addr %9llx size %8zu ctx %d has_pages %d dma_mapped %d mmu_mapped %d wc %d imported %d\n",
- action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx_id,
+ "%6s: bo %8p size %9zu ctx %d vpu_addr %9llx pages %d sgt %d mmu_mapped %d wc %d imported %d\n",
+ action, bo, ivpu_bo_size(bo), bo->ctx_id, bo->vpu_addr,
(bool)bo->base.pages, (bool)bo->base.sgt, bo->mmu_mapped, bo->base.map_wc,
(bool)bo->base.base.import_attach);
}
@@ -43,22 +43,46 @@ static inline void ivpu_bo_unlock(struct ivpu_bo *bo)
dma_resv_unlock(bo->base.base.resv);
}
+static struct sg_table *ivpu_bo_map_attachment(struct ivpu_device *vdev, struct ivpu_bo *bo)
+{
+ struct sg_table *sgt = bo->base.sgt;
+
+ drm_WARN_ON(&vdev->drm, !bo->base.base.import_attach);
+
+ ivpu_bo_lock(bo);
+
+ if (!sgt) {
+ sgt = dma_buf_map_attachment(bo->base.base.import_attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sgt))
+ ivpu_err(vdev, "Failed to map BO in IOMMU: %ld\n", PTR_ERR(sgt));
+ else
+ bo->base.sgt = sgt;
+ }
+
+ ivpu_bo_unlock(bo);
+
+ return sgt;
+}
+
/*
- * ivpu_bo_pin() - pin the backing physical pages and map them to VPU.
+ * ivpu_bo_bind() - pin the backing physical pages and map them to VPU.
*
* This function pins physical memory pages, then maps the physical pages
* to IOMMU address space and finally updates the VPU MMU page tables
* to allow the VPU to translate VPU address to IOMMU address.
*/
-int __must_check ivpu_bo_pin(struct ivpu_bo *bo)
+int __must_check ivpu_bo_bind(struct ivpu_bo *bo)
{
struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
struct sg_table *sgt;
int ret = 0;
- ivpu_dbg_bo(vdev, bo, "pin");
+ ivpu_dbg_bo(vdev, bo, "bind");
- sgt = drm_gem_shmem_get_pages_sgt(&bo->base);
+ if (bo->base.base.import_attach)
+ sgt = ivpu_bo_map_attachment(vdev, bo);
+ else
+ sgt = drm_gem_shmem_get_pages_sgt(&bo->base);
if (IS_ERR(sgt)) {
ret = PTR_ERR(sgt);
ivpu_err(vdev, "Failed to map BO in IOMMU: %d\n", ret);
@@ -99,7 +123,9 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx,
ret = ivpu_mmu_context_insert_node(ctx, range, ivpu_bo_size(bo), &bo->mm_node);
if (!ret) {
bo->ctx = ctx;
+ bo->ctx_id = ctx->id;
bo->vpu_addr = bo->mm_node.start;
+ ivpu_dbg_bo(vdev, bo, "vaddr");
} else {
ivpu_err(vdev, "Failed to add BO to context %u: %d\n", ctx->id, ret);
}
@@ -115,7 +141,7 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo)
{
struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
- lockdep_assert(dma_resv_held(bo->base.base.resv) || !kref_read(&bo->base.base.refcount));
+ dma_resv_assert_held(bo->base.base.resv);
if (bo->mmu_mapped) {
drm_WARN_ON(&vdev->drm, !bo->ctx);
@@ -134,9 +160,14 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo)
return;
if (bo->base.sgt) {
- dma_unmap_sgtable(vdev->drm.dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0);
- sg_free_table(bo->base.sgt);
- kfree(bo->base.sgt);
+ if (bo->base.base.import_attach) {
+ dma_buf_unmap_attachment(bo->base.base.import_attach,
+ bo->base.sgt, DMA_BIDIRECTIONAL);
+ } else {
+ dma_unmap_sgtable(vdev->drm.dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0);
+ sg_free_table(bo->base.sgt);
+ kfree(bo->base.sgt);
+ }
bo->base.sgt = NULL;
}
}
@@ -162,6 +193,7 @@ void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_m
struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size)
{
+ struct ivpu_device *vdev = to_ivpu_device(dev);
struct ivpu_bo *bo;
if (size == 0 || !PAGE_ALIGNED(size))
@@ -176,6 +208,11 @@ struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t siz
INIT_LIST_HEAD(&bo->bo_list_node);
+ mutex_lock(&vdev->bo_list_lock);
+ list_add_tail(&bo->bo_list_node, &vdev->bo_list);
+ mutex_unlock(&vdev->bo_list_lock);
+
+ ivpu_dbg(vdev, BO, " alloc: bo %8p size %9zu\n", bo, size);
return &bo->base.base;
}
@@ -184,7 +221,6 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev,
{
struct device *attach_dev = dev->dev;
struct dma_buf_attachment *attach;
- struct sg_table *sgt;
struct drm_gem_object *obj;
int ret;
@@ -194,16 +230,10 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev,
get_dma_buf(dma_buf);
- sgt = dma_buf_map_attachment_unlocked(attach, DMA_BIDIRECTIONAL);
- if (IS_ERR(sgt)) {
- ret = PTR_ERR(sgt);
- goto fail_detach;
- }
-
- obj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt);
+ obj = drm_gem_shmem_prime_import_sg_table(dev, attach, NULL);
if (IS_ERR(obj)) {
ret = PTR_ERR(obj);
- goto fail_unmap;
+ goto fail_detach;
}
obj->import_attach = attach;
@@ -211,8 +241,6 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev,
return obj;
-fail_unmap:
- dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_BIDIRECTIONAL);
fail_detach:
dma_buf_detach(dma_buf, attach);
dma_buf_put(dma_buf);
@@ -220,7 +248,7 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev,
return ERR_PTR(ret);
}
-static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, u32 ctx_id)
+static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags)
{
struct drm_gem_shmem_object *shmem;
struct ivpu_bo *bo;
@@ -238,16 +266,9 @@ static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 fla
return ERR_CAST(shmem);
bo = to_ivpu_bo(&shmem->base);
- bo->ctx_id = ctx_id;
bo->base.map_wc = flags & DRM_IVPU_BO_WC;
bo->flags = flags;
- mutex_lock(&vdev->bo_list_lock);
- list_add_tail(&bo->bo_list_node, &vdev->bo_list);
- mutex_unlock(&vdev->bo_list_lock);
-
- ivpu_dbg(vdev, BO, " alloc: bo %8p size %9llu\n", bo, size);
-
return bo;
}
@@ -281,6 +302,8 @@ static void ivpu_gem_bo_free(struct drm_gem_object *obj)
ivpu_dbg_bo(vdev, bo, "free");
+ drm_WARN_ON(&vdev->drm, list_empty(&bo->bo_list_node));
+
mutex_lock(&vdev->bo_list_lock);
list_del(&bo->bo_list_node);
@@ -289,7 +312,9 @@ static void ivpu_gem_bo_free(struct drm_gem_object *obj)
drm_WARN_ON(&vdev->drm, ivpu_bo_size(bo) == 0);
drm_WARN_ON(&vdev->drm, bo->base.vaddr);
+ ivpu_bo_lock(bo);
ivpu_bo_unbind_locked(bo);
+ ivpu_bo_unlock(bo);
mutex_unlock(&vdev->bo_list_lock);
drm_WARN_ON(&vdev->drm, bo->mmu_mapped);
@@ -327,7 +352,7 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
if (size == 0)
return -EINVAL;
- bo = ivpu_bo_alloc(vdev, size, args->flags, file_priv->ctx.id);
+ bo = ivpu_bo_alloc(vdev, size, args->flags);
if (IS_ERR(bo)) {
ivpu_err(vdev, "Failed to allocate BO: %pe (ctx %u size %llu flags 0x%x)",
bo, file_priv->ctx.id, args->size, args->flags);
@@ -361,7 +386,7 @@ ivpu_bo_create(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(range->end));
drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(size));
- bo = ivpu_bo_alloc(vdev, size, flags, IVPU_GLOBAL_CONTEXT_MMU_SSID);
+ bo = ivpu_bo_alloc(vdev, size, flags);
if (IS_ERR(bo)) {
ivpu_err(vdev, "Failed to allocate BO: %pe (vpu_addr 0x%llx size %llu flags 0x%x)",
bo, range->start, size, flags);
@@ -372,7 +397,7 @@ ivpu_bo_create(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
if (ret)
goto err_put;
- ret = ivpu_bo_pin(bo);
+ ret = ivpu_bo_bind(bo);
if (ret)
goto err_put;
diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h
index efca279758c8b..57c9c2db02069 100644
--- a/drivers/accel/ivpu/ivpu_gem.h
+++ b/drivers/accel/ivpu/ivpu_gem.h
@@ -24,7 +24,7 @@ struct ivpu_bo {
bool mmu_mapped;
};
-int ivpu_bo_pin(struct ivpu_bo *bo);
+int ivpu_bo_bind(struct ivpu_bo *bo);
void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx);
struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size);
diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c
index 172502b71b9cf..3856d9683ed86 100644
--- a/drivers/accel/ivpu/ivpu_job.c
+++ b/drivers/accel/ivpu/ivpu_job.c
@@ -668,7 +668,7 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32
job->bos[i] = to_ivpu_bo(obj);
- ret = ivpu_bo_pin(job->bos[i]);
+ ret = ivpu_bo_bind(job->bos[i]);
if (ret)
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 162/869] accel/ivpu: Fix page fault in ivpu_bo_unbind_all_bos_from_context()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (160 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 161/869] accel/ivpu: Rework bind/unbind of imported buffers Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 163/869] drm/panthor: Prevent potential UAF in group creation Greg Kroah-Hartman
` (707 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jacek Lawrynowicz, Maciej Falkowski,
Karol Wachowski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
[ Upstream commit 8b694b405a84696f1d964f6da7cf9721e68c4714 ]
Don't add BO to the vdev->bo_list in ivpu_gem_create_object().
When failure happens inside drm_gem_shmem_create(), the BO is not
fully created and ivpu_gem_bo_free() callback will not be called
causing a deleted BO to be left on the list.
Fixes: 8d88e4cdce4f ("accel/ivpu: Use GEM shmem helper for all buffers")
Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Signed-off-by: Maciej Falkowski <maciej.falkowski@linux.intel.com>
Reviewed-by: Karol Wachowski <karol.wachowski@linux.intel.com>
Signed-off-by: Karol Wachowski <karol.wachowski@linux.intel.com>
Link: https://lore.kernel.org/r/20250925145114.1446283-1-maciej.falkowski@linux.intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/accel/ivpu/ivpu_gem.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c
index b236a2e32bc0a..1f66355ffe9fb 100644
--- a/drivers/accel/ivpu/ivpu_gem.c
+++ b/drivers/accel/ivpu/ivpu_gem.c
@@ -193,7 +193,6 @@ void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_m
struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size)
{
- struct ivpu_device *vdev = to_ivpu_device(dev);
struct ivpu_bo *bo;
if (size == 0 || !PAGE_ALIGNED(size))
@@ -208,20 +207,17 @@ struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t siz
INIT_LIST_HEAD(&bo->bo_list_node);
- mutex_lock(&vdev->bo_list_lock);
- list_add_tail(&bo->bo_list_node, &vdev->bo_list);
- mutex_unlock(&vdev->bo_list_lock);
-
- ivpu_dbg(vdev, BO, " alloc: bo %8p size %9zu\n", bo, size);
return &bo->base.base;
}
struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev,
struct dma_buf *dma_buf)
{
+ struct ivpu_device *vdev = to_ivpu_device(dev);
struct device *attach_dev = dev->dev;
struct dma_buf_attachment *attach;
struct drm_gem_object *obj;
+ struct ivpu_bo *bo;
int ret;
attach = dma_buf_attach(dma_buf, attach_dev);
@@ -239,6 +235,14 @@ struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev,
obj->import_attach = attach;
obj->resv = dma_buf->resv;
+ bo = to_ivpu_bo(obj);
+
+ mutex_lock(&vdev->bo_list_lock);
+ list_add_tail(&bo->bo_list_node, &vdev->bo_list);
+ mutex_unlock(&vdev->bo_list_lock);
+
+ ivpu_dbg(vdev, BO, "import: bo %8p size %9zu\n", bo, ivpu_bo_size(bo));
+
return obj;
fail_detach:
@@ -269,6 +273,12 @@ static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 fla
bo->base.map_wc = flags & DRM_IVPU_BO_WC;
bo->flags = flags;
+ mutex_lock(&vdev->bo_list_lock);
+ list_add_tail(&bo->bo_list_node, &vdev->bo_list);
+ mutex_unlock(&vdev->bo_list_lock);
+
+ ivpu_dbg(vdev, BO, " alloc: bo %8p size %9llu\n", bo, size);
+
return bo;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 163/869] drm/panthor: Prevent potential UAF in group creation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (161 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 162/869] accel/ivpu: Fix page fault in ivpu_bo_unbind_all_bos_from_context() Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 164/869] scsi: qla2xxx: Clear cmds after chip reset Greg Kroah-Hartman
` (706 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Boris Brezillon, Akash Goel,
Steven Price, Chia-I Wu, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Akash Goel <akash.goel@arm.com>
[ Upstream commit eec7e23d848d2194dd8791fcd0f4a54d4378eecd ]
This commit prevents the possibility of a use after free issue in the
GROUP_CREATE ioctl function, which arose as pointer to the group is
accessed in that ioctl function after storing it in the Xarray.
A malicious userspace can second guess the handle of a group and try
to call GROUP_DESTROY ioctl from another thread around the same time
as GROUP_CREATE ioctl.
To prevent the use after free exploit, this commit uses a mark on an
entry of group pool Xarray which is added just before returning from
the GROUP_CREATE ioctl function. The mark is checked for all ioctls
that specify the group handle and so userspace won't be abe to delete
a group that isn't marked yet.
v2: Add R-bs and fixes tags
Fixes: de85488138247 ("drm/panthor: Add the scheduler logical block")
Co-developed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Akash Goel <akash.goel@arm.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Reviewed-by: Chia-I Wu <olvaffe@gmail.com>
Link: https://patch.msgid.link/20251127164912.3788155-1-akash.goel@arm.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/panthor/panthor_sched.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index 822b003893a89..c1fc52f1ee426 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -742,6 +742,12 @@ struct panthor_job_profiling_data {
*/
#define MAX_GROUPS_PER_POOL 128
+/*
+ * Mark added on an entry of group pool Xarray to identify if the group has
+ * been fully initialized and can be accessed elsewhere in the driver code.
+ */
+#define GROUP_REGISTERED XA_MARK_1
+
/**
* struct panthor_group_pool - Group pool
*
@@ -3509,6 +3515,8 @@ int panthor_group_create(struct panthor_file *pfile,
}
mutex_unlock(&sched->reset.lock);
+ xa_set_mark(&gpool->xa, gid, GROUP_REGISTERED);
+
return gid;
err_put_group:
@@ -3523,6 +3531,9 @@ int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle)
struct panthor_scheduler *sched = ptdev->scheduler;
struct panthor_group *group;
+ if (!xa_get_mark(&gpool->xa, group_handle, GROUP_REGISTERED))
+ return -EINVAL;
+
group = xa_erase(&gpool->xa, group_handle);
if (!group)
return -EINVAL;
@@ -3548,12 +3559,12 @@ int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle)
}
static struct panthor_group *group_from_handle(struct panthor_group_pool *pool,
- u32 group_handle)
+ unsigned long group_handle)
{
struct panthor_group *group;
xa_lock(&pool->xa);
- group = group_get(xa_load(&pool->xa, group_handle));
+ group = group_get(xa_find(&pool->xa, &group_handle, group_handle, GROUP_REGISTERED));
xa_unlock(&pool->xa);
return group;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 164/869] scsi: qla2xxx: Clear cmds after chip reset
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (162 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 163/869] drm/panthor: Prevent potential UAF in group creation Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 165/869] s390/fpu: Fix false-positive kmsan report in fpu_vstl() Greg Kroah-Hartman
` (705 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dmitry Bogdanov, Tony Battersby,
Martin K. Petersen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tony Battersby <tonyb@cybernetics.com>
[ Upstream commit d46c69a087aa3d1513f7a78f871b80251ea0c1ae ]
Commit aefed3e5548f ("scsi: qla2xxx: target: Fix offline port handling
and host reset handling") caused two problems:
1. Commands sent to FW, after chip reset got stuck and never freed as FW
is not going to respond to them anymore.
2. BUG_ON(cmd->sg_mapped) in qlt_free_cmd(). Commit 26f9ce53817a
("scsi: qla2xxx: Fix missed DMA unmap for aborted commands")
attempted to fix this, but introduced another bug under different
circumstances when two different CPUs were racing to call
qlt_unmap_sg() at the same time: BUG_ON(!valid_dma_direction(dir)) in
dma_unmap_sg_attrs().
So revert "scsi: qla2xxx: Fix missed DMA unmap for aborted commands" and
partially revert "scsi: qla2xxx: target: Fix offline port handling and
host reset handling" at __qla2x00_abort_all_cmds.
Fixes: aefed3e5548f ("scsi: qla2xxx: target: Fix offline port handling and host reset handling")
Fixes: 26f9ce53817a ("scsi: qla2xxx: Fix missed DMA unmap for aborted commands")
Co-developed-by: Dmitry Bogdanov <d.bogdanov@yadro.com>
Signed-off-by: Dmitry Bogdanov <d.bogdanov@yadro.com>
Signed-off-by: Tony Battersby <tonyb@cybernetics.com>
Link: https://patch.msgid.link/0e7e5d26-e7a0-42d1-8235-40eeb27f3e98@cybernetics.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/scsi/qla2xxx/qla_os.c | 20 ++++++++++++++++++--
drivers/scsi/qla2xxx/qla_target.c | 5 +----
drivers/scsi/qla2xxx/qla_target.h | 1 +
3 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 457fb3458ca7c..56330f6a396e1 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1888,10 +1888,26 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res)
continue;
}
cmd = (struct qla_tgt_cmd *)sp;
- cmd->aborted = 1;
+
+ if (cmd->sg_mapped)
+ qlt_unmap_sg(vha, cmd);
+
+ if (cmd->state == QLA_TGT_STATE_NEED_DATA) {
+ cmd->aborted = 1;
+ cmd->write_data_transferred = 0;
+ cmd->state = QLA_TGT_STATE_DATA_IN;
+ ha->tgt.tgt_ops->handle_data(cmd);
+ } else {
+ ha->tgt.tgt_ops->free_cmd(cmd);
+ }
break;
case TYPE_TGT_TMCMD:
- /* Skip task management functions. */
+ /*
+ * Currently, only ABTS response gets on the
+ * outstanding_cmds[]
+ */
+ ha->tgt.tgt_ops->free_mcmd(
+ (struct qla_tgt_mgmt_cmd *) sp);
break;
default:
break;
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 11eadb3bd36e5..a1f913fb84cb0 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -2487,7 +2487,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm)
return -1;
}
-static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
+void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
{
struct qla_hw_data *ha;
struct qla_qpair *qpair;
@@ -3817,9 +3817,6 @@ int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
spin_lock_irqsave(&cmd->cmd_lock, flags);
if (cmd->aborted) {
- if (cmd->sg_mapped)
- qlt_unmap_sg(vha, cmd);
-
spin_unlock_irqrestore(&cmd->cmd_lock, flags);
/*
* It's normal to see 2 calls in this path:
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index 354fca2e7feb2..3644ab140ff94 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -1059,6 +1059,7 @@ extern int qlt_abort_cmd(struct qla_tgt_cmd *);
extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
+extern void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd);
extern void qlt_async_event(uint16_t, struct scsi_qla_host *, uint16_t *);
extern void qlt_enable_vha(struct scsi_qla_host *);
extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 165/869] s390/fpu: Fix false-positive kmsan report in fpu_vstl()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (163 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 164/869] scsi: qla2xxx: Clear cmds after chip reset Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 166/869] staging: most: remove broken i2c driver Greg Kroah-Hartman
` (704 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Aleksei Nikiforov, Heiko Carstens,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksei Nikiforov <aleksei.nikiforov@linux.ibm.com>
[ Upstream commit 14e4e4175b64dd9216b522f6ece8af6997d063b2 ]
A false-positive kmsan report is detected when running ping command.
An inline assembly instruction 'vstl' can write varied amount of bytes
depending on value of 'index' argument. If 'index' > 0, 'vstl' writes
at least 2 bytes.
clang generates kmsan write helper call depending on inline assembly
constraints. Constraints are evaluated compile-time, but value of
'index' argument is known only at runtime.
clang currently generates call to __msan_instrument_asm_store with 1 byte
as size. Manually call kmsan function to indicate correct amount of bytes
written and fix false-positive report.
This change fixes following kmsan reports:
[ 36.563119] =====================================================
[ 36.563594] BUG: KMSAN: uninit-value in virtqueue_add+0x35c6/0x7c70
[ 36.563852] virtqueue_add+0x35c6/0x7c70
[ 36.564016] virtqueue_add_outbuf+0xa0/0xb0
[ 36.564266] start_xmit+0x288c/0x4a20
[ 36.564460] dev_hard_start_xmit+0x302/0x900
[ 36.564649] sch_direct_xmit+0x340/0xea0
[ 36.564894] __dev_queue_xmit+0x2e94/0x59b0
[ 36.565058] neigh_resolve_output+0x936/0xb40
[ 36.565278] __neigh_update+0x2f66/0x3a60
[ 36.565499] neigh_update+0x52/0x60
[ 36.565683] arp_process+0x1588/0x2de0
[ 36.565916] NF_HOOK+0x1da/0x240
[ 36.566087] arp_rcv+0x3e4/0x6e0
[ 36.566306] __netif_receive_skb_list_core+0x1374/0x15a0
[ 36.566527] netif_receive_skb_list_internal+0x1116/0x17d0
[ 36.566710] napi_complete_done+0x376/0x740
[ 36.566918] virtnet_poll+0x1bae/0x2910
[ 36.567130] __napi_poll+0xf4/0x830
[ 36.567294] net_rx_action+0x97c/0x1ed0
[ 36.567556] handle_softirqs+0x306/0xe10
[ 36.567731] irq_exit_rcu+0x14c/0x2e0
[ 36.567910] do_io_irq+0xd4/0x120
[ 36.568139] io_int_handler+0xc2/0xe8
[ 36.568299] arch_cpu_idle+0xb0/0xc0
[ 36.568540] arch_cpu_idle+0x76/0xc0
[ 36.568726] default_idle_call+0x40/0x70
[ 36.568953] do_idle+0x1d6/0x390
[ 36.569486] cpu_startup_entry+0x9a/0xb0
[ 36.569745] rest_init+0x1ea/0x290
[ 36.570029] start_kernel+0x95e/0xb90
[ 36.570348] startup_continue+0x2e/0x40
[ 36.570703]
[ 36.570798] Uninit was created at:
[ 36.571002] kmem_cache_alloc_node_noprof+0x9e8/0x10e0
[ 36.571261] kmalloc_reserve+0x12a/0x470
[ 36.571553] __alloc_skb+0x310/0x860
[ 36.571844] __ip_append_data+0x483e/0x6a30
[ 36.572170] ip_append_data+0x11c/0x1e0
[ 36.572477] raw_sendmsg+0x1c8c/0x2180
[ 36.572818] inet_sendmsg+0xe6/0x190
[ 36.573142] __sys_sendto+0x55e/0x8e0
[ 36.573392] __s390x_sys_socketcall+0x19ae/0x2ba0
[ 36.573571] __do_syscall+0x12e/0x240
[ 36.573823] system_call+0x6e/0x90
[ 36.573976]
[ 36.574017] Byte 35 of 98 is uninitialized
[ 36.574082] Memory access of size 98 starts at 0000000007aa0012
[ 36.574218]
[ 36.574325] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G B N 6.17.0-dirty #16 NONE
[ 36.574541] Tainted: [B]=BAD_PAGE, [N]=TEST
[ 36.574617] Hardware name: IBM 3931 A01 703 (KVM/Linux)
[ 36.574755] =====================================================
[ 63.532541] =====================================================
[ 63.533639] BUG: KMSAN: uninit-value in virtqueue_add+0x35c6/0x7c70
[ 63.533989] virtqueue_add+0x35c6/0x7c70
[ 63.534940] virtqueue_add_outbuf+0xa0/0xb0
[ 63.535861] start_xmit+0x288c/0x4a20
[ 63.536708] dev_hard_start_xmit+0x302/0x900
[ 63.537020] sch_direct_xmit+0x340/0xea0
[ 63.537997] __dev_queue_xmit+0x2e94/0x59b0
[ 63.538819] neigh_resolve_output+0x936/0xb40
[ 63.539793] ip_finish_output2+0x1ee2/0x2200
[ 63.540784] __ip_finish_output+0x272/0x7a0
[ 63.541765] ip_finish_output+0x4e/0x5e0
[ 63.542791] ip_output+0x166/0x410
[ 63.543771] ip_push_pending_frames+0x1a2/0x470
[ 63.544753] raw_sendmsg+0x1f06/0x2180
[ 63.545033] inet_sendmsg+0xe6/0x190
[ 63.546006] __sys_sendto+0x55e/0x8e0
[ 63.546859] __s390x_sys_socketcall+0x19ae/0x2ba0
[ 63.547730] __do_syscall+0x12e/0x240
[ 63.548019] system_call+0x6e/0x90
[ 63.548989]
[ 63.549779] Uninit was created at:
[ 63.550691] kmem_cache_alloc_node_noprof+0x9e8/0x10e0
[ 63.550975] kmalloc_reserve+0x12a/0x470
[ 63.551969] __alloc_skb+0x310/0x860
[ 63.552949] __ip_append_data+0x483e/0x6a30
[ 63.553902] ip_append_data+0x11c/0x1e0
[ 63.554912] raw_sendmsg+0x1c8c/0x2180
[ 63.556719] inet_sendmsg+0xe6/0x190
[ 63.557534] __sys_sendto+0x55e/0x8e0
[ 63.557875] __s390x_sys_socketcall+0x19ae/0x2ba0
[ 63.558869] __do_syscall+0x12e/0x240
[ 63.559832] system_call+0x6e/0x90
[ 63.560780]
[ 63.560972] Byte 35 of 98 is uninitialized
[ 63.561741] Memory access of size 98 starts at 0000000005704312
[ 63.561950]
[ 63.562824] CPU: 3 UID: 0 PID: 192 Comm: ping Tainted: G B N 6.17.0-dirty #16 NONE
[ 63.563868] Tainted: [B]=BAD_PAGE, [N]=TEST
[ 63.564751] Hardware name: IBM 3931 A01 703 (KVM/Linux)
[ 63.564986] =====================================================
Fixes: dcd3e1de9d17 ("s390/checksum: provide csum_partial_copy_nocheck()")
Signed-off-by: Aleksei Nikiforov <aleksei.nikiforov@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/include/asm/fpu-insn.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/s390/include/asm/fpu-insn.h b/arch/s390/include/asm/fpu-insn.h
index a4c9b4db62ff5..c74c6056087fe 100644
--- a/arch/s390/include/asm/fpu-insn.h
+++ b/arch/s390/include/asm/fpu-insn.h
@@ -12,6 +12,7 @@
#ifndef __ASSEMBLY__
#include <linux/instrumented.h>
+#include <linux/kmsan.h>
#include <asm/asm-extable.h>
asm(".include \"asm/fpu-insn-asm.h\"\n");
@@ -377,6 +378,7 @@ static __always_inline void fpu_vst(u8 v1, const void *vxr)
: [vxr] "=Q" (*(__vector128 *)vxr)
: [v1] "I" (v1)
: "memory");
+ kmsan_unpoison_memory(vxr, size);
}
#endif /* CONFIG_CC_IS_CLANG */
@@ -395,6 +397,7 @@ static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr)
: [vxr] "=R" (*(u8 *)vxr)
: [index] "d" (index), [v1] "I" (v1)
: "memory", "1");
+ kmsan_unpoison_memory(vxr, size);
}
#else /* CONFIG_CC_IS_CLANG */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 166/869] staging: most: remove broken i2c driver
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (164 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 165/869] s390/fpu: Fix false-positive kmsan report in fpu_vstl() Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 167/869] wifi: mac80211: fix typo in HE MCS check Greg Kroah-Hartman
` (703 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Gromm, Johan Hovold,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <johan@kernel.org>
[ Upstream commit 495df2da6944477d282d5cc0c13174d06e25b310 ]
The MOST I2C driver has been completely broken for five years without
anyone noticing so remove the driver from staging.
Specifically, commit 723de0f9171e ("staging: most: remove device from
interface structure") started requiring drivers to set the interface
device pointer before registration, but the I2C driver was never updated
which results in a NULL pointer dereference if anyone ever tries to
probe it.
Fixes: 723de0f9171e ("staging: most: remove device from interface structure")
Cc: Christian Gromm <christian.gromm@microchip.com>
Signed-off-by: Johan Hovold <johan@kernel.org>
Link: https://patch.msgid.link/20251029093442.29256-1-johan@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/staging/most/Kconfig | 2 -
drivers/staging/most/Makefile | 1 -
drivers/staging/most/i2c/Kconfig | 13 --
drivers/staging/most/i2c/Makefile | 4 -
drivers/staging/most/i2c/i2c.c | 374 ------------------------------
5 files changed, 394 deletions(-)
delete mode 100644 drivers/staging/most/i2c/Kconfig
delete mode 100644 drivers/staging/most/i2c/Makefile
delete mode 100644 drivers/staging/most/i2c/i2c.c
diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig
index 6f420cbcdcfff..e89658df6f124 100644
--- a/drivers/staging/most/Kconfig
+++ b/drivers/staging/most/Kconfig
@@ -24,6 +24,4 @@ source "drivers/staging/most/video/Kconfig"
source "drivers/staging/most/dim2/Kconfig"
-source "drivers/staging/most/i2c/Kconfig"
-
endif
diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile
index 8b3fc5a7af514..e45084df7803a 100644
--- a/drivers/staging/most/Makefile
+++ b/drivers/staging/most/Makefile
@@ -3,4 +3,3 @@
obj-$(CONFIG_MOST_NET) += net/
obj-$(CONFIG_MOST_VIDEO) += video/
obj-$(CONFIG_MOST_DIM2) += dim2/
-obj-$(CONFIG_MOST_I2C) += i2c/
diff --git a/drivers/staging/most/i2c/Kconfig b/drivers/staging/most/i2c/Kconfig
deleted file mode 100644
index ff64283cbad18..0000000000000
--- a/drivers/staging/most/i2c/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# MOST I2C configuration
-#
-
-config MOST_I2C
- tristate "I2C"
- depends on I2C
- help
- Say Y here if you want to connect via I2C to network transceiver.
-
- To compile this driver as a module, choose M here: the
- module will be called most_i2c.
diff --git a/drivers/staging/most/i2c/Makefile b/drivers/staging/most/i2c/Makefile
deleted file mode 100644
index 71099dd0f85b9..0000000000000
--- a/drivers/staging/most/i2c/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_MOST_I2C) += most_i2c.o
-
-most_i2c-objs := i2c.o
diff --git a/drivers/staging/most/i2c/i2c.c b/drivers/staging/most/i2c/i2c.c
deleted file mode 100644
index ce869280a056b..0000000000000
--- a/drivers/staging/most/i2c/i2c.c
+++ /dev/null
@@ -1,374 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * i2c.c - Hardware Dependent Module for I2C Interface
- *
- * Copyright (C) 2013-2015, Microchip Technology Germany II GmbH & Co. KG
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/most.h>
-
-enum { CH_RX, CH_TX, NUM_CHANNELS };
-
-#define MAX_BUFFERS_CONTROL 32
-#define MAX_BUF_SIZE_CONTROL 256
-
-/**
- * list_first_mbo - get the first mbo from a list
- * @ptr: the list head to take the mbo from.
- */
-#define list_first_mbo(ptr) \
- list_first_entry(ptr, struct mbo, list)
-
-static unsigned int polling_rate;
-module_param(polling_rate, uint, 0644);
-MODULE_PARM_DESC(polling_rate, "Polling rate [Hz]. Default = 0 (use IRQ)");
-
-struct hdm_i2c {
- struct most_interface most_iface;
- struct most_channel_capability capabilities[NUM_CHANNELS];
- struct i2c_client *client;
- struct rx {
- struct delayed_work dwork;
- struct list_head list;
- bool int_disabled;
- unsigned int delay;
- } rx;
- char name[64];
-};
-
-static inline struct hdm_i2c *to_hdm(struct most_interface *iface)
-{
- return container_of(iface, struct hdm_i2c, most_iface);
-}
-
-static irqreturn_t most_irq_handler(int, void *);
-static void pending_rx_work(struct work_struct *);
-
-/**
- * configure_channel - called from MOST core to configure a channel
- * @most_iface: interface the channel belongs to
- * @ch_idx: channel to be configured
- * @channel_config: structure that holds the configuration information
- *
- * Return 0 on success, negative on failure.
- *
- * Receives configuration information from MOST core and initialize the
- * corresponding channel.
- */
-static int configure_channel(struct most_interface *most_iface,
- int ch_idx,
- struct most_channel_config *channel_config)
-{
- int ret;
- struct hdm_i2c *dev = to_hdm(most_iface);
- unsigned int delay, pr;
-
- BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS);
-
- if (channel_config->data_type != MOST_CH_CONTROL) {
- pr_err("bad data type for channel %d\n", ch_idx);
- return -EPERM;
- }
-
- if (channel_config->direction != dev->capabilities[ch_idx].direction) {
- pr_err("bad direction for channel %d\n", ch_idx);
- return -EPERM;
- }
-
- if (channel_config->direction == MOST_CH_RX) {
- if (!polling_rate) {
- if (dev->client->irq <= 0) {
- pr_err("bad irq: %d\n", dev->client->irq);
- return -ENOENT;
- }
- dev->rx.int_disabled = false;
- ret = request_irq(dev->client->irq, most_irq_handler, 0,
- dev->client->name, dev);
- if (ret) {
- pr_err("request_irq(%d) failed: %d\n",
- dev->client->irq, ret);
- return ret;
- }
- } else {
- delay = msecs_to_jiffies(MSEC_PER_SEC / polling_rate);
- dev->rx.delay = delay ? delay : 1;
- pr = MSEC_PER_SEC / jiffies_to_msecs(dev->rx.delay);
- pr_info("polling rate is %u Hz\n", pr);
- }
- }
-
- return 0;
-}
-
-/**
- * enqueue - called from MOST core to enqueue a buffer for data transfer
- * @most_iface: intended interface
- * @ch_idx: ID of the channel the buffer is intended for
- * @mbo: pointer to the buffer object
- *
- * Return 0 on success, negative on failure.
- *
- * Transmit the data over I2C if it is a "write" request or push the buffer into
- * list if it is an "read" request
- */
-static int enqueue(struct most_interface *most_iface,
- int ch_idx, struct mbo *mbo)
-{
- struct hdm_i2c *dev = to_hdm(most_iface);
- int ret;
-
- BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS);
-
- if (ch_idx == CH_RX) {
- /* RX */
- if (!polling_rate)
- disable_irq(dev->client->irq);
- cancel_delayed_work_sync(&dev->rx.dwork);
- list_add_tail(&mbo->list, &dev->rx.list);
- if (dev->rx.int_disabled || polling_rate)
- pending_rx_work(&dev->rx.dwork.work);
- if (!polling_rate)
- enable_irq(dev->client->irq);
- } else {
- /* TX */
- ret = i2c_master_send(dev->client, mbo->virt_address,
- mbo->buffer_length);
- if (ret <= 0) {
- mbo->processed_length = 0;
- mbo->status = MBO_E_INVAL;
- } else {
- mbo->processed_length = mbo->buffer_length;
- mbo->status = MBO_SUCCESS;
- }
- mbo->complete(mbo);
- }
-
- return 0;
-}
-
-/**
- * poison_channel - called from MOST core to poison buffers of a channel
- * @most_iface: pointer to the interface the channel to be poisoned belongs to
- * @ch_idx: corresponding channel ID
- *
- * Return 0 on success, negative on failure.
- *
- * If channel direction is RX, complete the buffers in list with
- * status MBO_E_CLOSE
- */
-static int poison_channel(struct most_interface *most_iface,
- int ch_idx)
-{
- struct hdm_i2c *dev = to_hdm(most_iface);
- struct mbo *mbo;
-
- BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS);
-
- if (ch_idx == CH_RX) {
- if (!polling_rate)
- free_irq(dev->client->irq, dev);
- cancel_delayed_work_sync(&dev->rx.dwork);
-
- while (!list_empty(&dev->rx.list)) {
- mbo = list_first_mbo(&dev->rx.list);
- list_del(&mbo->list);
-
- mbo->processed_length = 0;
- mbo->status = MBO_E_CLOSE;
- mbo->complete(mbo);
- }
- }
-
- return 0;
-}
-
-static void do_rx_work(struct hdm_i2c *dev)
-{
- struct mbo *mbo;
- unsigned char msg[MAX_BUF_SIZE_CONTROL];
- int ret;
- u16 pml, data_size;
-
- /* Read PML (2 bytes) */
- ret = i2c_master_recv(dev->client, msg, 2);
- if (ret <= 0) {
- pr_err("Failed to receive PML\n");
- return;
- }
-
- pml = (msg[0] << 8) | msg[1];
- if (!pml)
- return;
-
- data_size = pml + 2;
-
- /* Read the whole message, including PML */
- ret = i2c_master_recv(dev->client, msg, data_size);
- if (ret <= 0) {
- pr_err("Failed to receive a Port Message\n");
- return;
- }
-
- mbo = list_first_mbo(&dev->rx.list);
- list_del(&mbo->list);
-
- mbo->processed_length = min(data_size, mbo->buffer_length);
- memcpy(mbo->virt_address, msg, mbo->processed_length);
- mbo->status = MBO_SUCCESS;
- mbo->complete(mbo);
-}
-
-/**
- * pending_rx_work - Read pending messages through I2C
- * @work: definition of this work item
- *
- * Invoked by the Interrupt Service Routine, most_irq_handler()
- */
-static void pending_rx_work(struct work_struct *work)
-{
- struct hdm_i2c *dev = container_of(work, struct hdm_i2c, rx.dwork.work);
-
- if (list_empty(&dev->rx.list))
- return;
-
- do_rx_work(dev);
-
- if (polling_rate) {
- schedule_delayed_work(&dev->rx.dwork, dev->rx.delay);
- } else {
- dev->rx.int_disabled = false;
- enable_irq(dev->client->irq);
- }
-}
-
-/*
- * most_irq_handler - Interrupt Service Routine
- * @irq: irq number
- * @_dev: private data
- *
- * Schedules a delayed work
- *
- * By default the interrupt line behavior is Active Low. Once an interrupt is
- * generated by the device, until driver clears the interrupt (by reading
- * the PMP message), device keeps the interrupt line in low state. Since i2c
- * read is done in work queue, the interrupt line must be disabled temporarily
- * to avoid ISR being called repeatedly. Re-enable the interrupt in workqueue,
- * after reading the message.
- *
- * Note: If we use the interrupt line in Falling edge mode, there is a
- * possibility to miss interrupts when ISR is getting executed.
- *
- */
-static irqreturn_t most_irq_handler(int irq, void *_dev)
-{
- struct hdm_i2c *dev = _dev;
-
- disable_irq_nosync(irq);
- dev->rx.int_disabled = true;
- schedule_delayed_work(&dev->rx.dwork, 0);
-
- return IRQ_HANDLED;
-}
-
-/*
- * i2c_probe - i2c probe handler
- * @client: i2c client device structure
- * @id: i2c client device id
- *
- * Return 0 on success, negative on failure.
- *
- * Register the i2c client device as a MOST interface
- */
-static int i2c_probe(struct i2c_client *client)
-{
- struct hdm_i2c *dev;
- int ret, i;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
- /* ID format: i2c-<bus>-<address> */
- snprintf(dev->name, sizeof(dev->name), "i2c-%d-%04x",
- client->adapter->nr, client->addr);
-
- for (i = 0; i < NUM_CHANNELS; i++) {
- dev->capabilities[i].data_type = MOST_CH_CONTROL;
- dev->capabilities[i].num_buffers_packet = MAX_BUFFERS_CONTROL;
- dev->capabilities[i].buffer_size_packet = MAX_BUF_SIZE_CONTROL;
- }
- dev->capabilities[CH_RX].direction = MOST_CH_RX;
- dev->capabilities[CH_RX].name_suffix = "rx";
- dev->capabilities[CH_TX].direction = MOST_CH_TX;
- dev->capabilities[CH_TX].name_suffix = "tx";
-
- dev->most_iface.interface = ITYPE_I2C;
- dev->most_iface.description = dev->name;
- dev->most_iface.num_channels = NUM_CHANNELS;
- dev->most_iface.channel_vector = dev->capabilities;
- dev->most_iface.configure = configure_channel;
- dev->most_iface.enqueue = enqueue;
- dev->most_iface.poison_channel = poison_channel;
-
- INIT_LIST_HEAD(&dev->rx.list);
-
- INIT_DELAYED_WORK(&dev->rx.dwork, pending_rx_work);
-
- dev->client = client;
- i2c_set_clientdata(client, dev);
-
- ret = most_register_interface(&dev->most_iface);
- if (ret) {
- pr_err("Failed to register i2c as a MOST interface\n");
- kfree(dev);
- return ret;
- }
-
- return 0;
-}
-
-/*
- * i2c_remove - i2c remove handler
- * @client: i2c client device structure
- *
- * Return 0 on success.
- *
- * Unregister the i2c client device as a MOST interface
- */
-static void i2c_remove(struct i2c_client *client)
-{
- struct hdm_i2c *dev = i2c_get_clientdata(client);
-
- most_deregister_interface(&dev->most_iface);
- kfree(dev);
-}
-
-static const struct i2c_device_id i2c_id[] = {
- { "most_i2c", 0 },
- { }, /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(i2c, i2c_id);
-
-static struct i2c_driver i2c_driver = {
- .driver = {
- .name = "hdm_i2c",
- },
- .probe = i2c_probe,
- .remove = i2c_remove,
- .id_table = i2c_id,
-};
-
-module_i2c_driver(i2c_driver);
-
-MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
-MODULE_DESCRIPTION("I2C Hardware Dependent Module");
-MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 167/869] wifi: mac80211: fix typo in HE MCS check
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (165 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 166/869] staging: most: remove broken i2c driver Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 168/869] wifi: mac80211: log link information in ieee80211_determine_chan_mode Greg Kroah-Hartman
` (702 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Benjamin Berg, Johannes Berg,
Miri Korenblit, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Berg <benjamin.berg@intel.com>
[ Upstream commit 29968432874bb03f7dcaea602efb7d00e7c33b0c ]
It printed the AP RX MCS value instead of the TX one.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250101070249.743c7c1914f4.I1e5888ac6c8324d078fe91d01da31daa76d0e328@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Stable-dep-of: 99067b58a408 ("wifi: mac80211: don't WARN for connections on invalid channels")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mac80211/mlme.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index fc02194233f82..d194587bf020a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -420,7 +420,7 @@ ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata,
ap_rx_val < ap_op_val || ap_tx_val < ap_op_val) {
sdata_info(sdata,
"Invalid rates for %d Nss, rx %d, tx %d oper %d, disable HE\n",
- nss, ap_rx_val, ap_rx_val, ap_op_val);
+ nss, ap_rx_val, ap_tx_val, ap_op_val);
return false;
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 168/869] wifi: mac80211: log link information in ieee80211_determine_chan_mode
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (166 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 167/869] wifi: mac80211: fix typo in HE MCS check Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 169/869] wifi: mac80211: dont WARN for connections on invalid channels Greg Kroah-Hartman
` (701 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Benjamin Berg, Johannes Berg,
Miri Korenblit, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Berg <benjamin.berg@intel.com>
[ Upstream commit 2e3de34f5ceebdccd9464e7400986d2131915465 ]
ieee80211_determine_chan_mode is called for each link and if there is a
downgrade, then it is interesting to know on which link it happened.
Pass through the link_id where relevant and use the new link_id_info
macro instead of sdata_info so that the link ID is printed when
relevant.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250101070249.d400da710fc4.I64775ec914603d3c7b0c6ea14b507c0370c11622@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Stable-dep-of: 99067b58a408 ("wifi: mac80211: don't WARN for connections on invalid channels")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mac80211/debug.h | 10 +++++++++-
net/mac80211/mlme.c | 30 +++++++++++++++++-------------
2 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
index 35a8ba25fa57f..5b81998cb0c98 100644
--- a/net/mac80211/debug.h
+++ b/net/mac80211/debug.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Portions
- * Copyright (C) 2022 - 2023 Intel Corporation
+ * Copyright (C) 2022 - 2024 Intel Corporation
*/
#ifndef __MAC80211_DEBUG_H
#define __MAC80211_DEBUG_H
@@ -152,6 +152,14 @@ do { \
else \
_sdata_err((link)->sdata, fmt, ##__VA_ARGS__); \
} while (0)
+#define link_id_info(sdata, link_id, fmt, ...) \
+ do { \
+ if (ieee80211_vif_is_mld(&sdata->vif)) \
+ _sdata_info(sdata, "[link %d] " fmt, link_id, \
+ ##__VA_ARGS__); \
+ else \
+ _sdata_info(sdata, fmt, ##__VA_ARGS__); \
+ } while (0)
#define _link_id_dbg(print, sdata, link_id, fmt, ...) \
do { \
if (ieee80211_vif_is_mld(&(sdata)->vif)) \
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d194587bf020a..4cde4792aede9 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -345,6 +345,7 @@ ieee80211_determine_ap_chan(struct ieee80211_sub_if_data *sdata,
static bool
ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata,
+ int link_id,
const struct ieee80211_he_cap_elem *he_cap,
const struct ieee80211_he_operation *he_op)
{
@@ -372,9 +373,9 @@ ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata,
*/
if ((mcs_80_map_tx & 0x3) == IEEE80211_HE_MCS_NOT_SUPPORTED ||
(mcs_80_map_rx & 0x3) == IEEE80211_HE_MCS_NOT_SUPPORTED) {
- sdata_info(sdata,
- "Missing mandatory rates for 1 Nss, rx 0x%x, tx 0x%x, disable HE\n",
- mcs_80_map_tx, mcs_80_map_rx);
+ link_id_info(sdata, link_id,
+ "Missing mandatory rates for 1 Nss, rx 0x%x, tx 0x%x, disable HE\n",
+ mcs_80_map_tx, mcs_80_map_rx);
return false;
}
@@ -418,9 +419,9 @@ ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata,
if (ap_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
ap_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
ap_rx_val < ap_op_val || ap_tx_val < ap_op_val) {
- sdata_info(sdata,
- "Invalid rates for %d Nss, rx %d, tx %d oper %d, disable HE\n",
- nss, ap_rx_val, ap_tx_val, ap_op_val);
+ link_id_info(sdata, link_id,
+ "Invalid rates for %d Nss, rx %d, tx %d oper %d, disable HE\n",
+ nss, ap_rx_val, ap_tx_val, ap_op_val);
return false;
}
}
@@ -871,8 +872,8 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
return elems;
case NL80211_BAND_6GHZ:
if (ap_mode < IEEE80211_CONN_MODE_HE) {
- sdata_info(sdata,
- "Rejecting non-HE 6/7 GHz connection");
+ link_id_info(sdata, link_id,
+ "Rejecting non-HE 6/7 GHz connection");
ret = -EINVAL;
goto free;
}
@@ -943,16 +944,18 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
}
if (chanreq->oper.width != ap_chandef->width || ap_mode != conn->mode)
- sdata_info(sdata,
- "regulatory prevented using AP config, downgraded\n");
+ link_id_info(sdata, link_id,
+ "regulatory prevented using AP config, downgraded\n");
if (conn->mode >= IEEE80211_CONN_MODE_HE &&
- (!ieee80211_verify_peer_he_mcs_support(sdata, (void *)elems->he_cap,
+ (!ieee80211_verify_peer_he_mcs_support(sdata, link_id,
+ (void *)elems->he_cap,
elems->he_operation) ||
!ieee80211_verify_sta_he_mcs_support(sdata, sband,
elems->he_operation))) {
conn->mode = IEEE80211_CONN_MODE_VHT;
- sdata_info(sdata, "required MCSes not supported, disabling HE\n");
+ link_id_info(sdata, link_id,
+ "required MCSes not supported, disabling HE\n");
}
if (conn->mode >= IEEE80211_CONN_MODE_EHT &&
@@ -962,7 +965,8 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
conn->bw_limit = min_t(enum ieee80211_conn_bw_limit,
conn->bw_limit,
IEEE80211_CONN_BW_LIMIT_160);
- sdata_info(sdata, "required MCSes not supported, disabling EHT\n");
+ link_id_info(sdata, link_id,
+ "required MCSes not supported, disabling EHT\n");
}
/* the mode can only decrease, so this must terminate */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 169/869] wifi: mac80211: dont WARN for connections on invalid channels
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (167 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 168/869] wifi: mac80211: log link information in ieee80211_determine_chan_mode Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 170/869] accel/qaic: Add config structs for supported cards Greg Kroah-Hartman
` (700 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+639af5aa411f2581ad38,
Johannes Berg, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Berg <johannes.berg@intel.com>
[ Upstream commit 99067b58a408a384d2a45c105eb3dce980a862ce ]
It's not clear (to me) how exactly syzbot managed to hit this,
but it seems conceivable that e.g. regulatory changed and has
disabled a channel between scanning (channel is checked to be
usable by cfg80211_get_ies_channel_number) and connecting on
the channel later.
With one scenario that isn't covered elsewhere described above,
the warning isn't good, replace it with a (more informative)
error message.
Reported-by: syzbot+639af5aa411f2581ad38@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20251202102511.5a8fb5184fa3.I961ee41b8f10538a54b8565dbf03ec1696e80e03@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mac80211/mlme.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 4cde4792aede9..7fd8fbe3400d3 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -917,7 +917,10 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
while (!ieee80211_chandef_usable(sdata, &chanreq->oper,
IEEE80211_CHAN_DISABLED)) {
- if (WARN_ON(chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT)) {
+ if (chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT) {
+ link_id_info(sdata, link_id,
+ "unusable channel (%d MHz) for connection\n",
+ chanreq->oper.chan->center_freq);
ret = -EINVAL;
goto free;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 170/869] accel/qaic: Add config structs for supported cards
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (168 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 169/869] wifi: mac80211: dont WARN for connections on invalid channels Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 171/869] net: qrtr: Drop the MHI auto_queue feature for IPCR DL channels Greg Kroah-Hartman
` (699 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Youssef Samir, Jeffrey Hugo,
Lizhi Hou, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeffrey Hugo <quic_jhugo@quicinc.com>
[ Upstream commit 5bbe412bc7937b5cabfe38aa186a2c6890f70df0 ]
As the number of cards supported by the driver grows, their
configurations will differ. The driver needs to become more dynamic
to support these configurations. Currently, each card may differ in
the exposed BARs, the regions they map to, and the family.
Create config structs for each card, and let the driver configure the
qaic_device struct based on the configurations passed to the driver.
Co-developed-by: Youssef Samir <quic_yabdulra@quicinc.com>
Signed-off-by: Youssef Samir <quic_yabdulra@quicinc.com>
Signed-off-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
Reviewed-by: Lizhi Hou <lizhi.hou@amd.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250117170943.2643280-7-quic_jhugo@quicinc.com
Stable-dep-of: 51731792a25c ("net: qrtr: Drop the MHI auto_queue feature for IPCR DL channels")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/accel/qaic/qaic.h | 13 +++--
drivers/accel/qaic/qaic_drv.c | 76 ++++++++++++++++++++----------
drivers/accel/qaic/qaic_timesync.c | 2 +-
3 files changed, 61 insertions(+), 30 deletions(-)
diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h
index 2d7b3af09e284..06aa35b7a4843 100644
--- a/drivers/accel/qaic/qaic.h
+++ b/drivers/accel/qaic/qaic.h
@@ -32,6 +32,11 @@
#define to_accel_kdev(qddev) (to_drm(qddev)->accel->kdev) /* Return Linux device of accel node */
#define to_qaic_device(dev) (to_qaic_drm_device((dev))->qdev)
+enum aic_families {
+ FAMILY_AIC100,
+ FAMILY_MAX,
+};
+
enum __packed dev_states {
/* Device is offline or will be very soon */
QAIC_OFFLINE,
@@ -115,10 +120,10 @@ struct qaic_device {
struct pci_dev *pdev;
/* Req. ID of request that will be queued next in MHI control device */
u32 next_seq_num;
- /* Base address of bar 0 */
- void __iomem *bar_0;
- /* Base address of bar 2 */
- void __iomem *bar_2;
+ /* Base address of the MHI bar */
+ void __iomem *bar_mhi;
+ /* Base address of the DBCs bar */
+ void __iomem *bar_dbc;
/* Controller structure for MHI devices */
struct mhi_controller *mhi_cntrl;
/* MHI control channel device */
diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c
index cb606c4bb8511..dda1ca4bcbfc5 100644
--- a/drivers/accel/qaic/qaic_drv.c
+++ b/drivers/accel/qaic/qaic_drv.c
@@ -34,13 +34,38 @@
MODULE_IMPORT_NS(DMA_BUF);
-#define PCI_DEV_AIC080 0xa080
-#define PCI_DEV_AIC100 0xa100
+#define PCI_DEVICE_ID_QCOM_AIC080 0xa080
+#define PCI_DEVICE_ID_QCOM_AIC100 0xa100
#define QAIC_NAME "qaic"
#define QAIC_DESC "Qualcomm Cloud AI Accelerators"
#define CNTL_MAJOR 5
#define CNTL_MINOR 0
+struct qaic_device_config {
+ /* Indicates the AIC family the device belongs to */
+ int family;
+ /* A bitmask representing the available BARs */
+ int bar_mask;
+ /* An index value used to identify the MHI controller BAR */
+ unsigned int mhi_bar_idx;
+ /* An index value used to identify the DBCs BAR */
+ unsigned int dbc_bar_idx;
+};
+
+static const struct qaic_device_config aic080_config = {
+ .family = FAMILY_AIC100,
+ .bar_mask = BIT(0) | BIT(2) | BIT(4),
+ .mhi_bar_idx = 0,
+ .dbc_bar_idx = 2,
+};
+
+static const struct qaic_device_config aic100_config = {
+ .family = FAMILY_AIC100,
+ .bar_mask = BIT(0) | BIT(2) | BIT(4),
+ .mhi_bar_idx = 0,
+ .dbc_bar_idx = 2,
+};
+
bool datapath_polling;
module_param(datapath_polling, bool, 0400);
MODULE_PARM_DESC(datapath_polling, "Operate the datapath in polling mode");
@@ -353,7 +378,8 @@ void qaic_dev_reset_clean_local_state(struct qaic_device *qdev)
release_dbc(qdev, i);
}
-static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_device_id *id)
+static struct qaic_device *create_qdev(struct pci_dev *pdev,
+ const struct qaic_device_config *config)
{
struct device *dev = &pdev->dev;
struct qaic_drm_device *qddev;
@@ -366,12 +392,10 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_de
return NULL;
qdev->dev_state = QAIC_OFFLINE;
- if (id->device == PCI_DEV_AIC080 || id->device == PCI_DEV_AIC100) {
- qdev->num_dbc = 16;
- qdev->dbc = devm_kcalloc(dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL);
- if (!qdev->dbc)
- return NULL;
- }
+ qdev->num_dbc = 16;
+ qdev->dbc = devm_kcalloc(dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL);
+ if (!qdev->dbc)
+ return NULL;
qddev = devm_drm_dev_alloc(&pdev->dev, &qaic_accel_driver, struct qaic_drm_device, drm);
if (IS_ERR(qddev))
@@ -430,7 +454,8 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_de
return qdev;
}
-static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev)
+static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev,
+ const struct qaic_device_config *config)
{
int bars;
int ret;
@@ -438,9 +463,9 @@ static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev)
bars = pci_select_bars(pdev, IORESOURCE_MEM) & 0x3f;
/* make sure the device has the expected BARs */
- if (bars != (BIT(0) | BIT(2) | BIT(4))) {
- pci_dbg(pdev, "%s: expected BARs 0, 2, and 4 not found in device. Found 0x%x\n",
- __func__, bars);
+ if (bars != config->bar_mask) {
+ pci_dbg(pdev, "%s: expected BARs %#x not found in device. Found %#x\n",
+ __func__, config->bar_mask, bars);
return -EINVAL;
}
@@ -453,13 +478,13 @@ static int init_pci(struct qaic_device *qdev, struct pci_dev *pdev)
return ret;
dma_set_max_seg_size(&pdev->dev, UINT_MAX);
- qdev->bar_0 = devm_ioremap_resource(&pdev->dev, &pdev->resource[0]);
- if (IS_ERR(qdev->bar_0))
- return PTR_ERR(qdev->bar_0);
+ qdev->bar_mhi = devm_ioremap_resource(&pdev->dev, &pdev->resource[config->mhi_bar_idx]);
+ if (IS_ERR(qdev->bar_mhi))
+ return PTR_ERR(qdev->bar_mhi);
- qdev->bar_2 = devm_ioremap_resource(&pdev->dev, &pdev->resource[2]);
- if (IS_ERR(qdev->bar_2))
- return PTR_ERR(qdev->bar_2);
+ qdev->bar_dbc = devm_ioremap_resource(&pdev->dev, &pdev->resource[config->dbc_bar_idx]);
+ if (IS_ERR(qdev->bar_dbc))
+ return PTR_ERR(qdev->bar_dbc);
/* Managed release since we use pcim_enable_device above */
pci_set_master(pdev);
@@ -519,21 +544,22 @@ static int init_msi(struct qaic_device *qdev, struct pci_dev *pdev)
static int qaic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
+ struct qaic_device_config *config = (struct qaic_device_config *)id->driver_data;
struct qaic_device *qdev;
int mhi_irq;
int ret;
int i;
- qdev = create_qdev(pdev, id);
+ qdev = create_qdev(pdev, config);
if (!qdev)
return -ENOMEM;
- ret = init_pci(qdev, pdev);
+ ret = init_pci(qdev, pdev, config);
if (ret)
return ret;
for (i = 0; i < qdev->num_dbc; ++i)
- qdev->dbc[i].dbc_base = qdev->bar_2 + QAIC_DBC_OFF(i);
+ qdev->dbc[i].dbc_base = qdev->bar_dbc + QAIC_DBC_OFF(i);
mhi_irq = init_msi(qdev, pdev);
if (mhi_irq < 0)
@@ -543,7 +569,7 @@ static int qaic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
return ret;
- qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_0, mhi_irq,
+ qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_mhi, mhi_irq,
qdev->single_msi);
if (IS_ERR(qdev->mhi_cntrl)) {
ret = PTR_ERR(qdev->mhi_cntrl);
@@ -611,8 +637,8 @@ static struct mhi_driver qaic_mhi_driver = {
};
static const struct pci_device_id qaic_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_QCOM, PCI_DEV_AIC080), },
- { PCI_DEVICE(PCI_VENDOR_ID_QCOM, PCI_DEV_AIC100), },
+ { PCI_DEVICE_DATA(QCOM, AIC080, (kernel_ulong_t)&aic080_config), },
+ { PCI_DEVICE_DATA(QCOM, AIC100, (kernel_ulong_t)&aic100_config), },
{ }
};
MODULE_DEVICE_TABLE(pci, qaic_ids);
diff --git a/drivers/accel/qaic/qaic_timesync.c b/drivers/accel/qaic/qaic_timesync.c
index 301f4462d51bd..2473c66309d40 100644
--- a/drivers/accel/qaic/qaic_timesync.c
+++ b/drivers/accel/qaic/qaic_timesync.c
@@ -201,7 +201,7 @@ static int qaic_timesync_probe(struct mhi_device *mhi_dev, const struct mhi_devi
goto free_sync_msg;
/* Qtimer register pointer */
- mqtsdev->qtimer_addr = qdev->bar_0 + QTIMER_REG_OFFSET;
+ mqtsdev->qtimer_addr = qdev->bar_mhi + QTIMER_REG_OFFSET;
timer_setup(timer, qaic_timesync_timer, 0);
timer->expires = jiffies + msecs_to_jiffies(timesync_delay_ms);
add_timer(timer);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 171/869] net: qrtr: Drop the MHI auto_queue feature for IPCR DL channels
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (169 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 170/869] accel/qaic: Add config structs for supported cards Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 172/869] PCI: endpoint: Add missing NULL check for alloc_workqueue() Greg Kroah-Hartman
` (698 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johan Hovold, Chris Lew,
Manivannan Sadhasivam, Jeff Hugo, Loic Poulain, Paolo Abeni,
Sasha Levin, Jeff Johnson
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
[ Upstream commit 51731792a25cb312ca94cdccfa139eb46de1b2ef ]
MHI stack offers the 'auto_queue' feature, which allows the MHI stack to
auto queue the buffers for the RX path (DL channel). Though this feature
simplifies the client driver design, it introduces race between the client
drivers and the MHI stack. For instance, with auto_queue, the 'dl_callback'
for the DL channel may get called before the client driver is fully probed.
This means, by the time the dl_callback gets called, the client driver's
structures might not be initialized, leading to NULL ptr dereference.
Currently, the drivers have to workaround this issue by initializing the
internal structures before calling mhi_prepare_for_transfer_autoqueue().
But even so, there is a chance that the client driver's internal code path
may call the MHI queue APIs before mhi_prepare_for_transfer_autoqueue() is
called, leading to similar NULL ptr dereference. This issue has been
reported on the Qcom X1E80100 CRD machines affecting boot.
So to properly fix all these races, drop the MHI 'auto_queue' feature
altogether and let the client driver (QRTR) manage the RX buffers manually.
In the QRTR driver, queue the RX buffers based on the ring length during
probe and recycle the buffers in 'dl_callback' once they are consumed. This
also warrants removing the setting of 'auto_queue' flag from controller
drivers.
Currently, this 'auto_queue' feature is only enabled for IPCR DL channel.
So only the QRTR client driver requires the modification.
Fixes: 227fee5fc99e ("bus: mhi: core: Add an API for auto queueing buffers for DL channel")
Fixes: 68a838b84eff ("net: qrtr: start MHI channel after endpoit creation")
Reported-by: Johan Hovold <johan@kernel.org>
Closes: https://lore.kernel.org/linux-arm-msm/ZyTtVdkCCES0lkl4@hovoldconsulting.com
Suggested-by: Chris Lew <quic_clew@quicinc.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Reviewed-by: Jeff Hugo <jeff.hugo@oss.qualcomm.com>
Reviewed-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Acked-by: Jeff Johnson <jjohnson@kernel.org> # drivers/net/wireless/ath/...
Acked-by: Jeff Hugo <jeff.hugo@oss.qualcomm.com>
Acked-by: Paolo Abeni <pabeni@redhat.com>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20251218-qrtr-fix-v2-1-c7499bfcfbe0@oss.qualcomm.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/accel/qaic/mhi_controller.c | 24 ----------
drivers/bus/mhi/host/pci_generic.c | 20 +-------
drivers/net/wireless/ath/ath11k/mhi.c | 4 --
drivers/net/wireless/ath/ath12k/mhi.c | 4 --
net/qrtr/mhi.c | 69 ++++++++++++++++++++++-----
5 files changed, 60 insertions(+), 61 deletions(-)
diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c
index ada9b1eb0787e..8b3a0690ee8fa 100644
--- a/drivers/accel/qaic/mhi_controller.c
+++ b/drivers/accel/qaic/mhi_controller.c
@@ -34,7 +34,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -50,7 +49,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -66,7 +64,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -82,7 +79,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -98,7 +94,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -114,7 +109,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -130,7 +124,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -146,7 +139,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -162,7 +154,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -178,7 +169,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -194,7 +184,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -210,7 +199,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -226,7 +214,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -242,7 +229,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -258,7 +244,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -274,7 +259,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -290,7 +274,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -306,7 +289,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -322,7 +304,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -338,7 +319,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -354,7 +334,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -370,7 +349,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -386,7 +364,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
{
@@ -402,7 +379,6 @@ static const struct mhi_channel_config aic100_channels[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
.wake_capable = false,
},
};
diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c
index 833d0c940477d..5fc526ddece27 100644
--- a/drivers/bus/mhi/host/pci_generic.c
+++ b/drivers/bus/mhi/host/pci_generic.c
@@ -86,22 +86,6 @@ struct mhi_pci_dev_info {
.doorbell_mode_switch = false, \
}
-#define MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(ch_num, ch_name, el_count, ev_ring) \
- { \
- .num = ch_num, \
- .name = ch_name, \
- .num_elements = el_count, \
- .event_ring = ev_ring, \
- .dir = DMA_FROM_DEVICE, \
- .ee_mask = BIT(MHI_EE_AMSS), \
- .pollcfg = 0, \
- .doorbell = MHI_DB_BRST_DISABLE, \
- .lpm_notify = false, \
- .offload_channel = false, \
- .doorbell_mode_switch = false, \
- .auto_queue = true, \
- }
-
#define MHI_EVENT_CONFIG_CTRL(ev_ring, el_count) \
{ \
.num_elements = el_count, \
@@ -253,7 +237,7 @@ static const struct mhi_channel_config modem_qcom_v1_mhi_channels[] = {
MHI_CHANNEL_CONFIG_UL(14, "QMI", 4, 0),
MHI_CHANNEL_CONFIG_DL(15, "QMI", 4, 0),
MHI_CHANNEL_CONFIG_UL(20, "IPCR", 8, 0),
- MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(21, "IPCR", 8, 0),
+ MHI_CHANNEL_CONFIG_DL(21, "IPCR", 8, 0),
MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0),
MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0),
MHI_CHANNEL_CONFIG_UL(46, "IP_SW0", 64, 2),
@@ -618,7 +602,7 @@ static const struct mhi_channel_config mhi_telit_fn980_hw_v1_channels[] = {
MHI_CHANNEL_CONFIG_UL(14, "QMI", 32, 0),
MHI_CHANNEL_CONFIG_DL(15, "QMI", 32, 0),
MHI_CHANNEL_CONFIG_UL(20, "IPCR", 16, 0),
- MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(21, "IPCR", 16, 0),
+ MHI_CHANNEL_CONFIG_DL(21, "IPCR", 16, 0),
MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 1),
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 2),
};
diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c
index 6974a551883fc..9c2200cc0348b 100644
--- a/drivers/net/wireless/ath/ath11k/mhi.c
+++ b/drivers/net/wireless/ath/ath11k/mhi.c
@@ -34,7 +34,6 @@ static const struct mhi_channel_config ath11k_mhi_channels_qca6390[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
},
{
.num = 21,
@@ -48,7 +47,6 @@ static const struct mhi_channel_config ath11k_mhi_channels_qca6390[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = true,
},
};
@@ -99,7 +97,6 @@ static const struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
},
{
.num = 21,
@@ -113,7 +110,6 @@ static const struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = true,
},
};
diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c
index df96b0f91f54c..af303b9e8acc7 100644
--- a/drivers/net/wireless/ath/ath12k/mhi.c
+++ b/drivers/net/wireless/ath/ath12k/mhi.c
@@ -31,7 +31,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
},
{
.num = 21,
@@ -45,7 +44,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = true,
},
};
@@ -96,7 +94,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = false,
},
{
.num = 21,
@@ -110,7 +107,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = {
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
- .auto_queue = true,
},
};
diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c
index 69f53625a049d..80e341d2f8a45 100644
--- a/net/qrtr/mhi.c
+++ b/net/qrtr/mhi.c
@@ -24,13 +24,25 @@ static void qcom_mhi_qrtr_dl_callback(struct mhi_device *mhi_dev,
struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev);
int rc;
- if (!qdev || mhi_res->transaction_status)
+ if (!qdev || (mhi_res->transaction_status && mhi_res->transaction_status != -ENOTCONN))
return;
+ /* Channel got reset. So just free the buffer */
+ if (mhi_res->transaction_status == -ENOTCONN) {
+ devm_kfree(&mhi_dev->dev, mhi_res->buf_addr);
+ return;
+ }
+
rc = qrtr_endpoint_post(&qdev->ep, mhi_res->buf_addr,
mhi_res->bytes_xferd);
if (rc == -EINVAL)
dev_err(qdev->dev, "invalid ipcrouter packet\n");
+
+ /* Done with the buffer, now recycle it for future use */
+ rc = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, mhi_res->buf_addr,
+ mhi_dev->mhi_cntrl->buffer_len, MHI_EOT);
+ if (rc)
+ dev_err(&mhi_dev->dev, "Failed to recycle the buffer: %d\n", rc);
}
/* From QRTR to MHI */
@@ -72,6 +84,29 @@ static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
return rc;
}
+static int qcom_mhi_qrtr_queue_dl_buffers(struct mhi_device *mhi_dev)
+{
+ u32 free_desc;
+ void *buf;
+ int ret;
+
+ free_desc = mhi_get_free_desc_count(mhi_dev, DMA_FROM_DEVICE);
+ while (free_desc--) {
+ buf = devm_kmalloc(&mhi_dev->dev, mhi_dev->mhi_cntrl->buffer_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, buf, mhi_dev->mhi_cntrl->buffer_len,
+ MHI_EOT);
+ if (ret) {
+ dev_err(&mhi_dev->dev, "Failed to queue buffer: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
const struct mhi_device_id *id)
{
@@ -87,20 +122,30 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
qdev->ep.xmit = qcom_mhi_qrtr_send;
dev_set_drvdata(&mhi_dev->dev, qdev);
- rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
- if (rc)
- return rc;
/* start channels */
- rc = mhi_prepare_for_transfer_autoqueue(mhi_dev);
- if (rc) {
- qrtr_endpoint_unregister(&qdev->ep);
+ rc = mhi_prepare_for_transfer(mhi_dev);
+ if (rc)
return rc;
- }
+
+ rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
+ if (rc)
+ goto err_unprepare;
+
+ rc = qcom_mhi_qrtr_queue_dl_buffers(mhi_dev);
+ if (rc)
+ goto err_unregister;
dev_dbg(qdev->dev, "Qualcomm MHI QRTR driver probed\n");
return 0;
+
+err_unregister:
+ qrtr_endpoint_unregister(&qdev->ep);
+err_unprepare:
+ mhi_unprepare_from_transfer(mhi_dev);
+
+ return rc;
}
static void qcom_mhi_qrtr_remove(struct mhi_device *mhi_dev)
@@ -151,11 +196,13 @@ static int __maybe_unused qcom_mhi_qrtr_pm_resume_early(struct device *dev)
if (state == MHI_STATE_M3)
return 0;
- rc = mhi_prepare_for_transfer_autoqueue(mhi_dev);
- if (rc)
+ rc = mhi_prepare_for_transfer(mhi_dev);
+ if (rc) {
dev_err(dev, "failed to prepare for autoqueue transfer %d\n", rc);
+ return rc;
+ }
- return rc;
+ return qcom_mhi_qrtr_queue_dl_buffers(mhi_dev);
}
static const struct dev_pm_ops qcom_mhi_qrtr_pm_ops = {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 172/869] PCI: endpoint: Add missing NULL check for alloc_workqueue()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (170 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 171/869] net: qrtr: Drop the MHI auto_queue feature for IPCR DL channels Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 173/869] bpf: Mark bpf_refcount field as unique Greg Kroah-Hartman
` (697 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Haotian Zhang, Manivannan Sadhasivam,
Bjorn Helgaas, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haotian Zhang <vulab@iscas.ac.cn>
[ Upstream commit 03f336a869b3a3f119d3ae52ac9723739c7fb7b6 ]
alloc_workqueue() can return NULL on memory allocation failure. Without
proper error checking, this may lead to a NULL pointer dereference when
queue_work() is later called with the NULL workqueue pointer in
epf_ntb_epc_init().
Add a NULL check immediately after alloc_workqueue() and return -ENOMEM on
failure to prevent the driver from loading with an invalid workqueue
pointer.
Fixes: e35f56bb0330 ("PCI: endpoint: Support NTB transfer between RC and EP")
Fixes: 8b821cf76150 ("PCI: endpoint: Add EP function driver to provide NTB functionality")
Signed-off-by: Haotian Zhang <vulab@iscas.ac.cn>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20251110040446.2065-1-vulab@iscas.ac.cn
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pci/endpoint/functions/pci-epf-ntb.c | 5 +++++
drivers/pci/endpoint/functions/pci-epf-vntb.c | 5 +++++
2 files changed, 10 insertions(+)
diff --git a/drivers/pci/endpoint/functions/pci-epf-ntb.c b/drivers/pci/endpoint/functions/pci-epf-ntb.c
index d12cf226f3282..040c32e438be0 100644
--- a/drivers/pci/endpoint/functions/pci-epf-ntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-ntb.c
@@ -2075,6 +2075,11 @@ static int __init epf_ntb_init(void)
kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM |
WQ_HIGHPRI, 0);
+ if (!kpcintb_workqueue) {
+ pr_err("Failed to allocate kpcintb workqueue\n");
+ return -ENOMEM;
+ }
+
ret = pci_epf_register_driver(&epf_ntb_driver);
if (ret) {
destroy_workqueue(kpcintb_workqueue);
diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c
index f9786637d21c4..963a1a1f983db 100644
--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c
@@ -1418,6 +1418,11 @@ static int __init epf_ntb_init(void)
kpcintb_workqueue = alloc_workqueue("kpcintb", WQ_MEM_RECLAIM |
WQ_HIGHPRI, 0);
+ if (!kpcintb_workqueue) {
+ pr_err("Failed to allocate kpcintb workqueue\n");
+ return -ENOMEM;
+ }
+
ret = pci_epf_register_driver(&epf_ntb_driver);
if (ret) {
destroy_workqueue(kpcintb_workqueue);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 173/869] bpf: Mark bpf_refcount field as unique
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (171 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 172/869] PCI: endpoint: Add missing NULL check for alloc_workqueue() Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 174/869] staging: rtl8723bs: fix xmit_frame/xmit_buf leaks on mgnt-frame error paths Greg Kroah-Hartman
` (696 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kumar Kartikeya Dwivedi,
Eduard Zingerman, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
[ Upstream commit 61e655391cb19c31f94ecd4354f624c81ce4cf75 ]
BPF_REFCOUNT is not marked as a unique field, while it should be. Fix
this oversight.
Fixes: d54730b50bae ("bpf: Introduce opaque bpf_refcount struct and add btf_record plumbing")
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://patch.msgid.link/20260719153634.2908692-4-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/btf.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 5f3b1162208b5..0c6d0b029f016 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -3518,7 +3518,15 @@ static int btf_get_field_type(const struct btf *btf, const struct btf_type *var_
field_mask_test_name(BPF_LIST_NODE, "bpf_list_node");
field_mask_test_name(BPF_RB_ROOT, "bpf_rb_root");
field_mask_test_name(BPF_RB_NODE, "bpf_rb_node");
- field_mask_test_name(BPF_REFCOUNT, "bpf_refcount");
+ if (field_mask & BPF_REFCOUNT) {
+ if (!strcmp(name, "bpf_refcount")) {
+ if (*seen_mask & BPF_REFCOUNT)
+ return -E2BIG;
+ *seen_mask |= BPF_REFCOUNT;
+ type = BPF_REFCOUNT;
+ goto end;
+ }
+ }
/* Only return BPF_KPTR when all other types with matchable names fail */
if (field_mask & BPF_KPTR && !__btf_type_is_struct(var_type)) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 174/869] staging: rtl8723bs: fix xmit_frame/xmit_buf leaks on mgnt-frame error paths
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (172 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 173/869] bpf: Mark bpf_refcount field as unique Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 175/869] drm/msm: Recover HW before retire hung submit Greg Kroah-Hartman
` (695 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Cong Nguyen, Dan Carpenter,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <congnt264@gmail.com>
[ Upstream commit 41b8209376dffbd7b0b85c8bc4697d9166ac62ef ]
issue_beacon(), issue_probersp() and issue_asocrsp() obtain a management
xmit_frame together with its xmit_buf from the driver's fixed-size
management-TX pools via alloc_mgtxmitframe(). On the normal path the frame
is handed to dump_mgntframe(), which transfers ownership and eventually
returns both objects to their pools (the frame and, for beacons, the buf
in rtl8723bs_mgnt_xmit(); other bufs via the pending-xmitbuf/TX-completion
path).
Several error/edge paths return early after a successful
alloc_mgtxmitframe() but before dump_mgntframe(), so ownership is never
transferred and neither object is freed:
- issue_beacon(): beacon larger than 512 bytes
- issue_probersp(): cur_network->ie_length > MAX_IE_SZ
- issue_probersp(): kzalloc() of the SSID scratch buffer fails
- issue_asocrsp(): pkt_type is neither ASSOCRSP nor REASSOCRSP
Because alloc_mgtxmitframe() removes the frame and buf from their free
lists (list_del_init) without placing them on any pending list, an
orphaned pair is on no list and referenced by nobody, so it is only
reclaimed at driver teardown. Repeated hits progressively exhaust the
management-TX pools until alloc_mgtxmitframe() returns NULL and the
interface can no longer send beacons or probe/assoc responses.
Free the frame and buffer on these paths, matching the existing correct
error handling in issue_assocreq().
Fixes: 554c0a3abf21 ("staging: Add rtl8723bs sdio wifi driver")
Signed-off-by: Cong Nguyen <congnt264@gmail.com>
Reviewed-by: Dan Carpenter <error27@gmail.com>
Link: https://patch.msgid.link/20260715111710.295052-1-congnt264@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 22 ++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
index 22c29d1955f5b..740868a156dcd 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
@@ -2258,8 +2258,11 @@ void issue_beacon(struct adapter *padapter, int timeout_ms)
spin_unlock_bh(&pmlmepriv->bcn_update_lock);
- if ((pattrib->pktlen + TXDESC_SIZE) > 512)
+ if ((pattrib->pktlen + TXDESC_SIZE) > 512) {
+ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf);
+ rtw_free_xmitframe(pxmitpriv, pmgntframe);
return;
+ }
pattrib->last_txcmdsz = pattrib->pktlen;
@@ -2322,8 +2325,11 @@ void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p
pframe += pattrib->hdrlen;
- if (cur_network->ie_length > MAX_IE_SZ)
+ if (cur_network->ie_length > MAX_IE_SZ) {
+ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf);
+ rtw_free_xmitframe(pxmitpriv, pmgntframe);
return;
+ }
if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
pwps_ie = rtw_get_wps_ie(cur_network->ies+_FIXED_IE_LENGTH_, cur_network->ie_length-_FIXED_IE_LENGTH_, NULL, &wps_ielen);
@@ -2370,8 +2376,11 @@ void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p
u8 *ies = pmgntframe->buf_addr+TXDESC_OFFSET+sizeof(struct ieee80211_hdr_3addr);
buf = rtw_zmalloc(MAX_IE_SZ);
- if (!buf)
+ if (!buf) {
+ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf);
+ rtw_free_xmitframe(pxmitpriv, pmgntframe);
return;
+ }
ssid_ie = rtw_get_ie(ies+_FIXED_IE_LENGTH_, WLAN_EID_SSID, &ssid_ielen,
(pframe-ies)-_FIXED_IE_LENGTH_);
@@ -2764,10 +2773,13 @@ void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_i
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
- if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP))
+ if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP)) {
SetFrameSubType(pwlanhdr, pkt_type);
- else
+ } else {
+ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf);
+ rtw_free_xmitframe(pxmitpriv, pmgntframe);
return;
+ }
pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr);
pattrib->pktlen += pattrib->hdrlen;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 175/869] drm/msm: Recover HW before retire hung submit
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (173 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 174/869] staging: rtl8723bs: fix xmit_frame/xmit_buf leaks on mgnt-frame error paths Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 176/869] block: zero non-PI portion of auto integrity buffer Greg Kroah-Hartman
` (694 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jie Zhang, Akhil P Oommen,
Konrad Dybcio, Rob Clark, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jie Zhang <jie.zhang@oss.qualcomm.com>
[ Upstream commit b303e1d52811de7d1bcf793560754d4df68d4a1c ]
During recovery, it is not safe to retire the hung submit before we
recover the GPU. Retiring the submit triggers BO free and that can
result in GPU pagefaults since the GPU may be actively accessing those
BOs.
To fix this, retire the submits after gpu recovery is complete in
recover_worker().
Fixes: 1a370be9ac51 ("drm/msm: restart queued submits after hang")
Signed-off-by: Jie Zhang <jie.zhang@oss.qualcomm.com>
Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
Acked-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Patchwork: https://patchwork.freedesktop.org/patch/730655/
Message-ID: <20260605-assorted-fixes-june-v1-2-2caa04f7287c@oss.qualcomm.com>
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/msm/msm_gpu.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index a274b84664237..ffb91e45aefde 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -422,11 +422,11 @@ static void recover_worker(struct kthread_work *work)
}
if (msm_gpu_active(gpu)) {
+ gpu->funcs->recover(gpu);
+
/* retire completed submits, plus the one that hung: */
retire_submits(gpu);
- gpu->funcs->recover(gpu);
-
/*
* Replay all remaining submits starting with highest priority
* ring
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 176/869] block: zero non-PI portion of auto integrity buffer
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (174 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 175/869] drm/msm: Recover HW before retire hung submit Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 177/869] idpf: fix error handling in the init_task on load Greg Kroah-Hartman
` (693 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Caleb Sander Mateos, Anuj Gupta,
Christoph Hellwig, Martin K. Petersen, Jens Axboe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Caleb Sander Mateos <csander@purestorage.com>
[ Upstream commit ca22c566b89164f6e670af56ecc45f47ef3df819 ]
The auto-generated integrity buffer for writes needs to be fully
initialized before being passed to the underlying block device,
otherwise the uninitialized memory can be read back by userspace or
anyone with physical access to the storage device. If protection
information is generated, that portion of the integrity buffer is
already initialized. The integrity data is also zeroed if PI generation
is disabled via sysfs or the PI tuple size is 0. However, this misses
the case where PI is generated and the PI tuple size is nonzero, but the
metadata size is larger than the PI tuple. In this case, the remainder
("opaque") of the metadata is left uninitialized.
Generalize the BLK_INTEGRITY_CSUM_NONE check to cover any case when the
metadata is larger than just the PI tuple.
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Fixes: c546d6f43833 ("block: only zero non-PI metadata tuples in bio_integrity_prep")
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
block/bio-integrity.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index 04bab987b0878..c6721b95d0348 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -12,6 +12,7 @@
#include <linux/bio.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
+#include <linux/t10-pi.h>
#include "blk.h"
static struct kmem_cache *bip_slab;
@@ -428,7 +429,10 @@ bool bio_integrity_prep(struct bio *bio)
* memory to disk for non-integrity metadata where nothing else
* initializes the memory.
*/
- if (bi->csum_type == BLK_INTEGRITY_CSUM_NONE)
+ if (bi->csum_type == BLK_INTEGRITY_CSUM_NONE ||
+ bi->tuple_size > (bi->csum_type == BLK_INTEGRITY_CSUM_CRC64 ?
+ sizeof(struct crc64_pi_tuple) :
+ sizeof(struct t10_pi_tuple)))
gfp |= __GFP_ZERO;
break;
default:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 177/869] idpf: fix error handling in the init_task on load
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (175 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 176/869] block: zero non-PI portion of auto integrity buffer Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 178/869] stddef: Introduce TRAILING_OVERLAP() helper macro Greg Kroah-Hartman
` (692 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vivek Kumar, Emil Tantilov,
Madhu Chittim, Samuel Salin, Tony Nguyen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emil Tantilov <emil.s.tantilov@intel.com>
[ Upstream commit 4d792219fe6f891b5b557a607ac8a0a14eda6e38 ]
If the init_task fails during a driver load, we end up without vports and
netdevs, effectively failing the entire process. In that state a
subsequent reset will result in a crash as the service task attempts to
access uninitialized resources. Following trace is from an error in the
init_task where the CREATE_VPORT (op 501) is rejected by the FW:
[40922.763136] idpf 0000:83:00.0: Device HW Reset initiated
[40924.449797] idpf 0000:83:00.0: Transaction failed (op 501)
[40958.148190] idpf 0000:83:00.0: HW reset detected
[40958.161202] BUG: kernel NULL pointer dereference, address: 00000000000000a8
...
[40958.168094] Workqueue: idpf-0000:83:00.0-vc_event idpf_vc_event_task [idpf]
[40958.168865] RIP: 0010:idpf_vc_event_task+0x9b/0x350 [idpf]
...
[40958.177932] Call Trace:
[40958.178491] <TASK>
[40958.179040] process_one_work+0x226/0x6d0
[40958.179609] worker_thread+0x19e/0x340
[40958.180158] ? __pfx_worker_thread+0x10/0x10
[40958.180702] kthread+0x10f/0x250
[40958.181238] ? __pfx_kthread+0x10/0x10
[40958.181774] ret_from_fork+0x251/0x2b0
[40958.182307] ? __pfx_kthread+0x10/0x10
[40958.182834] ret_from_fork_asm+0x1a/0x30
[40958.183370] </TASK>
Fix the error handling in the init_task to make sure the service and
mailbox tasks are disabled if the error happens during load. These are
started in idpf_vc_core_init(), which spawns the init_task and has no way
of knowing if it failed. If the error happens on reset, following
successful driver load, the tasks can still run, as that will allow the
netdevs to attempt recovery through another reset. Stop the PTP callbacks
either way as those will be restarted by the call to idpf_vc_core_init()
during a successful reset.
Fixes: 0fe45467a104 ("idpf: add create vport and netdev configuration")
Reported-by: Vivek Kumar <iamvivekkumar@google.com>
Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Reviewed-by: Madhu Chittim <madhu.chittim@intel.com>
Tested-by: Samuel Salin <Samuel.salin@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/idpf/idpf_lib.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index 36777ca10f32a..b7da39ba06169 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -1624,10 +1624,9 @@ void idpf_init_task(struct work_struct *work)
set_bit(IDPF_VPORT_REG_NETDEV, vport_config->flags);
}
- /* As all the required vports are created, clear the reset flag
- * unconditionally here in case we were in reset and the link was down.
- */
+ /* Clear the reset and load bits as all vports are created */
clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
+ clear_bit(IDPF_HR_DRV_LOAD, adapter->flags);
/* Start the statistics task now */
queue_delayed_work(adapter->stats_wq, &adapter->stats_task,
msecs_to_jiffies(10 * (pdev->devfn & 0x07)));
@@ -1641,6 +1640,14 @@ void idpf_init_task(struct work_struct *work)
idpf_vport_dealloc(adapter->vports[index]);
}
}
+ /* Cleanup after vc_core_init, which has no way of knowing the
+ * init task failed on driver load.
+ */
+ if (test_and_clear_bit(IDPF_HR_DRV_LOAD, adapter->flags)) {
+ cancel_delayed_work_sync(&adapter->serv_task);
+ cancel_delayed_work_sync(&adapter->mbx_task);
+ }
+
clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
}
@@ -1790,7 +1797,7 @@ static void idpf_init_hard_reset(struct idpf_adapter *adapter)
dev_info(dev, "Device HW Reset initiated\n");
/* Prepare for reset */
- if (test_and_clear_bit(IDPF_HR_DRV_LOAD, adapter->flags)) {
+ if (test_bit(IDPF_HR_DRV_LOAD, adapter->flags)) {
reg_ops->trigger_reset(adapter, IDPF_HR_DRV_LOAD);
} else if (test_and_clear_bit(IDPF_HR_FUNC_RESET, adapter->flags)) {
bool is_reset = idpf_is_reset_detected(adapter);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 178/869] stddef: Introduce TRAILING_OVERLAP() helper macro
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (176 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 177/869] idpf: fix error handling in the init_task on load Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 179/869] virtio_net: Fix misalignment bug in struct virtnet_info Greg Kroah-Hartman
` (691 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Gustavo A. R. Silva, Kees Cook,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gustavo A. R. Silva <gustavoars@kernel.org>
[ Upstream commit 29bb79e9dbf1ba100125e39deb7147acd490903f ]
Add new TRAILING_OVERLAP() helper macro to create a union between
a flexible-array member (FAM) and a set of members that would
otherwise follow it. This overlays the trailing members onto the
FAM while preserving the original memory layout.
Co-developed-by: Kees Cook <kees@kernel.org>
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Link: https://lore.kernel.org/r/aFG8gEwKXAWWIvX0@kspp
Signed-off-by: Kees Cook <kees@kernel.org>
Stable-dep-of: 4156c3745f06 ("virtio_net: Fix misalignment bug in struct virtnet_info")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/stddef.h | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/include/linux/stddef.h b/include/linux/stddef.h
index 929d67710cc51..dab49e2ec8c0a 100644
--- a/include/linux/stddef.h
+++ b/include/linux/stddef.h
@@ -93,4 +93,24 @@ enum {
#define DECLARE_FLEX_ARRAY(TYPE, NAME) \
__DECLARE_FLEX_ARRAY(TYPE, NAME)
+/**
+ * TRAILING_OVERLAP() - Overlap a flexible-array member with trailing members.
+ *
+ * Creates a union between a flexible-array member (FAM) in a struct and a set
+ * of additional members that would otherwise follow it.
+ *
+ * @TYPE: Flexible structure type name, including "struct" keyword.
+ * @NAME: Name for a variable to define.
+ * @FAM: The flexible-array member within @TYPE
+ * @MEMBERS: Trailing overlapping members.
+ */
+#define TRAILING_OVERLAP(TYPE, NAME, FAM, MEMBERS) \
+ union { \
+ TYPE NAME; \
+ struct { \
+ unsigned char __offset_to_##FAM[offsetof(TYPE, FAM)]; \
+ MEMBERS \
+ }; \
+ }
+
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 179/869] virtio_net: Fix misalignment bug in struct virtnet_info
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (177 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 178/869] stddef: Introduce TRAILING_OVERLAP() helper macro Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 180/869] ALSA: usb-audio: Prevent excessive number of frames Greg Kroah-Hartman
` (690 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Gustavo A. R. Silva,
Michael S. Tsirkin, Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gustavo A. R. Silva <gustavoars@kernel.org>
[ Upstream commit 4156c3745f06bc197094b9ee97a9584e69ed00bf ]
Use the new TRAILING_OVERLAP() helper to fix a misalignment bug
along with the following warning:
drivers/net/virtio_net.c:429:46: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
This helper creates a union between a flexible-array member (FAM)
and a set of members that would otherwise follow it (in this case
`u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE];`). This
overlays the trailing members (rss_hash_key_data) onto the FAM
(hash_key_data) while keeping the FAM and the start of MEMBERS aligned.
The static_assert() ensures this alignment remains.
Notice that due to tail padding in flexible `struct
virtio_net_rss_config_trailer`, `rss_trailer.hash_key_data`
(at offset 83 in struct virtnet_info) and `rss_hash_key_data` (at
offset 84 in struct virtnet_info) are misaligned by one byte. See
below:
struct virtio_net_rss_config_trailer {
__le16 max_tx_vq; /* 0 2 */
__u8 hash_key_length; /* 2 1 */
__u8 hash_key_data[]; /* 3 0 */
/* size: 4, cachelines: 1, members: 3 */
/* padding: 1 */
/* last cacheline: 4 bytes */
};
struct virtnet_info {
...
struct virtio_net_rss_config_trailer rss_trailer; /* 80 4 */
/* XXX last struct has 1 byte of padding */
u8 rss_hash_key_data[40]; /* 84 40 */
...
/* size: 832, cachelines: 13, members: 48 */
/* sum members: 801, holes: 8, sum holes: 31 */
/* paddings: 2, sum paddings: 5 */
};
After changes, those members are correctly aligned at offset 795:
struct virtnet_info {
...
union {
struct virtio_net_rss_config_trailer rss_trailer; /* 792 4 */
struct {
unsigned char __offset_to_hash_key_data[3]; /* 792 3 */
u8 rss_hash_key_data[40]; /* 795 40 */
}; /* 792 43 */
}; /* 792 44 */
...
/* size: 840, cachelines: 14, members: 47 */
/* sum members: 801, holes: 8, sum holes: 35 */
/* padding: 4 */
/* paddings: 1, sum paddings: 4 */
/* last cacheline: 8 bytes */
};
As a result, the RSS key passed to the device is shifted by 1
byte: the last byte is cut off, and instead a (possibly
uninitialized) byte is added at the beginning.
As a last note `struct virtio_net_rss_config_hdr *rss_hdr;` is also
moved to the end, since it seems those three members should stick
around together. :)
Cc: stable@vger.kernel.org
Fixes: ed3100e90d0d ("virtio_net: Use new RSS config structs")
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Link: https://patch.msgid.link/aWIItWq5dV9XTTCJ@kspp
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/virtio_net.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index cb640d29d7912..851defa105e04 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -409,9 +409,6 @@ struct virtnet_info {
u16 rss_indir_table_size;
u32 rss_hash_types_supported;
u32 rss_hash_types_saved;
- struct virtio_net_rss_config_hdr *rss_hdr;
- struct virtio_net_rss_config_trailer rss_trailer;
- u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE];
/* Has control virtqueue */
bool has_cvq;
@@ -470,7 +467,16 @@ struct virtnet_info {
struct failover *failover;
u64 device_stats_cap;
+
+ struct virtio_net_rss_config_hdr *rss_hdr;
+
+ /* Must be last as it ends in a flexible-array member. */
+ TRAILING_OVERLAP(struct virtio_net_rss_config_trailer, rss_trailer, hash_key_data,
+ u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE];
+ );
};
+static_assert(offsetof(struct virtnet_info, rss_trailer.hash_key_data) ==
+ offsetof(struct virtnet_info, rss_hash_key_data));
struct padded_vnet_hdr {
struct virtio_net_hdr_v1_hash hdr;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 180/869] ALSA: usb-audio: Prevent excessive number of frames
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (178 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 179/869] virtio_net: Fix misalignment bug in struct virtnet_info Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 181/869] riscv: trace: fix snapshot deadlock with sbi ecall Greg Kroah-Hartman
` (689 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+6db0415d6d5c635f72cb,
Edward Adam Davis, Takashi Iwai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Edward Adam Davis <eadavis@qq.com>
[ Upstream commit ef5749ef8b307bf8717945701b1b79d036af0a15 ]
In this case, the user constructed the parameters with maxpacksize 40
for rate 22050 / pps 1000, and packsize[0] 22 packsize[1] 23. The buffer
size for each data URB is maxpacksize * packets, which in this example
is 40 * 6 = 240; When the user performs a write operation to send audio
data into the ALSA PCM playback stream, the calculated number of frames
is packsize[0] * packets = 264, which exceeds the allocated URB buffer
size, triggering the out-of-bounds (OOB) issue reported by syzbot [1].
Added a check for the number of single data URB frames when calculating
the number of frames to prevent [1].
[1]
BUG: KASAN: slab-out-of-bounds in copy_to_urb+0x261/0x460 sound/usb/pcm.c:1487
Write of size 264 at addr ffff88804337e800 by task syz.0.17/5506
Call Trace:
copy_to_urb+0x261/0x460 sound/usb/pcm.c:1487
prepare_playback_urb+0x953/0x13d0 sound/usb/pcm.c:1611
prepare_outbound_urb+0x377/0xc50 sound/usb/endpoint.c:333
Reported-by: syzbot+6db0415d6d5c635f72cb@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=6db0415d6d5c635f72cb
Tested-by: syzbot+6db0415d6d5c635f72cb@syzkaller.appspotmail.com
Signed-off-by: Edward Adam Davis <eadavis@qq.com>
Link: https://patch.msgid.link/tencent_9AECE6CD2C7A826D902D696C289724E8120A@qq.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/usb/pcm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 08bf535ed1632..3a4666e3bf277 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -1505,7 +1505,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
for (i = 0; i < ctx->packets; i++) {
counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, avail);
- if (counts < 0)
+ if (counts < 0 || frames + counts >= ep->max_urb_frames)
break;
/* set up descriptor */
urb->iso_frame_desc[i].offset = frames * stride;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 181/869] riscv: trace: fix snapshot deadlock with sbi ecall
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (179 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 180/869] ALSA: usb-audio: Prevent excessive number of frames Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 182/869] io_uring/rw: free potentially allocated iovec on cache put failure Greg Kroah-Hartman
` (688 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Martin Kaiser, Paul Walmsley,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Martin Kaiser <martin@kaiser.cx>
[ Upstream commit b0d7f5f0c9f05f1b6d4ee7110f15bef9c11f9df0 ]
If sbi_ecall.c's functions are traceable,
echo "__sbi_ecall:snapshot" > /sys/kernel/tracing/set_ftrace_filter
may get the kernel into a deadlock.
(Functions in sbi_ecall.c are excluded from tracing if
CONFIG_RISCV_ALTERNATIVE_EARLY is set.)
__sbi_ecall triggers a snapshot of the ringbuffer. The snapshot code
raises an IPI interrupt, which results in another call to __sbi_ecall
and another snapshot...
All it takes to get into this endless loop is one initial __sbi_ecall.
On RISC-V systems without SSTC extension, the clock events in
timer-riscv.c issue periodic sbi ecalls, making the problem easy to
trigger.
Always exclude the sbi_ecall.c functions from tracing to fix the
potential deadlock.
sbi ecalls can easiliy be logged via trace events, excluding ecall
functions from function tracing is not a big limitation.
Signed-off-by: Martin Kaiser <martin@kaiser.cx>
Link: https://patch.msgid.link/20251223135043.1336524-1-martin@kaiser.cx
Signed-off-by: Paul Walmsley <pjw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/riscv/kernel/Makefile | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index 0678650817d4f..7328e62a7b8e8 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -3,12 +3,6 @@
# Makefile for the RISC-V Linux kernel
#
-ifdef CONFIG_FTRACE
-CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_sbi.o = $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_return_address.o = $(CC_FLAGS_FTRACE)
-endif
CFLAGS_syscall_table.o += $(call cc-disable-warning, override-init)
CFLAGS_compat_syscall_table.o += $(call cc-disable-warning, override-init)
@@ -24,7 +18,6 @@ CFLAGS_sbi_ecall.o := -mcmodel=medany
ifdef CONFIG_FTRACE
CFLAGS_REMOVE_alternative.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_cpufeature.o = $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_sbi_ecall.o = $(CC_FLAGS_FTRACE)
endif
ifdef CONFIG_RELOCATABLE
CFLAGS_alternative.o += -fno-pie
@@ -43,6 +36,14 @@ CFLAGS_sbi_ecall.o += -D__NO_FORTIFY
endif
endif
+ifdef CONFIG_FTRACE
+CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_sbi.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_return_address.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_sbi_ecall.o = $(CC_FLAGS_FTRACE)
+endif
+
extra-y += vmlinux.lds
obj-y += head.o
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 182/869] io_uring/rw: free potentially allocated iovec on cache put failure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (180 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 181/869] riscv: trace: fix snapshot deadlock with sbi ecall Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 183/869] cxl/mbox: validate payload size before accessing contents in cxl_payload_from_user_allowed() Greg Kroah-Hartman
` (687 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Nitesh Shetty, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <axboe@kernel.dk>
[ Upstream commit 4b9748055457ac3a0710bf210c229d01ea1b01b9 ]
If a read/write request goes through io_req_rw_cleanup() and has an
allocated iovec attached and fails to put to the rw_cache, then it may
end up with an unaccounted iovec pointer. Have io_rw_recycle() return
whether it recycled the request or not, and use that to gauge whether to
free a potential iovec or not.
Reviewed-by: Nitesh Shetty <nj.shetty@samsung.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/rw.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/io_uring/rw.c b/io_uring/rw.c
index d615c61bbbd2e..c8a536ce2fe32 100644
--- a/io_uring/rw.c
+++ b/io_uring/rw.c
@@ -156,22 +156,22 @@ static void io_rw_iovec_free(struct io_async_rw *rw)
}
}
-static void io_rw_recycle(struct io_kiocb *req, unsigned int issue_flags)
+static bool io_rw_recycle(struct io_kiocb *req, unsigned int issue_flags)
{
struct io_async_rw *rw = req->async_data;
struct iovec *iov;
- if (unlikely(issue_flags & IO_URING_F_UNLOCKED)) {
- io_rw_iovec_free(rw);
- return;
- }
+ if (unlikely(issue_flags & IO_URING_F_UNLOCKED))
+ return false;
iov = rw->free_iovec;
if (io_alloc_cache_put(&req->ctx->rw_cache, rw)) {
if (iov)
kasan_mempool_poison_object(iov);
req->async_data = NULL;
req->flags &= ~REQ_F_ASYNC_DATA;
+ return true;
}
+ return false;
}
static void io_req_rw_cleanup(struct io_kiocb *req, unsigned int issue_flags)
@@ -205,7 +205,11 @@ static void io_req_rw_cleanup(struct io_kiocb *req, unsigned int issue_flags)
*/
if (!(req->flags & REQ_F_REFCOUNT)) {
req->flags &= ~REQ_F_NEED_CLEANUP;
- io_rw_recycle(req, issue_flags);
+ if (!io_rw_recycle(req, issue_flags)) {
+ struct io_async_rw *rw = req->async_data;
+
+ io_rw_iovec_free(rw);
+ }
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 183/869] cxl/mbox: validate payload size before accessing contents in cxl_payload_from_user_allowed()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (181 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 182/869] io_uring/rw: free potentially allocated iovec on cache put failure Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 184/869] sched/deadline: Fix missing ENQUEUE_REPLENISH during PI de-boosting Greg Kroah-Hartman
` (686 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Davidlohr Bueso, Alison Schofield,
Dave Jiang, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Davidlohr Bueso <dave@stgolabs.net>
[ Upstream commit 60b5d1f68338aff2c5af0113f04aefa7169c50c2 ]
cxl_payload_from_user_allowed() casts and dereferences the input
payload without first verifying its size. When a raw mailbox command
is sent with an undersized payload (ie: 1 byte for CXL_MBOX_OP_CLEAR_LOG,
which expects a 16-byte UUID), uuid_equal() reads past the allocated buffer,
triggering a KASAN splat:
BUG: KASAN: slab-out-of-bounds in memcmp+0x176/0x1d0 lib/string.c:683
Read of size 8 at addr ffff88810130f5c0 by task syz.1.62/2258
CPU: 2 UID: 0 PID: 2258 Comm: syz.1.62 Not tainted 6.19.0-dirty #3 PREEMPT(voluntary)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:94 [inline]
dump_stack_lvl+0xab/0xe0 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:378 [inline]
print_report+0xce/0x650 mm/kasan/report.c:482
kasan_report+0xce/0x100 mm/kasan/report.c:595
memcmp+0x176/0x1d0 lib/string.c:683
uuid_equal include/linux/uuid.h:73 [inline]
cxl_payload_from_user_allowed drivers/cxl/core/mbox.c:345 [inline]
cxl_mbox_cmd_ctor drivers/cxl/core/mbox.c:368 [inline]
cxl_validate_cmd_from_user drivers/cxl/core/mbox.c:522 [inline]
cxl_send_cmd+0x9c0/0xb50 drivers/cxl/core/mbox.c:643
__cxl_memdev_ioctl drivers/cxl/core/memdev.c:698 [inline]
cxl_memdev_ioctl+0x14f/0x190 drivers/cxl/core/memdev.c:713
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl fs/ioctl.c:583 [inline]
__x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xa8/0x330 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fdaf331ba79
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fdaf1d77038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007fdaf3585fa0 RCX: 00007fdaf331ba79
RDX: 00002000000001c0 RSI: 00000000c030ce02 RDI: 0000000000000003
RBP: 00007fdaf33749df R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007fdaf3586038 R14: 00007fdaf3585fa0 R15: 00007ffced2af768
</TASK>
Add 'in_size' parameter to cxl_payload_from_user_allowed() and validate
the payload is large enough.
Fixes: 6179045ccc0c ("cxl/mbox: Block immediate mode in SET_PARTITION_INFO command")
Fixes: 206f9fa9d555 ("cxl/mbox: Add Clear Log mailbox command")
Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://patch.msgid.link/20260220001618.963490-2-dave@stgolabs.net
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/cxl/core/mbox.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index b094aac78ca15..a1de6b2d4c29a 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -310,6 +310,7 @@ static bool cxl_mem_raw_command_allowed(u16 opcode)
* cxl_payload_from_user_allowed() - Check contents of in_payload.
* @opcode: The mailbox command opcode.
* @payload_in: Pointer to the input payload passed in from user space.
+ * @in_size: Size of @payload_in in bytes.
*
* Return:
* * true - payload_in passes check for @opcode.
@@ -324,12 +325,15 @@ static bool cxl_mem_raw_command_allowed(u16 opcode)
*
* The specific checks are determined by the opcode.
*/
-static bool cxl_payload_from_user_allowed(u16 opcode, void *payload_in)
+static bool cxl_payload_from_user_allowed(u16 opcode, void *payload_in,
+ size_t in_size)
{
switch (opcode) {
case CXL_MBOX_OP_SET_PARTITION_INFO: {
struct cxl_mbox_set_partition_info *pi = payload_in;
+ if (in_size < sizeof(*pi))
+ return false;
if (pi->flags & CXL_SET_PARTITION_IMMEDIATE_FLAG)
return false;
break;
@@ -337,6 +341,8 @@ static bool cxl_payload_from_user_allowed(u16 opcode, void *payload_in)
case CXL_MBOX_OP_CLEAR_LOG: {
const uuid_t *uuid = (uuid_t *)payload_in;
+ if (in_size < sizeof(uuid_t))
+ return false;
/*
* Restrict the ‘Clear log’ action to only apply to
* Vendor debug logs.
@@ -364,7 +370,8 @@ static int cxl_mbox_cmd_ctor(struct cxl_mbox_cmd *mbox_cmd,
if (IS_ERR(mbox_cmd->payload_in))
return PTR_ERR(mbox_cmd->payload_in);
- if (!cxl_payload_from_user_allowed(opcode, mbox_cmd->payload_in)) {
+ if (!cxl_payload_from_user_allowed(opcode, mbox_cmd->payload_in,
+ in_size)) {
dev_dbg(cxl_mbox->host, "%s: input payload not allowed\n",
cxl_mem_opcode_to_name(opcode));
kvfree(mbox_cmd->payload_in);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 184/869] sched/deadline: Fix missing ENQUEUE_REPLENISH during PI de-boosting
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (182 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 183/869] cxl/mbox: validate payload size before accessing contents in cxl_payload_from_user_allowed() Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 185/869] ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz Greg Kroah-Hartman
` (685 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bruno Goncalves, Juri Lelli,
Peter Zijlstra (Intel), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Juri Lelli <juri.lelli@redhat.com>
[ Upstream commit d658686a1331db3bb108ca079d76deb3208ed949 ]
Running stress-ng --schedpolicy 0 on an RT kernel on a big machine
might lead to the following WARNINGs (edited).
sched: DL de-boosted task PID 22725: REPLENISH flag missing
WARNING: CPU: 93 PID: 0 at kernel/sched/deadline.c:239 dequeue_task_dl+0x15c/0x1f8
... (running_bw underflow)
Call trace:
dequeue_task_dl+0x15c/0x1f8 (P)
dequeue_task+0x80/0x168
deactivate_task+0x24/0x50
push_dl_task+0x264/0x2e0
dl_task_timer+0x1b0/0x228
__hrtimer_run_queues+0x188/0x378
hrtimer_interrupt+0xfc/0x260
...
The problem is that when a SCHED_DEADLINE task (lock holder) is
changed to a lower priority class via sched_setscheduler(), it may
fail to properly inherit the parameters of potential DEADLINE donors
if it didn't already inherit them in the past (shorter deadline than
donor's at that time). This might lead to bandwidth accounting
corruption, as enqueue_task_dl() won't recognize the lock holder as
boosted.
The scenario occurs when:
1. A DEADLINE task (donor) blocks on a PI mutex held by another
DEADLINE task (holder), but the holder doesn't inherit parameters
(e.g., it already has a shorter deadline)
2. sched_setscheduler() changes the holder from DEADLINE to a lower
class while still holding the mutex
3. The holder should now inherit DEADLINE parameters from the donor
and be enqueued with ENQUEUE_REPLENISH, but this doesn't happen
Fix the issue by introducing __setscheduler_dl_pi(), which detects when
a DEADLINE (proper or boosted) task gets setscheduled to a lower
priority class. In case, the function makes the task inherit DEADLINE
parameters of the donoer (pi_se) and sets ENQUEUE_REPLENISH flag to
ensure proper bandwidth accounting during the next enqueue operation.
Fixes: 2279f540ea7d ("sched/deadline: Fix priority inheritance with multiple scheduling classes")
Reported-by: Bruno Goncalves <bgoncalv@redhat.com>
Signed-off-by: Juri Lelli <juri.lelli@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260302-upstream-fix-deadline-piboost-b4-v3-1-6ba32184a9e0@redhat.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/sched/syscalls.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
index f9cb7896c1b96..b51b39a109e01 100644
--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -723,6 +723,23 @@ int __sched_setscheduler(struct task_struct *p,
__setscheduler_params(p, attr);
p->sched_class = next_class;
p->prio = newprio;
+#ifdef CONFIG_RT_MUTEXES
+ /*
+ * In case a DEADLINE task (either proper or boosted) gets
+ * setscheduled to a lower priority class, check if it neeeds to
+ * inherit parameters from a potential pi_task. In that case make
+ * sure replenishment happens with the next enqueue.
+ */
+
+ if (dl_prio(newprio) && !dl_policy(policy)) {
+ struct task_struct *pi_task = rt_mutex_get_top_task(p);
+
+ if (pi_task) {
+ p->dl.pi_se = pi_task->dl.pi_se;
+ queue_flags |= ENQUEUE_REPLENISH;
+ }
+ }
+#endif /* CONFIG_RT_MUTEXES */
}
__setscheduler_uclamp(p, attr);
check_class_changing(rq, p, prev_class);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 185/869] ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (183 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 184/869] sched/deadline: Fix missing ENQUEUE_REPLENISH during PI de-boosting Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 186/869] netfilter: nf_tables: clone set on flush only Greg Kroah-Hartman
` (684 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Aleksandr Loktionov, Larysa Zaremba,
Jakub Kicinski, Sasha Levin
6.12-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, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index 98c3764fed396..8d7a2f44469b4 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -546,13 +546,16 @@ 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_get_frame_sz(ring));
if (err)
return err;
}
ice_rx_xsk_pool(ring);
if (ring->xsk_pool) {
+ u32 frag_size =
+ xsk_pool_get_rx_frag_step(ring->xsk_pool);
+
xdp_rxq_info_unreg(&ring->xdp_rxq);
ring->rx_buf_len =
@@ -560,7 +563,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);
+ frag_size);
if (err)
return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
@@ -578,7 +581,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_get_frame_sz(ring));
if (err)
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 186/869] netfilter: nf_tables: clone set on flush only
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (184 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 185/869] ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 187/869] serial: rename local uart_port_lock() -> uart_port_ref_lock() Greg Kroah-Hartman
` (683 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+4924a0edc148e8b4b342,
Pablo Neira Ayuso, Florian Westphal, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <pablo@netfilter.org>
[ Upstream commit fb7fb4016300ac622c964069e286dc83166a5d52 ]
Syzbot with fault injection triggered a failing memory allocation with
GFP_KERNEL which results in a WARN splat:
iter.err
WARNING: net/netfilter/nf_tables_api.c:845 at nft_map_deactivate+0x34e/0x3c0 net/netfilter/nf_tables_api.c:845, CPU#0: syz.0.17/5992
Modules linked in:
CPU: 0 UID: 0 PID: 5992 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026
RIP: 0010:nft_map_deactivate+0x34e/0x3c0 net/netfilter/nf_tables_api.c:845
Code: 8b 05 86 5a 4e 09 48 3b 84 24 a0 00 00 00 75 62 48 8d 65 d8 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc cc e8 63 6d fa f7 90 <0f> 0b 90 43
+80 7c 35 00 00 0f 85 23 fe ff ff e9 26 fe ff ff 89 d9
RSP: 0018:ffffc900045af780 EFLAGS: 00010293
RAX: ffffffff89ca45bd RBX: 00000000fffffff4 RCX: ffff888028111e40
RDX: 0000000000000000 RSI: 00000000fffffff4 RDI: 0000000000000000
RBP: ffffc900045af870 R08: 0000000000400dc0 R09: 00000000ffffffff
R10: dffffc0000000000 R11: fffffbfff1d141db R12: ffffc900045af7e0
R13: 1ffff920008b5f24 R14: dffffc0000000000 R15: ffffc900045af920
FS: 000055557a6a5500(0000) GS:ffff888125496000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007fb5ea271fc0 CR3: 000000003269e000 CR4: 00000000003526f0
Call Trace:
<TASK>
__nft_release_table+0xceb/0x11f0 net/netfilter/nf_tables_api.c:12115
nft_rcv_nl_event+0xc25/0xdb0 net/netfilter/nf_tables_api.c:12187
notifier_call_chain+0x19d/0x3a0 kernel/notifier.c:85
blocking_notifier_call_chain+0x6a/0x90 kernel/notifier.c:380
netlink_release+0x123b/0x1ad0 net/netlink/af_netlink.c:761
__sock_release net/socket.c:662 [inline]
sock_close+0xc3/0x240 net/socket.c:1455
Restrict set clone to the flush set command in the preparation phase.
Add NFT_ITER_UPDATE_CLONE and use it for this purpose, update the rbtree
and pipapo backends to only clone the set when this iteration type is
used.
As for the existing NFT_ITER_UPDATE type, update the pipapo backend to
use the existing set clone if available, otherwise use the existing set
representation. After this update, there is no need to clone a set that
is being deleted, this includes bound anonymous set.
An alternative approach to NFT_ITER_UPDATE_CLONE is to add a .clone
interface and call it from the flush set path.
Reported-by: syzbot+4924a0edc148e8b4b342@syzkaller.appspotmail.com
Fixes: 3f1d886cc7c3 ("netfilter: nft_set_pipapo: move cloning of match info to insert/removal path")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/netfilter/nf_tables.h | 2 ++
net/netfilter/nf_tables_api.c | 10 +++++++++-
net/netfilter/nft_set_pipapo.c | 11 +++++++++--
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 923b2c0d6e844..d14acbc44b44b 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -306,11 +306,13 @@ static inline void *nft_elem_priv_cast(const struct nft_elem_priv *priv)
* @NFT_ITER_UNSPEC: unspecified, to catch errors
* @NFT_ITER_READ: read-only iteration over set elements
* @NFT_ITER_UPDATE: iteration under mutex to update set element state
+ * @NFT_ITER_UPDATE_CLONE: clone set before iteration under mutex to update element
*/
enum nft_iter_type {
NFT_ITER_UNSPEC,
NFT_ITER_READ,
NFT_ITER_UPDATE,
+ NFT_ITER_UPDATE_CLONE,
};
struct nft_set;
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index e4325686953e9..f30c4d8029e0c 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -701,6 +701,11 @@ static void nft_map_catchall_deactivate(const struct nft_ctx *ctx,
}
}
+/* Use NFT_ITER_UPDATE iterator even if this may be called from the preparation
+ * phase, the set clone might already exist from a previous command, or it might
+ * be a set that is going away and does not require a clone. The netns and
+ * netlink release paths also need to work on the live set.
+ */
static void nft_map_deactivate(const struct nft_ctx *ctx, struct nft_set *set)
{
struct nft_set_iter iter = {
@@ -7485,9 +7490,12 @@ static int nft_set_catchall_flush(const struct nft_ctx *ctx,
static int nft_set_flush(struct nft_ctx *ctx, struct nft_set *set, u8 genmask)
{
+ /* The set backend might need to clone the set, do it now from the
+ * preparation phase, use NFT_ITER_UPDATE_CLONE iterator type.
+ */
struct nft_set_iter iter = {
.genmask = genmask,
- .type = NFT_ITER_UPDATE,
+ .type = NFT_ITER_UPDATE_CLONE,
.fn = nft_setelem_flush,
};
diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
index 9d2cfdc94a523..96cd9e17bd64f 100644
--- a/net/netfilter/nft_set_pipapo.c
+++ b/net/netfilter/nft_set_pipapo.c
@@ -2188,13 +2188,20 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
const struct nft_pipapo_match *m;
switch (iter->type) {
- case NFT_ITER_UPDATE:
+ case NFT_ITER_UPDATE_CLONE:
m = pipapo_maybe_clone(set);
if (!m) {
iter->err = -ENOMEM;
return;
}
-
+ nft_pipapo_do_walk(ctx, set, m, iter);
+ break;
+ case NFT_ITER_UPDATE:
+ if (priv->clone)
+ m = priv->clone;
+ else
+ m = rcu_dereference_protected(priv->match,
+ nft_pipapo_transaction_mutex_held(set));
nft_pipapo_do_walk(ctx, set, m, iter);
break;
case NFT_ITER_READ:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 187/869] serial: rename local uart_port_lock() -> uart_port_ref_lock()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (185 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 186/869] netfilter: nf_tables: clone set on flush only Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 188/869] serial: core: fix infinite loop in handle_tx() for PORT_UNKNOWN Greg Kroah-Hartman
` (682 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jiri Slaby (SUSE), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Slaby (SUSE) <jirislaby@kernel.org>
[ Upstream commit 31e0b7863c9bf97bc3a6d735cb4956c929134a80 ]
uart_port_lock() and uart_port_unlock() are (at the same time) defined
as:
* functions in include/linux/serial_core.h
* macros in drivers/tty/serial/serial_core.c
The former are sane uart port lock wrappers.
The latter _lock() does something completely different: it inspects
a uart_state, obtains a uart_port from it, and increases its reference
count. And if that all succeeded, the port is locked too.
Similarly, the _unlock() counterpart first unlocks and then decrements
the refcount too.
This state is REALLY CONFUSING.
So rename the latter (local .c macros):
* uart_port_lock() -> uart_port_ref_lock(), and
* uart_port_unlock() -> uart_port_unlock_deref().
Now, the forbidden while-at-it part: convert from a macro to an inline
-- do it here as the passed 'flags' have to be pointer to ulong now. So
we avoid doubled changes on identical LOCs.
Signed-off-by: Jiri Slaby (SUSE) <jirislaby@kernel.org>
Link: https://lore.kernel.org/r/20250425111315.1036184-5-jirislaby@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: 455ce986fa35 ("serial: core: fix infinite loop in handle_tx() for PORT_UNKNOWN")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/tty/serial/serial_core.c | 75 ++++++++++++++++----------------
1 file changed, 38 insertions(+), 37 deletions(-)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 2a33ad1e039d0..3d5ad8975bf57 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -75,22 +75,23 @@ static inline void uart_port_deref(struct uart_port *uport)
wake_up(&uport->state->remove_wait);
}
-#define uart_port_lock(state, flags) \
- ({ \
- struct uart_port *__uport = uart_port_ref(state); \
- if (__uport) \
- uart_port_lock_irqsave(__uport, &flags); \
- __uport; \
- })
-
-#define uart_port_unlock(uport, flags) \
- ({ \
- struct uart_port *__uport = uport; \
- if (__uport) { \
- uart_port_unlock_irqrestore(__uport, flags); \
- uart_port_deref(__uport); \
- } \
- })
+static inline struct uart_port *uart_port_ref_lock(struct uart_state *state, unsigned long *flags)
+{
+ struct uart_port *uport = uart_port_ref(state);
+
+ if (uport)
+ uart_port_lock_irqsave(uport, flags);
+
+ return uport;
+}
+
+static inline void uart_port_unlock_deref(struct uart_port *uport, unsigned long flags)
+{
+ if (uport) {
+ uart_port_unlock_irqrestore(uport, flags);
+ uart_port_deref(uport);
+ }
+}
static inline struct uart_port *uart_port_check(struct uart_state *state)
{
@@ -127,10 +128,10 @@ static void uart_stop(struct tty_struct *tty)
struct uart_port *port;
unsigned long flags;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (port)
port->ops->stop_tx(port);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
}
static void __uart_start(struct uart_state *state)
@@ -168,9 +169,9 @@ static void uart_start(struct tty_struct *tty)
struct uart_port *port;
unsigned long flags;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
__uart_start(state);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
}
static void
@@ -258,14 +259,14 @@ static int uart_alloc_xmit_buf(struct tty_port *port)
if (!page)
return -ENOMEM;
- uport = uart_port_lock(state, flags);
+ uport = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
state->port.xmit_buf = (unsigned char *)page;
kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf,
PAGE_SIZE);
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
} else {
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
/*
* Do not free() the page under the port lock, see
* uart_free_xmit_buf().
@@ -289,11 +290,11 @@ static void uart_free_xmit_buf(struct tty_port *port)
* console driver may need to allocate/free a debug object, which
* can end up in printk() recursion.
*/
- uport = uart_port_lock(state, flags);
+ uport = uart_port_ref_lock(state, &flags);
xmit_buf = port->xmit_buf;
port->xmit_buf = NULL;
INIT_KFIFO(port->xmit_fifo);
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
free_page((unsigned long)xmit_buf);
}
@@ -592,15 +593,15 @@ static int uart_put_char(struct tty_struct *tty, u8 c)
unsigned long flags;
int ret = 0;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return 0;
}
if (port)
ret = kfifo_put(&state->port.xmit_fifo, c);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -623,9 +624,9 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
if (WARN_ON(!state))
return -EL3HLT;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return 0;
}
@@ -633,7 +634,7 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
ret = kfifo_in(&state->port.xmit_fifo, buf, count);
__uart_start(state);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -644,9 +645,9 @@ static unsigned int uart_write_room(struct tty_struct *tty)
unsigned long flags;
unsigned int ret;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
ret = kfifo_avail(&state->port.xmit_fifo);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -657,9 +658,9 @@ static unsigned int uart_chars_in_buffer(struct tty_struct *tty)
unsigned long flags;
unsigned int ret;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
ret = kfifo_len(&state->port.xmit_fifo);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -678,13 +679,13 @@ static void uart_flush_buffer(struct tty_struct *tty)
pr_debug("uart_flush_buffer(%d) called\n", tty->index);
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!port)
return;
kfifo_reset(&state->port.xmit_fifo);
if (port->ops->flush_buffer)
port->ops->flush_buffer(port);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
tty_port_tty_wakeup(&state->port);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 188/869] serial: core: fix infinite loop in handle_tx() for PORT_UNKNOWN
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (186 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 187/869] serial: rename local uart_port_lock() -> uart_port_ref_lock() Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 189/869] RDMA/efa: Fix use of completion ctx after free Greg Kroah-Hartman
` (681 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jiayuan Chen, stable, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <jiayuan.chen@shopee.com>
[ Upstream commit 455ce986fa356ff43a43c0d363ba95fa152f21d5 ]
uart_write_room() and uart_write() behave inconsistently when
xmit_buf is NULL (which happens for PORT_UNKNOWN ports that were
never properly initialized):
- uart_write_room() returns kfifo_avail() which can be > 0
- uart_write() checks xmit_buf and returns 0 if NULL
This inconsistency causes an infinite loop in drivers that rely on
tty_write_room() to determine if they can write:
while (tty_write_room(tty) > 0) {
written = tty->ops->write(...);
// written is always 0, loop never exits
}
For example, caif_serial's handle_tx() enters an infinite loop when
used with PORT_UNKNOWN serial ports, causing system hangs.
Fix by making uart_write_room() also check xmit_buf and return 0 if
it's NULL, consistent with uart_write().
Reproducer: https://gist.github.com/mrpre/d9a694cc0e19828ee3bc3b37983fde13
Signed-off-by: Jiayuan Chen <jiayuan.chen@shopee.com>
Cc: stable <stable@kernel.org>
Link: https://patch.msgid.link/20260204074327.226165-1-jiayuan.chen@linux.dev
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/tty/serial/serial_core.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 3d5ad8975bf57..816f83141afd3 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -646,7 +646,10 @@ static unsigned int uart_write_room(struct tty_struct *tty)
unsigned int ret;
port = uart_port_ref_lock(state, &flags);
- ret = kfifo_avail(&state->port.xmit_fifo);
+ if (!state->port.xmit_buf)
+ ret = 0;
+ else
+ ret = kfifo_avail(&state->port.xmit_fifo);
uart_port_unlock_deref(port, flags);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 189/869] RDMA/efa: Fix use of completion ctx after free
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (187 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 188/869] serial: core: fix infinite loop in handle_tx() for PORT_UNKNOWN Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 190/869] bpf: Fix exception exit lock checking for subprogs Greg Kroah-Hartman
` (680 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Daniel Kranzdorf, Michael Margolin,
Yonatan Nachum, Leon Romanovsky, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yonatan Nachum <ynachum@amazon.com>
[ Upstream commit ef3b06742c8a201d0e83edc9a33a89a4fe3009f8 ]
On admin queue completion handling, if the admin command completed with
error we print data from the completion context. The issue is that we
already freed the completion context in polling/interrupts handler which
means we print data from context in an unknown state (it might be
already used again).
Change the admin submission flow so alloc/dealloc of the context will be
symmetric and dealloc will be called after any potential use of the
context.
Fixes: 68fb9f3e312a ("RDMA/efa: Remove redundant NULL pointer check of CQE")
Reviewed-by: Daniel Kranzdorf <dkkranzd@amazon.com>
Reviewed-by: Michael Margolin <mrgolin@amazon.com>
Signed-off-by: Yonatan Nachum <ynachum@amazon.com>
Link: https://patch.msgid.link/20260308165350.18219-1-ynachum@amazon.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/efa/efa_com.c | 28 ++++++++++------------------
1 file changed, 10 insertions(+), 18 deletions(-)
diff --git a/drivers/infiniband/hw/efa/efa_com.c b/drivers/infiniband/hw/efa/efa_com.c
index 00e339abc2c13..090279dd0ab9d 100644
--- a/drivers/infiniband/hw/efa/efa_com.c
+++ b/drivers/infiniband/hw/efa/efa_com.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
/*
- * Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#include "efa_com.h"
@@ -499,7 +499,6 @@ static int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_c
{
unsigned long timeout;
unsigned long flags;
- int err;
timeout = jiffies + usecs_to_jiffies(aq->completion_timeout);
@@ -519,24 +518,20 @@ static int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_c
atomic64_inc(&aq->stats.no_completion);
clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state);
- err = -ETIME;
- goto out;
+ return -ETIME;
}
msleep(aq->poll_interval);
}
- err = efa_com_comp_status_to_errno(comp_ctx->user_cqe->acq_common_descriptor.status);
-out:
- efa_com_put_comp_ctx(aq, comp_ctx);
- return err;
+ return efa_com_comp_status_to_errno(
+ comp_ctx->user_cqe->acq_common_descriptor.status);
}
static int efa_com_wait_and_process_admin_cq_interrupts(struct efa_comp_ctx *comp_ctx,
struct efa_com_admin_queue *aq)
{
unsigned long flags;
- int err;
wait_for_completion_timeout(&comp_ctx->wait_event,
usecs_to_jiffies(aq->completion_timeout));
@@ -570,14 +565,11 @@ static int efa_com_wait_and_process_admin_cq_interrupts(struct efa_comp_ctx *com
comp_ctx, aq->sq.pc, aq->sq.cc, aq->cq.cc);
clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state);
- err = -ETIME;
- goto out;
+ return -ETIME;
}
- err = efa_com_comp_status_to_errno(comp_ctx->user_cqe->acq_common_descriptor.status);
-out:
- efa_com_put_comp_ctx(aq, comp_ctx);
- return err;
+ return efa_com_comp_status_to_errno(
+ comp_ctx->user_cqe->acq_common_descriptor.status);
}
/*
@@ -644,13 +636,13 @@ int efa_com_cmd_exec(struct efa_com_admin_queue *aq,
if (err) {
ibdev_err_ratelimited(
aq->efa_dev,
- "Failed to process command %s (opcode %u) comp_status %d err %d\n",
+ "Failed to process command %s (opcode %u) err %d\n",
efa_com_cmd_str(cmd->aq_common_descriptor.opcode),
- cmd->aq_common_descriptor.opcode,
- comp_ctx->user_cqe->acq_common_descriptor.status, err);
+ cmd->aq_common_descriptor.opcode, err);
atomic64_inc(&aq->stats.cmd_err);
}
+ efa_com_put_comp_ctx(aq, comp_ctx);
up(&aq->avail_cmds);
return err;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 190/869] bpf: Fix exception exit lock checking for subprogs
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (188 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 189/869] RDMA/efa: Fix use of completion ctx after free Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 191/869] drm/mediatek: dsi: Store driver data before invoking mipi_dsi_host_register Greg Kroah-Hartman
` (679 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ihor Solodrai, Yonghong Song,
Kumar Kartikeya Dwivedi, Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ihor Solodrai <ihor.solodrai@linux.dev>
[ Upstream commit 6c2128505f61b504c79a20b89596feba61388112 ]
process_bpf_exit_full() passes check_lock = !curframe to
check_resource_leak(), which is false in cases when bpf_throw() is
called from a static subprog. This makes check_resource_leak() to skip
validation of active_rcu_locks, active_preempt_locks, and
active_irq_id on exception exits from subprogs.
At runtime bpf_throw() unwinds the stack via ORC without releasing any
user-acquired locks, which may cause various issues as the result.
Fix by setting check_lock = true for exception exits regardless of
curframe, since exceptions bypass all intermediate frame
cleanup. Update the error message prefix to "bpf_throw" for exception
exits to distinguish them from normal BPF_EXIT.
Fix reject_subprog_with_rcu_read_lock test which was previously
passing for the wrong reason. Test program returned directly from the
subprog call without closing the RCU section, so the error was
triggered by the unclosed RCU lock on normal exit, not by
bpf_throw. Update __msg annotations for affected tests to match the
new "bpf_throw" error prefix.
The spin_lock case is not affected because they are already checked [1]
at the call site in do_check_insn() before bpf_throw can run.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/bpf/verifier.c?h=v7.0-rc4#n21098
Assisted-by: Claude:claude-opus-4-6
Fixes: f18b03fabaa9 ("bpf: Implement BPF exceptions")
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Acked-by: Yonghong Song <yonghong.song@linux.dev>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260320000809.643798-1-ihor.solodrai@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 26 +++++++++++++------
.../selftests/bpf/progs/exceptions_fail.c | 9 ++++---
2 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2bcd098f774ba..4978c1d68bd98 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -19024,20 +19024,30 @@ static int do_check(struct bpf_verifier_env *env)
return -EINVAL;
}
process_bpf_exit_full:
- if (env->cur_state->active_lock.ptr && !env->cur_state->curframe) {
- verbose(env, "bpf_spin_unlock is missing\n");
+ if (env->cur_state->active_lock.ptr &&
+ (exception_exit || !env->cur_state->curframe)) {
+ verbose(env, exception_exit ?
+ "bpf_throw cannot be used inside bpf_spin_lock-ed region\n" :
+ "bpf_spin_unlock is missing\n");
return -EINVAL;
}
- if (env->cur_state->active_rcu_lock && !env->cur_state->curframe) {
- verbose(env, "bpf_rcu_read_unlock is missing\n");
+ if (env->cur_state->active_rcu_lock &&
+ (exception_exit || !env->cur_state->curframe)) {
+ verbose(env, exception_exit ?
+ "bpf_throw cannot be used inside bpf_rcu_read_lock-ed region\n" :
+ "bpf_rcu_read_unlock is missing\n");
return -EINVAL;
}
- if (env->cur_state->active_preempt_lock && !env->cur_state->curframe) {
- verbose(env, "%d bpf_preempt_enable%s missing\n",
- env->cur_state->active_preempt_lock,
- env->cur_state->active_preempt_lock == 1 ? " is" : "(s) are");
+ if (env->cur_state->active_preempt_lock &&
+ (exception_exit || !env->cur_state->curframe)) {
+ if (exception_exit)
+ verbose(env, "bpf_throw cannot be used inside bpf_preempt_disable-ed region\n");
+ else
+ verbose(env, "%d bpf_preempt_enable%s missing\n",
+ env->cur_state->active_preempt_lock,
+ env->cur_state->active_preempt_lock == 1 ? " is" : "(s) are");
return -EINVAL;
}
diff --git a/tools/testing/selftests/bpf/progs/exceptions_fail.c b/tools/testing/selftests/bpf/progs/exceptions_fail.c
index 9cceb65211433..d7f1c492e3dd3 100644
--- a/tools/testing/selftests/bpf/progs/exceptions_fail.c
+++ b/tools/testing/selftests/bpf/progs/exceptions_fail.c
@@ -8,6 +8,7 @@
#include "bpf_experimental.h"
extern void bpf_rcu_read_lock(void) __ksym;
+extern void bpf_rcu_read_unlock(void) __ksym;
#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
@@ -131,7 +132,7 @@ int reject_subprog_with_lock(void *ctx)
}
SEC("?tc")
-__failure __msg("bpf_rcu_read_unlock is missing")
+__failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
int reject_with_rcu_read_lock(void *ctx)
{
bpf_rcu_read_lock();
@@ -147,11 +148,13 @@ __noinline static int throwing_subprog(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("bpf_rcu_read_unlock is missing")
+__failure __msg("bpf_throw cannot be used inside bpf_rcu_read_lock-ed region")
int reject_subprog_with_rcu_read_lock(void *ctx)
{
bpf_rcu_read_lock();
- return throwing_subprog(ctx);
+ throwing_subprog(ctx);
+ bpf_rcu_read_unlock();
+ return 0;
}
static bool rbless(struct bpf_rb_node *n1, const struct bpf_rb_node *n2)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 191/869] drm/mediatek: dsi: Store driver data before invoking mipi_dsi_host_register
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (189 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 190/869] bpf: Fix exception exit lock checking for subprogs Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 192/869] s390/mm: Add missing secure storage access fixups for donated memory Greg Kroah-Hartman
` (678 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Luca Leonardo Scorcia,
AngeloGioacchino Del Regno, CK Hu, Chun-Kuang Hu, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luca Leonardo Scorcia <l.scorcia@gmail.com>
[ Upstream commit 4cfdfeb6ac06079f92fccd977fa742d6c5b8dd3a ]
The call to mipi_dsi_host_register triggers a callback to mtk_dsi_bind,
which uses dev_get_drvdata to retrieve the mtk_dsi struct, so this
structure needs to be stored inside the driver data before invoking it.
As drvdata is currently uninitialized it leads to a crash when
registering the DSI DRM encoder right after acquiring
the mode_config.idr_mutex, blocking all subsequent DRM operations.
Fixes the following crash during mediatek-drm probe (tested on Xiaomi
Smart Clock x04g):
Unable to handle kernel NULL pointer dereference at virtual address
0000000000000040
[...]
Modules linked in: mediatek_drm(+) drm_display_helper cec drm_client_lib
drm_dma_helper drm_kms_helper panel_simple
[...]
Call trace:
drm_mode_object_add+0x58/0x98 (P)
__drm_encoder_init+0x48/0x140
drm_encoder_init+0x6c/0xa0
drm_simple_encoder_init+0x20/0x34 [drm_kms_helper]
mtk_dsi_bind+0x34/0x13c [mediatek_drm]
component_bind_all+0x120/0x280
mtk_drm_bind+0x284/0x67c [mediatek_drm]
try_to_bring_up_aggregate_device+0x23c/0x320
__component_add+0xa4/0x198
component_add+0x14/0x20
mtk_dsi_host_attach+0x78/0x100 [mediatek_drm]
mipi_dsi_attach+0x2c/0x50
panel_simple_dsi_probe+0x4c/0x9c [panel_simple]
mipi_dsi_drv_probe+0x1c/0x28
really_probe+0xc0/0x3dc
__driver_probe_device+0x80/0x160
driver_probe_device+0x40/0x120
__device_attach_driver+0xbc/0x17c
bus_for_each_drv+0x88/0xf0
__device_attach+0x9c/0x1cc
device_initial_probe+0x54/0x60
bus_probe_device+0x34/0xa0
device_add+0x5b0/0x800
mipi_dsi_device_register_full+0xdc/0x16c
mipi_dsi_host_register+0xc4/0x17c
mtk_dsi_probe+0x10c/0x260 [mediatek_drm]
platform_probe+0x5c/0xa4
really_probe+0xc0/0x3dc
__driver_probe_device+0x80/0x160
driver_probe_device+0x40/0x120
__driver_attach+0xc8/0x1f8
bus_for_each_dev+0x7c/0xe0
driver_attach+0x24/0x30
bus_add_driver+0x11c/0x240
driver_register+0x68/0x130
__platform_register_drivers+0x64/0x160
mtk_drm_init+0x24/0x1000 [mediatek_drm]
do_one_initcall+0x60/0x1d0
do_init_module+0x54/0x240
load_module+0x1838/0x1dc0
init_module_from_file+0xd8/0xf0
__arm64_sys_finit_module+0x1b4/0x428
invoke_syscall.constprop.0+0x48/0xc8
do_el0_svc+0x3c/0xb8
el0_svc+0x34/0xe8
el0t_64_sync_handler+0xa0/0xe4
el0t_64_sync+0x198/0x19c
Code: 52800022 941004ab 2a0003f3 37f80040 (29005a80)
Fixes: e4732b590a77 ("drm/mediatek: dsi: Register DSI host after acquiring clocks and PHY")
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: CK Hu <ck.hu@mediatek.com>
Link: https://patchwork.kernel.org/project/dri-devel/patch/20260225094047.76780-1-l.scorcia@gmail.com/
Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/mediatek/mtk_dsi.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 96dcfbf6ba5a9..57e8abc5c5f6f 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -1192,6 +1192,7 @@ static int mtk_dsi_probe(struct platform_device *pdev)
if (!dsi)
return -ENOMEM;
+ dsi->bridge.funcs = &mtk_dsi_bridge_funcs;
dsi->driver_data = of_device_get_match_data(dev);
dsi->engine_clk = devm_clk_get(dev, "engine");
@@ -1224,6 +1225,11 @@ static int mtk_dsi_probe(struct platform_device *pdev)
dsi->host.ops = &mtk_dsi_ops;
dsi->host.dev = dev;
+
+ init_waitqueue_head(&dsi->irq_wait_queue);
+
+ platform_set_drvdata(pdev, dsi);
+
ret = mipi_dsi_host_register(&dsi->host);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to register DSI host\n");
@@ -1235,11 +1241,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, ret, "Failed to request DSI irq\n");
}
- init_waitqueue_head(&dsi->irq_wait_queue);
-
- platform_set_drvdata(pdev, dsi);
-
- dsi->bridge.funcs = &mtk_dsi_bridge_funcs;
dsi->bridge.of_node = dev->of_node;
dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 192/869] s390/mm: Add missing secure storage access fixups for donated memory
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (190 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 191/869] drm/mediatek: dsi: Store driver data before invoking mipi_dsi_host_register Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 193/869] dm: limit swapping tables for devices with zone write plugs Greg Kroah-Hartman
` (677 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Heiko Carstens, Claudio Imbrenda,
Christian Borntraeger, Janosch Frank, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Janosch Frank <frankja@linux.ibm.com>
[ Upstream commit b00be77302d7ec4ad0367bb236494fce7172b730 ]
There are special cases where secure storage access exceptions happen
in a kernel context for pages that don't have the PG_arch_1 bit
set. That bit is set for non-exported guest secure storage (memory)
but is absent on storage donated to the Ultravisor since the kernel
isn't allowed to export donated pages.
Prior to this patch we would try to export the page by calling
arch_make_folio_accessible() which would instantly return since the
arch bit is absent signifying that the page was already exported and
no further action is necessary. This leads to secure storage access
exception loops which can never be resolved.
With this patch we unconditionally try to export and if that fails we
fixup.
Fixes: 084ea4d611a3 ("s390/mm: add (non)secure page access exceptions handlers")
Reported-by: Heiko Carstens <hca@linux.ibm.com>
Suggested-by: Heiko Carstens <hca@linux.ibm.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Tested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/mm/fault.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index f907e916aa20d..2d03af60ed88f 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -443,10 +443,17 @@ void do_secure_storage_access(struct pt_regs *regs)
folio = phys_to_folio(addr);
if (unlikely(!folio_try_get(folio)))
return;
- rc = arch_make_folio_accessible(folio);
+ rc = uv_convert_from_secure(folio_to_phys(folio));
+ if (!rc)
+ clear_bit(PG_arch_1, &folio->flags.f);
folio_put(folio);
+ /*
+ * There are some valid fixup types for kernel
+ * accesses to donated secure memory. zeropad is one
+ * of them.
+ */
if (rc)
- BUG();
+ return handle_fault_error_nolock(regs, 0);
} else {
if (faulthandler_disabled())
return handle_fault_error_nolock(regs, 0);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 193/869] dm: limit swapping tables for devices with zone write plugs
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (191 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 192/869] s390/mm: Add missing secure storage access fixups for donated memory Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 194/869] drm/tilcdc: Fix removal actions in case of failed probe Greg Kroah-Hartman
` (676 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Damien Le Moal, Benjamin Marzinski,
Mikulas Patocka, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Marzinski <bmarzins@redhat.com>
[ Upstream commit 121218bef4c1df165181f5cd8fc3a2246bac817e ]
dm_revalidate_zones() only allowed new or previously unzoned devices to
call blk_revalidate_disk_zones(). If the device was already zoned,
disk->nr_zones would always equal md->nr_zones, so dm_revalidate_zones()
returned without doing any work. This would make the zoned settings for
the device not match the new table. If the device had zone write plug
resources, it could run into errors like bdev_zone_is_seq() reading
invalid memory because disk->conv_zones_bitmap was the wrong size.
If the device doesn't have any zone write plug resources, calling
blk_revalidate_disk_zones() will always correctly update device. If
blk_revalidate_disk_zones() fails, it can still overwrite or clear the
current disk->nr_zones value. In this case, DM must restore the previous
value of disk->nr_zones, so that the zoned settings will continue to
match the previous value that it fell back to.
If the device already has zone write plug resources,
blk_revalidate_disk_zones() will not correctly update them, if it is
called for arbitrary zoned device changes. Since there is not much need
for this ability, the easiest solution is to disallow any table reloads
that change the zoned settings, for devices that already have zone plug
resources. Specifically, if a device already has zone plug resources
allocated, it can only switch to another zoned table that also emulates
zone append. Also, it cannot change the device size or the zone size. A
device can switch to an error target.
Fixes: bb37d77239af2 ("dm: introduce zone append emulation")
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Tested-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/dm-table.c | 41 ++++++++++++++++++++++++++++++++++++-----
drivers/md/dm-zone.c | 34 +++++++++++++++++++++++++---------
drivers/md/dm.c | 6 ++++++
drivers/md/dm.h | 5 +++++
4 files changed, 72 insertions(+), 14 deletions(-)
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 20b8f560a2da5..505f8a900ec9e 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -1505,6 +1505,18 @@ bool dm_table_has_no_data_devices(struct dm_table *t)
return true;
}
+bool dm_table_is_wildcard(struct dm_table *t)
+{
+ for (unsigned int i = 0; i < t->num_targets; i++) {
+ struct dm_target *ti = dm_table_get_target(t, i);
+
+ if (!dm_target_is_wildcard(ti->type))
+ return false;
+ }
+
+ return true;
+}
+
static int device_not_zoned(struct dm_target *ti, struct dm_dev *dev,
sector_t start, sector_t len, void *data)
{
@@ -1823,6 +1835,19 @@ static bool dm_table_supports_secure_erase(struct dm_table *t)
return true;
}
+bool dm_table_supports_size_change(struct dm_table *t, sector_t old_size,
+ sector_t new_size)
+{
+ if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && dm_has_zone_plugs(t->md) &&
+ old_size != new_size) {
+ DMWARN("%s: device has zone write plug resources. "
+ "Cannot change size",
+ dm_device_name(t->md));
+ return false;
+ }
+ return true;
+}
+
int dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
struct queue_limits *limits)
{
@@ -1864,11 +1889,17 @@ int dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
dax_write_cache(t->md->dax_dev, true);
/* For a zoned table, setup the zone related queue attributes. */
- if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
- (limits->features & BLK_FEAT_ZONED)) {
- r = dm_set_zones_restrictions(t, q, limits);
- if (r)
- return r;
+ if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
+ if (limits->features & BLK_FEAT_ZONED) {
+ r = dm_set_zones_restrictions(t, q, limits);
+ if (r)
+ return r;
+ } else if (dm_has_zone_plugs(t->md)) {
+ DMWARN("%s: device has zone write plug resources. "
+ "Cannot switch to non-zoned table.",
+ dm_device_name(t->md));
+ return -EINVAL;
+ }
}
r = queue_limits_set(q, limits);
diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c
index 912b9fe1f5648..85777d875cc00 100644
--- a/drivers/md/dm-zone.c
+++ b/drivers/md/dm-zone.c
@@ -163,22 +163,22 @@ int dm_revalidate_zones(struct dm_table *t, struct request_queue *q)
{
struct mapped_device *md = t->md;
struct gendisk *disk = md->disk;
+ unsigned int nr_zones = disk->nr_zones;
int ret;
if (!get_capacity(disk))
return 0;
- /* Revalidate only if something changed. */
- if (!disk->nr_zones || disk->nr_zones != md->nr_zones) {
- DMINFO("%s using %s zone append",
- disk->disk_name,
- queue_emulates_zone_append(q) ? "emulated" : "native");
- md->nr_zones = 0;
- }
-
- if (md->nr_zones)
+ /*
+ * Do not revalidate if zone write plug resources have already
+ * been allocated.
+ */
+ if (dm_has_zone_plugs(md))
return 0;
+ DMINFO("%s using %s zone append", disk->disk_name,
+ queue_emulates_zone_append(q) ? "emulated" : "native");
+
/*
* Our table is not live yet. So the call to dm_get_live_table()
* in dm_blk_report_zones() will fail. Set a temporary pointer to
@@ -192,6 +192,7 @@ int dm_revalidate_zones(struct dm_table *t, struct request_queue *q)
if (ret) {
DMERR("Revalidate zones failed %d", ret);
+ disk->nr_zones = nr_zones;
return ret;
}
@@ -401,6 +402,21 @@ int dm_set_zones_restrictions(struct dm_table *t, struct request_queue *q,
return 0;
}
+ if (get_capacity(disk) && dm_has_zone_plugs(t->md)) {
+ if (q->limits.chunk_sectors != lim->chunk_sectors) {
+ DMWARN("%s: device has zone write plug resources. "
+ "Cannot change zone size",
+ disk->disk_name);
+ return -EINVAL;
+ }
+ if (lim->max_zone_append_sectors != 0 &&
+ !dm_table_is_wildcard(t)) {
+ DMWARN("%s: device has zone write plug resources. "
+ "New table must emulate zone append",
+ disk->disk_name);
+ return -EINVAL;
+ }
+ }
/*
* Warn once (when the capacity is not yet set) if the mapped device is
* partially using zone resources of the target devices as that leads to
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 20f6c6ebace0e..e23d4c63484b3 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -2451,6 +2451,12 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
size = dm_table_get_size(t);
old_size = dm_get_size(md);
+
+ if (!dm_table_supports_size_change(t, old_size, size)) {
+ old_map = ERR_PTR(-EINVAL);
+ goto out;
+ }
+
set_capacity(md->disk, size);
ret = dm_table_set_restrictions(t, md->queue, limits);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 8ad782249af88..8887c1f65639d 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -58,6 +58,7 @@ void dm_table_event_callback(struct dm_table *t,
void (*fn)(void *), void *context);
struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector);
bool dm_table_has_no_data_devices(struct dm_table *table);
+bool dm_table_is_wildcard(struct dm_table *t);
int dm_calculate_queue_limits(struct dm_table *table,
struct queue_limits *limits);
int dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
@@ -73,6 +74,8 @@ struct dm_target *dm_table_get_immutable_target(struct dm_table *t);
struct dm_target *dm_table_get_wildcard_target(struct dm_table *t);
bool dm_table_bio_based(struct dm_table *t);
bool dm_table_request_based(struct dm_table *t);
+bool dm_table_supports_size_change(struct dm_table *t, sector_t old_size,
+ sector_t new_size);
void dm_lock_md_type(struct mapped_device *md);
void dm_unlock_md_type(struct mapped_device *md);
@@ -112,12 +115,14 @@ bool dm_is_zone_write(struct mapped_device *md, struct bio *bio);
int dm_zone_get_reset_bitmap(struct mapped_device *md, struct dm_table *t,
sector_t sector, unsigned int nr_zones,
unsigned long *need_reset);
+#define dm_has_zone_plugs(md) ((md)->disk->zone_wplugs_hash != NULL)
#else
#define dm_blk_report_zones NULL
static inline bool dm_is_zone_write(struct mapped_device *md, struct bio *bio)
{
return false;
}
+#define dm_has_zone_plugs(md) false
#endif
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 194/869] drm/tilcdc: Fix removal actions in case of failed probe
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (192 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 193/869] dm: limit swapping tables for devices with zone write plugs Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 195/869] net: Factorise setup_net() and cleanup_net() Greg Kroah-Hartman
` (675 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kory Maincent (TI.com),
Douglas Anderson, Luca Ceresoli, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kory Maincent (TI.com) <kory.maincent@bootlin.com>
[ Upstream commit a585c7ef9cabda58088916baedc6573e9a5cd2a7 ]
The drm_kms_helper_poll_fini() and drm_atomic_helper_shutdown() helpers
should only be called when the device has been successfully registered.
Currently, these functions are called unconditionally in tilcdc_fini(),
which causes warnings during probe deferral scenarios.
[ 7.972317] WARNING: CPU: 0 PID: 23 at drivers/gpu/drm/drm_atomic_state_helper.c:175 drm_atomic_helper_crtc_duplicate_state+0x60/0x68
...
[ 8.005820] drm_atomic_helper_crtc_duplicate_state from drm_atomic_get_crtc_state+0x68/0x108
[ 8.005858] drm_atomic_get_crtc_state from drm_atomic_helper_disable_all+0x90/0x1c8
[ 8.005885] drm_atomic_helper_disable_all from drm_atomic_helper_shutdown+0x90/0x144
[ 8.005911] drm_atomic_helper_shutdown from tilcdc_fini+0x68/0xf8 [tilcdc]
[ 8.005957] tilcdc_fini [tilcdc] from tilcdc_pdev_probe+0xb0/0x6d4 [tilcdc]
Fix this by rewriting the failed probe cleanup path using the standard
goto error handling pattern, which ensures that cleanup functions are
only called on successfully initialized resources. Additionally, remove
the now-unnecessary is_registered flag.
Cc: stable@vger.kernel.org
Fixes: 3c4babae3c4a ("drm: Call drm_atomic_helper_shutdown() at shutdown/remove time for misc drivers")
Signed-off-by: Kory Maincent (TI.com) <kory.maincent@bootlin.com>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Link: https://patch.msgid.link/20251125090546.137193-1-kory.maincent@bootlin.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 2 +-
drivers/gpu/drm/tilcdc/tilcdc_drv.c | 53 ++++++++++++++++++----------
drivers/gpu/drm/tilcdc/tilcdc_drv.h | 2 +-
3 files changed, 37 insertions(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index b5f60b2b2d0e7..41802c9bd1475 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -586,7 +586,7 @@ static void tilcdc_crtc_recover_work(struct work_struct *work)
drm_modeset_unlock(&crtc->mutex);
}
-static void tilcdc_crtc_destroy(struct drm_crtc *crtc)
+void tilcdc_crtc_destroy(struct drm_crtc *crtc)
{
struct tilcdc_drm_private *priv = crtc->dev->dev_private;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index cd5eefa06060d..322e02f5a763a 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -171,8 +171,7 @@ static void tilcdc_fini(struct drm_device *dev)
if (priv->crtc)
tilcdc_crtc_shutdown(priv->crtc);
- if (priv->is_registered)
- drm_dev_unregister(dev);
+ drm_dev_unregister(dev);
drm_kms_helper_poll_fini(dev);
drm_atomic_helper_shutdown(dev);
@@ -219,21 +218,21 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
priv->wq = alloc_ordered_workqueue("tilcdc", 0);
if (!priv->wq) {
ret = -ENOMEM;
- goto init_failed;
+ goto put_drm;
}
priv->mmio = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->mmio)) {
dev_err(dev, "failed to request / ioremap\n");
ret = PTR_ERR(priv->mmio);
- goto init_failed;
+ goto free_wq;
}
priv->clk = clk_get(dev, "fck");
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get functional clock\n");
ret = -ENODEV;
- goto init_failed;
+ goto free_wq;
}
pm_runtime_enable(dev);
@@ -312,7 +311,7 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
ret = tilcdc_crtc_create(ddev);
if (ret < 0) {
dev_err(dev, "failed to create crtc\n");
- goto init_failed;
+ goto disable_pm;
}
modeset_init(ddev);
@@ -323,46 +322,46 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
if (ret) {
dev_err(dev, "failed to register cpufreq notifier\n");
priv->freq_transition.notifier_call = NULL;
- goto init_failed;
+ goto destroy_crtc;
}
#endif
if (priv->is_componentized) {
ret = component_bind_all(dev, ddev);
if (ret < 0)
- goto init_failed;
+ goto unregister_cpufreq_notif;
ret = tilcdc_add_component_encoder(ddev);
if (ret < 0)
- goto init_failed;
+ goto unbind_component;
} else {
ret = tilcdc_attach_external_device(ddev);
if (ret)
- goto init_failed;
+ goto unregister_cpufreq_notif;
}
if (!priv->external_connector &&
((priv->num_encoders == 0) || (priv->num_connectors == 0))) {
dev_err(dev, "no encoders/connectors found\n");
ret = -EPROBE_DEFER;
- goto init_failed;
+ goto unbind_component;
}
ret = drm_vblank_init(ddev, 1);
if (ret < 0) {
dev_err(dev, "failed to initialize vblank\n");
- goto init_failed;
+ goto unbind_component;
}
ret = platform_get_irq(pdev, 0);
if (ret < 0)
- goto init_failed;
+ goto unbind_component;
priv->irq = ret;
ret = tilcdc_irq_install(ddev, priv->irq);
if (ret < 0) {
dev_err(dev, "failed to install IRQ handler\n");
- goto init_failed;
+ goto unbind_component;
}
drm_mode_config_reset(ddev);
@@ -371,15 +370,33 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
ret = drm_dev_register(ddev, 0);
if (ret)
- goto init_failed;
- priv->is_registered = true;
+ goto stop_poll;
drm_fbdev_dma_setup(ddev, bpp);
return 0;
-init_failed:
- tilcdc_fini(ddev);
+stop_poll:
+ drm_kms_helper_poll_fini(ddev);
+ tilcdc_irq_uninstall(ddev);
+unbind_component:
+ if (priv->is_componentized)
+ component_unbind_all(dev, ddev);
+unregister_cpufreq_notif:
+#ifdef CONFIG_CPU_FREQ
+ cpufreq_unregister_notifier(&priv->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+destroy_crtc:
+#endif
+ tilcdc_crtc_destroy(priv->crtc);
+disable_pm:
+ pm_runtime_disable(dev);
+ clk_put(priv->clk);
+free_wq:
+ destroy_workqueue(priv->wq);
+put_drm:
platform_set_drvdata(pdev, NULL);
+ ddev->dev_private = NULL;
+ drm_dev_put(ddev);
return ret;
}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index b818448c83f61..58b276f82a669 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -82,7 +82,6 @@ struct tilcdc_drm_private {
struct drm_encoder *external_encoder;
struct drm_connector *external_connector;
- bool is_registered;
bool is_componentized;
bool irq_enabled;
};
@@ -164,6 +163,7 @@ void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc,
void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc,
bool simulate_vesa_sync);
void tilcdc_crtc_shutdown(struct drm_crtc *crtc);
+void tilcdc_crtc_destroy(struct drm_crtc *crtc);
int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 195/869] net: Factorise setup_net() and cleanup_net().
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (193 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 194/869] drm/tilcdc: Fix removal actions in case of failed probe Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 196/869] net: Add ops_undo_single for module load/unload Greg Kroah-Hartman
` (674 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kuniyuki Iwashima, Sabrina Dubroca,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@amazon.com>
[ Upstream commit e333b1c3cf25fca348422c9ad5cc8db40b4243fa ]
When we roll back the changes made by struct pernet_operations.init(),
we execute mostly identical sequences in three places.
* setup_net()
* cleanup_net()
* free_exit_list()
The only difference between the first two is which list and RCU helpers
to use.
In setup_net(), an ops could fail on the way, so we need to perform a
reverse walk from its previous ops in pernet_list. OTOH, in cleanup_net(),
we iterate the full list from tail to head.
The former passes the failed ops to list_for_each_entry_continue_reverse().
It's tricky, but we can reuse it for the latter if we pass list_entry() of
the head node.
Also, synchronize_rcu() and synchronize_rcu_expedited() can be easily
switched by an argument.
Let's factorise the rollback part in setup_net() and cleanup_net().
In the next patch, ops_undo_list() will be reused for free_exit_list(),
and then two arguments (ops_list and hold_rtnl) will differ.
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Link: https://patch.msgid.link/20250411205258.63164-2-kuniyu@amazon.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 60a25ef8dacb ("wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/core/net_namespace.c | 106 +++++++++++++++++++--------------------
1 file changed, 51 insertions(+), 55 deletions(-)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 613b2b07bad9f..25f84a3764f71 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -189,6 +189,53 @@ static void ops_free_list(const struct pernet_operations *ops,
}
}
+static void ops_undo_list(const struct list_head *ops_list,
+ const struct pernet_operations *ops,
+ struct list_head *net_exit_list,
+ bool expedite_rcu, bool hold_rtnl)
+{
+ const struct pernet_operations *saved_ops;
+
+ if (!ops)
+ ops = list_entry(ops_list, typeof(*ops), list);
+
+ saved_ops = ops;
+
+ list_for_each_entry_continue_reverse(ops, ops_list, list)
+ ops_pre_exit_list(ops, net_exit_list);
+
+ /* Another CPU might be rcu-iterating the list, wait for it.
+ * This needs to be before calling the exit() notifiers, so the
+ * rcu_barrier() after ops_undo_list() isn't sufficient alone.
+ * Also the pre_exit() and exit() methods need this barrier.
+ */
+ if (expedite_rcu)
+ synchronize_rcu_expedited();
+ else
+ synchronize_rcu();
+
+ if (hold_rtnl) {
+ LIST_HEAD(dev_kill_list);
+
+ ops = saved_ops;
+ rtnl_lock();
+ list_for_each_entry_continue_reverse(ops, ops_list, list) {
+ if (ops->exit_batch_rtnl)
+ ops->exit_batch_rtnl(net_exit_list, &dev_kill_list);
+ }
+ unregister_netdevice_many(&dev_kill_list);
+ rtnl_unlock();
+ }
+
+ ops = saved_ops;
+ list_for_each_entry_continue_reverse(ops, ops_list, list)
+ ops_exit_list(ops, net_exit_list);
+
+ ops = saved_ops;
+ list_for_each_entry_continue_reverse(ops, ops_list, list)
+ ops_free_list(ops, net_exit_list);
+}
+
/* should be called with nsid_lock held */
static int alloc_netid(struct net *net, struct net *peer, int reqid)
{
@@ -349,9 +396,8 @@ static __net_init void preinit_net(struct net *net, struct user_namespace *user_
static __net_init int setup_net(struct net *net)
{
/* Must be called with pernet_ops_rwsem held */
- const struct pernet_operations *ops, *saved_ops;
+ const struct pernet_operations *ops;
LIST_HEAD(net_exit_list);
- LIST_HEAD(dev_kill_list);
int error = 0;
preempt_disable();
@@ -374,29 +420,7 @@ static __net_init int setup_net(struct net *net)
* for the pernet modules whose init functions did not fail.
*/
list_add(&net->exit_list, &net_exit_list);
- saved_ops = ops;
- list_for_each_entry_continue_reverse(ops, &pernet_list, list)
- ops_pre_exit_list(ops, &net_exit_list);
-
- synchronize_rcu();
-
- ops = saved_ops;
- rtnl_lock();
- list_for_each_entry_continue_reverse(ops, &pernet_list, list) {
- if (ops->exit_batch_rtnl)
- ops->exit_batch_rtnl(&net_exit_list, &dev_kill_list);
- }
- unregister_netdevice_many(&dev_kill_list);
- rtnl_unlock();
-
- ops = saved_ops;
- list_for_each_entry_continue_reverse(ops, &pernet_list, list)
- ops_exit_list(ops, &net_exit_list);
-
- ops = saved_ops;
- list_for_each_entry_continue_reverse(ops, &pernet_list, list)
- ops_free_list(ops, &net_exit_list);
-
+ ops_undo_list(&pernet_list, ops, &net_exit_list, false, true);
rcu_barrier();
goto out;
}
@@ -594,11 +618,9 @@ static LLIST_HEAD(cleanup_list);
static void cleanup_net(struct work_struct *work)
{
- const struct pernet_operations *ops;
- struct net *net, *tmp, *last;
struct llist_node *net_kill_list;
+ struct net *net, *tmp, *last;
LIST_HEAD(net_exit_list);
- LIST_HEAD(dev_kill_list);
/* Atomically snapshot the list of namespaces to cleanup */
net_kill_list = llist_del_all(&cleanup_list);
@@ -627,33 +649,7 @@ static void cleanup_net(struct work_struct *work)
list_add_tail(&net->exit_list, &net_exit_list);
}
- /* Run all of the network namespace pre_exit methods */
- list_for_each_entry_reverse(ops, &pernet_list, list)
- ops_pre_exit_list(ops, &net_exit_list);
-
- /*
- * Another CPU might be rcu-iterating the list, wait for it.
- * This needs to be before calling the exit() notifiers, so
- * the rcu_barrier() below isn't sufficient alone.
- * Also the pre_exit() and exit() methods need this barrier.
- */
- synchronize_rcu_expedited();
-
- rtnl_lock();
- list_for_each_entry_reverse(ops, &pernet_list, list) {
- if (ops->exit_batch_rtnl)
- ops->exit_batch_rtnl(&net_exit_list, &dev_kill_list);
- }
- unregister_netdevice_many(&dev_kill_list);
- rtnl_unlock();
-
- /* Run all of the network namespace exit methods */
- list_for_each_entry_reverse(ops, &pernet_list, list)
- ops_exit_list(ops, &net_exit_list);
-
- /* Free the net generic variables */
- list_for_each_entry_reverse(ops, &pernet_list, list)
- ops_free_list(ops, &net_exit_list);
+ ops_undo_list(&pernet_list, NULL, &net_exit_list, true, true);
up_read(&pernet_ops_rwsem);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 196/869] net: Add ops_undo_single for module load/unload.
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (194 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 195/869] net: Factorise setup_net() and cleanup_net() Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 197/869] net: Add ->exit_rtnl() hook to struct pernet_operations Greg Kroah-Hartman
` (673 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kuniyuki Iwashima, Sabrina Dubroca,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@amazon.com>
[ Upstream commit fed176bf3143362ac9935e3964949ab6a5c3286b ]
If ops_init() fails while loading a module or we unload the
module, free_exit_list() rolls back the changes.
The rollback sequence is the same as ops_undo_list().
The ops is already removed from pernet_list before calling
free_exit_list(). If we link the ops to a temporary list,
we can reuse ops_undo_list().
Let's add a wrapper of ops_undo_list() and use it instead
of free_exit_list().
Now, we have the central place to roll back ops_init().
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Link: https://patch.msgid.link/20250411205258.63164-3-kuniyu@amazon.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 60a25ef8dacb ("wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/core/net_namespace.c | 54 ++++++++++++++++++----------------------
1 file changed, 24 insertions(+), 30 deletions(-)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 25f84a3764f71..f2171ff0e7b09 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -236,6 +236,17 @@ static void ops_undo_list(const struct list_head *ops_list,
ops_free_list(ops, net_exit_list);
}
+static void ops_undo_single(struct pernet_operations *ops,
+ struct list_head *net_exit_list)
+{
+ bool hold_rtnl = !!ops->exit_batch_rtnl;
+ LIST_HEAD(ops_list);
+
+ list_add(&ops->list, &ops_list);
+ ops_undo_list(&ops_list, NULL, net_exit_list, false, hold_rtnl);
+ list_del(&ops->list);
+}
+
/* should be called with nsid_lock held */
static int alloc_netid(struct net *net, struct net *peer, int reqid)
{
@@ -1226,31 +1237,13 @@ void __init net_ns_init(void)
RTNL_FLAG_DUMP_UNLOCKED);
}
-static void free_exit_list(struct pernet_operations *ops, struct list_head *net_exit_list)
-{
- ops_pre_exit_list(ops, net_exit_list);
- synchronize_rcu();
-
- if (ops->exit_batch_rtnl) {
- LIST_HEAD(dev_kill_list);
-
- rtnl_lock();
- ops->exit_batch_rtnl(net_exit_list, &dev_kill_list);
- unregister_netdevice_many(&dev_kill_list);
- rtnl_unlock();
- }
- ops_exit_list(ops, net_exit_list);
-
- ops_free_list(ops, net_exit_list);
-}
-
#ifdef CONFIG_NET_NS
static int __register_pernet_operations(struct list_head *list,
struct pernet_operations *ops)
{
+ LIST_HEAD(net_exit_list);
struct net *net;
int error;
- LIST_HEAD(net_exit_list);
list_add_tail(&ops->list, list);
if (ops->init || ops->id) {
@@ -1269,21 +1262,21 @@ static int __register_pernet_operations(struct list_head *list,
out_undo:
/* If I have an error cleanup all namespaces I initialized */
list_del(&ops->list);
- free_exit_list(ops, &net_exit_list);
+ ops_undo_single(ops, &net_exit_list);
return error;
}
static void __unregister_pernet_operations(struct pernet_operations *ops)
{
- struct net *net;
LIST_HEAD(net_exit_list);
+ struct net *net;
- list_del(&ops->list);
/* See comment in __register_pernet_operations() */
for_each_net(net)
list_add_tail(&net->exit_list, &net_exit_list);
- free_exit_list(ops, &net_exit_list);
+ list_del(&ops->list);
+ ops_undo_single(ops, &net_exit_list);
}
#else
@@ -1291,22 +1284,23 @@ static void __unregister_pernet_operations(struct pernet_operations *ops)
static int __register_pernet_operations(struct list_head *list,
struct pernet_operations *ops)
{
- if (!init_net_initialized) {
- list_add_tail(&ops->list, list);
+ list_add_tail(&ops->list, list);
+
+ if (!init_net_initialized)
return 0;
- }
return ops_init(ops, &init_net);
}
static void __unregister_pernet_operations(struct pernet_operations *ops)
{
- if (!init_net_initialized) {
- list_del(&ops->list);
- } else {
+ list_del(&ops->list);
+
+ if (init_net_initialized) {
LIST_HEAD(net_exit_list);
+
list_add(&init_net.exit_list, &net_exit_list);
- free_exit_list(ops, &net_exit_list);
+ ops_undo_single(ops, &net_exit_list);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 197/869] net: Add ->exit_rtnl() hook to struct pernet_operations.
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (195 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 196/869] net: Add ops_undo_single for module load/unload Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 198/869] wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit Greg Kroah-Hartman
` (672 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kuniyuki Iwashima, Sabrina Dubroca,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@amazon.com>
[ Upstream commit 7a60d91c690bf73c2c78e763efa29f294e217c3a ]
struct pernet_operations provides two batching hooks; ->exit_batch()
and ->exit_batch_rtnl().
The batching variant is beneficial if ->exit() meets any of the
following conditions:
1) ->exit() repeatedly acquires a global lock for each netns
2) ->exit() has a time-consuming operation that can be factored
out (e.g. synchronize_rcu(), smp_mb(), etc)
3) ->exit() does not need to repeat the same iterations for each
netns (e.g. inet_twsk_purge())
Currently, none of the ->exit_batch_rtnl() functions satisfy any of
the above conditions because RTNL is factored out and held by the
caller and all of these functions iterate over the dying netns list.
Also, we want to hold per-netns RTNL there but avoid spreading
__rtnl_net_lock() across multiple locations.
Let's add ->exit_rtnl() hook and run it under __rtnl_net_lock().
The following patches will convert all ->exit_batch_rtnl() users
to ->exit_rtnl().
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Link: https://patch.msgid.link/20250411205258.63164-4-kuniyu@amazon.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 60a25ef8dacb ("wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/net_namespace.h | 2 ++
net/core/net_namespace.c | 53 +++++++++++++++++++++++++++----------
2 files changed, 41 insertions(+), 14 deletions(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 47181fd749b25..f659d1efcd3ce 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -470,6 +470,8 @@ struct pernet_operations {
void (*exit)(struct net *net);
void (*exit_batch)(struct list_head *net_exit_list);
/* Following method is called with RTNL held. */
+ void (*exit_rtnl)(struct net *net,
+ struct list_head *dev_kill_list);
void (*exit_batch_rtnl)(struct list_head *net_exit_list,
struct list_head *dev_kill_list);
unsigned int * const id;
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index f2171ff0e7b09..9e518df2cfeb5 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -164,16 +164,51 @@ static void ops_pre_exit_list(const struct pernet_operations *ops,
}
}
+static void ops_exit_rtnl_list(const struct list_head *ops_list,
+ const struct pernet_operations *ops,
+ struct list_head *net_exit_list)
+{
+ const struct pernet_operations *saved_ops = ops;
+ LIST_HEAD(dev_kill_list);
+ struct net *net;
+
+ rtnl_lock();
+
+ list_for_each_entry(net, net_exit_list, exit_list) {
+ __rtnl_net_lock(net);
+
+ ops = saved_ops;
+ list_for_each_entry_continue_reverse(ops, ops_list, list) {
+ if (ops->exit_rtnl)
+ ops->exit_rtnl(net, &dev_kill_list);
+ }
+
+ __rtnl_net_unlock(net);
+ }
+
+ ops = saved_ops;
+ list_for_each_entry_continue_reverse(ops, ops_list, list) {
+ if (ops->exit_batch_rtnl)
+ ops->exit_batch_rtnl(net_exit_list, &dev_kill_list);
+ }
+
+ unregister_netdevice_many(&dev_kill_list);
+
+ rtnl_unlock();
+}
+
static void ops_exit_list(const struct pernet_operations *ops,
struct list_head *net_exit_list)
{
- struct net *net;
if (ops->exit) {
+ struct net *net;
+
list_for_each_entry(net, net_exit_list, exit_list) {
ops->exit(net);
cond_resched();
}
}
+
if (ops->exit_batch)
ops->exit_batch(net_exit_list);
}
@@ -214,18 +249,8 @@ static void ops_undo_list(const struct list_head *ops_list,
else
synchronize_rcu();
- if (hold_rtnl) {
- LIST_HEAD(dev_kill_list);
-
- ops = saved_ops;
- rtnl_lock();
- list_for_each_entry_continue_reverse(ops, ops_list, list) {
- if (ops->exit_batch_rtnl)
- ops->exit_batch_rtnl(net_exit_list, &dev_kill_list);
- }
- unregister_netdevice_many(&dev_kill_list);
- rtnl_unlock();
- }
+ if (hold_rtnl)
+ ops_exit_rtnl_list(ops_list, saved_ops, net_exit_list);
ops = saved_ops;
list_for_each_entry_continue_reverse(ops, ops_list, list)
@@ -239,7 +264,7 @@ static void ops_undo_list(const struct list_head *ops_list,
static void ops_undo_single(struct pernet_operations *ops,
struct list_head *net_exit_list)
{
- bool hold_rtnl = !!ops->exit_batch_rtnl;
+ bool hold_rtnl = ops->exit_rtnl || ops->exit_batch_rtnl;
LIST_HEAD(ops_list);
list_add(&ops->list, &ops_list);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 198/869] wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (196 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 197/869] net: Add ->exit_rtnl() hook to struct pernet_operations Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 199/869] KVM: SEV: Use long-term pin when registering encrypted memory regions Greg Kroah-Hartman
` (671 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+f2fbf7478a35a94c8b7c,
Shardul Bankar, Jason A. Donenfeld, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shardul Bankar <shardul.b@mpiricsoftware.com>
[ Upstream commit 60a25ef8dacb3566b1a8c4de00572a498e2a3bf9 ]
wg_netns_pre_exit() manually acquires rtnl_lock() inside the
pernet .pre_exit callback. This causes a hung task when another
thread holds rtnl_mutex - the cleanup_net workqueue (or the
setup_net failure rollback path) blocks indefinitely in
wg_netns_pre_exit() waiting to acquire the lock.
Convert to .exit_rtnl, introduced in commit 7a60d91c690b ("net:
Add ->exit_rtnl() hook to struct pernet_operations."), where the
framework already holds RTNL and batches all callbacks under a
single rtnl_lock()/rtnl_unlock() pair, eliminating the contention
window.
The rcu_assign_pointer(wg->creating_net, NULL) is safe to move
from .pre_exit to .exit_rtnl (which runs after synchronize_rcu())
because all RCU readers of creating_net either use maybe_get_net()
- which returns NULL for a dying namespace with zero refcount - or
access net->user_ns which remains valid throughout the entire
ops_undo_list sequence.
Reported-by: syzbot+f2fbf7478a35a94c8b7c@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?id=cb64c22a492202ca929e18262fdb8cb89e635c70
Signed-off-by: Shardul Bankar <shardul.b@mpiricsoftware.com>
[ Jason: added __net_exit and __read_mostly annotations that were missing. ]
Fixes: 900575aa33a3 ("wireguard: device: avoid circular netns references")
Cc: stable@vger.kernel.org
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Link: https://patch.msgid.link/20260414153944.2742252-5-Jason@zx2c4.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireguard/device.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireguard/device.c b/drivers/net/wireguard/device.c
index 45e9b908dbfb0..055ea38771568 100644
--- a/drivers/net/wireguard/device.c
+++ b/drivers/net/wireguard/device.c
@@ -406,12 +406,11 @@ static struct rtnl_link_ops link_ops __read_mostly = {
.newlink = wg_newlink,
};
-static void wg_netns_pre_exit(struct net *net)
+static void __net_exit wg_netns_exit_rtnl(struct net *net, struct list_head *dev_kill_list)
{
struct wg_device *wg;
struct wg_peer *peer;
- rtnl_lock();
list_for_each_entry(wg, &device_list, device_list) {
if (rcu_access_pointer(wg->creating_net) == net) {
pr_debug("%s: Creating namespace exiting\n", wg->dev->name);
@@ -424,11 +423,10 @@ static void wg_netns_pre_exit(struct net *net)
mutex_unlock(&wg->device_update_lock);
}
}
- rtnl_unlock();
}
-static struct pernet_operations pernet_ops = {
- .pre_exit = wg_netns_pre_exit
+static struct pernet_operations pernet_ops __read_mostly = {
+ .exit_rtnl = wg_netns_exit_rtnl
};
int __init wg_device_init(void)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 199/869] KVM: SEV: Use long-term pin when registering encrypted memory regions
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (197 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 198/869] wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 200/869] KVM: SEV: Protect *all* of sev_mem_enc_register_region() with kvm->lock Greg Kroah-Hartman
` (670 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ge Yang, Tom Lendacky,
David Hildenbrand, Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ge Yang <yangge1116@126.com>
[ Upstream commit 7e066cb9b71a22c3e5ef233de63ff14525baf6f0 ]
When registering an encrypted memory region for SEV-MEM/SEV-ES guests,
pin the pages with FOLL_TERM so that the pages are migrated out of
MIGRATE_CMA/ZONE_MOVABLE. Failure to do so violates the CMA/MOVABLE
mechanisms and can result in fragmentation due to unmovable pages, e.g.
can make CMA allocations fail.
Signed-off-by: Ge Yang <yangge1116@126.com>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Acked-by: David Hildenbrand <david@redhat.com>
Link: https://lore.kernel.org/r/1739241423-14326-1-git-send-email-yangge1116@126.com
[sean: massage changelog, make @flags an unsigned int]
Signed-off-by: Sean Christopherson <seanjc@google.com>
Stable-dep-of: b6408b6cec5d ("KVM: SEV: Protect *all* of sev_mem_enc_register_region() with kvm->lock")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/svm/sev.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index eb9c1f9e23bd6..775704fb704ca 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -624,7 +624,7 @@ static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
unsigned long ulen, unsigned long *n,
- int write)
+ unsigned int flags)
{
struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
unsigned long npages, size;
@@ -668,7 +668,7 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
return ERR_PTR(-ENOMEM);
/* Pin the user virtual address. */
- npinned = pin_user_pages_fast(uaddr, npages, write ? FOLL_WRITE : 0, pages);
+ npinned = pin_user_pages_fast(uaddr, npages, flags, pages);
if (npinned != npages) {
pr_err("SEV: Failure locking %lu pages.\n", npages);
ret = -ENOMEM;
@@ -756,7 +756,7 @@ static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
vaddr_end = vaddr + size;
/* Lock the user memory. */
- inpages = sev_pin_memory(kvm, vaddr, size, &npages, 1);
+ inpages = sev_pin_memory(kvm, vaddr, size, &npages, FOLL_WRITE);
if (IS_ERR(inpages))
return PTR_ERR(inpages);
@@ -1261,7 +1261,7 @@ static int sev_dbg_crypt(struct kvm *kvm, struct kvm_sev_cmd *argp, bool dec)
if (IS_ERR(src_p))
return PTR_ERR(src_p);
- dst_p = sev_pin_memory(kvm, dst_vaddr & PAGE_MASK, PAGE_SIZE, &n, 1);
+ dst_p = sev_pin_memory(kvm, dst_vaddr & PAGE_MASK, PAGE_SIZE, &n, FOLL_WRITE);
if (IS_ERR(dst_p)) {
sev_unpin_memory(kvm, src_p, n);
return PTR_ERR(dst_p);
@@ -1328,7 +1328,7 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
if (copy_from_user(¶ms, u64_to_user_ptr(argp->data), sizeof(params)))
return -EFAULT;
- pages = sev_pin_memory(kvm, params.guest_uaddr, params.guest_len, &n, 1);
+ pages = sev_pin_memory(kvm, params.guest_uaddr, params.guest_len, &n, FOLL_WRITE);
if (IS_ERR(pages))
return PTR_ERR(pages);
@@ -1810,7 +1810,7 @@ static int sev_receive_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
/* Pin guest memory */
guest_page = sev_pin_memory(kvm, params.guest_uaddr & PAGE_MASK,
- PAGE_SIZE, &n, 1);
+ PAGE_SIZE, &n, FOLL_WRITE);
if (IS_ERR(guest_page)) {
ret = PTR_ERR(guest_page);
goto e_free_trans;
@@ -2718,7 +2718,8 @@ int sev_mem_enc_register_region(struct kvm *kvm,
return -ENOMEM;
mutex_lock(&kvm->lock);
- region->pages = sev_pin_memory(kvm, range->addr, range->size, ®ion->npages, 1);
+ region->pages = sev_pin_memory(kvm, range->addr, range->size, ®ion->npages,
+ FOLL_WRITE | FOLL_LONGTERM);
if (IS_ERR(region->pages)) {
ret = PTR_ERR(region->pages);
mutex_unlock(&kvm->lock);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 200/869] KVM: SEV: Protect *all* of sev_mem_enc_register_region() with kvm->lock
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (198 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 199/869] KVM: SEV: Use long-term pin when registering encrypted memory regions Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 201/869] rxrpc: proc: size address buffers for %pISpc output Greg Kroah-Hartman
` (669 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alexander Potapenko,
Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <seanjc@google.com>
[ Upstream commit b6408b6cec5df76a165575777800ef2aba12b109 ]
Take and hold kvm->lock for before checking sev_guest() in
sev_mem_enc_register_region(), as sev_guest() isn't stable unless kvm->lock
is held (or KVM can guarantee KVM_SEV_INIT{2} has completed and can't
rollack state). If KVM_SEV_INIT{2} fails, KVM can end up trying to add to
a not-yet-initialized sev->regions_list, e.g. triggering a #GP
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
CPU: 110 UID: 0 PID: 72717 Comm: syz.15.11462 Tainted: G U W O 6.16.0-smp-DEV #1 NONE
Tainted: [U]=USER, [W]=WARN, [O]=OOT_MODULE
Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 12.52.0-0 10/28/2024
RIP: 0010:sev_mem_enc_register_region+0x3f0/0x4f0 ../include/linux/list.h:83
Code: <41> 80 3c 04 00 74 08 4c 89 ff e8 f1 c7 a2 00 49 39 ed 0f 84 c6 00
RSP: 0018:ffff88838647fbb8 EFLAGS: 00010256
RAX: dffffc0000000000 RBX: 1ffff92015cf1e0b RCX: dffffc0000000000
RDX: 0000000000000000 RSI: 0000000000001000 RDI: ffff888367870000
RBP: ffffc900ae78f050 R08: ffffea000d9e0007 R09: 1ffffd4001b3c000
R10: dffffc0000000000 R11: fffff94001b3c001 R12: 0000000000000000
R13: ffff8982ab0bde00 R14: ffffc900ae78f058 R15: 0000000000000000
FS: 00007f34e9dc66c0(0000) GS:ffff89ee64d33000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007fe180adef98 CR3: 000000047210e000 CR4: 0000000000350ef0
Call Trace:
<TASK>
kvm_arch_vm_ioctl+0xa72/0x1240 ../arch/x86/kvm/x86.c:7371
kvm_vm_ioctl+0x649/0x990 ../virt/kvm/kvm_main.c:5363
__se_sys_ioctl+0x101/0x170 ../fs/ioctl.c:51
do_syscall_x64 ../arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x6f/0x1f0 ../arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x76/0x7e
RIP: 0033:0x7f34e9f7e9a9
Code: <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f34e9dc6038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f34ea1a6080 RCX: 00007f34e9f7e9a9
RDX: 0000200000000280 RSI: 000000008010aebb RDI: 0000000000000007
RBP: 00007f34ea000d69 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 0000000000000000 R14: 00007f34ea1a6080 R15: 00007ffce77197a8
</TASK>
with a syzlang reproducer that looks like:
syz_kvm_add_vcpu$x86(0x0, &(0x7f0000000040)={0x0, &(0x7f0000000180)=ANY=[], 0x70}) (async)
syz_kvm_add_vcpu$x86(0x0, &(0x7f0000000080)={0x0, &(0x7f0000000180)=ANY=[@ANYBLOB="..."], 0x4f}) (async)
r0 = openat$kvm(0xffffffffffffff9c, &(0x7f0000000200), 0x0, 0x0)
r1 = ioctl$KVM_CREATE_VM(r0, 0xae01, 0x0)
r2 = openat$kvm(0xffffffffffffff9c, &(0x7f0000000240), 0x0, 0x0)
r3 = ioctl$KVM_CREATE_VM(r2, 0xae01, 0x0)
ioctl$KVM_SET_CLOCK(r3, 0xc008aeba, &(0x7f0000000040)={0x1, 0x8, 0x0, 0x5625e9b0}) (async)
ioctl$KVM_SET_PIT2(r3, 0x8010aebb, &(0x7f0000000280)={[...], 0x5}) (async)
ioctl$KVM_SET_PIT2(r1, 0x4070aea0, 0x0) (async)
r4 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0)
openat$kvm(0xffffffffffffff9c, 0x0, 0x0, 0x0) (async)
ioctl$KVM_SET_USER_MEMORY_REGION(r4, 0x4020ae46, &(0x7f0000000400)={0x0, 0x0, 0x0, 0x2000, &(0x7f0000001000/0x2000)=nil}) (async)
r5 = ioctl$KVM_CREATE_VCPU(r4, 0xae41, 0x2)
close(r0) (async)
openat$kvm(0xffffffffffffff9c, &(0x7f0000000000), 0x8000, 0x0) (async)
ioctl$KVM_SET_GUEST_DEBUG(r5, 0x4048ae9b, &(0x7f0000000300)={0x4376ea830d46549b, 0x0, [0x46, 0x0, 0x0, 0x0, 0x0, 0x1000]}) (async)
ioctl$KVM_RUN(r5, 0xae80, 0x0)
Opportunistically use guard() to avoid having to define a new error label
and goto usage.
Fixes: 1e80fdc09d12 ("KVM: SVM: Pin guest memory when SEV is active")
Cc: stable@vger.kernel.org
Reported-by: Alexander Potapenko <glider@google.com>
Tested-by: Alexander Potapenko <glider@google.com>
Link: https://patch.msgid.link/20260310234829.2608037-4-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/svm/sev.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 775704fb704ca..1a766b3d95f23 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -2703,6 +2703,8 @@ int sev_mem_enc_register_region(struct kvm *kvm,
struct enc_region *region;
int ret = 0;
+ guard(mutex)(&kvm->lock);
+
if (!sev_guest(kvm))
return -ENOTTY;
@@ -2717,12 +2719,10 @@ int sev_mem_enc_register_region(struct kvm *kvm,
if (!region)
return -ENOMEM;
- mutex_lock(&kvm->lock);
region->pages = sev_pin_memory(kvm, range->addr, range->size, ®ion->npages,
FOLL_WRITE | FOLL_LONGTERM);
if (IS_ERR(region->pages)) {
ret = PTR_ERR(region->pages);
- mutex_unlock(&kvm->lock);
goto e_free;
}
@@ -2740,8 +2740,6 @@ int sev_mem_enc_register_region(struct kvm *kvm,
region->size = range->size;
list_add_tail(®ion->list, &sev->regions_list);
- mutex_unlock(&kvm->lock);
-
return ret;
e_free:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 201/869] rxrpc: proc: size address buffers for %pISpc output
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (199 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 200/869] KVM: SEV: Protect *all* of sev_mem_enc_register_region() with kvm->lock Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 202/869] Bluetooth: hci_event: move wake reason storage into validated event handlers Greg Kroah-Hartman
` (668 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pengpeng Hou, David Howells,
Marc Dionne, Anderson Nascimento, Simon Horman, linux-afs, stable,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <pengpeng@iscas.ac.cn>
[ Upstream commit a44ce6aa2efb61fe44f2cfab72bb01544bbca272 ]
The AF_RXRPC procfs helpers format local and remote socket addresses into
fixed 50-byte stack buffers with "%pISpc".
That is too small for the longest current-tree IPv6-with-port form the
formatter can produce. In lib/vsprintf.c, the compressed IPv6 path uses a
dotted-quad tail not only for v4mapped addresses, but also for ISATAP
addresses via ipv6_addr_is_isatap().
As a result, a case such as
[ffff:ffff:ffff:ffff:0:5efe:255.255.255.255]:65535
is possible with the current formatter. That is 50 visible characters, so
51 bytes including the trailing NUL, which does not fit in the existing
char[50] buffers used by net/rxrpc/proc.c.
Size the buffers from the formatter's maximum textual form and switch the
call sites to scnprintf().
Changes since v1:
- correct the changelog to cite the actual maximum current-tree case
explicitly
- frame the proof around the ISATAP formatting path instead of the earlier
mapped-v4 example
Fixes: 75b54cb57ca3 ("rxrpc: Add IPv6 support")
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Anderson Nascimento <anderson@allelesecurity.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: stable@kernel.org
Link: https://patch.msgid.link/20260408121252.2249051-22-dhowells@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/rxrpc/proc.c | 32 ++++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c
index 2dd9567cb1cfd..7a2279cd11a7d 100644
--- a/net/rxrpc/proc.c
+++ b/net/rxrpc/proc.c
@@ -10,6 +10,10 @@
#include <net/af_rxrpc.h>
#include "ar-internal.h"
+#define RXRPC_PROC_ADDRBUF_SIZE \
+ (sizeof("[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255]") + \
+ sizeof(":12345"))
+
static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
[RXRPC_CONN_UNUSED] = "Unused ",
[RXRPC_CONN_CLIENT_UNSECURED] = "ClUnsec ",
@@ -53,7 +57,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
enum rxrpc_call_state state;
rxrpc_seq_t acks_hard_ack;
- char lbuff[50], rbuff[50];
+ char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
long timeout = 0;
if (v == &rxnet->calls) {
@@ -69,11 +73,11 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
local = call->local;
if (local)
- sprintf(lbuff, "%pISpc", &local->srx.transport);
+ scnprintf(lbuff, sizeof(lbuff), "%pISpc", &local->srx.transport);
else
strcpy(lbuff, "no_local");
- sprintf(rbuff, "%pISpc", &call->dest_srx.transport);
+ scnprintf(rbuff, sizeof(rbuff), "%pISpc", &call->dest_srx.transport);
state = rxrpc_call_state(call);
if (state != RXRPC_CALL_SERVER_PREALLOC)
@@ -142,7 +146,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
struct rxrpc_connection *conn;
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
const char *state;
- char lbuff[50], rbuff[50];
+ char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
if (v == &rxnet->conn_proc_list) {
seq_puts(seq,
@@ -161,8 +165,8 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
goto print;
}
- sprintf(lbuff, "%pISpc", &conn->local->srx.transport);
- sprintf(rbuff, "%pISpc", &conn->peer->srx.transport);
+ scnprintf(lbuff, sizeof(lbuff), "%pISpc", &conn->local->srx.transport);
+ scnprintf(rbuff, sizeof(rbuff), "%pISpc", &conn->peer->srx.transport);
print:
state = rxrpc_is_conn_aborted(conn) ?
rxrpc_call_completions[conn->completion] :
@@ -228,7 +232,7 @@ static int rxrpc_bundle_seq_show(struct seq_file *seq, void *v)
{
struct rxrpc_bundle *bundle;
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
- char lbuff[50], rbuff[50];
+ char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
if (v == &rxnet->bundle_proc_list) {
seq_puts(seq,
@@ -242,8 +246,8 @@ static int rxrpc_bundle_seq_show(struct seq_file *seq, void *v)
bundle = list_entry(v, struct rxrpc_bundle, proc_link);
- sprintf(lbuff, "%pISpc", &bundle->local->srx.transport);
- sprintf(rbuff, "%pISpc", &bundle->peer->srx.transport);
+ scnprintf(lbuff, sizeof(lbuff), "%pISpc", &bundle->local->srx.transport);
+ scnprintf(rbuff, sizeof(rbuff), "%pISpc", &bundle->peer->srx.transport);
seq_printf(seq,
"UDP %-47.47s %-47.47s %4x %3u %3d"
" %c%c%c %08x | %08x %08x %08x %08x %08x\n",
@@ -279,7 +283,7 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
{
struct rxrpc_peer *peer;
time64_t now;
- char lbuff[50], rbuff[50];
+ char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
@@ -292,9 +296,9 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
peer = list_entry(v, struct rxrpc_peer, hash_link);
- sprintf(lbuff, "%pISpc", &peer->local->srx.transport);
+ scnprintf(lbuff, sizeof(lbuff), "%pISpc", &peer->local->srx.transport);
- sprintf(rbuff, "%pISpc", &peer->srx.transport);
+ scnprintf(rbuff, sizeof(rbuff), "%pISpc", &peer->srx.transport);
now = ktime_get_seconds();
seq_printf(seq,
@@ -404,7 +408,7 @@ const struct seq_operations rxrpc_peer_seq_ops = {
static int rxrpc_local_seq_show(struct seq_file *seq, void *v)
{
struct rxrpc_local *local;
- char lbuff[50];
+ char lbuff[RXRPC_PROC_ADDRBUF_SIZE];
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
@@ -415,7 +419,7 @@ static int rxrpc_local_seq_show(struct seq_file *seq, void *v)
local = hlist_entry(v, struct rxrpc_local, link);
- sprintf(lbuff, "%pISpc", &local->srx.transport);
+ scnprintf(lbuff, sizeof(lbuff), "%pISpc", &local->srx.transport);
seq_printf(seq,
"UDP %-47.47s %3u %3u %3u\n",
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 202/869] Bluetooth: hci_event: move wake reason storage into validated event handlers
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (200 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 201/869] rxrpc: proc: size address buffers for %pISpc output Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 203/869] ALSA: ctxfi: Add hw parameter to daio_mgr_dao_init() Greg Kroah-Hartman
` (667 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Oleh Konko, Luiz Augusto von Dentz,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oleh Konko <security@1seal.org>
[ Upstream commit 2b2bf47cd75518c36fa2d41380e4a40641cc89cd ]
hci_store_wake_reason() is called from hci_event_packet() immediately
after stripping the HCI event header but before hci_event_func()
enforces the per-event minimum payload length from hci_ev_table.
This means a short HCI event frame can reach bacpy() before any bounds
check runs.
Rather than duplicating skb parsing and per-event length checks inside
hci_store_wake_reason(), move wake-address storage into the individual
event handlers after their existing event-length validation has
succeeded. Convert hci_store_wake_reason() into a small helper that only
stores an already-validated bdaddr while the caller holds hci_dev_lock().
Use the same helper after hci_event_func() with a NULL address to
preserve the existing unexpected-wake fallback semantics when no
validated event handler records a wake address.
Annotate the helper with __must_hold(&hdev->lock) and add
lockdep_assert_held(&hdev->lock) so future call paths keep the lock
contract explicit.
Call the helper from hci_conn_request_evt(), hci_conn_complete_evt(),
hci_sync_conn_complete_evt(), le_conn_complete_evt(),
hci_le_adv_report_evt(), hci_le_ext_adv_report_evt(),
hci_le_direct_adv_report_evt(), hci_le_pa_sync_established_evt(), and
hci_le_past_received_evt().
Fixes: 2f20216c1d6f ("Bluetooth: Emit controller suspend and resume events")
Cc: stable@vger.kernel.org
Signed-off-by: Oleh Konko <security@1seal.org>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/hci_event.c | 93 ++++++++++++++-------------------------
1 file changed, 34 insertions(+), 59 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 53732f8ddf63d..cbb1c3ee07525 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -80,6 +80,10 @@ static void *hci_le_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
return data;
}
+static void hci_store_wake_reason(struct hci_dev *hdev,
+ const bdaddr_t *bdaddr, u8 addr_type)
+ __must_hold(&hdev->lock);
+
static u8 hci_cc_inquiry_cancel(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
@@ -3060,6 +3064,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "status 0x%2.2x", status);
hci_dev_lock(hdev);
+ hci_store_wake_reason(hdev, &ev->bdaddr, BDADDR_BREDR);
/* Check for existing connection:
*
@@ -3234,6 +3239,10 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "bdaddr %pMR type 0x%x", &ev->bdaddr, ev->link_type);
+ hci_dev_lock(hdev);
+ hci_store_wake_reason(hdev, &ev->bdaddr, BDADDR_BREDR);
+ hci_dev_unlock(hdev);
+
/* Reject incoming connection from device with same BD ADDR against
* CVE-2020-26555
*/
@@ -4955,6 +4964,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "status 0x%2.2x", status);
hci_dev_lock(hdev);
+ hci_store_wake_reason(hdev, &ev->bdaddr, BDADDR_BREDR);
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
if (!conn) {
@@ -5656,6 +5666,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
u8 addr_type;
hci_dev_lock(hdev);
+ hci_store_wake_reason(hdev, bdaddr, bdaddr_type);
/* Advertising stops when a connection is created. On a failed
* connection it keeps running, so leave the state bit alone.
@@ -6275,6 +6286,8 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, void *data,
info->length + 1))
break;
+ hci_store_wake_reason(hdev, &info->bdaddr, info->bdaddr_type);
+
if (info->length <= max_adv_len(hdev)) {
rssi = info->data[info->length];
process_adv_report(hdev, info->type, &info->bdaddr,
@@ -6363,6 +6376,8 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, void *data,
info->length))
break;
+ hci_store_wake_reason(hdev, &info->bdaddr, info->bdaddr_type);
+
evt_type = __le16_to_cpu(info->type) & LE_EXT_ADV_EVT_TYPE_MASK;
legacy_evt_type = ext_evt_type_to_legacy(hdev, evt_type);
@@ -6418,6 +6433,7 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
hci_dev_lock(hdev);
+ hci_store_wake_reason(hdev, &ev->bdaddr, ev->bdaddr_type);
hci_dev_clear_flag(hdev, HCI_PA_SYNC);
@@ -6712,6 +6728,8 @@ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, void *data,
for (i = 0; i < ev->num; i++) {
struct hci_ev_le_direct_adv_info *info = &ev->info[i];
+ hci_store_wake_reason(hdev, &info->bdaddr, info->bdaddr_type);
+
process_adv_report(hdev, info->type, &info->bdaddr,
info->bdaddr_type, &info->direct_addr,
info->direct_addr_type, HCI_ADV_PHY_1M, 0,
@@ -7297,73 +7315,29 @@ static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
return true;
}
-static void hci_store_wake_reason(struct hci_dev *hdev, u8 event,
- struct sk_buff *skb)
+static void hci_store_wake_reason(struct hci_dev *hdev,
+ const bdaddr_t *bdaddr, u8 addr_type)
+ __must_hold(&hdev->lock)
{
- struct hci_ev_le_advertising_info *adv;
- struct hci_ev_le_direct_adv_info *direct_adv;
- struct hci_ev_le_ext_adv_info *ext_adv;
- const struct hci_ev_conn_complete *conn_complete = (void *)skb->data;
- const struct hci_ev_conn_request *conn_request = (void *)skb->data;
-
- hci_dev_lock(hdev);
+ lockdep_assert_held(&hdev->lock);
/* If we are currently suspended and this is the first BT event seen,
* save the wake reason associated with the event.
*/
if (!hdev->suspended || hdev->wake_reason)
- goto unlock;
+ return;
+
+ if (!bdaddr) {
+ hdev->wake_reason = MGMT_WAKE_REASON_UNEXPECTED;
+ return;
+ }
/* Default to remote wake. Values for wake_reason are documented in the
* Bluez mgmt api docs.
*/
hdev->wake_reason = MGMT_WAKE_REASON_REMOTE_WAKE;
-
- /* Once configured for remote wakeup, we should only wake up for
- * reconnections. It's useful to see which device is waking us up so
- * keep track of the bdaddr of the connection event that woke us up.
- */
- if (event == HCI_EV_CONN_REQUEST) {
- bacpy(&hdev->wake_addr, &conn_request->bdaddr);
- hdev->wake_addr_type = BDADDR_BREDR;
- } else if (event == HCI_EV_CONN_COMPLETE) {
- bacpy(&hdev->wake_addr, &conn_complete->bdaddr);
- hdev->wake_addr_type = BDADDR_BREDR;
- } else if (event == HCI_EV_LE_META) {
- struct hci_ev_le_meta *le_ev = (void *)skb->data;
- u8 subevent = le_ev->subevent;
- u8 *ptr = &skb->data[sizeof(*le_ev)];
- u8 num_reports = *ptr;
-
- if ((subevent == HCI_EV_LE_ADVERTISING_REPORT ||
- subevent == HCI_EV_LE_DIRECT_ADV_REPORT ||
- subevent == HCI_EV_LE_EXT_ADV_REPORT) &&
- num_reports) {
- adv = (void *)(ptr + 1);
- direct_adv = (void *)(ptr + 1);
- ext_adv = (void *)(ptr + 1);
-
- switch (subevent) {
- case HCI_EV_LE_ADVERTISING_REPORT:
- bacpy(&hdev->wake_addr, &adv->bdaddr);
- hdev->wake_addr_type = adv->bdaddr_type;
- break;
- case HCI_EV_LE_DIRECT_ADV_REPORT:
- bacpy(&hdev->wake_addr, &direct_adv->bdaddr);
- hdev->wake_addr_type = direct_adv->bdaddr_type;
- break;
- case HCI_EV_LE_EXT_ADV_REPORT:
- bacpy(&hdev->wake_addr, &ext_adv->bdaddr);
- hdev->wake_addr_type = ext_adv->bdaddr_type;
- break;
- }
- }
- } else {
- hdev->wake_reason = MGMT_WAKE_REASON_UNEXPECTED;
- }
-
-unlock:
- hci_dev_unlock(hdev);
+ bacpy(&hdev->wake_addr, bdaddr);
+ hdev->wake_addr_type = addr_type;
}
#define HCI_EV_VL(_op, _func, _min_len, _max_len) \
@@ -7610,14 +7584,15 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
skb_pull(skb, HCI_EVENT_HDR_SIZE);
- /* Store wake reason if we're suspended */
- hci_store_wake_reason(hdev, event, skb);
-
bt_dev_dbg(hdev, "event 0x%2.2x", event);
hci_event_func(hdev, event, skb, &opcode, &status, &req_complete,
&req_complete_skb);
+ hci_dev_lock(hdev);
+ hci_store_wake_reason(hdev, NULL, 0);
+ hci_dev_unlock(hdev);
+
if (req_complete) {
req_complete(hdev, status, opcode);
} else if (req_complete_skb) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 203/869] ALSA: ctxfi: Add hw parameter to daio_mgr_dao_init()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (201 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 202/869] Bluetooth: hci_event: move wake reason storage into validated event handlers Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 204/869] ALSA: ctxfi: Use explicit output flag for DAIO resources Greg Kroah-Hartman
` (666 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Harin Lee, Takashi Iwai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harin Lee <me@harin.net>
[ Upstream commit 5ebd054272718334c543998a6d0b77a9846c16d9 ]
Add a hw parameter to the daio_mgr_dao_init() function to provide
access to model-specific information. This is necessary for proper
configuration of S/PDIF and I2S output ports on different hardware
variants.
Signed-off-by: Harin Lee <me@harin.net>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20251124180501.2760421-2-me@harin.net
Stable-dep-of: 277c6960d4dd ("ALSA: ctxfi: Check the error for index mapping")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/pci/ctxfi/ctdaio.c | 2 +-
sound/pci/ctxfi/cthardware.h | 2 +-
sound/pci/ctxfi/cthw20k1.c | 2 +-
sound/pci/ctxfi/cthw20k2.c | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index 5a50f6452a1df..b20c10196579d 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -413,7 +413,7 @@ static int dao_rsc_init(struct dao *dao,
hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
conf = (desc->msr & 0x7) | (desc->passthru << 3);
- hw->daio_mgr_dao_init(mgr->mgr.ctrl_blk,
+ hw->daio_mgr_dao_init(hw, mgr->mgr.ctrl_blk,
daio_device_index(dao->daio.type, hw), conf);
hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
daio_device_index(dao->daio.type, hw));
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
index 2875cec83b8f2..d29b4e5b3fcc4 100644
--- a/sound/pci/ctxfi/cthardware.h
+++ b/sound/pci/ctxfi/cthardware.h
@@ -167,7 +167,7 @@ struct hw {
int (*daio_mgr_dsb_dai)(void *blk, unsigned int idx);
int (*daio_mgr_enb_dao)(void *blk, unsigned int idx);
int (*daio_mgr_dsb_dao)(void *blk, unsigned int idx);
- int (*daio_mgr_dao_init)(void *blk, unsigned int idx,
+ int (*daio_mgr_dao_init)(struct hw *hw, void *blk, unsigned int idx,
unsigned int conf);
int (*daio_mgr_set_imaparc)(void *blk, unsigned int slot);
int (*daio_mgr_set_imapnxt)(void *blk, unsigned int next);
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index 9edbf5d8c3c70..7b41e1ffda082 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1031,7 +1031,7 @@ static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
return 0;
}
-static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
+static int daio_mgr_dao_init(struct hw *hw __maybe_unused, void *blk, unsigned int idx, unsigned int conf)
{
struct daio_mgr_ctrl_blk *ctl = blk;
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 4d970f25a2c6c..e45c655528f51 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -985,7 +985,7 @@ static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
return 0;
}
-static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
+static int daio_mgr_dao_init(struct hw *hw __maybe_unused, void *blk, unsigned int idx, unsigned int conf)
{
struct daio_mgr_ctrl_blk *ctl = blk;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 204/869] ALSA: ctxfi: Use explicit output flag for DAIO resources
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (202 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 203/869] ALSA: ctxfi: Add hw parameter to daio_mgr_dao_init() Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 205/869] ALSA: ctxfi: Refactor resource alloc for sparse mappings Greg Kroah-Hartman
` (665 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Harin Lee, Takashi Iwai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harin Lee <me@harin.net>
[ Upstream commit 9bb003a1f98b11b80238d522778115ad07355149 ]
Replace the index-based type check with an explicit output flag in
struct daio and struct daio_desc.
This allows handling DAIO resource types correctly regardless of their
index. This is necessary for hardware variants where resource types do
not follow a sequential order.
Signed-off-by: Harin Lee <me@harin.net>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20251124180501.2760421-4-me@harin.net
Stable-dep-of: 277c6960d4dd ("ALSA: ctxfi: Check the error for index mapping")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/pci/ctxfi/ctatc.c | 3 ++-
sound/pci/ctxfi/ctdaio.c | 14 +++++++-------
sound/pci/ctxfi/ctdaio.h | 2 ++
3 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index 74eecc9ebd846..fa70c4504db5f 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -1166,7 +1166,7 @@ static int atc_release_resources(struct ct_atc *atc)
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
for (i = 0; i < atc->n_daio; i++) {
daio = atc->daios[i];
- if (daio->type < LINEIM) {
+ if (daio->output) {
dao = container_of(daio, struct dao, daio);
dao->ops->clear_left_input(dao);
dao->ops->clear_right_input(dao);
@@ -1396,6 +1396,7 @@ static int atc_get_resources(struct ct_atc *atc)
for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
da_desc.type = (atc->model != CTSB073X) ? i :
((i == SPDIFIO) ? SPDIFI1 : i);
+ da_desc.output = i < LINEIM;
err = daio_mgr->get_daio(daio_mgr, &da_desc,
(struct daio **)&atc->daios[i]);
if (err) {
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index b20c10196579d..143dd0979cc9a 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -18,8 +18,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
-#define DAIO_OUT_MAX SPDIFOO
-
struct daio_usage {
unsigned short data;
};
@@ -352,7 +350,7 @@ static int daio_rsc_init(struct daio *daio,
goto error1;
/* Set daio->rscl/r->ops to daio specific ones */
- if (desc->type <= DAIO_OUT_MAX) {
+ if (desc->output) {
daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops;
} else {
switch (hw->chip_type) {
@@ -367,6 +365,7 @@ static int daio_rsc_init(struct daio *daio,
}
}
daio->type = desc->type;
+ daio->output = desc->output;
return 0;
@@ -456,6 +455,7 @@ static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc)
dsc.type = dao->daio.type;
dsc.msr = desc->msr;
dsc.passthru = desc->passthru;
+ dsc.output = dao->daio.output;
dao_rsc_uninit(dao);
return dao_rsc_init(dao, &dsc, mgr);
}
@@ -542,7 +542,7 @@ static int get_daio_rsc(struct daio_mgr *mgr,
err = -ENOMEM;
/* Allocate mem for daio resource */
- if (desc->type <= DAIO_OUT_MAX) {
+ if (desc->output) {
struct dao *dao = kzalloc(sizeof(*dao), GFP_KERNEL);
if (!dao)
goto error;
@@ -591,7 +591,7 @@ static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio)
daio_mgr_put_rsc(&mgr->mgr, daio->type);
spin_unlock_irqrestore(&mgr->mgr_lock, flags);
- if (daio->type <= DAIO_OUT_MAX) {
+ if (daio->output) {
dao_rsc_uninit(container_of(daio, struct dao, daio));
kfree(container_of(daio, struct dao, daio));
} else {
@@ -606,7 +606,7 @@ static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio)
{
struct hw *hw = mgr->mgr.hw;
- if (DAIO_OUT_MAX >= daio->type) {
+ if (daio->output) {
hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
daio_device_index(daio->type, hw));
} else {
@@ -620,7 +620,7 @@ static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio)
{
struct hw *hw = mgr->mgr.hw;
- if (DAIO_OUT_MAX >= daio->type) {
+ if (daio->output) {
hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
daio_device_index(daio->type, hw));
} else {
diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h
index 15147fe5f74a0..b337da2de8b50 100644
--- a/sound/pci/ctxfi/ctdaio.h
+++ b/sound/pci/ctxfi/ctdaio.h
@@ -43,6 +43,7 @@ struct daio {
struct rsc rscl; /* Basic resource info for left TX/RX */
struct rsc rscr; /* Basic resource info for right TX/RX */
enum DAIOTYP type;
+ unsigned char output;
};
struct dao {
@@ -91,6 +92,7 @@ struct daio_desc {
unsigned int type:4;
unsigned int msr:4;
unsigned int passthru:1;
+ unsigned int output:1;
};
struct daio_mgr {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 205/869] ALSA: ctxfi: Refactor resource alloc for sparse mappings
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (203 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 204/869] ALSA: ctxfi: Use explicit output flag for DAIO resources Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 17:10 ` Harin Lee
2026-10-17 15:50 ` [PATCH 6.12 206/869] ALSA: ctxfi: Check the error for index mapping Greg Kroah-Hartman
` (664 subsequent siblings)
869 siblings, 1 reply; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Harin Lee, Takashi Iwai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harin Lee <me@harin.net>
[ Upstream commit a2dbaeb5c61ef110ceefe0d48fe94d428d3bcf16 ]
Refactor atc_get_resources(), atc_connect_resources(), and
atc_release_resources() to allocate resources based on maximum type
definitions.
This allows specific resources to be conditionally skipped based on
capabilities. This is necessary for hardware variants where resource
allocations do not follow a sequential order.
Signed-off-by: Harin Lee <me@harin.net>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20251124180501.2760421-5-me@harin.net
Stable-dep-of: 277c6960d4dd ("ALSA: ctxfi: Check the error for index mapping")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/pci/ctxfi/ctatc.c | 60 ++++++++++++++++++++++++-----------------
sound/pci/ctxfi/ctatc.h | 4 ---
2 files changed, 35 insertions(+), 29 deletions(-)
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index fa70c4504db5f..6f0695efaafc8 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -25,6 +25,9 @@
#include <sound/control.h>
#include <sound/asoundef.h>
+#define NUM_ATC_SRCS 6
+#define NUM_ATC_PCM (2 * 4)
+
#define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */
#define MAX_MULTI_CHN 8
@@ -1164,8 +1167,10 @@ static int atc_release_resources(struct ct_atc *atc)
if (atc->daios) {
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
- for (i = 0; i < atc->n_daio; i++) {
+ for (i = 0; i < NUM_DAIOTYP; i++) {
daio = atc->daios[i];
+ if (!daio)
+ continue;
if (daio->output) {
dao = container_of(daio, struct dao, daio);
dao->ops->clear_left_input(dao);
@@ -1179,8 +1184,9 @@ static int atc_release_resources(struct ct_atc *atc)
if (atc->pcm) {
sum_mgr = atc->rsc_mgrs[SUM];
- for (i = 0; i < atc->n_pcm; i++)
- sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
+ for (i = 0; i < NUM_ATC_PCM; i++)
+ if (atc->pcm[i])
+ sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
kfree(atc->pcm);
atc->pcm = NULL;
@@ -1188,8 +1194,9 @@ static int atc_release_resources(struct ct_atc *atc)
if (atc->srcs) {
src_mgr = atc->rsc_mgrs[SRC];
- for (i = 0; i < atc->n_src; i++)
- src_mgr->put_src(src_mgr, atc->srcs[i]);
+ for (i = 0; i < NUM_ATC_SRCS; i++)
+ if (atc->srcs[i])
+ src_mgr->put_src(src_mgr, atc->srcs[i]);
kfree(atc->srcs);
atc->srcs = NULL;
@@ -1197,7 +1204,9 @@ static int atc_release_resources(struct ct_atc *atc)
if (atc->srcimps) {
srcimp_mgr = atc->rsc_mgrs[SRCIMP];
- for (i = 0; i < atc->n_srcimp; i++) {
+ for (i = 0; i < NUM_ATC_SRCS; i++) {
+ if (!atc->srcimps[i])
+ continue;
srcimp = atc->srcimps[i];
srcimp->ops->unmap(srcimp);
srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]);
@@ -1370,30 +1379,32 @@ static int atc_get_resources(struct ct_atc *atc)
struct srcimp_mgr *srcimp_mgr;
struct sum_desc sum_dsc = {0};
struct sum_mgr *sum_mgr;
- int err, i, num_srcs, num_daios;
+ struct capabilities cap;
+ int err, i;
- num_daios = ((atc->model == CTSB1270) ? 8 : 7);
- num_srcs = ((atc->model == CTSB1270) ? 6 : 4);
+ cap = atc->capabilities(atc);
- atc->daios = kcalloc(num_daios, sizeof(void *), GFP_KERNEL);
+ atc->daios = kcalloc(NUM_DAIOTYP, sizeof(void *), GFP_KERNEL);
if (!atc->daios)
return -ENOMEM;
- atc->srcs = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL);
+ atc->srcs = kcalloc(NUM_ATC_SRCS, sizeof(void *), GFP_KERNEL);
if (!atc->srcs)
return -ENOMEM;
- atc->srcimps = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL);
+ atc->srcimps = kcalloc(NUM_ATC_SRCS, sizeof(void *), GFP_KERNEL);
if (!atc->srcimps)
return -ENOMEM;
- atc->pcm = kcalloc(2 * 4, sizeof(void *), GFP_KERNEL);
+ atc->pcm = kcalloc(NUM_ATC_PCM, sizeof(void *), GFP_KERNEL);
if (!atc->pcm)
return -ENOMEM;
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
da_desc.msr = atc->msr;
- for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
+ for (i = 0; i < NUM_DAIOTYP; i++) {
+ if ((i == MIC) && !cap.dedicated_mic)
+ continue;
da_desc.type = (atc->model != CTSB073X) ? i :
((i == SPDIFIO) ? SPDIFI1 : i);
da_desc.output = i < LINEIM;
@@ -1405,42 +1416,39 @@ static int atc_get_resources(struct ct_atc *atc)
i);
return err;
}
- atc->n_daio++;
}
src_mgr = atc->rsc_mgrs[SRC];
src_dsc.multi = 1;
src_dsc.msr = atc->msr;
src_dsc.mode = ARCRW;
- for (i = 0, atc->n_src = 0; i < num_srcs; i++) {
+ for (i = 0; i < NUM_ATC_SRCS; i++) {
+ if (((i > 3) && !cap.dedicated_mic))
+ continue;
err = src_mgr->get_src(src_mgr, &src_dsc,
(struct src **)&atc->srcs[i]);
if (err)
return err;
-
- atc->n_src++;
}
srcimp_mgr = atc->rsc_mgrs[SRCIMP];
srcimp_dsc.msr = 8;
- for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) {
+ for (i = 0; i < NUM_ATC_SRCS; i++) {
+ if (((i > 3) && !cap.dedicated_mic))
+ continue;
err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
(struct srcimp **)&atc->srcimps[i]);
if (err)
return err;
-
- atc->n_srcimp++;
}
sum_mgr = atc->rsc_mgrs[SUM];
sum_dsc.msr = atc->msr;
- for (i = 0, atc->n_pcm = 0; i < (2*4); i++) {
+ for (i = 0; i < NUM_ATC_PCM; i++) {
err = sum_mgr->get_sum(sum_mgr, &sum_dsc,
(struct sum **)&atc->pcm[i]);
if (err)
return err;
-
- atc->n_pcm++;
}
return 0;
@@ -1493,9 +1501,11 @@ static void atc_connect_resources(struct ct_atc *atc)
struct sum *sum;
struct ct_mixer *mixer;
struct rsc *rscs[2] = {NULL};
+ struct capabilities cap;
int i, j;
mixer = atc->mixer;
+ cap = atc->capabilities(atc);
for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) {
mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]);
@@ -1513,7 +1523,7 @@ static void atc_connect_resources(struct ct_atc *atc)
src = atc->srcs[3];
mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
- if (atc->model == CTSB1270) {
+ if (cap.dedicated_mic) {
/* Titanium HD has a dedicated ADC for the Mic. */
dai = container_of(atc->daios[MIC], struct dai, daio);
atc_connect_dai(atc->rsc_mgrs[SRC], dai,
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h
index 0bc7b71d910b0..671edc46bd503 100644
--- a/sound/pci/ctxfi/ctatc.h
+++ b/sound/pci/ctxfi/ctatc.h
@@ -132,10 +132,6 @@ struct ct_atc {
void **pcm; /* SUMs for collecting all pcm stream */
void **srcs; /* Sample Rate Converters for input signal */
void **srcimps; /* input mappers for SRCs */
- unsigned char n_daio;
- unsigned char n_src;
- unsigned char n_srcimp;
- unsigned char n_pcm;
struct ct_timer *timer;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 206/869] ALSA: ctxfi: Check the error for index mapping
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (204 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 205/869] ALSA: ctxfi: Refactor resource alloc for sparse mappings Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 207/869] bpf: Factor out atomic_ptr_type_ok() Greg Kroah-Hartman
` (663 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Takashi Iwai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <tiwai@suse.de>
[ Upstream commit 277c6960d4ddb94d16198afd70c92c3d4593d131 ]
The ctxfi driver blindly assumed a proper value returned from
daio_device_index(), but it's not always true. Add a proper error
check to deal with the error from the function.
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/87cy149n6k.wl-tiwai@suse.de
Link: https://patch.msgid.link/20260329091240.420194-2-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/pci/ctxfi/ctdaio.c | 85 ++++++++++++++++++++++++----------------
1 file changed, 52 insertions(+), 33 deletions(-)
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index 143dd0979cc9a..85bc1fbef9bf2 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -98,7 +98,7 @@ static const struct rsc_ops daio_in_rsc_ops_20k2 = {
.output_slot = daio_index,
};
-static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
+static int daio_device_index(enum DAIOTYP type, struct hw *hw)
{
switch (hw->chip_type) {
case ATC20K1:
@@ -111,7 +111,9 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
case LINEO3: return 5;
case LINEO4: return 6;
case LINEIM: return 7;
- default: return -EINVAL;
+ default:
+ pr_err("ctxfi: Invalid type %d for hw20k1\n", type);
+ return -EINVAL;
}
case ATC20K2:
switch (type) {
@@ -124,9 +126,12 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
case LINEO4: return 6;
case LINEIM: return 4;
case MIC: return 5;
- default: return -EINVAL;
+ default:
+ pr_err("ctxfi: Invalid type %d for hw20k2\n", type);
+ return -EINVAL;
}
default:
+ pr_err("ctxfi: Invalid chip type %d\n", hw->chip_type);
return -EINVAL;
}
}
@@ -147,8 +152,11 @@ static int dao_spdif_set_spos(struct dao *dao, unsigned int spos)
static int dao_commit_write(struct dao *dao)
{
- dao->hw->dao_commit_write(dao->hw,
- daio_device_index(dao->daio.type, dao->hw), dao->ctrl_blk);
+ int idx = daio_device_index(dao->daio.type, dao->hw);
+
+ if (idx < 0)
+ return idx;
+ dao->hw->dao_commit_write(dao->hw, idx, dao->ctrl_blk);
return 0;
}
@@ -308,8 +316,11 @@ static int dai_set_enb_srt(struct dai *dai, unsigned int enb)
static int dai_commit_write(struct dai *dai)
{
- dai->hw->dai_commit_write(dai->hw,
- daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);
+ int idx = daio_device_index(dai->daio.type, dai->hw);
+
+ if (idx < 0)
+ return idx;
+ dai->hw->dai_commit_write(dai->hw, idx, dai->ctrl_blk);
return 0;
}
@@ -388,7 +399,7 @@ static int dao_rsc_init(struct dao *dao,
{
struct hw *hw = mgr->mgr.hw;
unsigned int conf;
- int err;
+ int idx, err;
err = daio_rsc_init(&dao->daio, desc, mgr->mgr.hw);
if (err)
@@ -407,15 +418,18 @@ static int dao_rsc_init(struct dao *dao,
if (err)
goto error2;
- hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
- daio_device_index(dao->daio.type, hw));
+ idx = daio_device_index(dao->daio.type, hw);
+ if (idx < 0) {
+ err = idx;
+ goto error2;
+ }
+
+ hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk, idx);
hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
conf = (desc->msr & 0x7) | (desc->passthru << 3);
- hw->daio_mgr_dao_init(hw, mgr->mgr.ctrl_blk,
- daio_device_index(dao->daio.type, hw), conf);
- hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
- daio_device_index(dao->daio.type, hw));
+ hw->daio_mgr_dao_init(hw, mgr->mgr.ctrl_blk, idx, conf);
+ hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk, idx);
hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
return 0;
@@ -464,7 +478,7 @@ static int dai_rsc_init(struct dai *dai,
const struct daio_desc *desc,
struct daio_mgr *mgr)
{
- int err;
+ int idx, err;
struct hw *hw = mgr->mgr.hw;
unsigned int rsr, msr;
@@ -478,6 +492,12 @@ static int dai_rsc_init(struct dai *dai,
if (err)
goto error1;
+ idx = daio_device_index(dai->daio.type, dai->hw);
+ if (idx < 0) {
+ err = idx;
+ goto error1;
+ }
+
for (rsr = 0, msr = desc->msr; msr > 1; msr >>= 1)
rsr++;
@@ -486,8 +506,7 @@ static int dai_rsc_init(struct dai *dai,
/* default to disabling control of a SRC */
hw->dai_srt_set_ec(dai->ctrl_blk, 0);
hw->dai_srt_set_et(dai->ctrl_blk, 0); /* default to disabling SRT */
- hw->dai_commit_write(hw,
- daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);
+ hw->dai_commit_write(hw, idx, dai->ctrl_blk);
return 0;
@@ -605,28 +624,28 @@ static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio)
static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio)
{
struct hw *hw = mgr->mgr.hw;
-
- if (daio->output) {
- hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
- daio_device_index(daio->type, hw));
- } else {
- hw->daio_mgr_enb_dai(mgr->mgr.ctrl_blk,
- daio_device_index(daio->type, hw));
- }
+ int idx = daio_device_index(daio->type, hw);
+
+ if (idx < 0)
+ return idx;
+ if (daio->output)
+ hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk, idx);
+ else
+ hw->daio_mgr_enb_dai(mgr->mgr.ctrl_blk, idx);
return 0;
}
static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio)
{
struct hw *hw = mgr->mgr.hw;
-
- if (daio->output) {
- hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
- daio_device_index(daio->type, hw));
- } else {
- hw->daio_mgr_dsb_dai(mgr->mgr.ctrl_blk,
- daio_device_index(daio->type, hw));
- }
+ int idx = daio_device_index(daio->type, hw);
+
+ if (idx < 0)
+ return idx;
+ if (daio->output)
+ hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk, idx);
+ else
+ hw->daio_mgr_dsb_dai(mgr->mgr.ctrl_blk, idx);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 207/869] bpf: Factor out atomic_ptr_type_ok()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (205 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 206/869] ALSA: ctxfi: Check the error for index mapping Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 208/869] bpf: Factor out check_atomic_rmw() Greg Kroah-Hartman
` (662 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Peilin Ye, Alexei Starovoitov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peilin Ye <yepeilin@google.com>
[ Upstream commit 66faaea94e1a8e8197d98de6e9d07591970837d6 ]
Factor out atomic_ptr_type_ok() as a helper function to be used later.
Signed-off-by: Peilin Ye <yepeilin@google.com>
Link: https://lore.kernel.org/r/e5ef8b3116f3fffce78117a14060ddce05eba52a.1740978603.git.yepeilin@google.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Stable-dep-of: 179ee84a8911 ("bpf: Fix incorrect pruning due to atomic fetch precision tracking")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 4978c1d68bd98..1f5c8b5b74ffb 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5986,6 +5986,26 @@ static bool is_arena_reg(struct bpf_verifier_env *env, int regno)
return reg->type == PTR_TO_ARENA;
}
+/* Return false if @regno contains a pointer whose type isn't supported for
+ * atomic instruction @insn.
+ */
+static bool atomic_ptr_type_ok(struct bpf_verifier_env *env, int regno,
+ struct bpf_insn *insn)
+{
+ if (is_ctx_reg(env, regno))
+ return false;
+ if (is_pkt_reg(env, regno))
+ return false;
+ if (is_flow_key_reg(env, regno))
+ return false;
+ if (is_sk_reg(env, regno))
+ return false;
+ if (is_arena_reg(env, regno))
+ return bpf_jit_supports_insn(insn, true);
+
+ return true;
+}
+
static u32 *reg2btf_ids[__BPF_REG_TYPE_MAX] = {
#ifdef CONFIG_NET
[PTR_TO_SOCKET] = &btf_sock_ids[BTF_SOCK_TYPE_SOCK],
@@ -7439,11 +7459,7 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i
return -EACCES;
}
- if (is_ctx_reg(env, insn->dst_reg) ||
- is_pkt_reg(env, insn->dst_reg) ||
- is_flow_key_reg(env, insn->dst_reg) ||
- is_sk_reg(env, insn->dst_reg) ||
- (is_arena_reg(env, insn->dst_reg) && !bpf_jit_supports_insn(insn, true))) {
+ if (!atomic_ptr_type_ok(env, insn->dst_reg, insn)) {
verbose(env, "BPF_ATOMIC stores into R%d %s is not allowed\n",
insn->dst_reg,
reg_type_str(env, reg_state(env, insn->dst_reg)->type));
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 208/869] bpf: Factor out check_atomic_rmw()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (206 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 207/869] bpf: Factor out atomic_ptr_type_ok() Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 209/869] bpf: Factor out check_load_mem() and check_store_reg() Greg Kroah-Hartman
` (661 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Peilin Ye, Alexei Starovoitov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peilin Ye <yepeilin@google.com>
[ Upstream commit 2626ffe9f33f9e27aa0a60b2761c2d0760dbcca4 ]
Currently, check_atomic() only handles atomic read-modify-write (RMW)
instructions. Since we are planning to introduce other types of atomic
instructions (i.e., atomic load/store), extract the existing RMW
handling logic into its own function named check_atomic_rmw().
Remove the @insn_idx parameter as it is not really necessary. Use
'env->insn_idx' instead, as in other places in verifier.c.
Signed-off-by: Peilin Ye <yepeilin@google.com>
Link: https://lore.kernel.org/r/6323ac8e73a10a1c8ee547c77ed68cf8eb6b90e1.1740978603.git.yepeilin@google.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Stable-dep-of: 179ee84a8911 ("bpf: Fix incorrect pruning due to atomic fetch precision tracking")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 53 +++++++++++++++++++++++--------------------
1 file changed, 29 insertions(+), 24 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 1f5c8b5b74ffb..fdeb3948467d1 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -7403,28 +7403,12 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
static int save_aux_ptr_type(struct bpf_verifier_env *env, enum bpf_reg_type type,
bool allow_trust_mismatch);
-static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_insn *insn)
+static int check_atomic_rmw(struct bpf_verifier_env *env,
+ struct bpf_insn *insn)
{
int load_reg;
int err;
- switch (insn->imm) {
- case BPF_ADD:
- case BPF_ADD | BPF_FETCH:
- case BPF_AND:
- case BPF_AND | BPF_FETCH:
- case BPF_OR:
- case BPF_OR | BPF_FETCH:
- case BPF_XOR:
- case BPF_XOR | BPF_FETCH:
- case BPF_XCHG:
- case BPF_CMPXCHG:
- break;
- default:
- verbose(env, "BPF_ATOMIC uses invalid atomic opcode %02x\n", insn->imm);
- return -EINVAL;
- }
-
if (BPF_SIZE(insn->code) != BPF_W && BPF_SIZE(insn->code) != BPF_DW) {
verbose(env, "invalid atomic operand size\n");
return -EINVAL;
@@ -7486,12 +7470,12 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i
/* Check whether we can read the memory, with second call for fetch
* case to simulate the register fill.
*/
- err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
+ err = check_mem_access(env, env->insn_idx, insn->dst_reg, insn->off,
BPF_SIZE(insn->code), BPF_READ, -1, true, false);
if (!err && load_reg >= 0)
- err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
- BPF_SIZE(insn->code), BPF_READ, load_reg,
- true, false);
+ err = check_mem_access(env, env->insn_idx, insn->dst_reg,
+ insn->off, BPF_SIZE(insn->code),
+ BPF_READ, load_reg, true, false);
if (err)
return err;
@@ -7501,13 +7485,34 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i
return err;
}
/* Check whether we can write into the same memory. */
- err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
+ err = check_mem_access(env, env->insn_idx, insn->dst_reg, insn->off,
BPF_SIZE(insn->code), BPF_WRITE, -1, true, false);
if (err)
return err;
return 0;
}
+static int check_atomic(struct bpf_verifier_env *env, struct bpf_insn *insn)
+{
+ switch (insn->imm) {
+ case BPF_ADD:
+ case BPF_ADD | BPF_FETCH:
+ case BPF_AND:
+ case BPF_AND | BPF_FETCH:
+ case BPF_OR:
+ case BPF_OR | BPF_FETCH:
+ case BPF_XOR:
+ case BPF_XOR | BPF_FETCH:
+ case BPF_XCHG:
+ case BPF_CMPXCHG:
+ return check_atomic_rmw(env, insn);
+ default:
+ verbose(env, "BPF_ATOMIC uses invalid atomic opcode %02x\n",
+ insn->imm);
+ return -EINVAL;
+ }
+}
+
/* When register 'regno' is used to read the stack (either directly or through
* a helper function) make sure that it's within stack boundary and, depending
* on the access type and privileges, that all elements of the stack are
@@ -18916,7 +18921,7 @@ static int do_check(struct bpf_verifier_env *env)
enum bpf_reg_type dst_reg_type;
if (BPF_MODE(insn->code) == BPF_ATOMIC) {
- err = check_atomic(env, env->insn_idx, insn);
+ err = check_atomic(env, insn);
if (err)
return err;
env->insn_idx++;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 209/869] bpf: Factor out check_load_mem() and check_store_reg()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (207 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 208/869] bpf: Factor out check_atomic_rmw() Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 210/869] bpf: Fix incorrect pruning due to atomic fetch precision tracking Greg Kroah-Hartman
` (660 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eduard Zingerman, Peilin Ye,
Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peilin Ye <yepeilin@google.com>
[ Upstream commit a752ba4332788cd7ddfbe267c392898841799b44 ]
Extract BPF_LDX and most non-ATOMIC BPF_STX instruction handling logic
in do_check() into helper functions to be used later. While we are
here, make that comment about "reserved fields" more specific.
Suggested-by: Eduard Zingerman <eddyz87@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Peilin Ye <yepeilin@google.com>
Link: https://lore.kernel.org/r/8b39c94eac2bb7389ff12392ca666f939124ec4f.1740978603.git.yepeilin@google.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Stable-dep-of: 179ee84a8911 ("bpf: Fix incorrect pruning due to atomic fetch precision tracking")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 110 +++++++++++++++++++++++++-----------------
1 file changed, 67 insertions(+), 43 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index fdeb3948467d1..d598c8f409c3e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -7403,6 +7403,67 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
static int save_aux_ptr_type(struct bpf_verifier_env *env, enum bpf_reg_type type,
bool allow_trust_mismatch);
+static int check_load_mem(struct bpf_verifier_env *env, struct bpf_insn *insn,
+ bool strict_alignment_once, bool is_ldsx,
+ bool allow_trust_mismatch, const char *ctx)
+{
+ struct bpf_reg_state *regs = cur_regs(env);
+ enum bpf_reg_type src_reg_type;
+ int err;
+
+ /* check src operand */
+ err = check_reg_arg(env, insn->src_reg, SRC_OP);
+ if (err)
+ return err;
+
+ /* check dst operand */
+ err = check_reg_arg(env, insn->dst_reg, DST_OP_NO_MARK);
+ if (err)
+ return err;
+
+ src_reg_type = regs[insn->src_reg].type;
+
+ /* Check if (src_reg + off) is readable. The state of dst_reg will be
+ * updated by this call.
+ */
+ err = check_mem_access(env, env->insn_idx, insn->src_reg, insn->off,
+ BPF_SIZE(insn->code), BPF_READ, insn->dst_reg,
+ strict_alignment_once, is_ldsx);
+ err = err ?: save_aux_ptr_type(env, src_reg_type,
+ allow_trust_mismatch);
+ err = err ?: reg_bounds_sanity_check(env, ®s[insn->dst_reg], ctx);
+
+ return err;
+}
+
+static int check_store_reg(struct bpf_verifier_env *env, struct bpf_insn *insn,
+ bool strict_alignment_once)
+{
+ struct bpf_reg_state *regs = cur_regs(env);
+ enum bpf_reg_type dst_reg_type;
+ int err;
+
+ /* check src1 operand */
+ err = check_reg_arg(env, insn->src_reg, SRC_OP);
+ if (err)
+ return err;
+
+ /* check src2 operand */
+ err = check_reg_arg(env, insn->dst_reg, SRC_OP);
+ if (err)
+ return err;
+
+ dst_reg_type = regs[insn->dst_reg].type;
+
+ /* Check if (dst_reg + off) is writeable. */
+ err = check_mem_access(env, env->insn_idx, insn->dst_reg, insn->off,
+ BPF_SIZE(insn->code), BPF_WRITE, insn->src_reg,
+ strict_alignment_once, false);
+ err = err ?: save_aux_ptr_type(env, dst_reg_type, false);
+
+ return err;
+}
+
static int check_atomic_rmw(struct bpf_verifier_env *env,
struct bpf_insn *insn)
{
@@ -18891,35 +18952,16 @@ static int do_check(struct bpf_verifier_env *env)
return err;
} else if (class == BPF_LDX) {
- enum bpf_reg_type src_reg_type;
-
- /* check for reserved fields is already done */
-
- /* check src operand */
- err = check_reg_arg(env, insn->src_reg, SRC_OP);
- if (err)
- return err;
+ bool is_ldsx = BPF_MODE(insn->code) == BPF_MEMSX;
- err = check_reg_arg(env, insn->dst_reg, DST_OP_NO_MARK);
- if (err)
- return err;
-
- src_reg_type = regs[insn->src_reg].type;
-
- /* check that memory (src_reg + off) is readable,
- * the state of dst_reg will be updated by this func
+ /* Check for reserved fields is already done in
+ * resolve_pseudo_ldimm64().
*/
- err = check_mem_access(env, env->insn_idx, insn->src_reg,
- insn->off, BPF_SIZE(insn->code),
- BPF_READ, insn->dst_reg, false,
- BPF_MODE(insn->code) == BPF_MEMSX);
- err = err ?: save_aux_ptr_type(env, src_reg_type, true);
- err = err ?: reg_bounds_sanity_check(env, ®s[insn->dst_reg], "ldx");
+ err = check_load_mem(env, insn, false, is_ldsx, true,
+ "ldx");
if (err)
return err;
} else if (class == BPF_STX) {
- enum bpf_reg_type dst_reg_type;
-
if (BPF_MODE(insn->code) == BPF_ATOMIC) {
err = check_atomic(env, insn);
if (err)
@@ -18933,25 +18975,7 @@ static int do_check(struct bpf_verifier_env *env)
return -EINVAL;
}
- /* check src1 operand */
- err = check_reg_arg(env, insn->src_reg, SRC_OP);
- if (err)
- return err;
- /* check src2 operand */
- err = check_reg_arg(env, insn->dst_reg, SRC_OP);
- if (err)
- return err;
-
- dst_reg_type = regs[insn->dst_reg].type;
-
- /* check that memory (dst_reg + off) is writeable */
- err = check_mem_access(env, env->insn_idx, insn->dst_reg,
- insn->off, BPF_SIZE(insn->code),
- BPF_WRITE, insn->src_reg, false, false);
- if (err)
- return err;
-
- err = save_aux_ptr_type(env, dst_reg_type, false);
+ err = check_store_reg(env, insn, false);
if (err)
return err;
} else if (class == BPF_ST) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 210/869] bpf: Fix incorrect pruning due to atomic fetch precision tracking
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (208 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 209/869] bpf: Factor out check_load_mem() and check_store_reg() Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 211/869] Bluetooth: hci_sync: hci_cmd_sync_queue_once() return -EEXIST if exists Greg Kroah-Hartman
` (659 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, STAR Labs SG, Daniel Borkmann,
Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Borkmann <daniel@iogearbox.net>
[ Upstream commit 179ee84a89114b854ac2dd1d293633a7f6c8dac1 ]
When backtrack_insn encounters a BPF_STX instruction with BPF_ATOMIC
and BPF_FETCH, the src register (or r0 for BPF_CMPXCHG) also acts as
a destination, thus receiving the old value from the memory location.
The current backtracking logic does not account for this. It treats
atomic fetch operations the same as regular stores where the src
register is only an input. This leads the backtrack_insn to fail to
propagate precision to the stack location, which is then not marked
as precise!
Later, the verifier's path pruning can incorrectly consider two states
equivalent when they differ in terms of stack state. Meaning, two
branches can be treated as equivalent and thus get pruned when they
should not be seen as such.
Fix it as follows: Extend the BPF_LDX handling in backtrack_insn to
also cover atomic fetch operations via is_atomic_fetch_insn() helper.
When the fetch dst register is being tracked for precision, clear it,
and propagate precision over to the stack slot. For non-stack memory,
the precision walk stops at the atomic instruction, same as regular
BPF_LDX. This covers all fetch variants.
Before:
0: (b7) r1 = 8 ; R1=8
1: (7b) *(u64 *)(r10 -8) = r1 ; R1=8 R10=fp0 fp-8=8
2: (b7) r2 = 0 ; R2=0
3: (db) r2 = atomic64_fetch_add((u64 *)(r10 -8), r2) ; R2=8 R10=fp0 fp-8=mmmmmmmm
4: (bf) r3 = r10 ; R3=fp0 R10=fp0
5: (0f) r3 += r2
mark_precise: frame0: last_idx 5 first_idx 0 subseq_idx -1
mark_precise: frame0: regs=r2 stack= before 4: (bf) r3 = r10
mark_precise: frame0: regs=r2 stack= before 3: (db) r2 = atomic64_fetch_add((u64 *)(r10 -8), r2)
mark_precise: frame0: regs=r2 stack= before 2: (b7) r2 = 0
6: R2=8 R3=fp8
6: (b7) r0 = 0 ; R0=0
7: (95) exit
After:
0: (b7) r1 = 8 ; R1=8
1: (7b) *(u64 *)(r10 -8) = r1 ; R1=8 R10=fp0 fp-8=8
2: (b7) r2 = 0 ; R2=0
3: (db) r2 = atomic64_fetch_add((u64 *)(r10 -8), r2) ; R2=8 R10=fp0 fp-8=mmmmmmmm
4: (bf) r3 = r10 ; R3=fp0 R10=fp0
5: (0f) r3 += r2
mark_precise: frame0: last_idx 5 first_idx 0 subseq_idx -1
mark_precise: frame0: regs=r2 stack= before 4: (bf) r3 = r10
mark_precise: frame0: regs=r2 stack= before 3: (db) r2 = atomic64_fetch_add((u64 *)(r10 -8), r2)
mark_precise: frame0: regs= stack=-8 before 2: (b7) r2 = 0
mark_precise: frame0: regs= stack=-8 before 1: (7b) *(u64 *)(r10 -8) = r1
mark_precise: frame0: regs=r1 stack= before 0: (b7) r1 = 8
6: R2=8 R3=fp8
6: (b7) r0 = 0 ; R0=0
7: (95) exit
Fixes: 5ffa25502b5a ("bpf: Add instructions for atomic_[cmp]xchg")
Fixes: 5ca419f2864a ("bpf: Add BPF_FETCH field / create atomic_fetch_add instruction")
Reported-by: STAR Labs SG <info@starlabs.sg>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/r/20260331222020.401848-1-daniel@iogearbox.net
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index d598c8f409c3e..5a1c8733f3222 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -578,6 +578,13 @@ static bool is_cmpxchg_insn(const struct bpf_insn *insn)
insn->imm == BPF_CMPXCHG;
}
+static bool is_atomic_fetch_insn(const struct bpf_insn *insn)
+{
+ return BPF_CLASS(insn->code) == BPF_STX &&
+ BPF_MODE(insn->code) == BPF_ATOMIC &&
+ (insn->imm & BPF_FETCH);
+}
+
static int __get_spi(s32 off)
{
return (-off - 1) / BPF_REG_SIZE;
@@ -3968,10 +3975,22 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
* dreg still needs precision before this insn
*/
}
- } else if (class == BPF_LDX) {
- if (!bt_is_reg_set(bt, dreg))
+ } else if (class == BPF_LDX || is_atomic_fetch_insn(insn)) {
+ u32 load_reg = dreg;
+
+ /*
+ * Atomic fetch operation writes the old value into
+ * a register (sreg or r0) and if it was tracked for
+ * precision, propagate to the stack slot like we do
+ * in regular ldx.
+ */
+ if (is_atomic_fetch_insn(insn))
+ load_reg = insn->imm == BPF_CMPXCHG ?
+ BPF_REG_0 : sreg;
+
+ if (!bt_is_reg_set(bt, load_reg))
return 0;
- bt_clear_reg(bt, dreg);
+ bt_clear_reg(bt, load_reg);
/* scalars can only be spilled into stack w/o losing precision.
* Load from any other memory can be zero extended.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 211/869] Bluetooth: hci_sync: hci_cmd_sync_queue_once() return -EEXIST if exists
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (209 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 210/869] bpf: Fix incorrect pruning due to atomic fetch precision tracking Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 212/869] mptcp: move the whole rx path under msk socket lock protection Greg Kroah-Hartman
` (658 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pauli Virtanen,
Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <pav@iki.fi>
[ Upstream commit 2969554bcfccb5c609f6b6cd4a014933f3a66dd0 ]
hci_cmd_sync_queue_once() needs to indicate whether a queue item was
added, so caller can know if callbacks are called, so it can avoid
leaking resources.
Change the function to return -EEXIST if queue item already exists.
Modify all callsites to handle that.
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/hci_sync.c | 37 ++++++++++++++++++++++++++-----------
1 file changed, 26 insertions(+), 11 deletions(-)
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 6d7caf00fc897..b0ab43145e47f 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -794,7 +794,7 @@ int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy)
{
if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy))
- return 0;
+ return -EEXIST;
return hci_cmd_sync_queue(hdev, func, data, destroy);
}
@@ -3383,6 +3383,8 @@ static int update_passive_scan_sync(struct hci_dev *hdev, void *data)
int hci_update_passive_scan(struct hci_dev *hdev)
{
+ int err;
+
/* Only queue if it would have any effect */
if (!test_bit(HCI_UP, &hdev->flags) ||
test_bit(HCI_INIT, &hdev->flags) ||
@@ -3392,8 +3394,9 @@ int hci_update_passive_scan(struct hci_dev *hdev)
hci_dev_test_flag(hdev, HCI_UNREGISTER))
return 0;
- return hci_cmd_sync_queue_once(hdev, update_passive_scan_sync, NULL,
- NULL);
+ err = hci_cmd_sync_queue_once(hdev, update_passive_scan_sync, NULL,
+ NULL);
+ return (err == -EEXIST) ? 0 : err;
}
int hci_write_sc_support_sync(struct hci_dev *hdev, u8 val)
@@ -7112,8 +7115,11 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
- return hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn,
- NULL);
+ int err;
+
+ err = hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn,
+ NULL);
+ return (err == -EEXIST) ? 0 : err;
}
static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
@@ -7149,8 +7155,11 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
- return hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync, conn,
- create_le_conn_complete);
+ int err;
+
+ err = hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync, conn,
+ create_le_conn_complete);
+ return (err == -EEXIST) ? 0 : err;
}
static int hci_acl_cancel_create_conn_sync(struct hci_dev *hdev,
@@ -7383,8 +7392,11 @@ static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data)
int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
- return hci_cmd_sync_queue_once(hdev, hci_le_pa_create_sync, conn,
- create_pa_complete);
+ int err;
+
+ err = hci_cmd_sync_queue_once(hdev, hci_le_pa_create_sync, conn,
+ create_pa_complete);
+ return (err == -EEXIST) ? 0 : err;
}
static void create_big_complete(struct hci_dev *hdev, void *data, int err)
@@ -7447,6 +7459,9 @@ static int hci_le_big_create_sync(struct hci_dev *hdev, void *data)
int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
- return hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync, conn,
- create_big_complete);
+ int err;
+
+ err = hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync, conn,
+ create_big_complete);
+ return (err == -EEXIST) ? 0 : err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 212/869] mptcp: move the whole rx path under msk socket lock protection
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (210 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 211/869] Bluetooth: hci_sync: hci_cmd_sync_queue_once() return -EEXIST if exists Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 213/869] mptcp: cleanup mem accounting Greg Kroah-Hartman
` (657 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Paolo Abeni, Mat Martineau,
Matthieu Baerts (NGI0), Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <pabeni@redhat.com>
[ Upstream commit bc68b0efa1bf923cef1294a631d8e7416c7e06e4 ]
After commit c2e6048fa1cf ("mptcp: fix race in release_cb") we can
move the whole MPTCP rx path under the socket lock leveraging the
release_cb.
We can drop a bunch of spin_lock pairs in the receive functions, use
a single receive queue and invoke __mptcp_move_skbs only when subflows
ask for it.
This will allow more cleanup in the next patch.
Some changes are worth specific mention:
The msk rcvbuf update now always happens under both the msk and the
subflow socket lock: we can drop a bunch of ONCE annotation and
consolidate the checks.
When the skbs move is delayed at msk release callback time, even the
msk rcvbuf update is delayed; additionally take care of such action in
__mptcp_move_skbs().
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Reviewed-by: Mat Martineau <martineau@kernel.org>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20250218-net-next-mptcp-rx-path-refactor-v1-3-4a47d90d7998@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 5dd8025a49c2 ("mptcp: fix soft lockup in mptcp_recvmsg()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mptcp/fastopen.c | 1 +
net/mptcp/protocol.c | 122 ++++++++++++++++++++-----------------------
net/mptcp/protocol.h | 2 +-
3 files changed, 59 insertions(+), 66 deletions(-)
diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c
index 35b93adf1b735..40ca9aa21a626 100644
--- a/net/mptcp/fastopen.c
+++ b/net/mptcp/fastopen.c
@@ -51,6 +51,7 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf
MPTCP_SKB_CB(skb)->cant_coalesce = 1;
mptcp_data_lock(sk);
+ DEBUG_NET_WARN_ON_ONCE(sock_owned_by_user_nocheck(sk));
mptcp_set_owner_r(skb, sk);
__skb_queue_tail(&sk->sk_receive_queue, skb);
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index da774b1a94607..6106c561026d6 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -694,18 +694,6 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,
bool more_data_avail;
struct tcp_sock *tp;
bool done = false;
- int sk_rbuf;
-
- sk_rbuf = READ_ONCE(sk->sk_rcvbuf);
-
- if (!(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) {
- int ssk_rbuf = READ_ONCE(ssk->sk_rcvbuf);
-
- if (unlikely(ssk_rbuf > sk_rbuf)) {
- WRITE_ONCE(sk->sk_rcvbuf, ssk_rbuf);
- sk_rbuf = ssk_rbuf;
- }
- }
pr_debug("msk=%p ssk=%p\n", msk, ssk);
tp = tcp_sk(ssk);
@@ -775,7 +763,7 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,
WRITE_ONCE(tp->copied_seq, seq);
more_data_avail = mptcp_subflow_data_available(ssk);
- if (atomic_read(&sk->sk_rmem_alloc) > sk_rbuf) {
+ if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf) {
done = true;
break;
}
@@ -900,11 +888,30 @@ static bool move_skbs_to_msk(struct mptcp_sock *msk, struct sock *ssk)
return moved > 0;
}
+static void __mptcp_rcvbuf_update(struct sock *sk, struct sock *ssk)
+{
+ if (unlikely(ssk->sk_rcvbuf > sk->sk_rcvbuf))
+ WRITE_ONCE(sk->sk_rcvbuf, ssk->sk_rcvbuf);
+}
+
+static void __mptcp_data_ready(struct sock *sk, struct sock *ssk)
+{
+ struct mptcp_sock *msk = mptcp_sk(sk);
+
+ __mptcp_rcvbuf_update(sk, ssk);
+
+ /* over limit? can't append more skbs to msk, Also, no need to wake-up*/
+ if (__mptcp_rmem(sk) > sk->sk_rcvbuf)
+ return;
+
+ /* Wake-up the reader only for in-sequence data */
+ if (move_skbs_to_msk(msk, ssk) && mptcp_epollin_ready(sk))
+ sk->sk_data_ready(sk);
+}
+
void mptcp_data_ready(struct sock *sk, struct sock *ssk)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
- struct mptcp_sock *msk = mptcp_sk(sk);
- int sk_rbuf, ssk_rbuf;
/* The peer can send data while we are shutting down this
* subflow at subflow destruction time, but we must avoid enqueuing
@@ -913,19 +920,11 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk)
if (unlikely(subflow->closing))
return;
- ssk_rbuf = READ_ONCE(ssk->sk_rcvbuf);
- sk_rbuf = READ_ONCE(sk->sk_rcvbuf);
- if (unlikely(ssk_rbuf > sk_rbuf))
- sk_rbuf = ssk_rbuf;
-
- /* over limit? can't append more skbs to msk, Also, no need to wake-up*/
- if (__mptcp_rmem(sk) > sk_rbuf)
- return;
-
- /* Wake-up the reader only for in-sequence data */
mptcp_data_lock(sk);
- if (move_skbs_to_msk(msk, ssk) && mptcp_epollin_ready(sk))
- sk->sk_data_ready(sk);
+ if (!sock_owned_by_user(sk))
+ __mptcp_data_ready(sk, ssk);
+ else
+ __set_bit(MPTCP_DEQUEUE, &mptcp_sk(sk)->cb_flags);
mptcp_data_unlock(sk);
}
@@ -2032,17 +2031,18 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied);
-static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk,
+static int __mptcp_recvmsg_mskq(struct sock *sk,
struct msghdr *msg,
size_t len, int flags, int copied_total,
struct scm_timestamping_internal *tss,
int *cmsg_flags)
{
+ struct mptcp_sock *msk = mptcp_sk(sk);
struct sk_buff *skb, *tmp;
int total_data_len = 0;
int copied = 0;
- skb_queue_walk_safe(&msk->receive_queue, skb, tmp) {
+ skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) {
u32 delta, offset = MPTCP_SKB_CB(skb)->offset;
u32 data_len = skb->len - offset;
u32 count;
@@ -2090,7 +2090,7 @@ static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk,
/* we will bulk release the skb memory later */
skb->destructor = NULL;
WRITE_ONCE(msk->rmem_released, msk->rmem_released + skb->truesize);
- __skb_unlink(skb, &msk->receive_queue);
+ __skb_unlink(skb, &sk->sk_receive_queue);
__kfree_skb(skb);
}
@@ -2214,55 +2214,46 @@ static void __mptcp_update_rmem(struct sock *sk)
WRITE_ONCE(msk->rmem_released, 0);
}
-static void __mptcp_splice_receive_queue(struct sock *sk)
+static bool __mptcp_move_skbs(struct sock *sk)
{
+ struct mptcp_subflow_context *subflow;
struct mptcp_sock *msk = mptcp_sk(sk);
-
- skb_queue_splice_tail_init(&sk->sk_receive_queue, &msk->receive_queue);
-}
-
-static bool __mptcp_move_skbs(struct mptcp_sock *msk)
-{
- struct sock *sk = (struct sock *)msk;
unsigned int moved = 0;
bool ret, done;
+ /* verify we can move any data from the subflow, eventually updating */
+ if (!(sk->sk_userlocks & SOCK_RCVBUF_LOCK))
+ mptcp_for_each_subflow(msk, subflow)
+ __mptcp_rcvbuf_update(sk, subflow->tcp_sock);
+
+ if (__mptcp_rmem(sk) > sk->sk_rcvbuf)
+ return false;
+
do {
struct sock *ssk = mptcp_subflow_recv_lookup(msk);
bool slowpath;
- /* we can have data pending in the subflows only if the msk
- * receive buffer was full at subflow_data_ready() time,
- * that is an unlikely slow path.
- */
- if (likely(!ssk))
+ if (unlikely(!ssk))
break;
slowpath = lock_sock_fast(ssk);
- mptcp_data_lock(sk);
__mptcp_update_rmem(sk);
done = __mptcp_move_skbs_from_subflow(msk, ssk, &moved);
- mptcp_data_unlock(sk);
if (unlikely(ssk->sk_err))
__mptcp_error_report(sk);
unlock_sock_fast(ssk, slowpath);
} while (!done);
- /* acquire the data lock only if some input data is pending */
ret = moved > 0;
if (!RB_EMPTY_ROOT(&msk->out_of_order_queue) ||
- !skb_queue_empty_lockless(&sk->sk_receive_queue)) {
- mptcp_data_lock(sk);
+ !skb_queue_empty(&sk->sk_receive_queue)) {
__mptcp_update_rmem(sk);
ret |= __mptcp_ofo_queue(msk);
- __mptcp_splice_receive_queue(sk);
- mptcp_data_unlock(sk);
}
if (ret)
mptcp_check_data_fin((struct sock *)msk);
- ret = !skb_queue_empty(&msk->receive_queue);
if (ret && mptcp_epollin_ready(sk))
sk->sk_data_ready(sk);
return ret;
@@ -2273,7 +2264,7 @@ static unsigned int mptcp_inq_hint(const struct sock *sk)
const struct mptcp_sock *msk = mptcp_sk(sk);
const struct sk_buff *skb;
- skb = skb_peek(&msk->receive_queue);
+ skb = skb_peek(&sk->sk_receive_queue);
if (skb) {
u64 hint_val = READ_ONCE(msk->ack_seq) - MPTCP_SKB_CB(skb)->map_seq;
@@ -2319,7 +2310,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
while (copied < len) {
int err, bytes_read;
- bytes_read = __mptcp_recvmsg_mskq(msk, msg, len - copied, flags,
+ bytes_read = __mptcp_recvmsg_mskq(sk, msg, len - copied, flags,
copied, &tss, &cmsg_flags);
if (unlikely(bytes_read < 0)) {
if (!copied)
@@ -2329,7 +2320,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
copied += bytes_read;
- if (skb_queue_empty(&msk->receive_queue) && __mptcp_move_skbs(msk))
+ if (skb_queue_empty(&sk->sk_receive_queue) && __mptcp_move_skbs(sk))
continue;
/* only the MPTCP socket status is relevant here. The exit
@@ -2355,7 +2346,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
/* race breaker: the shutdown could be after the
* previous receive queue check
*/
- if (__mptcp_move_skbs(msk))
+ if (__mptcp_move_skbs(sk))
continue;
break;
}
@@ -2399,9 +2390,8 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
}
}
- pr_debug("msk=%p rx queue empty=%d:%d copied=%d\n",
- msk, skb_queue_empty_lockless(&sk->sk_receive_queue),
- skb_queue_empty(&msk->receive_queue), copied);
+ pr_debug("msk=%p rx queue empty=%d copied=%d\n",
+ msk, skb_queue_empty(&sk->sk_receive_queue), copied);
release_sock(sk);
return copied;
@@ -2982,7 +2972,6 @@ static void __mptcp_init_sock(struct sock *sk)
INIT_LIST_HEAD(&msk->join_list);
INIT_LIST_HEAD(&msk->rtx_queue);
INIT_WORK(&msk->work, mptcp_worker);
- __skb_queue_head_init(&msk->receive_queue);
msk->out_of_order_queue = RB_ROOT;
msk->first_pending = NULL;
WRITE_ONCE(msk->rmem_fwd_alloc, 0);
@@ -3591,12 +3580,8 @@ void mptcp_destroy_common(struct mptcp_sock *msk)
mptcp_for_each_subflow_safe(msk, subflow, tmp)
__mptcp_close_ssk(sk, mptcp_subflow_tcp_sock(subflow), subflow, 0);
- /* move to sk_receive_queue, sk_stream_kill_queues will purge it */
- mptcp_data_lock(sk);
- skb_queue_splice_tail_init(&msk->receive_queue, &sk->sk_receive_queue);
__skb_queue_purge(&sk->sk_receive_queue);
skb_rbtree_purge(&msk->out_of_order_queue);
- mptcp_data_unlock(sk);
/* move all the rx fwd alloc into the sk_mem_reclaim_final in
* inet_sock_destruct() will dispose it
@@ -3645,7 +3630,8 @@ void __mptcp_check_push(struct sock *sk, struct sock *ssk)
#define MPTCP_FLAGS_PROCESS_CTX_NEED (BIT(MPTCP_PUSH_PENDING) | \
BIT(MPTCP_RETRANSMIT) | \
- BIT(MPTCP_FLUSH_JOIN_LIST))
+ BIT(MPTCP_FLUSH_JOIN_LIST) | \
+ BIT(MPTCP_DEQUEUE))
/* processes deferred events and flush wmem */
static void mptcp_release_cb(struct sock *sk)
@@ -3679,6 +3665,11 @@ static void mptcp_release_cb(struct sock *sk)
__mptcp_push_pending(sk, 0);
if (flags & BIT(MPTCP_RETRANSMIT))
__mptcp_retrans(sk);
+ if ((flags & BIT(MPTCP_DEQUEUE)) && __mptcp_move_skbs(sk)) {
+ /* notify ack seq update */
+ mptcp_cleanup_rbuf(msk, 0);
+ sk->sk_data_ready(sk);
+ }
cond_resched();
spin_lock_bh(&sk->sk_lock.slock);
@@ -3923,7 +3914,8 @@ static int mptcp_ioctl(struct sock *sk, int cmd, int *karg)
return -EINVAL;
lock_sock(sk);
- __mptcp_move_skbs(msk);
+ if (__mptcp_move_skbs(sk))
+ mptcp_cleanup_rbuf(msk, 0);
*karg = mptcp_inq_hint(sk);
release_sock(sk);
break;
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index dbfe959d3a18e..2f298250d575c 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -126,6 +126,7 @@
#define MPTCP_FLUSH_JOIN_LIST 5
#define MPTCP_SYNC_STATE 6
#define MPTCP_SYNC_SNDBUF 7
+#define MPTCP_DEQUEUE 8
struct mptcp_skb_cb {
u64 map_seq;
@@ -329,7 +330,6 @@ struct mptcp_sock {
struct work_struct work;
struct sk_buff *ooo_last_skb;
struct rb_root out_of_order_queue;
- struct sk_buff_head receive_queue;
struct list_head conn_list;
struct list_head rtx_queue;
struct mptcp_data_frag *first_pending;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 213/869] mptcp: cleanup mem accounting
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (211 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 212/869] mptcp: move the whole rx path under msk socket lock protection Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 214/869] mptcp: leverage skb deferral free Greg Kroah-Hartman
` (656 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Paolo Abeni, Mat Martineau,
Matthieu Baerts (NGI0), Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <pabeni@redhat.com>
[ Upstream commit 6639498ed85fdb135dfb0dfbcc0f540b2d4ad6a6 ]
After the previous patch, updating sk_forward_memory is cheap and
we can drop a lot of complexity from the MPTCP memory accounting,
removing the custom fwd mem allocations for rmem.
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Reviewed-by: Mat Martineau <martineau@kernel.org>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20250218-net-next-mptcp-rx-path-refactor-v1-4-4a47d90d7998@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 5dd8025a49c2 ("mptcp: fix soft lockup in mptcp_recvmsg()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mptcp/fastopen.c | 2 +-
net/mptcp/protocol.c | 115 +++----------------------------------------
net/mptcp/protocol.h | 4 +-
3 files changed, 10 insertions(+), 111 deletions(-)
diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c
index 40ca9aa21a626..3db79f3a52bac 100644
--- a/net/mptcp/fastopen.c
+++ b/net/mptcp/fastopen.c
@@ -53,7 +53,7 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf
mptcp_data_lock(sk);
DEBUG_NET_WARN_ON_ONCE(sock_owned_by_user_nocheck(sk));
- mptcp_set_owner_r(skb, sk);
+ skb_set_owner_r(skb, sk);
__skb_queue_tail(&sk->sk_receive_queue, skb);
mptcp_sk(sk)->bytes_received += skb->len;
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 6106c561026d6..5e094c72dcbb7 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -141,17 +141,6 @@ static void mptcp_drop(struct sock *sk, struct sk_buff *skb)
__kfree_skb(skb);
}
-static void mptcp_rmem_fwd_alloc_add(struct sock *sk, int size)
-{
- WRITE_ONCE(mptcp_sk(sk)->rmem_fwd_alloc,
- mptcp_sk(sk)->rmem_fwd_alloc + size);
-}
-
-static void mptcp_rmem_charge(struct sock *sk, int size)
-{
- mptcp_rmem_fwd_alloc_add(sk, -size);
-}
-
static bool mptcp_try_coalesce(struct sock *sk, struct sk_buff *to,
struct sk_buff *from)
{
@@ -174,7 +163,7 @@ static bool mptcp_try_coalesce(struct sock *sk, struct sk_buff *to,
* negative one
*/
atomic_add(delta, &sk->sk_rmem_alloc);
- mptcp_rmem_charge(sk, delta);
+ sk_mem_charge(sk, delta);
kfree_skb_partial(from, fragstolen);
return true;
@@ -189,44 +178,6 @@ static bool mptcp_ooo_try_coalesce(struct mptcp_sock *msk, struct sk_buff *to,
return mptcp_try_coalesce((struct sock *)msk, to, from);
}
-static void __mptcp_rmem_reclaim(struct sock *sk, int amount)
-{
- amount >>= PAGE_SHIFT;
- mptcp_rmem_charge(sk, amount << PAGE_SHIFT);
- __sk_mem_reduce_allocated(sk, amount);
-}
-
-static void mptcp_rmem_uncharge(struct sock *sk, int size)
-{
- struct mptcp_sock *msk = mptcp_sk(sk);
- int reclaimable;
-
- mptcp_rmem_fwd_alloc_add(sk, size);
- reclaimable = msk->rmem_fwd_alloc - sk_unused_reserved_mem(sk);
-
- /* see sk_mem_uncharge() for the rationale behind the following schema */
- if (unlikely(reclaimable >= PAGE_SIZE))
- __mptcp_rmem_reclaim(sk, reclaimable);
-}
-
-static void mptcp_rfree(struct sk_buff *skb)
-{
- unsigned int len = skb->truesize;
- struct sock *sk = skb->sk;
-
- atomic_sub(len, &sk->sk_rmem_alloc);
- mptcp_rmem_uncharge(sk, len);
-}
-
-void mptcp_set_owner_r(struct sk_buff *skb, struct sock *sk)
-{
- skb_orphan(skb);
- skb->sk = sk;
- skb->destructor = mptcp_rfree;
- atomic_add(skb->truesize, &sk->sk_rmem_alloc);
- mptcp_rmem_charge(sk, skb->truesize);
-}
-
/* "inspired" by tcp_data_queue_ofo(), main differences:
* - use mptcp seqs
* - don't cope with sacks
@@ -339,25 +290,7 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk, struct sk_buff *skb)
end:
skb_condense(skb);
- mptcp_set_owner_r(skb, sk);
-}
-
-static bool mptcp_rmem_schedule(struct sock *sk, int size)
-{
- struct mptcp_sock *msk = mptcp_sk(sk);
- int amt, amount;
-
- if (size <= msk->rmem_fwd_alloc)
- return true;
-
- size -= msk->rmem_fwd_alloc;
- amt = sk_mem_pages(size);
- amount = amt << PAGE_SHIFT;
- if (!__sk_mem_raise_allocated(sk, size, amt, SK_MEM_RECV))
- return false;
-
- mptcp_rmem_fwd_alloc_add(sk, amount);
- return true;
+ skb_set_owner_r(skb, sk);
}
static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int offset,
@@ -389,7 +322,7 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb)
struct sk_buff *tail;
/* try to fetch required memory from subflow */
- if (!mptcp_rmem_schedule(sk, skb->truesize)) {
+ if (!sk_rmem_schedule(sk, skb, skb->truesize)) {
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED);
mptcp_drop(sk, skb);
return false;
@@ -403,7 +336,7 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb)
if (tail && mptcp_try_coalesce(sk, tail, skb))
return true;
- mptcp_set_owner_r(skb, sk);
+ skb_set_owner_r(skb, sk);
__skb_queue_tail(&sk->sk_receive_queue, skb);
return true;
} else if (after64(MPTCP_SKB_CB(skb)->map_seq, msk->ack_seq)) {
@@ -2087,9 +2020,10 @@ static int __mptcp_recvmsg_mskq(struct sock *sk,
break;
}
- /* we will bulk release the skb memory later */
+ /* avoid the indirect call, we know the destructor is sock_wfree */
skb->destructor = NULL;
- WRITE_ONCE(msk->rmem_released, msk->rmem_released + skb->truesize);
+ atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
+ sk_mem_uncharge(sk, skb->truesize);
__skb_unlink(skb, &sk->sk_receive_queue);
__kfree_skb(skb);
}
@@ -2202,18 +2136,6 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)
msk->rcvq_space.time = mstamp;
}
-static void __mptcp_update_rmem(struct sock *sk)
-{
- struct mptcp_sock *msk = mptcp_sk(sk);
-
- if (!msk->rmem_released)
- return;
-
- atomic_sub(msk->rmem_released, &sk->sk_rmem_alloc);
- mptcp_rmem_uncharge(sk, msk->rmem_released);
- WRITE_ONCE(msk->rmem_released, 0);
-}
-
static bool __mptcp_move_skbs(struct sock *sk)
{
struct mptcp_subflow_context *subflow;
@@ -2237,7 +2159,6 @@ static bool __mptcp_move_skbs(struct sock *sk)
break;
slowpath = lock_sock_fast(ssk);
- __mptcp_update_rmem(sk);
done = __mptcp_move_skbs_from_subflow(msk, ssk, &moved);
if (unlikely(ssk->sk_err))
@@ -2245,12 +2166,7 @@ static bool __mptcp_move_skbs(struct sock *sk)
unlock_sock_fast(ssk, slowpath);
} while (!done);
- ret = moved > 0;
- if (!RB_EMPTY_ROOT(&msk->out_of_order_queue) ||
- !skb_queue_empty(&sk->sk_receive_queue)) {
- __mptcp_update_rmem(sk);
- ret |= __mptcp_ofo_queue(msk);
- }
+ ret = moved > 0 || __mptcp_ofo_queue(msk);
if (ret)
mptcp_check_data_fin((struct sock *)msk);
@@ -2974,8 +2890,6 @@ static void __mptcp_init_sock(struct sock *sk)
INIT_WORK(&msk->work, mptcp_worker);
msk->out_of_order_queue = RB_ROOT;
msk->first_pending = NULL;
- WRITE_ONCE(msk->rmem_fwd_alloc, 0);
- WRITE_ONCE(msk->rmem_released, 0);
msk->timer_ival = TCP_RTO_MIN;
msk->scaling_ratio = TCP_DEFAULT_SCALING_RATIO;
@@ -3205,8 +3119,6 @@ static void __mptcp_destroy_sock(struct sock *sk)
sk->sk_prot->destroy(sk);
- WARN_ON_ONCE(READ_ONCE(msk->rmem_fwd_alloc));
- WARN_ON_ONCE(msk->rmem_released);
sk_stream_kill_queues(sk);
xfrm_sk_free_policy(sk);
@@ -3586,8 +3498,6 @@ void mptcp_destroy_common(struct mptcp_sock *msk)
/* move all the rx fwd alloc into the sk_mem_reclaim_final in
* inet_sock_destruct() will dispose it
*/
- sk_forward_alloc_add(sk, msk->rmem_fwd_alloc);
- WRITE_ONCE(msk->rmem_fwd_alloc, 0);
mptcp_token_destroy(msk);
spin_lock_bh(&msk->pm.lock);
@@ -3689,8 +3599,6 @@ static void mptcp_release_cb(struct sock *sk)
if (__test_and_clear_bit(MPTCP_SYNC_SNDBUF, &msk->cb_flags))
__mptcp_sync_sndbuf(sk);
}
-
- __mptcp_update_rmem(sk);
}
/* MP_JOIN client subflow must wait for 4th ack before sending any data:
@@ -3868,12 +3776,6 @@ static void mptcp_shutdown(struct sock *sk, int how)
__mptcp_wr_shutdown(sk);
}
-static int mptcp_forward_alloc_get(const struct sock *sk)
-{
- return READ_ONCE(sk->sk_forward_alloc) +
- READ_ONCE(mptcp_sk(sk)->rmem_fwd_alloc);
-}
-
static int mptcp_ioctl_outq(const struct mptcp_sock *msk, u64 v)
{
const struct sock *sk = (void *)msk;
@@ -4032,7 +3934,6 @@ static struct proto mptcp_prot = {
.hash = mptcp_hash,
.unhash = mptcp_unhash,
.get_port = mptcp_get_port,
- .forward_alloc_get = mptcp_forward_alloc_get,
.stream_memory_free = mptcp_stream_memory_free,
.sockets_allocated = &mptcp_sockets_allocated,
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 2f298250d575c..f3955c06be671 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -284,7 +284,6 @@ struct mptcp_sock {
u64 rcv_data_fin_seq;
u64 bytes_retrans;
u64 bytes_consumed;
- int rmem_fwd_alloc;
int snd_burst;
int old_wspace;
u64 recovery_snd_nxt; /* in recovery mode accept up to this seq;
@@ -299,7 +298,6 @@ struct mptcp_sock {
u32 last_ack_recv;
unsigned long timer_ival;
u32 token;
- int rmem_released;
unsigned long flags;
unsigned long cb_flags;
bool recovery; /* closing subflow write queue reinjected */
@@ -397,7 +395,7 @@ static inline void msk_owned_by_me(const struct mptcp_sock *msk)
*/
static inline int __mptcp_rmem(const struct sock *sk)
{
- return atomic_read(&sk->sk_rmem_alloc) - READ_ONCE(mptcp_sk(sk)->rmem_released);
+ return atomic_read(&sk->sk_rmem_alloc);
}
static inline int mptcp_win_from_space(const struct sock *sk, int space)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 214/869] mptcp: leverage skb deferral free
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (212 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 213/869] mptcp: cleanup mem accounting Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 215/869] mptcp: add eat_recv_skb helper Greg Kroah-Hartman
` (655 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Geliang Tang, Matthieu Baerts (NGI0),
Paolo Abeni, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <pabeni@redhat.com>
[ Upstream commit 9aa59323f2709370cb4f01acbba599a9167f317b ]
Usage of the skb deferral API is straight-forward; with multiple
subflows actives this allow moving part of the received application
load into multiple CPUs.
Also fix a typo in the related comment.
Reviewed-by: Geliang Tang <geliang@kernel.org>
Tested-by: Geliang Tang <geliang@kernel.org>
Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20250927-net-next-mptcp-rcv-path-imp-v1-1-5da266aa9c1a@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 5dd8025a49c2 ("mptcp: fix soft lockup in mptcp_recvmsg()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mptcp/protocol.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 5e094c72dcbb7..894fbda97f45f 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -2020,12 +2020,13 @@ static int __mptcp_recvmsg_mskq(struct sock *sk,
break;
}
- /* avoid the indirect call, we know the destructor is sock_wfree */
+ /* avoid the indirect call, we know the destructor is sock_rfree */
skb->destructor = NULL;
+ skb->sk = NULL;
atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
sk_mem_uncharge(sk, skb->truesize);
__skb_unlink(skb, &sk->sk_receive_queue);
- __kfree_skb(skb);
+ skb_attempt_defer_free(skb);
}
if (copied >= len)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 215/869] mptcp: add eat_recv_skb helper
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (213 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 214/869] mptcp: leverage skb deferral free Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 216/869] mptcp: fix soft lockup in mptcp_recvmsg() Greg Kroah-Hartman
` (654 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Geliang Tang, Mat Martineau,
Matthieu Baerts (NGI0), Eric Dumazet, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geliang Tang <tanggeliang@kylinos.cn>
[ Upstream commit 436510df0cafb1bc36f12e92e0e76599be28d8f4 ]
This patch extracts the free skb related code in __mptcp_recvmsg_mskq()
into a new helper mptcp_eat_recv_skb().
This new helper will be used in the next patch.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
Reviewed-by: Mat Martineau <martineau@kernel.org>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260130-net-next-mptcp-splice-v2-1-31332ba70d7f@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 5dd8025a49c2 ("mptcp: fix soft lockup in mptcp_recvmsg()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mptcp/protocol.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 894fbda97f45f..21a5991ae0f59 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -1964,6 +1964,17 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied);
+static void mptcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb)
+{
+ /* avoid the indirect call, we know the destructor is sock_rfree */
+ skb->destructor = NULL;
+ skb->sk = NULL;
+ atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
+ sk_mem_uncharge(sk, skb->truesize);
+ __skb_unlink(skb, &sk->sk_receive_queue);
+ skb_attempt_defer_free(skb);
+}
+
static int __mptcp_recvmsg_mskq(struct sock *sk,
struct msghdr *msg,
size_t len, int flags, int copied_total,
@@ -2020,13 +2031,7 @@ static int __mptcp_recvmsg_mskq(struct sock *sk,
break;
}
- /* avoid the indirect call, we know the destructor is sock_rfree */
- skb->destructor = NULL;
- skb->sk = NULL;
- atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
- sk_mem_uncharge(sk, skb->truesize);
- __skb_unlink(skb, &sk->sk_receive_queue);
- skb_attempt_defer_free(skb);
+ mptcp_eat_recv_skb(sk, skb);
}
if (copied >= len)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 216/869] mptcp: fix soft lockup in mptcp_recvmsg()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (214 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 215/869] mptcp: add eat_recv_skb helper Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 217/869] bnxt_en: Update firmware interface spec to 1.10.3.85 Greg Kroah-Hartman
` (653 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Li Xiasong, Matthieu Baerts (NGI0),
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Xiasong <lixiasong1@huawei.com>
[ Upstream commit 5dd8025a49c268ab6b94d978532af3ad341132a7 ]
syzbot reported a soft lockup in mptcp_recvmsg() [0].
When receiving data with MSG_PEEK | MSG_WAITALL flags, the skb is not
removed from the sk_receive_queue. This causes sk_wait_data() to always
find available data and never perform actual waiting, leading to a soft
lockup.
Fix this by adding a 'last' parameter to track the last peeked skb.
This allows sk_wait_data() to make informed waiting decisions and prevent
infinite loops when MSG_PEEK is used.
[0]:
watchdog: BUG: soft lockup - CPU#2 stuck for 156s! [server:1963]
Modules linked in:
CPU: 2 UID: 0 PID: 1963 Comm: server Not tainted 6.19.0-rc8 #61 PREEMPT(none)
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
RIP: 0010:sk_wait_data+0x15/0x190
Code: 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 41 56 41 55 41 54 49 89 f4 55 48 89 d5 53 48 89 fb <48> 83 ec 30 65 48 8b 05 17 a4 6b 01 48 89 44 24 28 31 c0 65 48 8b
RSP: 0018:ffffc90000603ca0 EFLAGS: 00000246
RAX: 0000000000000000 RBX: ffff888102bf0800 RCX: 0000000000000001
RDX: 0000000000000000 RSI: ffffc90000603d18 RDI: ffff888102bf0800
RBP: 0000000000000000 R08: 0000000000000002 R09: 0000000000000101
R10: 0000000000000000 R11: 0000000000000075 R12: ffffc90000603d18
R13: ffff888102bf0800 R14: ffff888102bf0800 R15: 0000000000000000
FS: 00007f6e38b8c4c0(0000) GS:ffff8881b877e000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000055aa7bff1680 CR3: 0000000105cbe000 CR4: 00000000000006f0
Call Trace:
<TASK>
mptcp_recvmsg+0x547/0x8c0 net/mptcp/protocol.c:2329
inet_recvmsg+0x11f/0x130 net/ipv4/af_inet.c:891
sock_recvmsg+0x94/0xc0 net/socket.c:1100
__sys_recvfrom+0xb2/0x130 net/socket.c:2256
__x64_sys_recvfrom+0x1f/0x30 net/socket.c:2267
do_syscall_64+0x59/0x2d0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x76/0x7e arch/x86/entry/entry_64.S:131
RIP: 0033:0x7f6e386a4a1d
Code: 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 8d 05 f1 de 2c 00 41 89 ca 8b 00 85 c0 75 20 45 31 c9 45 31 c0 b8 2d 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 6b f3 c3 66 0f 1f 84 00 00 00 00 00 41 56 41
RSP: 002b:00007ffc3c4bb078 EFLAGS: 00000246 ORIG_RAX: 000000000000002d
RAX: ffffffffffffffda RBX: 000000000000861e RCX: 00007f6e386a4a1d
RDX: 00000000000003ff RSI: 00007ffc3c4bb150 RDI: 0000000000000004
RBP: 00007ffc3c4bb570 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000103 R11: 0000000000000246 R12: 00005605dbc00be0
R13: 00007ffc3c4bb650 R14: 0000000000000000 R15: 0000000000000000
</TASK>
Fixes: 8e04ce45a8db ("mptcp: fix MSG_PEEK stream corruption")
Signed-off-by: Li Xiasong <lixiasong1@huawei.com>
Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20260330120335.659027-1-lixiasong1@huawei.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mptcp/protocol.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 21a5991ae0f59..e1ebf398ba9ec 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -1979,7 +1979,7 @@ static int __mptcp_recvmsg_mskq(struct sock *sk,
struct msghdr *msg,
size_t len, int flags, int copied_total,
struct scm_timestamping_internal *tss,
- int *cmsg_flags)
+ int *cmsg_flags, struct sk_buff **last)
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct sk_buff *skb, *tmp;
@@ -1996,6 +1996,7 @@ static int __mptcp_recvmsg_mskq(struct sock *sk,
/* skip already peeked skbs */
if (total_data_len + data_len <= copied_total) {
total_data_len += data_len;
+ *last = skb;
continue;
}
@@ -2032,6 +2033,8 @@ static int __mptcp_recvmsg_mskq(struct sock *sk,
}
mptcp_eat_recv_skb(sk, skb);
+ } else {
+ *last = skb;
}
if (copied >= len)
@@ -2230,10 +2233,12 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
cmsg_flags = MPTCP_CMSG_INQ;
while (copied < len) {
+ struct sk_buff *last = NULL;
int err, bytes_read;
bytes_read = __mptcp_recvmsg_mskq(sk, msg, len - copied, flags,
- copied, &tss, &cmsg_flags);
+ copied, &tss, &cmsg_flags,
+ &last);
if (unlikely(bytes_read < 0)) {
if (!copied)
copied = bytes_read;
@@ -2291,7 +2296,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
pr_debug("block timeout %ld\n", timeo);
mptcp_cleanup_rbuf(msk, copied);
- err = sk_wait_data(sk, &timeo, NULL);
+ err = sk_wait_data(sk, &timeo, last);
if (err < 0) {
copied = copied ? : err;
goto out_err;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 217/869] bnxt_en: Update firmware interface spec to 1.10.3.85
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (215 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 216/869] mptcp: fix soft lockup in mptcp_recvmsg() Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 218/869] bnxt_en: set backing store type from query type Greg Kroah-Hartman
` (652 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Hongguang Gao, Kalesh AP,
Michael Chan, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Chan <michael.chan@broadcom.com>
[ Upstream commit ff00bcc9ecccf4a1ce3a06eb38a9b4592f870f80 ]
The major change is the new firmware command to flush the FW debug
logs to the host backing store context memory buffers.
Reviewed-by: Hongguang Gao <hongguang.gao@broadcom.com>
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Link: https://patch.msgid.link/20241115151438.550106-2-michael.chan@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 4ee937107d52 ("bnxt_en: set backing store type from query type")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h | 173 ++++++++++++++----
1 file changed, 136 insertions(+), 37 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
index f8ef6f1a1964e..5f8de16343788 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
@@ -42,6 +42,10 @@ struct hwrm_resp_hdr {
#define TLV_TYPE_MODIFY_ROCE_CC_GEN1 0x5UL
#define TLV_TYPE_QUERY_ROCE_CC_GEN2 0x6UL
#define TLV_TYPE_MODIFY_ROCE_CC_GEN2 0x7UL
+#define TLV_TYPE_QUERY_ROCE_CC_GEN1_EXT 0x8UL
+#define TLV_TYPE_MODIFY_ROCE_CC_GEN1_EXT 0x9UL
+#define TLV_TYPE_QUERY_ROCE_CC_GEN2_EXT 0xaUL
+#define TLV_TYPE_MODIFY_ROCE_CC_GEN2_EXT 0xbUL
#define TLV_TYPE_ENGINE_CKV_ALIAS_ECC_PUBLIC_KEY 0x8001UL
#define TLV_TYPE_ENGINE_CKV_IV 0x8003UL
#define TLV_TYPE_ENGINE_CKV_AUTH_TAG 0x8004UL
@@ -509,6 +513,7 @@ struct cmd_nums {
#define HWRM_TFC_IF_TBL_GET 0x399UL
#define HWRM_TFC_TBL_SCOPE_CONFIG_GET 0x39aUL
#define HWRM_TFC_RESC_USAGE_QUERY 0x39bUL
+ #define HWRM_TFC_GLOBAL_ID_FREE 0x39cUL
#define HWRM_SV 0x400UL
#define HWRM_DBG_SERDES_TEST 0xff0eUL
#define HWRM_DBG_LOG_BUFFER_FLUSH 0xff0fUL
@@ -624,8 +629,8 @@ struct hwrm_err_output {
#define HWRM_VERSION_MAJOR 1
#define HWRM_VERSION_MINOR 10
#define HWRM_VERSION_UPDATE 3
-#define HWRM_VERSION_RSVD 68
-#define HWRM_VERSION_STR "1.10.3.68"
+#define HWRM_VERSION_RSVD 85
+#define HWRM_VERSION_STR "1.10.3.85"
/* hwrm_ver_get_input (size:192b/24B) */
struct hwrm_ver_get_input {
@@ -1302,6 +1307,43 @@ struct hwrm_async_event_cmpl_error_report {
#define ASYNC_EVENT_CMPL_ERROR_REPORT_EVENT_DATA1_ERROR_TYPE_SFT 0
};
+/* hwrm_async_event_cmpl_dbg_buf_producer (size:128b/16B) */
+struct hwrm_async_event_cmpl_dbg_buf_producer {
+ __le16 type;
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_MASK 0x3fUL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_HWRM_ASYNC_EVENT 0x2eUL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_LAST ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_HWRM_ASYNC_EVENT
+ __le16 event_id;
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_ID_DBG_BUF_PRODUCER 0x4cUL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_ID_LAST ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_ID_DBG_BUF_PRODUCER
+ __le32 event_data2;
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURR_OFF_MASK 0xffffffffUL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURR_OFF_SFT 0
+ u8 opaque_v;
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_V 0x1UL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_OPAQUE_MASK 0xfeUL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_OPAQUE_SFT 1
+ u8 timestamp_lo;
+ __le16 timestamp_hi;
+ __le32 event_data1;
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_MASK 0xffffUL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_SRT_TRACE 0x0UL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_SRT2_TRACE 0x1UL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CRT_TRACE 0x2UL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CRT2_TRACE 0x3UL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_RIGP0_TRACE 0x4UL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_L2_HWRM_TRACE 0x5UL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_ROCE_HWRM_TRACE 0x6UL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CA0_TRACE 0x7UL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CA1_TRACE 0x8UL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CA2_TRACE 0x9UL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_RIGP1_TRACE 0xaUL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_AFM_KONG_HWRM_TRACE 0xbUL
+ #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_LAST ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_AFM_KONG_HWRM_TRACE
+};
+
/* hwrm_async_event_cmpl_hwrm_error (size:128b/16B) */
struct hwrm_async_event_cmpl_hwrm_error {
__le16 type;
@@ -1864,7 +1906,10 @@ struct hwrm_func_qcaps_output {
__le32 roce_vf_max_gid;
__le32 flags_ext3;
#define FUNC_QCAPS_RESP_FLAGS_EXT3_RM_RSV_WHILE_ALLOC_CAP 0x1UL
- u8 unused_3[7];
+ #define FUNC_QCAPS_RESP_FLAGS_EXT3_REQUIRE_L2_FILTER 0x2UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT3_MAX_ROCE_VFS_SUPPORTED 0x4UL
+ __le16 max_roce_vfs;
+ u8 unused_3[5];
u8 valid;
};
@@ -2253,17 +2298,18 @@ struct hwrm_func_cfg_input {
#define FUNC_CFG_REQ_FLAGS2_KTLS_KEY_CTX_ASSETS_TEST 0x1UL
#define FUNC_CFG_REQ_FLAGS2_QUIC_KEY_CTX_ASSETS_TEST 0x2UL
__le32 enables2;
- #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL
- #define FUNC_CFG_REQ_ENABLES2_DB_PAGE_SIZE 0x2UL
- #define FUNC_CFG_REQ_ENABLES2_QUIC_TX_KEY_CTXS 0x4UL
- #define FUNC_CFG_REQ_ENABLES2_QUIC_RX_KEY_CTXS 0x8UL
- #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_AV_PER_VF 0x10UL
- #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_CQ_PER_VF 0x20UL
- #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_MRW_PER_VF 0x40UL
- #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_QP_PER_VF 0x80UL
- #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_SRQ_PER_VF 0x100UL
- #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_GID_PER_VF 0x200UL
- #define FUNC_CFG_REQ_ENABLES2_XID_PARTITION_CFG 0x400UL
+ #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL
+ #define FUNC_CFG_REQ_ENABLES2_DB_PAGE_SIZE 0x2UL
+ #define FUNC_CFG_REQ_ENABLES2_QUIC_TX_KEY_CTXS 0x4UL
+ #define FUNC_CFG_REQ_ENABLES2_QUIC_RX_KEY_CTXS 0x8UL
+ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_AV_PER_VF 0x10UL
+ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_CQ_PER_VF 0x20UL
+ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_MRW_PER_VF 0x40UL
+ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_QP_PER_VF 0x80UL
+ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_SRQ_PER_VF 0x100UL
+ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_GID_PER_VF 0x200UL
+ #define FUNC_CFG_REQ_ENABLES2_XID_PARTITION_CFG 0x400UL
+ #define FUNC_CFG_REQ_ENABLES2_PHYSICAL_SLOT_NUMBER 0x800UL
u8 port_kdnet_mode;
#define FUNC_CFG_REQ_PORT_KDNET_MODE_DISABLED 0x0UL
#define FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED 0x1UL
@@ -2281,7 +2327,7 @@ struct hwrm_func_cfg_input {
#define FUNC_CFG_REQ_DB_PAGE_SIZE_2MB 0x9UL
#define FUNC_CFG_REQ_DB_PAGE_SIZE_4MB 0xaUL
#define FUNC_CFG_REQ_DB_PAGE_SIZE_LAST FUNC_CFG_REQ_DB_PAGE_SIZE_4MB
- u8 unused_1[2];
+ __le16 physical_slot_number;
__le32 num_ktls_tx_key_ctxs;
__le32 num_ktls_rx_key_ctxs;
__le32 num_quic_tx_key_ctxs;
@@ -3683,7 +3729,7 @@ struct hwrm_func_ptp_ext_qcfg_output {
u8 valid;
};
-/* hwrm_func_backing_store_cfg_v2_input (size:448b/56B) */
+/* hwrm_func_backing_store_cfg_v2_input (size:512b/64B) */
struct hwrm_func_backing_store_cfg_v2_input {
__le16 req_type;
__le16 cmpl_ring;
@@ -3721,6 +3767,7 @@ struct hwrm_func_backing_store_cfg_v2_input {
#define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_CA1_TRACE 0x27UL
#define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_CA2_TRACE 0x28UL
#define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_RIGP1_TRACE 0x29UL
+ #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL
#define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_INVALID 0xffffUL
#define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_INVALID
__le16 instance;
@@ -3752,6 +3799,9 @@ struct hwrm_func_backing_store_cfg_v2_input {
__le32 split_entry_1;
__le32 split_entry_2;
__le32 split_entry_3;
+ __le32 enables;
+ #define FUNC_BACKING_STORE_CFG_V2_REQ_ENABLES_NEXT_BS_OFFSET 0x1UL
+ __le32 next_bs_offset;
};
/* hwrm_func_backing_store_cfg_v2_output (size:128b/16B) */
@@ -3802,6 +3852,7 @@ struct hwrm_func_backing_store_qcfg_v2_input {
#define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CA1_TRACE 0x27UL
#define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CA2_TRACE 0x28UL
#define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_RIGP1_TRACE 0x29UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL
#define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID 0xffffUL
#define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID
__le16 instance;
@@ -3963,6 +4014,7 @@ struct hwrm_func_backing_store_qcaps_v2_input {
#define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA1_TRACE 0x27UL
#define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA2_TRACE 0x28UL
#define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RIGP1_TRACE 0x29UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL
#define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_INVALID 0xffffUL
#define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_INVALID
u8 rsvd[6];
@@ -4005,6 +4057,7 @@ struct hwrm_func_backing_store_qcaps_v2_output {
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_CA1_TRACE 0x27UL
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_CA2_TRACE 0x28UL
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_RIGP1_TRACE 0x29UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_INVALID 0xffffUL
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_LAST FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_INVALID
__le16 entry_size;
@@ -4014,6 +4067,8 @@ struct hwrm_func_backing_store_qcaps_v2_output {
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_DRIVER_MANAGED_MEMORY 0x4UL
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_ROCE_QP_PSEUDO_STATIC_ALLOC 0x8UL
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_FW_DBG_TRACE 0x10UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_FW_BIN_DBG_TRACE 0x20UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_NEXT_BS_OFFSET 0x40UL
__le32 instance_bit_map;
u8 ctx_init_value;
u8 ctx_init_offset;
@@ -4034,7 +4089,8 @@ struct hwrm_func_backing_store_qcaps_v2_output {
__le32 split_entry_1;
__le32 split_entry_2;
__le32 split_entry_3;
- u8 rsvd3[3];
+ __le16 max_instance_count;
+ u8 rsvd3;
u8 valid;
};
@@ -4535,11 +4591,12 @@ struct hwrm_port_phy_qcfg_output {
#define PORT_PHY_QCFG_RESP_PHY_TYPE_800G_BASEDR8 0x3dUL
#define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_800G_BASEDR8
u8 media_type;
- #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_UNKNOWN 0x0UL
- #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP 0x1UL
- #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC 0x2UL
- #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE 0x3UL
- #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_LAST PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE
+ #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_UNKNOWN 0x0UL
+ #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP 0x1UL
+ #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC 0x2UL
+ #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE 0x3UL
+ #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_BACKPLANE 0x4UL
+ #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_LAST PORT_PHY_QCFG_RESP_MEDIA_TYPE_BACKPLANE
u8 xcvr_pkg_type;
#define PORT_PHY_QCFG_RESP_XCVR_PKG_TYPE_XCVR_INTERNAL 0x1UL
#define PORT_PHY_QCFG_RESP_XCVR_PKG_TYPE_XCVR_EXTERNAL 0x2UL
@@ -4654,7 +4711,8 @@ struct hwrm_port_phy_qcfg_output {
#define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_100GB 0x2UL
#define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_200GB 0x4UL
u8 link_down_reason;
- #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF 0x1UL
+ #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF 0x1UL
+ #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_OTP_SPEED_VIOLATION 0x2UL
__le16 support_speeds2;
#define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_1GB 0x1UL
#define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_10GB 0x2UL
@@ -9241,20 +9299,22 @@ struct hwrm_fw_set_time_output {
/* hwrm_struct_hdr (size:128b/16B) */
struct hwrm_struct_hdr {
__le16 struct_id;
- #define STRUCT_HDR_STRUCT_ID_LLDP_CFG 0x41bUL
- #define STRUCT_HDR_STRUCT_ID_DCBX_ETS 0x41dUL
- #define STRUCT_HDR_STRUCT_ID_DCBX_PFC 0x41fUL
- #define STRUCT_HDR_STRUCT_ID_DCBX_APP 0x421UL
- #define STRUCT_HDR_STRUCT_ID_DCBX_FEATURE_STATE 0x422UL
- #define STRUCT_HDR_STRUCT_ID_LLDP_GENERIC 0x424UL
- #define STRUCT_HDR_STRUCT_ID_LLDP_DEVICE 0x426UL
- #define STRUCT_HDR_STRUCT_ID_POWER_BKUP 0x427UL
- #define STRUCT_HDR_STRUCT_ID_PEER_MMAP 0x429UL
- #define STRUCT_HDR_STRUCT_ID_AFM_OPAQUE 0x1UL
- #define STRUCT_HDR_STRUCT_ID_PORT_DESCRIPTION 0xaUL
- #define STRUCT_HDR_STRUCT_ID_RSS_V2 0x64UL
- #define STRUCT_HDR_STRUCT_ID_MSIX_PER_VF 0xc8UL
- #define STRUCT_HDR_STRUCT_ID_LAST STRUCT_HDR_STRUCT_ID_MSIX_PER_VF
+ #define STRUCT_HDR_STRUCT_ID_LLDP_CFG 0x41bUL
+ #define STRUCT_HDR_STRUCT_ID_DCBX_ETS 0x41dUL
+ #define STRUCT_HDR_STRUCT_ID_DCBX_PFC 0x41fUL
+ #define STRUCT_HDR_STRUCT_ID_DCBX_APP 0x421UL
+ #define STRUCT_HDR_STRUCT_ID_DCBX_FEATURE_STATE 0x422UL
+ #define STRUCT_HDR_STRUCT_ID_LLDP_GENERIC 0x424UL
+ #define STRUCT_HDR_STRUCT_ID_LLDP_DEVICE 0x426UL
+ #define STRUCT_HDR_STRUCT_ID_POWER_BKUP 0x427UL
+ #define STRUCT_HDR_STRUCT_ID_PEER_MMAP 0x429UL
+ #define STRUCT_HDR_STRUCT_ID_AFM_OPAQUE 0x1UL
+ #define STRUCT_HDR_STRUCT_ID_PORT_DESCRIPTION 0xaUL
+ #define STRUCT_HDR_STRUCT_ID_RSS_V2 0x64UL
+ #define STRUCT_HDR_STRUCT_ID_MSIX_PER_VF 0xc8UL
+ #define STRUCT_HDR_STRUCT_ID_UDCC_RTT_BUCKET_COUNT 0x12cUL
+ #define STRUCT_HDR_STRUCT_ID_UDCC_RTT_BUCKET_BOUND 0x12dUL
+ #define STRUCT_HDR_STRUCT_ID_LAST STRUCT_HDR_STRUCT_ID_UDCC_RTT_BUCKET_BOUND
__le16 len;
u8 version;
u8 count;
@@ -9756,6 +9816,7 @@ struct hwrm_dbg_qcaps_output {
#define DBG_QCAPS_RESP_FLAGS_COREDUMP_HOST_DDR 0x10UL
#define DBG_QCAPS_RESP_FLAGS_COREDUMP_HOST_CAPTURE 0x20UL
#define DBG_QCAPS_RESP_FLAGS_PTRACE 0x40UL
+ #define DBG_QCAPS_RESP_FLAGS_REG_ACCESS_RESTRICTED 0x80UL
u8 unused_1[3];
u8 valid;
};
@@ -9996,6 +10057,43 @@ struct hwrm_dbg_ring_info_get_output {
u8 valid;
};
+/* hwrm_dbg_log_buffer_flush_input (size:192b/24B) */
+struct hwrm_dbg_log_buffer_flush_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le16 type;
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_SRT_TRACE 0x0UL
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_SRT2_TRACE 0x1UL
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CRT_TRACE 0x2UL
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CRT2_TRACE 0x3UL
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_RIGP0_TRACE 0x4UL
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_L2_HWRM_TRACE 0x5UL
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_ROCE_HWRM_TRACE 0x6UL
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA0_TRACE 0x7UL
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA1_TRACE 0x8UL
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA2_TRACE 0x9UL
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_RIGP1_TRACE 0xaUL
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_AFM_KONG_HWRM_TRACE 0xbUL
+ #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_LAST DBG_LOG_BUFFER_FLUSH_REQ_TYPE_AFM_KONG_HWRM_TRACE
+ u8 unused_1[2];
+ __le32 flags;
+ #define DBG_LOG_BUFFER_FLUSH_REQ_FLAGS_FLUSH_ALL_BUFFERS 0x1UL
+};
+
+/* hwrm_dbg_log_buffer_flush_output (size:128b/16B) */
+struct hwrm_dbg_log_buffer_flush_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ __le32 current_buffer_offset;
+ u8 unused_1[3];
+ u8 valid;
+};
+
/* hwrm_nvm_read_input (size:320b/40B) */
struct hwrm_nvm_read_input {
__le16 req_type;
@@ -10080,6 +10178,7 @@ struct hwrm_nvm_write_input {
#define NVM_WRITE_REQ_FLAGS_KEEP_ORIG_ACTIVE_IMG 0x1UL
#define NVM_WRITE_REQ_FLAGS_BATCH_MODE 0x2UL
#define NVM_WRITE_REQ_FLAGS_BATCH_LAST 0x4UL
+ #define NVM_WRITE_REQ_FLAGS_SKIP_CRID_CHECK 0x8UL
__le32 dir_item_length;
__le32 offset;
__le32 len;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 218/869] bnxt_en: set backing store type from query type
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (216 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 217/869] bnxt_en: Update firmware interface spec to 1.10.3.85 Greg Kroah-Hartman
@ 2026-10-17 15:50 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 219/869] mpls: Hold dev refcnt for mpls_nh Greg Kroah-Hartman
` (651 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:50 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pengpeng Hou, Michael Chan,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <pengpeng@iscas.ac.cn>
[ Upstream commit 4ee937107d52f9e5c350e4b5e629760e328b3d9f ]
bnxt_hwrm_func_backing_store_qcaps_v2() stores resp->type from the
firmware response in ctxm->type and later uses that value to index
fixed backing-store metadata arrays such as ctx_arr[] and
bnxt_bstore_to_trace[].
ctxm->type is fixed by the current backing-store query type and matches
the array index of ctx->ctx_arr. Set ctxm->type from the current loop
variable instead of depending on resp->type.
Also update the loop to advance type from next_valid_type in the for
statement, which keeps the control flow simpler for non-valid and
unchanged entries.
Fixes: 6a4d0774f02d ("bnxt_en: Add support for new backing store query firmware API")
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Reviewed-by: Michael Chan <michael.chan@broadcom.com>
Tested-by: Michael Chan <michael.chan@broadcom.com>
Link: https://patch.msgid.link/20260328234357.43669-1-pengpeng@iscas.ac.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index ef2462e94b3f7..867be7b4142b2 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -8379,7 +8379,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
struct hwrm_func_backing_store_qcaps_v2_output *resp;
struct hwrm_func_backing_store_qcaps_v2_input *req;
struct bnxt_ctx_mem_info *ctx = bp->ctx;
- u16 type;
+ u16 type, next_type = 0;
int rc;
rc = hwrm_req_init(bp, req, HWRM_FUNC_BACKING_STORE_QCAPS_V2);
@@ -8395,7 +8395,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
resp = hwrm_req_hold(bp, req);
- for (type = 0; type < BNXT_CTX_V2_MAX; ) {
+ for (type = 0; type < BNXT_CTX_V2_MAX; type = next_type) {
struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
u8 init_val, init_off, i;
__le32 *p;
@@ -8406,11 +8406,11 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
if (rc)
goto ctx_done;
flags = le32_to_cpu(resp->flags);
- type = le16_to_cpu(resp->next_valid_type);
+ next_type = le16_to_cpu(resp->next_valid_type);
if (!(flags & FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_TYPE_VALID))
continue;
- ctxm->type = le16_to_cpu(resp->type);
+ ctxm->type = type;
ctxm->entry_size = le16_to_cpu(resp->entry_size);
ctxm->flags = flags;
ctxm->instance_bmap = le32_to_cpu(resp->instance_bit_map);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 219/869] mpls: Hold dev refcnt for mpls_nh.
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (217 preceding siblings ...)
2026-10-17 15:50 ` [PATCH 6.12 218/869] bnxt_en: set backing store type from query type Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 220/869] mpls: Unify return paths in mpls_dev_notify() Greg Kroah-Hartman
` (650 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kuniyuki Iwashima, Guillaume Nault,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit f0914b8436c589b7ab32c614d8d7868eb4ebd5bf ]
MPLS uses RTNL
1) to guarantee the lifetime of struct mpls_nh.nh_dev
2) to protect net->mpls.platform_label
, but neither actually requires RTNL.
If we do not call dev_put() in find_outdev() and call it
just before freeing struct mpls_route, we can drop RTNL for 1).
Let's hold the refcnt of mpls_nh.nh_dev and track it with
netdevice_tracker.
Two notable changes:
If mpls_nh_build_multi() fails to set up a neighbour, we need
to call netdev_put() for successfully created neighbours in
mpls_rt_free_rcu(), so the number of neighbours (rt->rt_nhn)
is now updated in each iteration.
When a dev is unregistered, mpls_ifdown() clones mpls_route
and replaces it with the clone, so the clone requires extra
netdev_hold().
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Guillaume Nault <gnault@redhat.com>
Link: https://patch.msgid.link/20251029173344.2934622-3-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 629ec78ef860 ("mpls: add seqcount to protect the platform_label{,s} pair")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mpls/af_mpls.c | 63 +++++++++++++++++++++++++++++++--------------
net/mpls/internal.h | 1 +
2 files changed, 45 insertions(+), 19 deletions(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 82909a59d410f..7e38c71f7212c 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -532,10 +532,23 @@ static struct mpls_route *mpls_rt_alloc(u8 num_nh, u8 max_alen, u8 max_labels)
return rt;
}
+static void mpls_rt_free_rcu(struct rcu_head *head)
+{
+ struct mpls_route *rt;
+
+ rt = container_of(head, struct mpls_route, rt_rcu);
+
+ change_nexthops(rt) {
+ netdev_put(nh->nh_dev, &nh->nh_dev_tracker);
+ } endfor_nexthops(rt);
+
+ kfree(rt);
+}
+
static void mpls_rt_free(struct mpls_route *rt)
{
if (rt)
- kfree_rcu(rt, rt_rcu);
+ call_rcu(&rt->rt_rcu, mpls_rt_free_rcu);
}
static void mpls_notify_route(struct net *net, unsigned index,
@@ -589,6 +602,7 @@ static unsigned find_free_label(struct net *net)
#if IS_ENABLED(CONFIG_INET)
static struct net_device *inet_fib_lookup_dev(struct net *net,
+ struct mpls_nh *nh,
const void *addr)
{
struct net_device *dev;
@@ -601,14 +615,14 @@ static struct net_device *inet_fib_lookup_dev(struct net *net,
return ERR_CAST(rt);
dev = rt->dst.dev;
- dev_hold(dev);
-
+ netdev_hold(dev, &nh->nh_dev_tracker, GFP_KERNEL);
ip_rt_put(rt);
return dev;
}
#else
static struct net_device *inet_fib_lookup_dev(struct net *net,
+ struct mpls_nh *nh,
const void *addr)
{
return ERR_PTR(-EAFNOSUPPORT);
@@ -617,6 +631,7 @@ static struct net_device *inet_fib_lookup_dev(struct net *net,
#if IS_ENABLED(CONFIG_IPV6)
static struct net_device *inet6_fib_lookup_dev(struct net *net,
+ struct mpls_nh *nh,
const void *addr)
{
struct net_device *dev;
@@ -633,13 +648,14 @@ static struct net_device *inet6_fib_lookup_dev(struct net *net,
return ERR_CAST(dst);
dev = dst->dev;
- dev_hold(dev);
+ netdev_hold(dev, &nh->nh_dev_tracker, GFP_KERNEL);
dst_release(dst);
return dev;
}
#else
static struct net_device *inet6_fib_lookup_dev(struct net *net,
+ struct mpls_nh *nh,
const void *addr)
{
return ERR_PTR(-EAFNOSUPPORT);
@@ -655,16 +671,17 @@ static struct net_device *find_outdev(struct net *net,
if (!oif) {
switch (nh->nh_via_table) {
case NEIGH_ARP_TABLE:
- dev = inet_fib_lookup_dev(net, mpls_nh_via(rt, nh));
+ dev = inet_fib_lookup_dev(net, nh, mpls_nh_via(rt, nh));
break;
case NEIGH_ND_TABLE:
- dev = inet6_fib_lookup_dev(net, mpls_nh_via(rt, nh));
+ dev = inet6_fib_lookup_dev(net, nh, mpls_nh_via(rt, nh));
break;
case NEIGH_LINK_TABLE:
break;
}
} else {
- dev = dev_get_by_index(net, oif);
+ dev = netdev_get_by_index(net, oif,
+ &nh->nh_dev_tracker, GFP_KERNEL);
}
if (!dev)
@@ -673,8 +690,7 @@ static struct net_device *find_outdev(struct net *net,
if (IS_ERR(dev))
return dev;
- /* The caller is holding rtnl anyways, so release the dev reference */
- dev_put(dev);
+ nh->nh_dev = dev;
return dev;
}
@@ -688,20 +704,17 @@ static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,
dev = find_outdev(net, rt, nh, oif);
if (IS_ERR(dev)) {
err = PTR_ERR(dev);
- dev = NULL;
goto errout;
}
/* Ensure this is a supported device */
err = -EINVAL;
if (!mpls_dev_get(dev))
- goto errout;
+ goto errout_put;
if ((nh->nh_via_table == NEIGH_LINK_TABLE) &&
(dev->addr_len != nh->nh_via_alen))
- goto errout;
-
- nh->nh_dev = dev;
+ goto errout_put;
if (!(dev->flags & IFF_UP)) {
nh->nh_flags |= RTNH_F_DEAD;
@@ -715,6 +728,9 @@ static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,
return 0;
+errout_put:
+ netdev_put(nh->nh_dev, &nh->nh_dev_tracker);
+ nh->nh_dev = NULL;
errout:
return err;
}
@@ -892,7 +908,8 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
struct nlattr *nla_via, *nla_newdst;
int remaining = cfg->rc_mp_len;
int err = 0;
- u8 nhs = 0;
+
+ rt->rt_nhn = 0;
change_nexthops(rt) {
int attrlen;
@@ -928,11 +945,9 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
rt->rt_nhn_alive--;
rtnh = rtnh_next(rtnh, &remaining);
- nhs++;
+ rt->rt_nhn++;
} endfor_nexthops(rt);
- rt->rt_nhn = nhs;
-
return 0;
errout:
@@ -1526,8 +1541,12 @@ static int mpls_ifdown(struct net_device *dev, int event)
change_nexthops(rt) {
unsigned int nh_flags = nh->nh_flags;
- if (nh->nh_dev != dev)
+ if (nh->nh_dev != dev) {
+ if (nh_del)
+ netdev_hold(nh->nh_dev, &nh->nh_dev_tracker,
+ GFP_KERNEL);
goto next;
+ }
switch (event) {
case NETDEV_DOWN:
@@ -2525,10 +2544,13 @@ static int resize_platform_label_table(struct net *net, size_t limit)
/* In case the predefined labels need to be populated */
if (limit > MPLS_LABEL_IPV4NULL) {
struct net_device *lo = net->loopback_dev;
+
rt0 = mpls_rt_alloc(1, lo->addr_len, 0);
if (IS_ERR(rt0))
goto nort0;
+
rt0->rt_nh->nh_dev = lo;
+ netdev_hold(lo, &rt0->rt_nh->nh_dev_tracker, GFP_KERNEL);
rt0->rt_protocol = RTPROT_KERNEL;
rt0->rt_payload_type = MPT_IPV4;
rt0->rt_ttl_propagate = MPLS_TTL_PROP_DEFAULT;
@@ -2539,10 +2561,13 @@ static int resize_platform_label_table(struct net *net, size_t limit)
}
if (limit > MPLS_LABEL_IPV6NULL) {
struct net_device *lo = net->loopback_dev;
+
rt2 = mpls_rt_alloc(1, lo->addr_len, 0);
if (IS_ERR(rt2))
goto nort2;
+
rt2->rt_nh->nh_dev = lo;
+ netdev_hold(lo, &rt2->rt_nh->nh_dev_tracker, GFP_KERNEL);
rt2->rt_protocol = RTPROT_KERNEL;
rt2->rt_payload_type = MPT_IPV6;
rt2->rt_ttl_propagate = MPLS_TTL_PROP_DEFAULT;
diff --git a/net/mpls/internal.h b/net/mpls/internal.h
index b9f492ddf93be..76a133cb8efe7 100644
--- a/net/mpls/internal.h
+++ b/net/mpls/internal.h
@@ -88,6 +88,7 @@ enum mpls_payload_type {
struct mpls_nh { /* next hop label forwarding entry */
struct net_device *nh_dev;
+ netdevice_tracker nh_dev_tracker;
/* nh_flags is accessed under RCU in the packet path; it is
* modified handling netdev events with rtnl lock held
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 220/869] mpls: Unify return paths in mpls_dev_notify().
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (218 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 219/869] mpls: Hold dev refcnt for mpls_nh Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 221/869] mpls: Add mpls_dev_rcu() Greg Kroah-Hartman
` (649 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kuniyuki Iwashima, Guillaume Nault,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit 451c538ec067e84c1bf1c2b99ebc2b1ca0a09090 ]
We will protect net->mpls.platform_label by a dedicated mutex.
Then, we need to wrap functions called from mpls_dev_notify()
with the mutex.
As a prep, let's unify the return paths.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Guillaume Nault <gnault@redhat.com>
Link: https://patch.msgid.link/20251029173344.2934622-4-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 629ec78ef860 ("mpls: add seqcount to protect the platform_label{,s} pair")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mpls/af_mpls.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 7e38c71f7212c..65fc18eaf4171 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -1619,22 +1619,24 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
if (event == NETDEV_REGISTER) {
mdev = mpls_add_dev(dev);
- if (IS_ERR(mdev))
- return notifier_from_errno(PTR_ERR(mdev));
+ if (IS_ERR(mdev)) {
+ err = PTR_ERR(mdev);
+ goto err;
+ }
- return NOTIFY_OK;
+ goto out;
}
mdev = mpls_dev_get(dev);
if (!mdev)
- return NOTIFY_OK;
+ goto out;
switch (event) {
case NETDEV_DOWN:
err = mpls_ifdown(dev, event);
if (err)
- return notifier_from_errno(err);
+ goto err;
break;
case NETDEV_UP:
flags = dev_get_flags(dev);
@@ -1650,13 +1652,14 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
} else {
err = mpls_ifdown(dev, event);
if (err)
- return notifier_from_errno(err);
+ goto err;
}
break;
case NETDEV_UNREGISTER:
err = mpls_ifdown(dev, event);
if (err)
- return notifier_from_errno(err);
+ goto err;
+
mdev = mpls_dev_get(dev);
if (mdev) {
mpls_dev_sysctl_unregister(dev, mdev);
@@ -1670,11 +1673,16 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
mpls_dev_sysctl_unregister(dev, mdev);
err = mpls_dev_sysctl_register(dev, mdev);
if (err)
- return notifier_from_errno(err);
+ goto err;
}
break;
}
+
+out:
return NOTIFY_OK;
+
+err:
+ return notifier_from_errno(err);
}
static struct notifier_block mpls_dev_notifier = {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 221/869] mpls: Add mpls_dev_rcu().
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (219 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 220/869] mpls: Unify return paths in mpls_dev_notify() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 222/869] mpls: Pass net to mpls_dev_get() Greg Kroah-Hartman
` (648 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kuniyuki Iwashima, Guillaume Nault,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit ab061f3347923b6e3aa7731056dc58cbe5044c9f ]
mpls_dev_get() uses rcu_dereference_rtnl() to fetch dev->mpls_ptr.
We will replace RTNL with a dedicated mutex to protect the field.
Then, we will use rcu_dereference_protected() for clarity.
Let's add mpls_dev_rcu() for the RCU reader.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Guillaume Nault <gnault@redhat.com>
Link: https://patch.msgid.link/20251029173344.2934622-7-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 629ec78ef860 ("mpls: add seqcount to protect the platform_label{,s} pair")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mpls/af_mpls.c | 12 ++++++------
net/mpls/internal.h | 5 +++++
net/mpls/mpls_iptunnel.c | 2 +-
3 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 65fc18eaf4171..7e1b0d08c0c20 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -135,7 +135,7 @@ void mpls_stats_inc_outucastpkts(struct net_device *dev,
struct mpls_dev *mdev;
if (skb->protocol == htons(ETH_P_MPLS_UC)) {
- mdev = mpls_dev_get(dev);
+ mdev = mpls_dev_rcu(dev);
if (mdev)
MPLS_INC_STATS_LEN(mdev, skb->len,
tx_packets,
@@ -359,7 +359,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
/* Careful this entire function runs inside of an rcu critical section */
- mdev = mpls_dev_get(dev);
+ mdev = mpls_dev_rcu(dev);
if (!mdev)
goto drop;
@@ -468,7 +468,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
return 0;
tx_err:
- out_mdev = out_dev ? mpls_dev_get(out_dev) : NULL;
+ out_mdev = out_dev ? mpls_dev_rcu(out_dev) : NULL;
if (out_mdev)
MPLS_INC_STATS(out_mdev, tx_errors);
goto drop;
@@ -1120,7 +1120,7 @@ static int mpls_fill_stats_af(struct sk_buff *skb,
struct mpls_dev *mdev;
struct nlattr *nla;
- mdev = mpls_dev_get(dev);
+ mdev = mpls_dev_rcu(dev);
if (!mdev)
return -ENODATA;
@@ -1140,7 +1140,7 @@ static size_t mpls_get_stats_af_size(const struct net_device *dev)
{
struct mpls_dev *mdev;
- mdev = mpls_dev_get(dev);
+ mdev = mpls_dev_rcu(dev);
if (!mdev)
return 0;
@@ -1343,7 +1343,7 @@ static int mpls_netconf_dump_devconf(struct sk_buff *skb,
rcu_read_lock();
for_each_netdev_dump(net, dev, ctx->ifindex) {
- mdev = mpls_dev_get(dev);
+ mdev = mpls_dev_rcu(dev);
if (!mdev)
continue;
err = mpls_netconf_fill_devconf(skb, mdev,
diff --git a/net/mpls/internal.h b/net/mpls/internal.h
index 76a133cb8efe7..9adbbdeb8f848 100644
--- a/net/mpls/internal.h
+++ b/net/mpls/internal.h
@@ -185,6 +185,11 @@ static inline struct mpls_entry_decoded mpls_entry_decode(struct mpls_shim_hdr *
return result;
}
+static inline struct mpls_dev *mpls_dev_rcu(const struct net_device *dev)
+{
+ return rcu_dereference(dev->mpls_ptr);
+}
+
static inline struct mpls_dev *mpls_dev_get(const struct net_device *dev)
{
return rcu_dereference_rtnl(dev->mpls_ptr);
diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c
index 6e73da94af7fb..33872b4b90070 100644
--- a/net/mpls/mpls_iptunnel.c
+++ b/net/mpls/mpls_iptunnel.c
@@ -153,7 +153,7 @@ static int mpls_xmit(struct sk_buff *skb)
return LWTUNNEL_XMIT_DONE;
drop:
- out_mdev = out_dev ? mpls_dev_get(out_dev) : NULL;
+ out_mdev = out_dev ? mpls_dev_rcu(out_dev) : NULL;
if (out_mdev)
MPLS_INC_STATS(out_mdev, tx_errors);
kfree_skb(skb);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 222/869] mpls: Pass net to mpls_dev_get().
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (220 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 221/869] mpls: Add mpls_dev_rcu() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 223/869] mpls: Add mpls_route_input() Greg Kroah-Hartman
` (647 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kuniyuki Iwashima, Guillaume Nault,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit 1fb462de9329731c17267c7ccf19619f22790a0a ]
We will replace RTNL with a per-netns mutex to protect dev->mpls_ptr.
Then, we will use rcu_dereference_protected() with the lockdep_is_held()
annotation, which requires net to access the per-netns mutex.
However, dev_net(dev) is not safe without RTNL.
Let's pass net to mpls_dev_get().
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Guillaume Nault <gnault@redhat.com>
Link: https://patch.msgid.link/20251029173344.2934622-8-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 629ec78ef860 ("mpls: add seqcount to protect the platform_label{,s} pair")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mpls/af_mpls.c | 11 ++++++-----
net/mpls/internal.h | 3 ++-
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 7e1b0d08c0c20..7181af81e4290 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -709,7 +709,7 @@ static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,
/* Ensure this is a supported device */
err = -EINVAL;
- if (!mpls_dev_get(dev))
+ if (!mpls_dev_get(net, dev))
goto errout_put;
if ((nh->nh_via_table == NEIGH_LINK_TABLE) &&
@@ -1290,7 +1290,7 @@ static int mpls_netconf_get_devconf(struct sk_buff *in_skb,
if (!dev)
goto errout;
- mdev = mpls_dev_get(dev);
+ mdev = mpls_dev_get(net, dev);
if (!mdev)
goto errout;
@@ -1613,6 +1613,7 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct net *net = dev_net(dev);
struct mpls_dev *mdev;
unsigned int flags;
int err;
@@ -1627,7 +1628,7 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
goto out;
}
- mdev = mpls_dev_get(dev);
+ mdev = mpls_dev_get(net, dev);
if (!mdev)
goto out;
@@ -1660,7 +1661,7 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
if (err)
goto err;
- mdev = mpls_dev_get(dev);
+ mdev = mpls_dev_get(net, dev);
if (mdev) {
mpls_dev_sysctl_unregister(dev, mdev);
RCU_INIT_POINTER(dev->mpls_ptr, NULL);
@@ -1668,7 +1669,7 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
}
break;
case NETDEV_CHANGENAME:
- mdev = mpls_dev_get(dev);
+ mdev = mpls_dev_get(net, dev);
if (mdev) {
mpls_dev_sysctl_unregister(dev, mdev);
err = mpls_dev_sysctl_register(dev, mdev);
diff --git a/net/mpls/internal.h b/net/mpls/internal.h
index 9adbbdeb8f848..324988a77681c 100644
--- a/net/mpls/internal.h
+++ b/net/mpls/internal.h
@@ -190,7 +190,8 @@ static inline struct mpls_dev *mpls_dev_rcu(const struct net_device *dev)
return rcu_dereference(dev->mpls_ptr);
}
-static inline struct mpls_dev *mpls_dev_get(const struct net_device *dev)
+static inline struct mpls_dev *mpls_dev_get(const struct net *net,
+ const struct net_device *dev)
{
return rcu_dereference_rtnl(dev->mpls_ptr);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 223/869] mpls: Add mpls_route_input().
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (221 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 222/869] mpls: Pass net to mpls_dev_get() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 224/869] mpls: Convert mpls_dump_routes() to RCU Greg Kroah-Hartman
` (646 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kuniyuki Iwashima, Guillaume Nault,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit 73e40539399101667945ed8b8299d0fa67a4fca2 ]
mpls_route_input_rcu() is called from mpls_forward() and
mpls_getroute().
The former is under RCU, and the latter is under RTNL, so
mpls_route_input_rcu() uses rcu_dereference_rtnl().
Let's use rcu_dereference() in mpls_route_input_rcu() and
add an RTNL variant for mpls_getroute().
Later, we will remove rtnl_dereference() there.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Guillaume Nault <gnault@redhat.com>
Link: https://patch.msgid.link/20251029173344.2934622-9-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 629ec78ef860 ("mpls: add seqcount to protect the platform_label{,s} pair")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mpls/af_mpls.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 7181af81e4290..5e060d373d7db 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -75,16 +75,23 @@ static void rtmsg_lfib(int event, u32 label, struct mpls_route *rt,
struct nlmsghdr *nlh, struct net *net, u32 portid,
unsigned int nlm_flags);
-static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
+static struct mpls_route *mpls_route_input(struct net *net, unsigned int index)
{
- struct mpls_route *rt = NULL;
+ struct mpls_route __rcu **platform_label;
- if (index < net->mpls.platform_labels) {
- struct mpls_route __rcu **platform_label =
- rcu_dereference_rtnl(net->mpls.platform_label);
- rt = rcu_dereference_rtnl(platform_label[index]);
- }
- return rt;
+ platform_label = rtnl_dereference(net->mpls.platform_label);
+ return rtnl_dereference(platform_label[index]);
+}
+
+static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned int index)
+{
+ struct mpls_route __rcu **platform_label;
+
+ if (index >= net->mpls.platform_labels)
+ return NULL;
+
+ platform_label = rcu_dereference(net->mpls.platform_label);
+ return rcu_dereference(platform_label[index]);
}
bool mpls_output_possible(const struct net_device *dev)
@@ -2378,12 +2385,12 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
u32 portid = NETLINK_CB(in_skb).portid;
u32 in_label = LABEL_NOT_SPECIFIED;
struct nlattr *tb[RTA_MAX + 1];
+ struct mpls_route *rt = NULL;
u32 labels[MAX_NEW_LABELS];
struct mpls_shim_hdr *hdr;
unsigned int hdr_size = 0;
const struct mpls_nh *nh;
struct net_device *dev;
- struct mpls_route *rt;
struct rtmsg *rtm, *r;
struct nlmsghdr *nlh;
struct sk_buff *skb;
@@ -2411,7 +2418,8 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
}
}
- rt = mpls_route_input_rcu(net, in_label);
+ if (in_label < net->mpls.platform_labels)
+ rt = mpls_route_input(net, in_label);
if (!rt) {
err = -ENETUNREACH;
goto errout;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 224/869] mpls: Convert mpls_dump_routes() to RCU.
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (222 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 223/869] mpls: Add mpls_route_input() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 225/869] mpls: Protect net->mpls.platform_label with a per-netns mutex Greg Kroah-Hartman
` (645 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kuniyuki Iwashima, Guillaume Nault,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit dde1b38e873cff70f0af36e884bbeb1b14a536ed ]
mpls_dump_routes() sets fib_dump_filter.rtnl_held to true and
calls __dev_get_by_index() in mpls_valid_fib_dump_req().
This is the only RTNL dependant in mpls_dump_routes().
Also, synchronize_rcu() in resize_platform_label_table()
guarantees that net->mpls.platform_label is alive under RCU.
Let's convert mpls_dump_routes() to RCU and use dev_get_by_index_rcu().
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Guillaume Nault <gnault@redhat.com>
Link: https://patch.msgid.link/20251029173344.2934622-11-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 629ec78ef860 ("mpls: add seqcount to protect the platform_label{,s} pair")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mpls/af_mpls.c | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 5e060d373d7db..c555005cfcf55 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -2164,7 +2164,7 @@ static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
continue;
ifindex = nla_get_u32(tb[i]);
- filter->dev = __dev_get_by_index(net, ifindex);
+ filter->dev = dev_get_by_index_rcu(net, ifindex);
if (!filter->dev)
return -ENODEV;
filter->filter_set = 1;
@@ -2202,20 +2202,19 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
struct net *net = sock_net(skb->sk);
struct mpls_route __rcu **platform_label;
struct fib_dump_filter filter = {
- .rtnl_held = true,
+ .rtnl_held = false,
};
unsigned int flags = NLM_F_MULTI;
size_t platform_labels;
unsigned int index;
+ int err;
- ASSERT_RTNL();
+ rcu_read_lock();
if (cb->strict_check) {
- int err;
-
err = mpls_valid_fib_dump_req(net, nlh, &filter, cb);
if (err < 0)
- return err;
+ goto err;
/* for MPLS, there is only 1 table with fixed type and flags.
* If either are set in the filter then return nothing.
@@ -2223,14 +2222,14 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
if ((filter.table_id && filter.table_id != RT_TABLE_MAIN) ||
(filter.rt_type && filter.rt_type != RTN_UNICAST) ||
filter.flags)
- return skb->len;
+ goto unlock;
}
index = cb->args[0];
if (index < MPLS_LABEL_FIRST_UNRESERVED)
index = MPLS_LABEL_FIRST_UNRESERVED;
- platform_label = rtnl_dereference(net->mpls.platform_label);
+ platform_label = rcu_dereference(net->mpls.platform_label);
platform_labels = net->mpls.platform_labels;
if (filter.filter_set)
@@ -2239,7 +2238,7 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
for (; index < platform_labels; index++) {
struct mpls_route *rt;
- rt = rtnl_dereference(platform_label[index]);
+ rt = rcu_dereference(platform_label[index]);
if (!rt)
continue;
@@ -2254,7 +2253,13 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
}
cb->args[0] = index;
+unlock:
+ rcu_read_unlock();
return skb->len;
+
+err:
+ rcu_read_unlock();
+ return err;
}
static inline size_t lfib_nlmsg_size(struct mpls_route *rt)
@@ -2779,7 +2784,8 @@ static struct rtnl_af_ops mpls_af_ops __read_mostly = {
static const struct rtnl_msg_handler mpls_rtnl_msg_handlers[] __initdata_or_module = {
{THIS_MODULE, PF_MPLS, RTM_NEWROUTE, mpls_rtm_newroute, NULL, 0},
{THIS_MODULE, PF_MPLS, RTM_DELROUTE, mpls_rtm_delroute, NULL, 0},
- {THIS_MODULE, PF_MPLS, RTM_GETROUTE, mpls_getroute, mpls_dump_routes, 0},
+ {THIS_MODULE, PF_MPLS, RTM_GETROUTE, mpls_getroute, mpls_dump_routes,
+ RTNL_FLAG_DUMP_UNLOCKED},
{THIS_MODULE, PF_MPLS, RTM_GETNETCONF,
mpls_netconf_get_devconf, mpls_netconf_dump_devconf,
RTNL_FLAG_DUMP_UNLOCKED},
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 225/869] mpls: Protect net->mpls.platform_label with a per-netns mutex.
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (223 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 224/869] mpls: Convert mpls_dump_routes() to RCU Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 226/869] mpls: add seqcount to protect the platform_label{,s} pair Greg Kroah-Hartman
` (644 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kuniyuki Iwashima, Guillaume Nault,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit e833eb25161aae6cd0caf14782f405d0ed5765ed ]
MPLS (re)uses RTNL to protect net->mpls.platform_label,
but the lock does not need to be RTNL at all.
Let's protect net->mpls.platform_label with a dedicated
per-netns mutex.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Guillaume Nault <gnault@redhat.com>
Link: https://patch.msgid.link/20251029173344.2934622-13-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 629ec78ef860 ("mpls: add seqcount to protect the platform_label{,s} pair")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/netns/mpls.h | 1 +
net/mpls/af_mpls.c | 55 ++++++++++++++++++++++++++--------------
net/mpls/internal.h | 7 ++++-
3 files changed, 43 insertions(+), 20 deletions(-)
diff --git a/include/net/netns/mpls.h b/include/net/netns/mpls.h
index 19ad2574b267c..6682e51513efa 100644
--- a/include/net/netns/mpls.h
+++ b/include/net/netns/mpls.h
@@ -16,6 +16,7 @@ struct netns_mpls {
int default_ttl;
size_t platform_labels;
struct mpls_route __rcu * __rcu *platform_label;
+ struct mutex platform_mutex;
struct ctl_table_header *ctl;
};
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index c555005cfcf55..c621ab55f3b82 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -79,8 +79,8 @@ static struct mpls_route *mpls_route_input(struct net *net, unsigned int index)
{
struct mpls_route __rcu **platform_label;
- platform_label = rtnl_dereference(net->mpls.platform_label);
- return rtnl_dereference(platform_label[index]);
+ platform_label = mpls_dereference(net, net->mpls.platform_label);
+ return mpls_dereference(net, platform_label[index]);
}
static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned int index)
@@ -579,10 +579,8 @@ static void mpls_route_update(struct net *net, unsigned index,
struct mpls_route __rcu **platform_label;
struct mpls_route *rt;
- ASSERT_RTNL();
-
- platform_label = rtnl_dereference(net->mpls.platform_label);
- rt = rtnl_dereference(platform_label[index]);
+ platform_label = mpls_dereference(net, net->mpls.platform_label);
+ rt = mpls_dereference(net, platform_label[index]);
rcu_assign_pointer(platform_label[index], new);
mpls_notify_route(net, index, rt, new, info);
@@ -1462,8 +1460,6 @@ static struct mpls_dev *mpls_add_dev(struct net_device *dev)
int err = -ENOMEM;
int i;
- ASSERT_RTNL();
-
mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
if (!mdev)
return ERR_PTR(err);
@@ -1625,6 +1621,8 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
unsigned int flags;
int err;
+ mutex_lock(&net->mpls.platform_mutex);
+
if (event == NETDEV_REGISTER) {
mdev = mpls_add_dev(dev);
if (IS_ERR(mdev)) {
@@ -1687,9 +1685,11 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
}
out:
+ mutex_unlock(&net->mpls.platform_mutex);
return NOTIFY_OK;
err:
+ mutex_unlock(&net->mpls.platform_mutex);
return notifier_from_errno(err);
}
@@ -1965,6 +1965,7 @@ static int rtm_to_route_config(struct sk_buff *skb,
static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
+ struct net *net = sock_net(skb->sk);
struct mpls_route_config *cfg;
int err;
@@ -1976,7 +1977,9 @@ static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err < 0)
goto out;
+ mutex_lock(&net->mpls.platform_mutex);
err = mpls_route_del(cfg, extack);
+ mutex_unlock(&net->mpls.platform_mutex);
out:
kfree(cfg);
@@ -1987,6 +1990,7 @@ static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
+ struct net *net = sock_net(skb->sk);
struct mpls_route_config *cfg;
int err;
@@ -1998,7 +2002,9 @@ static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err < 0)
goto out;
+ mutex_lock(&net->mpls.platform_mutex);
err = mpls_route_add(cfg, extack);
+ mutex_unlock(&net->mpls.platform_mutex);
out:
kfree(cfg);
@@ -2402,6 +2408,8 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
u8 n_labels;
int err;
+ mutex_lock(&net->mpls.platform_mutex);
+
err = mpls_valid_getroute_req(in_skb, in_nlh, tb, extack);
if (err < 0)
goto errout;
@@ -2445,7 +2453,8 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
goto errout_free;
}
- return rtnl_unicast(skb, net, portid);
+ err = rtnl_unicast(skb, net, portid);
+ goto errout;
}
if (tb[RTA_NEWDST]) {
@@ -2538,12 +2547,14 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
err = rtnl_unicast(skb, net, portid);
errout:
+ mutex_unlock(&net->mpls.platform_mutex);
return err;
nla_put_failure:
nlmsg_cancel(skb, nlh);
err = -EMSGSIZE;
errout_free:
+ mutex_unlock(&net->mpls.platform_mutex);
kfree_skb(skb);
return err;
}
@@ -2599,9 +2610,10 @@ static int resize_platform_label_table(struct net *net, size_t limit)
lo->addr_len);
}
- rtnl_lock();
+ mutex_lock(&net->mpls.platform_mutex);
+
/* Remember the original table */
- old = rtnl_dereference(net->mpls.platform_label);
+ old = mpls_dereference(net, net->mpls.platform_label);
old_limit = net->mpls.platform_labels;
/* Free any labels beyond the new table */
@@ -2632,7 +2644,7 @@ static int resize_platform_label_table(struct net *net, size_t limit)
net->mpls.platform_labels = limit;
rcu_assign_pointer(net->mpls.platform_label, labels);
- rtnl_unlock();
+ mutex_unlock(&net->mpls.platform_mutex);
mpls_rt_free(rt2);
mpls_rt_free(rt0);
@@ -2705,12 +2717,13 @@ static const struct ctl_table mpls_table[] = {
},
};
-static int mpls_net_init(struct net *net)
+static __net_init int mpls_net_init(struct net *net)
{
size_t table_size = ARRAY_SIZE(mpls_table);
struct ctl_table *table;
int i;
+ mutex_init(&net->mpls.platform_mutex);
net->mpls.platform_labels = 0;
net->mpls.platform_label = NULL;
net->mpls.ip_ttl_propagate = 1;
@@ -2736,7 +2749,7 @@ static int mpls_net_init(struct net *net)
return 0;
}
-static void mpls_net_exit(struct net *net)
+static __net_exit void mpls_net_exit(struct net *net)
{
struct mpls_route __rcu **platform_label;
size_t platform_labels;
@@ -2756,16 +2769,20 @@ static void mpls_net_exit(struct net *net)
* As such no additional rcu synchronization is necessary when
* freeing the platform_label table.
*/
- rtnl_lock();
- platform_label = rtnl_dereference(net->mpls.platform_label);
+ mutex_lock(&net->mpls.platform_mutex);
+
+ platform_label = mpls_dereference(net, net->mpls.platform_label);
platform_labels = net->mpls.platform_labels;
+
for (index = 0; index < platform_labels; index++) {
- struct mpls_route *rt = rtnl_dereference(platform_label[index]);
- RCU_INIT_POINTER(platform_label[index], NULL);
+ struct mpls_route *rt;
+
+ rt = mpls_dereference(net, platform_label[index]);
mpls_notify_route(net, index, rt, NULL, NULL);
mpls_rt_free(rt);
}
- rtnl_unlock();
+
+ mutex_unlock(&net->mpls.platform_mutex);
kvfree(platform_label);
}
diff --git a/net/mpls/internal.h b/net/mpls/internal.h
index 324988a77681c..8ddc8b7e6cbd4 100644
--- a/net/mpls/internal.h
+++ b/net/mpls/internal.h
@@ -185,6 +185,11 @@ static inline struct mpls_entry_decoded mpls_entry_decode(struct mpls_shim_hdr *
return result;
}
+#define mpls_dereference(net, p) \
+ rcu_dereference_protected( \
+ (p), \
+ lockdep_is_held(&(net)->mpls.platform_mutex))
+
static inline struct mpls_dev *mpls_dev_rcu(const struct net_device *dev)
{
return rcu_dereference(dev->mpls_ptr);
@@ -193,7 +198,7 @@ static inline struct mpls_dev *mpls_dev_rcu(const struct net_device *dev)
static inline struct mpls_dev *mpls_dev_get(const struct net *net,
const struct net_device *dev)
{
- return rcu_dereference_rtnl(dev->mpls_ptr);
+ return mpls_dereference(net, dev->mpls_ptr);
}
int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 226/869] mpls: add seqcount to protect the platform_label{,s} pair
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (224 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 225/869] mpls: Protect net->mpls.platform_label with a per-netns mutex Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 227/869] HID: core: Add reserved item tag for main items Greg Kroah-Hartman
` (643 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yuan Tan, Yifan Wu, Juefei Pu,
Xin Liu, Sabrina Dubroca, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sabrina Dubroca <sd@queasysnail.net>
[ Upstream commit 629ec78ef8608d955ce217880cdc3e1873af3a15 ]
The RCU-protected codepaths (mpls_forward, mpls_dump_routes) can have
an inconsistent view of platform_labels vs platform_label in case of a
concurrent resize (resize_platform_label_table, under
platform_mutex). This can lead to OOB accesses.
This patch adds a seqcount, so that we get a consistent snapshot.
Note that mpls_label_ok is also susceptible to this, so the check
against RTA_DST in rtm_to_route_config, done outside platform_mutex,
is not sufficient. This value gets passed to mpls_label_ok once more
in both mpls_route_add and mpls_route_del, so there is no issue, but
that additional check must not be removed.
Reported-by: Yuan Tan <tanyuan98@outlook.com>
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Fixes: 7720c01f3f590 ("mpls: Add a sysctl to control the size of the mpls label table")
Fixes: dde1b38e873c ("mpls: Convert mpls_dump_routes() to RCU.")
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Link: https://patch.msgid.link/cd8fca15e3eb7e212b094064cd83652e20fd9d31.1774284088.git.sd@queasysnail.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/netns/mpls.h | 1 +
net/mpls/af_mpls.c | 29 +++++++++++++++++++++++++----
2 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/include/net/netns/mpls.h b/include/net/netns/mpls.h
index 6682e51513efa..2073cbac2afb5 100644
--- a/include/net/netns/mpls.h
+++ b/include/net/netns/mpls.h
@@ -17,6 +17,7 @@ struct netns_mpls {
size_t platform_labels;
struct mpls_route __rcu * __rcu *platform_label;
struct mutex platform_mutex;
+ seqcount_mutex_t platform_label_seq;
struct ctl_table_header *ctl;
};
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index c621ab55f3b82..5c293fa655d0d 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -83,14 +83,30 @@ static struct mpls_route *mpls_route_input(struct net *net, unsigned int index)
return mpls_dereference(net, platform_label[index]);
}
+static struct mpls_route __rcu **mpls_platform_label_rcu(struct net *net, size_t *platform_labels)
+{
+ struct mpls_route __rcu **platform_label;
+ unsigned int sequence;
+
+ do {
+ sequence = read_seqcount_begin(&net->mpls.platform_label_seq);
+ platform_label = rcu_dereference(net->mpls.platform_label);
+ *platform_labels = net->mpls.platform_labels;
+ } while (read_seqcount_retry(&net->mpls.platform_label_seq, sequence));
+
+ return platform_label;
+}
+
static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned int index)
{
struct mpls_route __rcu **platform_label;
+ size_t platform_labels;
+
+ platform_label = mpls_platform_label_rcu(net, &platform_labels);
- if (index >= net->mpls.platform_labels)
+ if (index >= platform_labels)
return NULL;
- platform_label = rcu_dereference(net->mpls.platform_label);
return rcu_dereference(platform_label[index]);
}
@@ -2235,8 +2251,7 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
if (index < MPLS_LABEL_FIRST_UNRESERVED)
index = MPLS_LABEL_FIRST_UNRESERVED;
- platform_label = rcu_dereference(net->mpls.platform_label);
- platform_labels = net->mpls.platform_labels;
+ platform_label = mpls_platform_label_rcu(net, &platform_labels);
if (filter.filter_set)
flags |= NLM_F_DUMP_FILTERED;
@@ -2641,8 +2656,12 @@ static int resize_platform_label_table(struct net *net, size_t limit)
}
/* Update the global pointers */
+ local_bh_disable();
+ write_seqcount_begin(&net->mpls.platform_label_seq);
net->mpls.platform_labels = limit;
rcu_assign_pointer(net->mpls.platform_label, labels);
+ write_seqcount_end(&net->mpls.platform_label_seq);
+ local_bh_enable();
mutex_unlock(&net->mpls.platform_mutex);
@@ -2724,6 +2743,8 @@ static __net_init int mpls_net_init(struct net *net)
int i;
mutex_init(&net->mpls.platform_mutex);
+ seqcount_mutex_init(&net->mpls.platform_label_seq, &net->mpls.platform_mutex);
+
net->mpls.platform_labels = 0;
net->mpls.platform_label = NULL;
net->mpls.ip_ttl_propagate = 1;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 227/869] HID: core: Add reserved item tag for main items
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (225 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 226/869] mpls: add seqcount to protect the platform_label{,s} pair Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 228/869] HID: rate-limit hid_warn to prevent log flooding Greg Kroah-Hartman
` (642 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Tatsuya S, Jiri Kosina, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tatsuya S <tatsuya.s2862@gmail.com>
[ Upstream commit c600a55922640b1c4dcfdc5a694cadd2dd9d1599 ]
For main items, separate warning of reserved item tag from
warning of unknown item tag.
This comes from 6.2.2.4 Main Items of Device Class Definition
for HID 1.11 specification.
Signed-off-by: Tatsuya S <tatsuya.s2862@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Stable-dep-of: 0a3fe972a7cb ("HID: core: Mitigate potential OOB by removing bogus memset()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/hid-core.c | 6 +++++-
include/linux/hid.h | 2 ++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index df2e43b27388d..ba6d42a3e634e 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -670,7 +670,11 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
break;
default:
- hid_warn(parser->device, "unknown main item tag 0x%x\n", item->tag);
+ if (item->tag >= HID_MAIN_ITEM_TAG_RESERVED_MIN &&
+ item->tag <= HID_MAIN_ITEM_TAG_RESERVED_MAX)
+ hid_warn(parser->device, "reserved main item tag 0x%x\n", item->tag);
+ else
+ hid_warn(parser->device, "unknown main item tag 0x%x\n", item->tag);
ret = 0;
}
diff --git a/include/linux/hid.h b/include/linux/hid.h
index e2734b9d3ee05..89529c58da0a4 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -81,6 +81,8 @@ struct hid_item {
#define HID_MAIN_ITEM_TAG_FEATURE 11
#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10
#define HID_MAIN_ITEM_TAG_END_COLLECTION 12
+#define HID_MAIN_ITEM_TAG_RESERVED_MIN 13
+#define HID_MAIN_ITEM_TAG_RESERVED_MAX 15
/*
* HID report descriptor main item contents
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 228/869] HID: rate-limit hid_warn to prevent log flooding
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (226 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 227/869] HID: core: Add reserved item tag for main items Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 229/869] HID: core: Mitigate potential OOB by removing bogus memset() Greg Kroah-Hartman
` (641 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Li Chen, Jiri Kosina, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Chen <chenl311@chinatelecom.cn>
[ Upstream commit 4051ead99888f101be92c7ce90d2de09aac6fd1c ]
Syzkaller can create many uhid devices that trigger
repeated warnings like:
"hid-generic xxxx: unknown main item tag 0x0"
These messages can flood the system log, especially if a crash occurs
(e.g., with a slow UART console, leading to soft lockups). To mitigate
this, convert `hid_warn()` to use `dev_warn_ratelimited()`.
This helps reduce log noise and improves system stability under fuzzing
or faulty device scenarios.
Signed-off-by: Li Chen <chenl311@chinatelecom.cn>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Stable-dep-of: 0a3fe972a7cb ("HID: core: Mitigate potential OOB by removing bogus memset()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/hid-core.c | 4 ++--
include/linux/hid.h | 2 ++
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index ba6d42a3e634e..bf9cd8c7e4c5c 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -672,9 +672,9 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
default:
if (item->tag >= HID_MAIN_ITEM_TAG_RESERVED_MIN &&
item->tag <= HID_MAIN_ITEM_TAG_RESERVED_MAX)
- hid_warn(parser->device, "reserved main item tag 0x%x\n", item->tag);
+ hid_warn_ratelimited(parser->device, "reserved main item tag 0x%x\n", item->tag);
else
- hid_warn(parser->device, "unknown main item tag 0x%x\n", item->tag);
+ hid_warn_ratelimited(parser->device, "unknown main item tag 0x%x\n", item->tag);
ret = 0;
}
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 89529c58da0a4..2edaa8cbdd4a9 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -1262,6 +1262,8 @@ void hid_quirks_exit(__u16 bus);
dev_notice(&(hid)->dev, fmt, ##__VA_ARGS__)
#define hid_warn(hid, fmt, ...) \
dev_warn(&(hid)->dev, fmt, ##__VA_ARGS__)
+#define hid_warn_ratelimited(hid, fmt, ...) \
+ dev_warn_ratelimited(&(hid)->dev, fmt, ##__VA_ARGS__)
#define hid_info(hid, fmt, ...) \
dev_info(&(hid)->dev, fmt, ##__VA_ARGS__)
#define hid_dbg(hid, fmt, ...) \
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 229/869] HID: core: Mitigate potential OOB by removing bogus memset()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (227 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 228/869] HID: rate-limit hid_warn to prevent log flooding Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 230/869] xfs: remove bp->b_error check in xfs_attr3_root_inactive Greg Kroah-Hartman
` (640 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lee Jones, Benjamin Tissoires,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lee Jones <lee@kernel.org>
[ Upstream commit 0a3fe972a7cb1404f693d6f1711f32bc1d244b1c ]
The memset() in hid_report_raw_event() has the good intention of
clearing out bogus data by zeroing the area from the end of the incoming
data string to the assumed end of the buffer. However, as we have
previously seen, doing so can easily result in OOB reads and writes in
the subsequent thread of execution.
The current suggestion from one of the HID maintainers is to remove the
memset() and simply return if the incoming event buffer size is not
large enough to fill the associated report.
Suggested-by Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Lee Jones <lee@kernel.org>
[bentiss: changed the return value]
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/hid-core.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index bf9cd8c7e4c5c..52eda362bb1a1 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2061,9 +2061,9 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
}
if (csize < rsize) {
- dbg_hid("report %d is too short, (%d < %d)\n", report->id,
- csize, rsize);
- memset(cdata + csize, 0, rsize - csize);
+ hid_warn_ratelimited(hid, "Event data for report %d was too short (%d vs %d)\n",
+ report->id, rsize, csize);
+ return -EINVAL;
}
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 230/869] xfs: remove bp->b_error check in xfs_attr3_root_inactive
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (228 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 229/869] HID: core: Mitigate potential OOB by removing bogus memset() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 231/869] xfs: factor out xfs_attr3_node_entry_remove Greg Kroah-Hartman
` (639 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Long Li, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <leo.lilong@huawei.com>
[ Upstream commit 09f7680dea8760d48dd5b8b5288a388fec122275 ]
The b_error check right after xfs_trans_get_buf() is redundant:
1) If the buffer is found in transaction via xfs_trans_buf_item_match(),
any corrupted metadata error would have already been exposed during
previous reads like xfs_da3_node_read().
2) If the buffer is obtained via xfs_buf_get_map():
- It's called without XBF_READ flag, so won't return buffer with
b_error set, since xfs_buf_get_map() will clear it anyway.
- Buffer found in cache normally won't have error since previous reads
had checked it, unless someone corrupts the buffer and the AIL
pushes it out to disk while the buffer's unlocked. But in this case,
AIL will shut down the log.
Remove this redundant check to simplify the code, make the code consistent
with most other xfs_trans_get_buf() callers in XFS.
Signed-off-by: Long Li <leo.lilong@huawei.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
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/xfs_attr_inactive.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
index 24fb12986a568..319004bf089fa 100644
--- a/fs/xfs/xfs_attr_inactive.c
+++ b/fs/xfs/xfs_attr_inactive.c
@@ -305,11 +305,6 @@ xfs_attr3_root_inactive(
XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0, &bp);
if (error)
return error;
- error = bp->b_error;
- if (error) {
- xfs_trans_brelse(*trans, bp);
- return error;
- }
xfs_trans_binval(*trans, bp); /* remove from cache */
/*
* Commit the invalidate and start the next transaction.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 231/869] xfs: factor out xfs_attr3_node_entry_remove
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (229 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 230/869] xfs: remove bp->b_error check in xfs_attr3_root_inactive Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 232/869] xfs: close crash window in attr dabtree inactivation Greg Kroah-Hartman
` (638 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Long Li,
Carlos Maiolino, Sasha Levin
6.12-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] 872+ messages in thread
* [PATCH 6.12 232/869] xfs: close crash window in attr dabtree inactivation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (230 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 231/869] xfs: factor out xfs_attr3_node_entry_remove Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 233/869] net: ioam6: fix OOB and missing lock Greg Kroah-Hartman
` (637 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Long Li, Darrick J. Wong,
Carlos Maiolino, Sasha Levin
6.12-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] 872+ messages in thread
* [PATCH 6.12 233/869] net: ioam6: fix OOB and missing lock
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (231 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 232/869] xfs: close crash window in attr dabtree inactivation Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 234/869] ipv6: ioam: fix potential NULL dereferences in __ioam6_fill_trace_data() Greg Kroah-Hartman
` (636 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jakub Kicinski, Justin Iurman,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Justin Iurman <justin.iurman@gmail.com>
[ Upstream commit b30b1675aa2bcf0491fd3830b051df4e08a7c8ca ]
When trace->type.bit6 is set:
if (trace->type.bit6) {
...
queue = skb_get_tx_queue(dev, skb);
qdisc = rcu_dereference(queue->qdisc);
This code can lead to an out-of-bounds access of the dev->_tx[] array
when is_input is true. In such a case, the packet is on the RX path and
skb->queue_mapping contains the RX queue index of the ingress device. If
the ingress device has more RX queues than the egress device (dev) has
TX queues, skb_get_queue_mapping(skb) will exceed dev->num_tx_queues.
Add a check to avoid this situation since skb_get_tx_queue() does not
clamp the index. This issue has also revealed that per queue visibility
cannot be accurate and will be replaced later as a new feature.
While at it, add missing lock around qdisc_qstats_qlen_backlog(). The
function __ioam6_fill_trace_data() is called from both softirq and
process contexts, hence the use of spin_lock_bh() here.
Fixes: b63c5478e9cb ("ipv6: ioam: Support for Queue depth data field")
Reported-by: Jakub Kicinski <kuba@kernel.org>
Closes: https://lore.kernel.org/netdev/20260403214418.2233266-2-kuba@kernel.org/
Signed-off-by: Justin Iurman <justin.iurman@gmail.com>
Link: https://patch.msgid.link/20260404134137.24553-1-justin.iurman@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv6/ioam6.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c
index bea2cf0163074..0cb96663f99b7 100644
--- a/net/ipv6/ioam6.c
+++ b/net/ipv6/ioam6.c
@@ -802,12 +802,16 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
struct Qdisc *qdisc;
__u32 qlen, backlog;
- if (dev->flags & IFF_LOOPBACK) {
+ if (dev->flags & IFF_LOOPBACK ||
+ skb_get_queue_mapping(skb) >= dev->num_tx_queues) {
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
} else {
queue = skb_get_tx_queue(dev, skb);
qdisc = rcu_dereference(queue->qdisc);
+
+ spin_lock_bh(qdisc_lock(qdisc));
qdisc_qstats_qlen_backlog(qdisc, &qlen, &backlog);
+ spin_unlock_bh(qdisc_lock(qdisc));
*(__be32 *)data = cpu_to_be32(backlog);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 234/869] ipv6: ioam: fix potential NULL dereferences in __ioam6_fill_trace_data()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (232 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 233/869] net: ioam6: fix OOB and missing lock Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 235/869] srcu: Use irq_work to start GP in tiny SRCU Greg Kroah-Hartman
` (635 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yiming Qian, Eric Dumazet,
Justin Iurman, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 4e65a8b8daa18d63255ec58964dd192c7fdd9f8b ]
We need to check __in6_dev_get() for possible NULL value, as
suggested by Yiming Qian.
Also add skb_dst_dev_rcu() instead of skb_dst_dev(),
and two missing READ_ONCE().
Note that @dev can't be NULL.
Fixes: 9ee11f0fff20 ("ipv6: ioam: Data plane support for Pre-allocated Trace")
Reported-by: Yiming Qian <yimingqian591@gmail.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
Link: https://patch.msgid.link/20260402101732.1188059-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv6/ioam6.c | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c
index 0cb96663f99b7..04e02ec689b9d 100644
--- a/net/ipv6/ioam6.c
+++ b/net/ipv6/ioam6.c
@@ -714,7 +714,9 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
struct ioam6_schema *sc,
unsigned int sclen, bool is_input)
{
- struct net_device *dev = skb_dst_dev(skb);
+ /* Note: skb_dst_dev_rcu() can't be NULL at this point. */
+ struct net_device *dev = skb_dst_dev_rcu(skb);
+ struct inet6_dev *i_skb_dev, *idev;
struct timespec64 ts;
ktime_t tstamp;
u64 raw64;
@@ -725,13 +727,16 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
data = trace->data + trace->remlen * 4 - trace->nodelen * 4 - sclen * 4;
+ i_skb_dev = skb->dev ? __in6_dev_get(skb->dev) : NULL;
+ idev = __in6_dev_get(dev);
+
/* hop_lim and node_id */
if (trace->type.bit0) {
byte = ipv6_hdr(skb)->hop_limit;
if (is_input)
byte--;
- raw32 = dev_net(dev)->ipv6.sysctl.ioam6_id;
+ raw32 = READ_ONCE(dev_net(dev)->ipv6.sysctl.ioam6_id);
*(__be32 *)data = cpu_to_be32((byte << 24) | raw32);
data += sizeof(__be32);
@@ -739,18 +744,18 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
/* ingress_if_id and egress_if_id */
if (trace->type.bit1) {
- if (!skb->dev)
+ if (!i_skb_dev)
raw16 = IOAM6_U16_UNAVAILABLE;
else
- raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id);
+ raw16 = (__force u16)READ_ONCE(i_skb_dev->cnf.ioam6_id);
*(__be16 *)data = cpu_to_be16(raw16);
data += sizeof(__be16);
- if (dev->flags & IFF_LOOPBACK)
+ if ((dev->flags & IFF_LOOPBACK) || !idev)
raw16 = IOAM6_U16_UNAVAILABLE;
else
- raw16 = (__force u16)READ_ONCE(__in6_dev_get(dev)->cnf.ioam6_id);
+ raw16 = (__force u16)READ_ONCE(idev->cnf.ioam6_id);
*(__be16 *)data = cpu_to_be16(raw16);
data += sizeof(__be16);
@@ -830,7 +835,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
if (is_input)
byte--;
- raw64 = dev_net(dev)->ipv6.sysctl.ioam6_id_wide;
+ raw64 = READ_ONCE(dev_net(dev)->ipv6.sysctl.ioam6_id_wide);
*(__be64 *)data = cpu_to_be64(((u64)byte << 56) | raw64);
data += sizeof(__be64);
@@ -838,18 +843,18 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
/* ingress_if_id and egress_if_id (wide) */
if (trace->type.bit9) {
- if (!skb->dev)
+ if (!i_skb_dev)
raw32 = IOAM6_U32_UNAVAILABLE;
else
- raw32 = READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id_wide);
+ raw32 = READ_ONCE(i_skb_dev->cnf.ioam6_id_wide);
*(__be32 *)data = cpu_to_be32(raw32);
data += sizeof(__be32);
- if (dev->flags & IFF_LOOPBACK)
+ if ((dev->flags & IFF_LOOPBACK) || !idev)
raw32 = IOAM6_U32_UNAVAILABLE;
else
- raw32 = READ_ONCE(__in6_dev_get(dev)->cnf.ioam6_id_wide);
+ raw32 = READ_ONCE(idev->cnf.ioam6_id_wide);
*(__be32 *)data = cpu_to_be32(raw32);
data += sizeof(__be32);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 235/869] srcu: Use irq_work to start GP in tiny SRCU
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (233 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 234/869] ipv6: ioam: fix potential NULL dereferences in __ioam6_fill_trace_data() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 236/869] btrfs: tree-log: dont use token set/get accessors in fill_inode_item() Greg Kroah-Hartman
` (634 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Joel Fernandes, Paul E. McKenney,
Boqun Feng, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joel Fernandes <joelagnelf@nvidia.com>
[ Upstream commit a6fc88b22bc8d12ad52e8412c667ec0f5bf055af ]
Tiny SRCU's srcu_gp_start_if_needed() directly calls schedule_work(),
which acquires the workqueue pool->lock.
This causes a lockdep splat when call_srcu() is called with a scheduler
lock held, due to:
call_srcu() [holding pi_lock]
srcu_gp_start_if_needed()
schedule_work() -> pool->lock
workqueue_init() / create_worker() [holding pool->lock]
wake_up_process() -> try_to_wake_up() -> pi_lock
Also add irq_work_sync() to cleanup_srcu_struct() to prevent a
use-after-free if a queued irq_work fires after cleanup begins.
Tested with rcutorture SRCU-T and no lockdep warnings.
[ Thanks to Boqun for similar fix in patch "rcu: Use an intermediate irq_work
to start process_srcu()" ]
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
Signed-off-by: Boqun Feng <boqun@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/srcutiny.h | 4 ++++
kernel/rcu/srcutiny.c | 19 ++++++++++++++++++-
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/include/linux/srcutiny.h b/include/linux/srcutiny.h
index 4d96bbdb45f08..6f39d3d8ef879 100644
--- a/include/linux/srcutiny.h
+++ b/include/linux/srcutiny.h
@@ -11,6 +11,7 @@
#ifndef _LINUX_SRCU_TINY_H
#define _LINUX_SRCU_TINY_H
+#include <linux/irq_work_types.h>
#include <linux/swait.h>
struct srcu_struct {
@@ -24,18 +25,21 @@ struct srcu_struct {
struct rcu_head *srcu_cb_head; /* Pending callbacks: Head. */
struct rcu_head **srcu_cb_tail; /* Pending callbacks: Tail. */
struct work_struct srcu_work; /* For driving grace periods. */
+ struct irq_work srcu_irq_work; /* Defer schedule_work() to irq work. */
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
};
void srcu_drive_gp(struct work_struct *wp);
+void srcu_tiny_irq_work(struct irq_work *irq_work);
#define __SRCU_STRUCT_INIT(name, __ignored, ___ignored) \
{ \
.srcu_wq = __SWAIT_QUEUE_HEAD_INITIALIZER(name.srcu_wq), \
.srcu_cb_tail = &name.srcu_cb_head, \
.srcu_work = __WORK_INITIALIZER(name.srcu_work, srcu_drive_gp), \
+ .srcu_irq_work = { .func = srcu_tiny_irq_work }, \
__SRCU_DEP_MAP_INIT(name) \
}
diff --git a/kernel/rcu/srcutiny.c b/kernel/rcu/srcutiny.c
index 4dcbf8aa80ff7..ddea40b68e5f6 100644
--- a/kernel/rcu/srcutiny.c
+++ b/kernel/rcu/srcutiny.c
@@ -9,6 +9,7 @@
*/
#include <linux/export.h>
+#include <linux/irq_work.h>
#include <linux/mutex.h>
#include <linux/preempt.h>
#include <linux/rcupdate_wait.h>
@@ -37,6 +38,7 @@ static int init_srcu_struct_fields(struct srcu_struct *ssp)
ssp->srcu_idx_max = 0;
INIT_WORK(&ssp->srcu_work, srcu_drive_gp);
INIT_LIST_HEAD(&ssp->srcu_work.entry);
+ init_irq_work(&ssp->srcu_irq_work, srcu_tiny_irq_work);
return 0;
}
@@ -80,6 +82,7 @@ EXPORT_SYMBOL_GPL(init_srcu_struct);
void cleanup_srcu_struct(struct srcu_struct *ssp)
{
WARN_ON(ssp->srcu_lock_nesting[0] || ssp->srcu_lock_nesting[1]);
+ irq_work_sync(&ssp->srcu_irq_work);
flush_work(&ssp->srcu_work);
WARN_ON(ssp->srcu_gp_running);
WARN_ON(ssp->srcu_gp_waiting);
@@ -168,6 +171,20 @@ void srcu_drive_gp(struct work_struct *wp)
}
EXPORT_SYMBOL_GPL(srcu_drive_gp);
+/*
+ * Use an irq_work to defer schedule_work() to avoid acquiring the workqueue
+ * pool->lock while the caller might hold scheduler locks, causing lockdep
+ * splats due to workqueue_init() doing a wakeup.
+ */
+void srcu_tiny_irq_work(struct irq_work *irq_work)
+{
+ struct srcu_struct *ssp;
+
+ ssp = container_of(irq_work, struct srcu_struct, srcu_irq_work);
+ schedule_work(&ssp->srcu_work);
+}
+EXPORT_SYMBOL_GPL(srcu_tiny_irq_work);
+
static void srcu_gp_start_if_needed(struct srcu_struct *ssp)
{
unsigned long cookie;
@@ -181,7 +198,7 @@ static void srcu_gp_start_if_needed(struct srcu_struct *ssp)
WRITE_ONCE(ssp->srcu_idx_max, cookie);
if (!READ_ONCE(ssp->srcu_gp_running)) {
if (likely(srcu_init_done))
- schedule_work(&ssp->srcu_work);
+ irq_work_queue(&ssp->srcu_irq_work);
else if (list_empty(&ssp->srcu_work.entry))
list_add(&ssp->srcu_work.entry, &srcu_boot_list);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 236/869] btrfs: tree-log: dont use token set/get accessors in fill_inode_item()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (234 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 235/869] srcu: Use irq_work to start GP in tiny SRCU Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 237/869] btrfs: fix zero size inode with non-zero size after log replay Greg Kroah-Hartman
` (633 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johannes Thumshirn, Qu Wenruo,
David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Sterba <dsterba@suse.com>
[ Upstream commit c418a1504540c6678279b965ea73fe61621faa65 ]
The token versions of set/get accessors will be removed, use the normal
helpers.
There's additional overhead of the token helpers that update the cached
address in case it moves to another page/folio. The normal versions
don't need to do that.
Note this is similar to fill_inode_item() in inode.c but with slight
differences. The two functions could be deduplicated eventually.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Stable-dep-of: 5254d4181add ("btrfs: fix zero size inode with non-zero size after log replay")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/tree-log.c | 48 ++++++++++++++++++---------------------------
1 file changed, 19 insertions(+), 29 deletions(-)
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 983771a2a4568..ab036ef65fdc8 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -4276,44 +4276,34 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
struct inode *inode, int log_inode_only,
u64 logged_isize)
{
- struct btrfs_map_token token;
u64 flags;
- btrfs_init_map_token(&token, leaf);
-
if (log_inode_only) {
/* set the generation to zero so the recover code
* can tell the difference between an logging
* just to say 'this inode exists' and a logging
* to say 'update this inode with these values'
*/
- btrfs_set_token_inode_generation(&token, item, 0);
- btrfs_set_token_inode_size(&token, item, logged_isize);
+ btrfs_set_inode_generation(leaf, item, 0);
+ btrfs_set_inode_size(leaf, item, logged_isize);
} else {
- btrfs_set_token_inode_generation(&token, item,
- BTRFS_I(inode)->generation);
- btrfs_set_token_inode_size(&token, item, inode->i_size);
+ btrfs_set_inode_generation(leaf, item, BTRFS_I(inode)->generation);
+ btrfs_set_inode_size(leaf, item, inode->i_size);
}
- btrfs_set_token_inode_uid(&token, item, i_uid_read(inode));
- btrfs_set_token_inode_gid(&token, item, i_gid_read(inode));
- btrfs_set_token_inode_mode(&token, item, inode->i_mode);
- btrfs_set_token_inode_nlink(&token, item, inode->i_nlink);
+ btrfs_set_inode_uid(leaf, item, i_uid_read(inode));
+ btrfs_set_inode_gid(leaf, item, i_gid_read(inode));
+ btrfs_set_inode_mode(leaf, item, inode->i_mode);
+ btrfs_set_inode_nlink(leaf, item, inode->i_nlink);
- btrfs_set_token_timespec_sec(&token, &item->atime,
- inode_get_atime_sec(inode));
- btrfs_set_token_timespec_nsec(&token, &item->atime,
- inode_get_atime_nsec(inode));
+ btrfs_set_timespec_sec(leaf, &item->atime, inode_get_atime_sec(inode));
+ btrfs_set_timespec_nsec(leaf, &item->atime, inode_get_atime_nsec(inode));
- btrfs_set_token_timespec_sec(&token, &item->mtime,
- inode_get_mtime_sec(inode));
- btrfs_set_token_timespec_nsec(&token, &item->mtime,
- inode_get_mtime_nsec(inode));
+ btrfs_set_timespec_sec(leaf, &item->mtime, inode_get_mtime_sec(inode));
+ btrfs_set_timespec_nsec(leaf, &item->mtime, inode_get_mtime_nsec(inode));
- btrfs_set_token_timespec_sec(&token, &item->ctime,
- inode_get_ctime_sec(inode));
- btrfs_set_token_timespec_nsec(&token, &item->ctime,
- inode_get_ctime_nsec(inode));
+ btrfs_set_timespec_sec(leaf, &item->ctime, inode_get_ctime_sec(inode));
+ btrfs_set_timespec_nsec(leaf, &item->ctime, inode_get_ctime_nsec(inode));
btrfs_set_timespec_sec(leaf, &item->otime, BTRFS_I(inode)->i_otime_sec);
btrfs_set_timespec_nsec(leaf, &item->otime, BTRFS_I(inode)->i_otime_nsec);
@@ -4327,13 +4317,13 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
* inode item in subvolume tree as needed (see overwrite_item()).
*/
- btrfs_set_token_inode_sequence(&token, item, inode_peek_iversion(inode));
- btrfs_set_token_inode_transid(&token, item, trans->transid);
- btrfs_set_token_inode_rdev(&token, item, inode->i_rdev);
+ btrfs_set_inode_sequence(leaf, item, inode_peek_iversion(inode));
+ btrfs_set_inode_transid(leaf, item, trans->transid);
+ btrfs_set_inode_rdev(leaf, item, inode->i_rdev);
flags = btrfs_inode_combine_flags(BTRFS_I(inode)->flags,
BTRFS_I(inode)->ro_flags);
- btrfs_set_token_inode_flags(&token, item, flags);
- btrfs_set_token_inode_block_group(&token, item, 0);
+ btrfs_set_inode_flags(leaf, item, flags);
+ btrfs_set_inode_block_group(leaf, item, 0);
}
static int log_inode_item(struct btrfs_trans_handle *trans,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 237/869] btrfs: fix zero size inode with non-zero size after log replay
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (235 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 236/869] btrfs: tree-log: dont use token set/get accessors in fill_inode_item() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 238/869] fs/ntfs3: Accumulated refactoring changes Greg Kroah-Hartman
` (632 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vyacheslav Kovalevsky, Filipe Manana,
David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Filipe Manana <fdmanana@suse.com>
[ Upstream commit 5254d4181add9dfaa5e3519edd71cc8f752b2f85 ]
When logging that an inode exists, as part of logging a new name or
logging new dir entries for a directory, we always set the generation of
the logged inode item to 0. This is to signal during log replay (in
overwrite_item()), that we should not set the i_size since we only logged
that an inode exists, so the i_size of the inode in the subvolume tree
must be preserved (as when we log new names or that an inode exists, we
don't log extents).
This works fine except when we have already logged an inode in full mode
or it's the first time we are logging an inode created in a past
transaction, that inode has a new i_size of 0 and then we log a new name
for the inode (due to a new hardlink or a rename), in which case we log
an i_size of 0 for the inode and a generation of 0, which causes the log
replay code to not update the inode's i_size to 0 (in overwrite_item()).
An example scenario:
mkdir /mnt/dir
xfs_io -f -c "pwrite 0 64K" /mnt/dir/foo
sync
xfs_io -c "truncate 0" -c "fsync" /mnt/dir/foo
ln /mnt/dir/foo /mnt/dir/bar
xfs_io -c "fsync" /mnt/dir
<power fail>
After log replay the file remains with a size of 64K. This is because when
we first log the inode, when we fsync file foo, we log its current i_size
of 0, and then when we create a hard link we log again the inode in exists
mode (LOG_INODE_EXISTS) but we set a generation of 0 for the inode item we
add to the log tree, so during log replay overwrite_item() sees that the
generation is 0 and i_size is 0 so we skip updating the inode's i_size
from 64K to 0.
Fix this by making sure at fill_inode_item() we always log the real
generation of the inode if it was logged in the current transaction with
the i_size we logged before. Also if an inode created in a previous
transaction is logged in exists mode only, make sure we log the i_size
stored in the inode item located from the commit root, so that if we log
multiple times that the inode exists we get the correct i_size.
A test case for fstests will follow soon.
Reported-by: Vyacheslav Kovalevsky <slava.kovalevskiy.2014@gmail.com>
Link: https://lore.kernel.org/linux-btrfs/af8c15fa-4e41-4bb2-885c-0bc4e97532a6@gmail.com/
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/tree-log.c | 98 ++++++++++++++++++++++++++++++---------------
1 file changed, 65 insertions(+), 33 deletions(-)
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index ab036ef65fdc8..ef2794fd28b65 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -4276,21 +4276,32 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
struct inode *inode, int log_inode_only,
u64 logged_isize)
{
+ u64 gen = BTRFS_I(inode)->generation;
u64 flags;
if (log_inode_only) {
- /* set the generation to zero so the recover code
- * can tell the difference between an logging
- * just to say 'this inode exists' and a logging
- * to say 'update this inode with these values'
+ /*
+ * Set the generation to zero so the recover code can tell the
+ * difference between a logging just to say 'this inode exists'
+ * and a logging to say 'update this inode with these values'.
+ * But only if the inode was not already logged before.
+ * We access ->logged_trans directly since it was already set
+ * up in the call chain by btrfs_log_inode(), and data_race()
+ * to avoid false alerts from KCSAN and since it was set already
+ * and one can set it to 0 since that only happens on eviction
+ * and we are holding a ref on the inode.
*/
- btrfs_set_inode_generation(leaf, item, 0);
+ ASSERT(data_race(BTRFS_I(inode)->logged_trans) > 0);
+ if (data_race(BTRFS_I(inode)->logged_trans) < trans->transid)
+ gen = 0;
+
btrfs_set_inode_size(leaf, item, logged_isize);
} else {
- btrfs_set_inode_generation(leaf, item, BTRFS_I(inode)->generation);
btrfs_set_inode_size(leaf, item, inode->i_size);
}
+ btrfs_set_inode_generation(leaf, item, gen);
+
btrfs_set_inode_uid(leaf, item, i_uid_read(inode));
btrfs_set_inode_gid(leaf, item, i_gid_read(inode));
btrfs_set_inode_mode(leaf, item, inode->i_mode);
@@ -5100,42 +5111,63 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
return 0;
}
-static int logged_inode_size(struct btrfs_root *log, struct btrfs_inode *inode,
- struct btrfs_path *path, u64 *size_ret)
+static int get_inode_size_to_log(struct btrfs_trans_handle *trans,
+ struct btrfs_inode *inode,
+ struct btrfs_path *path, u64 *size_ret)
{
struct btrfs_key key;
+ struct btrfs_inode_item *item;
int ret;
key.objectid = btrfs_ino(inode);
key.type = BTRFS_INODE_ITEM_KEY;
key.offset = 0;
- ret = btrfs_search_slot(NULL, log, &key, path, 0, 0);
- if (ret < 0) {
- return ret;
- } else if (ret > 0) {
- *size_ret = 0;
- } else {
- struct btrfs_inode_item *item;
+ /*
+ * Our caller called inode_logged(), so logged_trans is up to date.
+ * Use data_race() to silence any warning from KCSAN. Once logged_trans
+ * is set, it can only be reset to 0 after inode eviction.
+ */
+ if (data_race(inode->logged_trans) == trans->transid) {
+ ret = btrfs_search_slot(NULL, inode->root->log_root, &key, path, 0, 0);
+ } else if (inode->generation < trans->transid) {
+ path->search_commit_root = true;
+ path->skip_locking = true;
+ ret = btrfs_search_slot(NULL, inode->root, &key, path, 0, 0);
+ path->search_commit_root = false;
+ path->skip_locking = false;
- item = btrfs_item_ptr(path->nodes[0], path->slots[0],
- struct btrfs_inode_item);
- *size_ret = btrfs_inode_size(path->nodes[0], item);
- /*
- * If the in-memory inode's i_size is smaller then the inode
- * size stored in the btree, return the inode's i_size, so
- * that we get a correct inode size after replaying the log
- * when before a power failure we had a shrinking truncate
- * followed by addition of a new name (rename / new hard link).
- * Otherwise return the inode size from the btree, to avoid
- * data loss when replaying a log due to previously doing a
- * write that expands the inode's size and logging a new name
- * immediately after.
- */
- if (*size_ret > inode->vfs_inode.i_size)
- *size_ret = inode->vfs_inode.i_size;
+ } else {
+ *size_ret = 0;
+ return 0;
}
+ /*
+ * If the inode was logged before or is from a past transaction, then
+ * its inode item must exist in the log root or in the commit root.
+ */
+ ASSERT(ret <= 0);
+ if (WARN_ON_ONCE(ret > 0))
+ ret = -ENOENT;
+
+ if (ret < 0)
+ return ret;
+
+ item = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_inode_item);
+ *size_ret = btrfs_inode_size(path->nodes[0], item);
+ /*
+ * If the in-memory inode's i_size is smaller then the inode size stored
+ * in the btree, return the inode's i_size, so that we get a correct
+ * inode size after replaying the log when before a power failure we had
+ * a shrinking truncate followed by addition of a new name (rename / new
+ * hard link). Otherwise return the inode size from the btree, to avoid
+ * data loss when replaying a log due to previously doing a write that
+ * expands the inode's size and logging a new name immediately after.
+ */
+ if (*size_ret > inode->vfs_inode.i_size)
+ *size_ret = inode->vfs_inode.i_size;
+
btrfs_release_path(path);
return 0;
}
@@ -6653,7 +6685,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
ret = drop_inode_items(trans, log, path, inode,
BTRFS_XATTR_ITEM_KEY);
} else {
- if (inode_only == LOG_INODE_EXISTS && ctx->logged_before) {
+ if (inode_only == LOG_INODE_EXISTS) {
/*
* Make sure the new inode item we write to the log has
* the same isize as the current one (if it exists).
@@ -6667,7 +6699,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
* (zeroes), as if an expanding truncate happened,
* instead of getting a file of 4Kb only.
*/
- ret = logged_inode_size(log, inode, path, &logged_isize);
+ ret = get_inode_size_to_log(trans, inode, path, &logged_isize);
if (ret)
goto out_unlock;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 238/869] fs/ntfs3: Accumulated refactoring changes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (236 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 237/869] btrfs: fix zero size inode with non-zero size after log replay Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 239/869] ntfs3: fix circular locking dependency in run_unpack_ex Greg Kroah-Hartman
` (631 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Konstantin Komarov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
[ Upstream commit bac89bb33d91cdd75092e15cf59fe6be34571142 ]
Changes made to improve readability and debuggability.
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Stable-dep-of: 08ce2fee1b86 ("ntfs3: fix circular locking dependency in run_unpack_ex")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ntfs3/bitmap.c | 62 +++++++++++++---------------------------------
fs/ntfs3/frecord.c | 1 -
fs/ntfs3/fsntfs.c | 2 +-
fs/ntfs3/run.c | 6 ++---
4 files changed, 21 insertions(+), 50 deletions(-)
diff --git a/fs/ntfs3/bitmap.c b/fs/ntfs3/bitmap.c
index 29b585f443f3e..65d05e6a05665 100644
--- a/fs/ntfs3/bitmap.c
+++ b/fs/ntfs3/bitmap.c
@@ -710,20 +710,17 @@ int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits)
{
int err = 0;
struct super_block *sb = wnd->sb;
- size_t bits0 = bits;
u32 wbits = 8 * sb->s_blocksize;
size_t iw = bit >> (sb->s_blocksize_bits + 3);
u32 wbit = bit & (wbits - 1);
struct buffer_head *bh;
+ u32 op;
- while (iw < wnd->nwnd && bits) {
- u32 tail, op;
-
+ for (; iw < wnd->nwnd && bits; iw++, bit += op, bits -= op, wbit = 0) {
if (iw + 1 == wnd->nwnd)
wbits = wnd->bits_last;
- tail = wbits - wbit;
- op = min_t(u32, tail, bits);
+ op = min_t(u32, wbits - wbit, bits);
bh = wnd_map(wnd, iw);
if (IS_ERR(bh)) {
@@ -736,20 +733,15 @@ int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits)
ntfs_bitmap_clear_le(bh->b_data, wbit, op);
wnd->free_bits[iw] += op;
+ wnd->total_zeroes += op;
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
unlock_buffer(bh);
put_bh(bh);
- wnd->total_zeroes += op;
- bits -= op;
- wbit = 0;
- iw += 1;
+ wnd_add_free_ext(wnd, bit, op, false);
}
-
- wnd_add_free_ext(wnd, bit, bits0, false);
-
return err;
}
@@ -760,20 +752,17 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
{
int err = 0;
struct super_block *sb = wnd->sb;
- size_t bits0 = bits;
size_t iw = bit >> (sb->s_blocksize_bits + 3);
u32 wbits = 8 * sb->s_blocksize;
u32 wbit = bit & (wbits - 1);
struct buffer_head *bh;
+ u32 op;
- while (iw < wnd->nwnd && bits) {
- u32 tail, op;
-
+ for (; iw < wnd->nwnd && bits; iw++, bit += op, bits -= op, wbit = 0) {
if (unlikely(iw + 1 == wnd->nwnd))
wbits = wnd->bits_last;
- tail = wbits - wbit;
- op = min_t(u32, tail, bits);
+ op = min_t(u32, wbits - wbit, bits);
bh = wnd_map(wnd, iw);
if (IS_ERR(bh)) {
@@ -785,21 +774,16 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
ntfs_bitmap_set_le(bh->b_data, wbit, op);
wnd->free_bits[iw] -= op;
+ wnd->total_zeroes -= op;
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
unlock_buffer(bh);
put_bh(bh);
- wnd->total_zeroes -= op;
- bits -= op;
- wbit = 0;
- iw += 1;
+ if (!RB_EMPTY_ROOT(&wnd->start_tree))
+ wnd_remove_free_ext(wnd, bit, op);
}
-
- if (!RB_EMPTY_ROOT(&wnd->start_tree))
- wnd_remove_free_ext(wnd, bit, bits0);
-
return err;
}
@@ -852,15 +836,13 @@ static bool wnd_is_free_hlp(struct wnd_bitmap *wnd, size_t bit, size_t bits)
size_t iw = bit >> (sb->s_blocksize_bits + 3);
u32 wbits = 8 * sb->s_blocksize;
u32 wbit = bit & (wbits - 1);
+ u32 op;
- while (iw < wnd->nwnd && bits) {
- u32 tail, op;
-
+ for (; iw < wnd->nwnd && bits; iw++, bits -= op, wbit = 0) {
if (unlikely(iw + 1 == wnd->nwnd))
wbits = wnd->bits_last;
- tail = wbits - wbit;
- op = min_t(u32, tail, bits);
+ op = min_t(u32, wbits - wbit, bits);
if (wbits != wnd->free_bits[iw]) {
bool ret;
@@ -875,10 +857,6 @@ static bool wnd_is_free_hlp(struct wnd_bitmap *wnd, size_t bit, size_t bits)
if (!ret)
return false;
}
-
- bits -= op;
- wbit = 0;
- iw += 1;
}
return true;
@@ -928,6 +906,7 @@ bool wnd_is_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
size_t iw = bit >> (sb->s_blocksize_bits + 3);
u32 wbits = 8 * sb->s_blocksize;
u32 wbit = bit & (wbits - 1);
+ u32 op;
size_t end;
struct rb_node *n;
struct e_node *e;
@@ -945,14 +924,11 @@ bool wnd_is_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
return false;
use_wnd:
- while (iw < wnd->nwnd && bits) {
- u32 tail, op;
-
+ for (; iw < wnd->nwnd && bits; iw++, bits -= op, wbit = 0) {
if (unlikely(iw + 1 == wnd->nwnd))
wbits = wnd->bits_last;
- tail = wbits - wbit;
- op = min_t(u32, tail, bits);
+ op = min_t(u32, wbits - wbit, bits);
if (wnd->free_bits[iw]) {
bool ret;
@@ -966,10 +942,6 @@ bool wnd_is_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
if (!ret)
goto out;
}
-
- bits -= op;
- wbit = 0;
- iw += 1;
}
ret = true;
diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c
index 45e8d73d38f8f..ab8615abb981b 100644
--- a/fs/ntfs3/frecord.c
+++ b/fs/ntfs3/frecord.c
@@ -1977,7 +1977,6 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
if (end > alloc_size)
end = alloc_size;
-
while (vbo < end) {
if (idx == -1) {
ok = run_lookup_entry(&run, vcn, &lcn, &clen, &idx);
diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c
index 170836749de68..c9ff8293fea73 100644
--- a/fs/ntfs3/fsntfs.c
+++ b/fs/ntfs3/fsntfs.c
@@ -2716,4 +2716,4 @@ int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len)
out:
kfree(uni);
return err;
-}
\ No newline at end of file
+}
diff --git a/fs/ntfs3/run.c b/fs/ntfs3/run.c
index 12f93f5a3d9bc..18b8767acba5f 100644
--- a/fs/ntfs3/run.c
+++ b/fs/ntfs3/run.c
@@ -1133,9 +1133,9 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
err = wnd_set_used_safe(wnd, lcn, len, &done);
if (zone) {
/* Restore zone. Lock mft run. */
- struct rw_semaphore *lock;
- lock = is_mounted(sbi) ? &sbi->mft.ni->file.run_lock :
- NULL;
+ struct rw_semaphore *lock =
+ is_mounted(sbi) ? &sbi->mft.ni->file.run_lock :
+ NULL;
if (lock)
down_read(lock);
ntfs_refresh_zone(sbi);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 239/869] ntfs3: fix circular locking dependency in run_unpack_ex
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (237 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 238/869] fs/ntfs3: Accumulated refactoring changes Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 240/869] wifi: iwlwifi: fix 22000 series SMEM parsing Greg Kroah-Hartman
` (630 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+d27edf9f96ae85939222,
Szymon Wilczek, Konstantin Komarov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Szymon Wilczek <swilczek.lx@gmail.com>
[ Upstream commit 08ce2fee1b869ecbfbd94e0eb2630e52203a2e03 ]
Syzbot reported a circular locking dependency between wnd->rw_lock
(sbi->used.bitmap) and ni->file.run_lock.
The deadlock scenario:
1. ntfs_extend_mft() takes ni->file.run_lock then wnd->rw_lock.
2. run_unpack_ex() takes wnd->rw_lock then tries to acquire
ni->file.run_lock inside ntfs_refresh_zone().
This creates an AB-BA deadlock.
Fix this by using down_read_trylock() instead of down_read() when
acquiring run_lock in run_unpack_ex(). If the lock is contended,
skip ntfs_refresh_zone() - the MFT zone will be refreshed on the
next MFT operation. This breaks the circular dependency since we
never block waiting for run_lock while holding wnd->rw_lock.
Reported-by: syzbot+d27edf9f96ae85939222@syzkaller.appspotmail.com
Tested-by: syzbot+d27edf9f96ae85939222@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d27edf9f96ae85939222
Signed-off-by: Szymon Wilczek <swilczek.lx@gmail.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ntfs3/run.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/fs/ntfs3/run.c b/fs/ntfs3/run.c
index 18b8767acba5f..66baaada02e9a 100644
--- a/fs/ntfs3/run.c
+++ b/fs/ntfs3/run.c
@@ -1136,11 +1136,14 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
struct rw_semaphore *lock =
is_mounted(sbi) ? &sbi->mft.ni->file.run_lock :
NULL;
- if (lock)
- down_read(lock);
- ntfs_refresh_zone(sbi);
- if (lock)
- up_read(lock);
+ if (lock) {
+ if (down_read_trylock(lock)) {
+ ntfs_refresh_zone(sbi);
+ up_read(lock);
+ }
+ } else {
+ ntfs_refresh_zone(sbi);
+ }
}
up_write(&wnd->rw_lock);
if (err)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 240/869] wifi: iwlwifi: fix 22000 series SMEM parsing
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (238 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 239/869] ntfs3: fix circular locking dependency in run_unpack_ex Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 241/869] ksmbd: fix signededness bug in smb_direct_prepare_negotiation() Greg Kroah-Hartman
` (629 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johannes Berg, Miri Korenblit,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Berg <johannes.berg@intel.com>
[ Upstream commit 58192b9ce09b0f0f86e2036683bd542130b91a98 ]
If the firmware were to report three LMACs (which doesn't
exist in hardware) then using "fwrt->smem_cfg.lmac[2]" is
an overrun of the array. Reject such and use IWL_FW_CHECK
instead of WARN_ON in this function.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20251110150012.16e8c2d70c26.Iadfcc1aedf43c5175b3f0757bea5aa232454f1ac@changeid
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/intel/iwlwifi/fw/smem.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/smem.c b/drivers/net/wireless/intel/iwlwifi/fw/smem.c
index 3f1272014dafb..50ebc81a3748c 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/smem.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/smem.c
@@ -6,6 +6,7 @@
*/
#include "iwl-drv.h"
#include "runtime.h"
+#include "dbg.h"
#include "fw/api/commands.h"
static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt,
@@ -17,7 +18,9 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt,
u8 api_ver = iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP,
SHARED_MEM_CFG_CMD, 0);
- if (WARN_ON(lmac_num > ARRAY_SIZE(mem_cfg->lmac_smem)))
+ /* Note: notification has 3 entries, but we only expect 2 */
+ if (IWL_FW_CHECK(fwrt, lmac_num > ARRAY_SIZE(fwrt->smem_cfg.lmac),
+ "FW advertises %d LMACs\n", lmac_num))
return;
fwrt->smem_cfg.num_lmacs = lmac_num;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 241/869] ksmbd: fix signededness bug in smb_direct_prepare_negotiation()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (239 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 240/869] wifi: iwlwifi: fix 22000 series SMEM parsing Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 242/869] drm/amd/display: Adjust PHY FSM transition to TX_EN-to-PLL_ON for TMDS on DCN35 Greg Kroah-Hartman
` (628 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini, Stefan Metzmacher,
Namjae Jeon, Steve French, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicholas Carlini <nicholas@carlini.com>
[ Upstream commit 6b4f875aac344cdd52a1f34cc70ed2f874a65757 ]
smb_direct_prepare_negotiation() casts an unsigned __u32 value
from sp->max_recv_size and req->preferred_send_size to a signed
int before computing min_t(int, ...). A maliciously provided
preferred_send_size of 0x80000000 will return as smaller than
max_recv_size, and then be used to set the maximum allowed
alowed receive size for the next message.
By sending a second message with a large value (>1420 bytes)
the attacker can then achieve a heap buffer overflow.
This fix replaces min_t(int, ...) with min_t(u32)
Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers")
Signed-off-by: Nicholas Carlini <nicholas@carlini.com>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
Acked-by: Stefan Metzmacher <metze@samba.org>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/transport_rdma.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c
index 3976009596d99..585617595727b 100644
--- a/fs/smb/server/transport_rdma.c
+++ b/fs/smb/server/transport_rdma.c
@@ -1977,9 +1977,9 @@ static int smb_direct_prepare(struct ksmbd_transport *t)
goto out;
req = (struct smb_direct_negotiate_req *)recvmsg->packet;
- st->max_recv_size = min_t(int, st->max_recv_size,
+ st->max_recv_size = min_t(u32, st->max_recv_size,
le32_to_cpu(req->preferred_send_size));
- st->max_send_size = min_t(int, st->max_send_size,
+ st->max_send_size = min_t(u32, st->max_send_size,
le32_to_cpu(req->max_receive_size));
st->max_fragmented_send_size =
le32_to_cpu(req->max_fragmented_size);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 242/869] drm/amd/display: Adjust PHY FSM transition to TX_EN-to-PLL_ON for TMDS on DCN35
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (240 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 241/869] ksmbd: fix signededness bug in smb_direct_prepare_negotiation() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 243/869] ASoC: qcom: q6asm: handle the responses after closing Greg Kroah-Hartman
` (627 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yihan Zhu, Nicholas Kazlauskas,
Matthew Stewart, Dan Wheeler, Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
[ Upstream commit 75372d75a4e23783583998ed99d5009d555850da ]
[Why]
A backport of the change made for DCN401 that addresses an issue where
we turn off the PHY PLL when disabling TMDS output, which causes the
OTG to remain stuck.
The OTG being stuck can lead to a hang in the DCHVM's ability to ACK
invalidations when it thinks the HUBP is still on but it's not receiving
global sync.
The transition to PLL_ON needs to be atomic as there's no guarantee
that the thread isn't pre-empted or is able to complete before the
IOMMU watchdog times out.
[How]
Backport the implementation from dcn401 back to dcn35.
There's a functional difference in when the eDP output is disabled in
dcn401 code so we don't want to utilize it directly.
Reviewed-by: Yihan Zhu <yihan.zhu@amd.com>
Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: Matthew Stewart <matthew.stewart2@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 52 +++++++++++++++++++
.../amd/display/dc/hwss/dcn35/dcn35_hwseq.h | 4 ++
.../amd/display/dc/hwss/dcn35/dcn35_init.c | 2 +-
3 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
index c739e5b2c5595..0745980483898 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
@@ -1617,3 +1617,55 @@ bool dcn35_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx)
return false;
}
+
+static void disable_link_output_symclk_on_tx_off(struct dc_link *link, enum dp_link_encoding link_encoding)
+{
+ struct dc *dc = link->ctx->dc;
+ struct pipe_ctx *pipe_ctx = NULL;
+ uint8_t i;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
+ if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) {
+ pipe_ctx->clock_source->funcs->program_pix_clk(
+ pipe_ctx->clock_source,
+ &pipe_ctx->stream_res.pix_clk_params,
+ link_encoding,
+ &pipe_ctx->pll_settings);
+ break;
+ }
+ }
+}
+
+void dcn35_disable_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal)
+{
+ struct dc *dc = link->ctx->dc;
+ const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+ struct dmcu *dmcu = dc->res_pool->dmcu;
+
+ if (signal == SIGNAL_TYPE_EDP &&
+ link->dc->hwss.edp_backlight_control &&
+ !link->skip_implict_edp_power_control)
+ link->dc->hwss.edp_backlight_control(link, false);
+ else if (dmcu != NULL && dmcu->funcs->lock_phy)
+ dmcu->funcs->lock_phy(dmcu);
+
+ if (dc_is_tmds_signal(signal) && link->phy_state.symclk_ref_cnts.otg > 0) {
+ disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING);
+ link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
+ } else {
+ link_hwss->disable_link_output(link, link_res, signal);
+ link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
+ }
+ /*
+ * Add the logic to extract BOTH power up and power down sequences
+ * from enable/disable link output and only call edp panel control
+ * in enable_link_dp and disable_link_dp once.
+ */
+ if (dmcu != NULL && dmcu->funcs->unlock_phy)
+ dmcu->funcs->unlock_phy(dmcu);
+
+ dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
index e27b3609020ff..45e762f99119f 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
@@ -99,4 +99,8 @@ void dcn35_set_long_vblank(struct pipe_ctx **pipe_ctx,
bool dcn35_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx);
+void dcn35_disable_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal);
+
#endif /* __DC_HWSS_DCN35_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
index 2bbf1fef94fd2..e34f292f5c41a 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
@@ -107,7 +107,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
.enable_lvds_link_output = dce110_enable_lvds_link_output,
.enable_tmds_link_output = dce110_enable_tmds_link_output,
.enable_dp_link_output = dce110_enable_dp_link_output,
- .disable_link_output = dcn32_disable_link_output,
+ .disable_link_output = dcn35_disable_link_output,
.z10_restore = dcn35_z10_restore,
.z10_save_init = dcn31_z10_save_init,
.set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 243/869] ASoC: qcom: q6asm: handle the responses after closing
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (241 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 242/869] drm/amd/display: Adjust PHY FSM transition to TX_EN-to-PLL_ON for TMDS on DCN35 Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 244/869] ASoC: qcom: q6asm: drop DSP responses for closed data streams Greg Kroah-Hartman
` (626 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Martino Facchin, Srinivas Kandagatla,
Mark Brown, Sasha Levin, Alexey Klimov
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
[ Upstream commit a354f030dbce17ab3cf299660a38b162d97f7151 ]
For record path, multiple read requests are queued to dsp in advance.
However when data stream is closed, the pending read requests are rejected
by the dsp and a response is sent to the driver, this case is not handled
in the driver resulting in errors like below
q6asm-dai ab00000.remoteproc:glink-edge:apr:service@7:dais: command[0x10dac] not expecting rsp
q6asm-dai ab00000.remoteproc:glink-edge:apr:service@7:dais: command[0x10dac] not expecting rsp
q6asm-dai ab00000.remoteproc:glink-edge:apr:service@7:dais: command[0x10dac] not expecting rsp
This is same for both write and eos.
Fix this by allowing ASM_DATA_CMD_READ_V2, ASM_DATA_CMD_EOS and
ASM_DATA_CMD_WRITE_V2 as expected response.
Reported-by: Martino Facchin <m.facchin@arduino.cc>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
Tested-by: Alexey Klimov <alexey.klimov@linaro.org> # RB5, RB3
Link: https://patch.msgid.link/20251023102444.88158-6-srinivas.kandagatla@oss.qualcomm.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Stable-dep-of: 8a066a81ee0c ("ASoC: qcom: q6asm: drop DSP responses for closed data streams")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/soc/qcom/qdsp6/q6asm.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index 67e9ca18883cd..4c3315d4e27da 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -638,6 +638,7 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE;
break;
case ASM_STREAM_CMD_OPEN_WRITE_V3:
+ case ASM_DATA_CMD_WRITE_V2:
case ASM_STREAM_CMD_OPEN_READ_V3:
case ASM_STREAM_CMD_OPEN_READWRITE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
@@ -654,6 +655,10 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
goto done;
}
break;
+ case ASM_DATA_CMD_EOS:
+ case ASM_DATA_CMD_READ_V2:
+ /* response as result of close stream */
+ break;
default:
dev_err(ac->dev, "command[0x%x] not expecting rsp\n",
result->opcode);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 244/869] ASoC: qcom: q6asm: drop DSP responses for closed data streams
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (242 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 243/869] ASoC: qcom: q6asm: handle the responses after closing Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 245/869] wifi: rtw89: pci: validate sequence number of TX release report Greg Kroah-Hartman
` (625 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Cédric Bellegarde, Mark Brown,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cédric Bellegarde <cedric.bellegarde@adishatz.org>
[ Upstream commit 8a066a81ee0c1b6cdbd81393536c3b2d19ccef25 ]
'Commit a354f030dbce ("ASoC: qcom: q6asm: handle the responses
after closing")' attempted to ignore DSP responses arriving
after a stream had been closed.
However, those responses were still handled, causing lockups.
Fix this by unconditionally dropping all DSP responses associated with
closed data streams.
Signed-off-by: Cédric Bellegarde <cedric.bellegarde@adishatz.org>
Link: https://patch.msgid.link/20260102215225.609166-1-cedric.bellegarde@adishatz.org
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/soc/qcom/qdsp6/q6asm.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index 4c3315d4e27da..60c81edd945d5 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -638,7 +638,6 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE;
break;
case ASM_STREAM_CMD_OPEN_WRITE_V3:
- case ASM_DATA_CMD_WRITE_V2:
case ASM_STREAM_CMD_OPEN_READ_V3:
case ASM_STREAM_CMD_OPEN_READWRITE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
@@ -657,8 +656,9 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
break;
case ASM_DATA_CMD_EOS:
case ASM_DATA_CMD_READ_V2:
+ case ASM_DATA_CMD_WRITE_V2:
/* response as result of close stream */
- break;
+ goto done;
default:
dev_err(ac->dev, "command[0x%x] not expecting rsp\n",
result->opcode);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 245/869] wifi: rtw89: pci: validate sequence number of TX release report
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (243 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 244/869] ASoC: qcom: q6asm: drop DSP responses for closed data streams Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 246/869] team: avoid NETDEV_CHANGEMTU event when unregistering slave Greg Kroah-Hartman
` (624 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Ping-Ke Shih, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ping-Ke Shih <pkshih@realtek.com>
[ Upstream commit 957eda596c7665f2966970fd1dcc35fe299b38e8 ]
Hardware rarely reports abnormal sequence number in TX release report,
which will access out-of-bounds of wd_ring->pages array, causing NULL
pointer dereference.
BUG: kernel NULL pointer dereference, address: 0000000000000000
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: 0000 [#1] PREEMPT SMP NOPTI
CPU: 1 PID: 1085 Comm: irq/129-rtw89_p Tainted: G S U
6.1.145-17510-g2f3369c91536 #1 (HASH:69e8 1)
Call Trace:
<IRQ>
rtw89_pci_release_tx+0x18f/0x300 [rtw89_pci (HASH:4c83 2)]
rtw89_pci_napi_poll+0xc2/0x190 [rtw89_pci (HASH:4c83 2)]
net_rx_action+0xfc/0x460 net/core/dev.c:6578 net/core/dev.c:6645 net/core/dev.c:6759
handle_softirqs+0xbe/0x290 kernel/softirq.c:601
? rtw89_pci_interrupt_threadfn+0xc5/0x350 [rtw89_pci (HASH:4c83 2)]
__local_bh_enable_ip+0xeb/0x120 kernel/softirq.c:499 kernel/softirq.c:423
</IRQ>
<TASK>
rtw89_pci_interrupt_threadfn+0xf8/0x350 [rtw89_pci (HASH:4c83 2)]
? irq_thread+0xa7/0x340 kernel/irq/manage.c:0
irq_thread+0x177/0x340 kernel/irq/manage.c:1205 kernel/irq/manage.c:1314
? thaw_kernel_threads+0xb0/0xb0 kernel/irq/manage.c:1202
? irq_forced_thread_fn+0x80/0x80 kernel/irq/manage.c:1220
kthread+0xea/0x110 kernel/kthread.c:376
? synchronize_irq+0x1a0/0x1a0 kernel/irq/manage.c:1287
? kthread_associate_blkcg+0x80/0x80 kernel/kthread.c:331
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:295
</TASK>
To prevent crash, validate rpp_info.seq before using.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20260110022019.2254969-2-pkshih@realtek.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/realtek/rtw89/pci.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index 43285d341870e..d24dcbf26caa9 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -578,11 +578,16 @@ static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev,
tx_status = le32_get_bits(rpp->dword, RTW89_PCI_RPP_TX_STATUS);
txch = rtw89_core_get_ch_dma(rtwdev, qsel);
- if (txch == RTW89_TXCH_CH12) {
+ if (unlikely(txch == RTW89_TXCH_CH12)) {
rtw89_warn(rtwdev, "should no fwcmd release report\n");
return;
}
+ if (unlikely(seq >= RTW89_PCI_TXWD_NUM_MAX)) {
+ rtw89_warn(rtwdev, "invalid seq %d\n", seq);
+ return;
+ }
+
tx_ring = &rtwpci->tx_rings[txch];
wd_ring = &tx_ring->wd_ring;
txwd = &wd_ring->pages[seq];
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 246/869] team: avoid NETDEV_CHANGEMTU event when unregistering slave
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (244 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 245/869] wifi: rtw89: pci: validate sequence number of TX release report Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 247/869] media: chips-media: wave5: Fix Null reference while testing fluster Greg Kroah-Hartman
` (623 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+881d65229ca4f9ae8c84,
Ido Schimmel, Jiri Pirko, Tetsuo Handa, Stanislav Fomichev,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
[ Upstream commit bb4c698633c0e19717586a6524a33196cff01a32 ]
syzbot is reporting
unregister_netdevice: waiting for netdevsim0 to become free. Usage count = 3
ref_tracker: netdev@ffff88807dcf8618 has 1/2 users at
__netdev_tracker_alloc include/linux/netdevice.h:4400 [inline]
netdev_hold include/linux/netdevice.h:4429 [inline]
inetdev_init+0x201/0x4e0 net/ipv4/devinet.c:286
inetdev_event+0x251/0x1610 net/ipv4/devinet.c:1600
notifier_call_chain+0x19d/0x3a0 kernel/notifier.c:85
call_netdevice_notifiers_mtu net/core/dev.c:2318 [inline]
netif_set_mtu_ext+0x5aa/0x800 net/core/dev.c:9886
netif_set_mtu+0xd7/0x1b0 net/core/dev.c:9907
dev_set_mtu+0x126/0x260 net/core/dev_api.c:248
team_port_del+0xb07/0xcb0 drivers/net/team/team_core.c:1333
team_del_slave drivers/net/team/team_core.c:1936 [inline]
team_device_event+0x207/0x5b0 drivers/net/team/team_core.c:2929
notifier_call_chain+0x19d/0x3a0 kernel/notifier.c:85
call_netdevice_notifiers_extack net/core/dev.c:2281 [inline]
call_netdevice_notifiers net/core/dev.c:2295 [inline]
__dev_change_net_namespace+0xcb7/0x2050 net/core/dev.c:12592
do_setlink+0x2ce/0x4590 net/core/rtnetlink.c:3060
rtnl_changelink net/core/rtnetlink.c:3776 [inline]
__rtnl_newlink net/core/rtnetlink.c:3935 [inline]
rtnl_newlink+0x15a9/0x1be0 net/core/rtnetlink.c:4072
rtnetlink_rcv_msg+0x7d5/0xbe0 net/core/rtnetlink.c:6958
netlink_rcv_skb+0x232/0x4b0 net/netlink/af_netlink.c:2550
netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
netlink_unicast+0x80f/0x9b0 net/netlink/af_netlink.c:1344
netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1894
problem. Ido Schimmel found steps to reproduce
ip link add name team1 type team
ip link add name dummy1 mtu 1499 master team1 type dummy
ip netns add ns1
ip link set dev dummy1 netns ns1
ip -n ns1 link del dev dummy1
and also found that the same issue was fixed in the bond driver in
commit f51048c3e07b ("bonding: avoid NETDEV_CHANGEMTU event when
unregistering slave").
Let's do similar thing for the team driver, with commit ad7c7b2172c3 ("net:
hold netdev instance lock during sysfs operations") and commit 303a8487a657
("net: s/__dev_set_mtu/__netif_set_mtu/") also applied.
Reported-by: syzbot+881d65229ca4f9ae8c84@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=881d65229ca4f9ae8c84
Suggested-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Fixes: 3d249d4ca7d0 ("net: introduce ethernet teaming device")
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20260224125709.317574-2-idosch@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/team/team_core.c | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index 0cdcff2537c8f..a83f996f0f2e7 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -1365,7 +1365,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
static void __team_port_change_port_removed(struct team_port *port);
-static int team_port_del(struct team *team, struct net_device *port_dev)
+static int team_port_del(struct team *team, struct net_device *port_dev, bool unregister)
{
struct net_device *dev = team->dev;
struct team_port *port;
@@ -1403,7 +1403,10 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
__team_port_change_port_removed(port);
team_port_set_orig_dev_addr(port);
- dev_set_mtu(port_dev, port->orig.mtu);
+ if (unregister)
+ __dev_set_mtu(port_dev, port->orig.mtu);
+ else
+ dev_set_mtu(port_dev, port->orig.mtu);
kfree_rcu(port, rcu);
netdev_info(dev, "Port device %s removed\n", portname);
__team_compute_features(team);
@@ -1708,7 +1711,7 @@ static void team_uninit(struct net_device *dev)
mutex_lock(&team->lock);
list_for_each_entry_safe(port, tmp, &team->port_list, list)
- team_port_del(team, port->dev);
+ team_port_del(team, port->dev, false);
__team_change_mode(team, NULL); /* cleanup */
__team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
@@ -2019,13 +2022,14 @@ static int team_add_slave(struct net_device *dev, struct net_device *port_dev,
return err;
}
-static int team_del_slave(struct net_device *dev, struct net_device *port_dev)
+static int __team_del_slave(struct net_device *dev, struct net_device *port_dev,
+ bool unregister)
{
struct team *team = netdev_priv(dev);
int err;
mutex_lock(&team->lock);
- err = team_port_del(team, port_dev);
+ err = team_port_del(team, port_dev, unregister);
mutex_unlock(&team->lock);
if (err)
@@ -2041,6 +2045,16 @@ static int team_del_slave(struct net_device *dev, struct net_device *port_dev)
return err;
}
+static int team_del_slave(struct net_device *dev, struct net_device *port_dev)
+{
+ return __team_del_slave(dev, port_dev, false);
+}
+
+static int team_del_slave_on_unregister(struct net_device *dev, struct net_device *port_dev)
+{
+ return __team_del_slave(dev, port_dev, true);
+}
+
static netdev_features_t team_fix_features(struct net_device *dev,
netdev_features_t features)
{
@@ -3082,7 +3096,7 @@ static int team_device_event(struct notifier_block *unused,
!!netif_oper_up(port->dev));
break;
case NETDEV_UNREGISTER:
- team_del_slave(port->team->dev, dev);
+ team_del_slave_on_unregister(port->team->dev, dev);
break;
case NETDEV_FEAT_CHANGE:
if (!port->team->notifier_ctx) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 247/869] media: chips-media: wave5: Fix Null reference while testing fluster
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (245 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 246/869] team: avoid NETDEV_CHANGEMTU event when unregistering slave Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 248/869] ring-buffer: Fix possible dereference of uninitialized pointer Greg Kroah-Hartman
` (622 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jackson Lee, Nas Chung,
Brandon Brnich, Nicolas Dufresne, Hans Verkuil, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jackson Lee <jackson.lee@chipsnmedia.com>
[ Upstream commit e66ff2b08e4ee1c4d3b84f24818e5bcc178cc3a4 ]
When multi instances are created/destroyed, many interrupts happens
and structures for decoder are removed.
"struct vpu_instance" this structure is shared for all flow in the decoder,
so if the structure is not protected by lock, Null dereference
could happens sometimes.
IRQ Handler was spilt to two phases and Lock was added as well.
Fixes: 9707a6254a8a ("media: chips-media: wave5: Add the v4l2 layer")
Cc: stable@vger.kernel.org
Signed-off-by: Jackson Lee <jackson.lee@chipsnmedia.com>
Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
Tested-by: Brandon Brnich <b-brnich@ti.com>
Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../platform/chips-media/wave5/wave5-helper.c | 28 +++++-
.../platform/chips-media/wave5/wave5-helper.h | 1 +
.../chips-media/wave5/wave5-vpu-dec.c | 5 +
.../chips-media/wave5/wave5-vpu-enc.c | 5 +
.../platform/chips-media/wave5/wave5-vpu.c | 97 +++++++++++++++++--
.../platform/chips-media/wave5/wave5-vpuapi.h | 6 ++
6 files changed, 131 insertions(+), 11 deletions(-)
diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c
index d60841c54a802..56914c749c045 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-helper.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c
@@ -25,6 +25,11 @@ const char *state_to_str(enum vpu_instance_state state)
}
}
+int wave5_kfifo_alloc(struct vpu_instance *inst)
+{
+ return kfifo_alloc(&inst->irq_status, 16 * sizeof(int), GFP_KERNEL);
+}
+
void wave5_cleanup_instance(struct vpu_instance *inst)
{
int i;
@@ -47,7 +52,7 @@ void wave5_cleanup_instance(struct vpu_instance *inst)
v4l2_fh_del(&inst->v4l2_fh);
v4l2_fh_exit(&inst->v4l2_fh);
}
- list_del_init(&inst->list);
+ kfifo_free(&inst->irq_status);
ida_free(&inst->dev->inst_ida, inst->id);
kfree(inst->codec_info);
kfree(inst);
@@ -60,8 +65,29 @@ int wave5_vpu_release_device(struct file *filp,
struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data);
struct vpu_device *dev = inst->dev;
int ret = 0;
+ unsigned long flags;
v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
+ /*
+ * To prevent Null reference exception, the existing irq handler were
+ * separated to two modules.
+ * One is to queue interrupt reason into the irq handler,
+ * the other is irq_thread to call the wave5_vpu_dec_finish_decode
+ * to get decoded frame.
+ * The list of instances should be protected between all flow of the
+ * decoding process, but to protect the list in the irq_handler, spin lock
+ * should be used, and mutex should be used in the irq_thread because spin lock
+ * is not able to be used because mutex is already being used
+ * in the wave5_vpu_dec_finish_decode.
+ * So the spin lock and mutex were used to protect the list in the release function.
+ */
+ ret = mutex_lock_interruptible(&inst->dev->irq_lock);
+ if (ret)
+ return ret;
+ spin_lock_irqsave(&inst->dev->irq_spinlock, flags);
+ list_del_init(&inst->list);
+ spin_unlock_irqrestore(&inst->dev->irq_spinlock, flags);
+ mutex_unlock(&inst->dev->irq_lock);
if (inst->state != VPU_INST_STATE_NONE) {
u32 fail_res;
diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.h b/drivers/media/platform/chips-media/wave5/wave5-helper.h
index 6cee1c14d3ce2..f84a0365186aa 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-helper.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-helper.h
@@ -28,4 +28,5 @@ const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx,
const struct vpu_format fmt_list[MAX_FMTS]);
enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type);
void wave5_return_bufs(struct vb2_queue *q, u32 state);
+int wave5_kfifo_alloc(struct vpu_instance *inst);
#endif
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
index fba3d7cc4cca8..19510a363724e 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
@@ -1923,6 +1923,11 @@ static int wave5_vpu_open_dec(struct file *filp)
inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
init_completion(&inst->irq_done);
+ ret = wave5_kfifo_alloc(inst);
+ if (ret) {
+ dev_err(inst->dev->dev, "failed to allocate fifo\n");
+ goto cleanup_inst;
+ }
inst->id = ida_alloc(&inst->dev->inst_ida, GFP_KERNEL);
if (inst->id < 0) {
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
index 0e92eca182365..917264348b554 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
@@ -1705,6 +1705,11 @@ static int wave5_vpu_open_enc(struct file *filp)
inst->frame_rate = 30;
init_completion(&inst->irq_done);
+ ret = wave5_kfifo_alloc(inst);
+ if (ret) {
+ dev_err(inst->dev->dev, "failed to allocate fifo\n");
+ goto cleanup_inst;
+ }
inst->id = ida_alloc(&inst->dev->inst_ida, GFP_KERNEL);
if (inst->id < 0) {
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c
index 4f7eda0504abe..5ec14a7c70c7c 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.c
@@ -50,8 +50,11 @@ static void wave5_vpu_handle_irq(void *dev_id)
u32 seq_done;
u32 cmd_done;
u32 irq_reason;
- struct vpu_instance *inst;
+ u32 irq_subreason;
+ struct vpu_instance *inst, *tmp;
struct vpu_device *dev = dev_id;
+ int val;
+ unsigned long flags;
irq_reason = wave5_vdi_read_register(dev, W5_VPU_VINT_REASON);
seq_done = wave5_vdi_read_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO);
@@ -59,7 +62,8 @@ static void wave5_vpu_handle_irq(void *dev_id)
wave5_vdi_write_register(dev, W5_VPU_VINT_REASON_CLR, irq_reason);
wave5_vdi_write_register(dev, W5_VPU_VINT_CLEAR, 0x1);
- list_for_each_entry(inst, &dev->instances, list) {
+ spin_lock_irqsave(&dev->irq_spinlock, flags);
+ list_for_each_entry_safe(inst, tmp, &dev->instances, list) {
if (irq_reason & BIT(INT_WAVE5_INIT_SEQ) ||
irq_reason & BIT(INT_WAVE5_ENC_SET_PARAM)) {
@@ -81,22 +85,54 @@ static void wave5_vpu_handle_irq(void *dev_id)
irq_reason & BIT(INT_WAVE5_ENC_PIC)) {
if (cmd_done & BIT(inst->id)) {
cmd_done &= ~BIT(inst->id);
- wave5_vdi_write_register(dev, W5_RET_QUEUE_CMD_DONE_INST,
- cmd_done);
- inst->ops->finish_process(inst);
+ if (dev->irq >= 0) {
+ irq_subreason =
+ wave5_vdi_read_register(dev, W5_VPU_VINT_REASON);
+ if (!(irq_subreason & BIT(INT_WAVE5_DEC_PIC)))
+ wave5_vdi_write_register(dev,
+ W5_RET_QUEUE_CMD_DONE_INST,
+ cmd_done);
+ }
+ val = BIT(INT_WAVE5_DEC_PIC);
+ kfifo_in(&inst->irq_status, &val, sizeof(int));
}
}
+ }
+ spin_unlock_irqrestore(&dev->irq_spinlock, flags);
+
+ if (dev->irq < 0)
+ up(&dev->irq_sem);
+}
+
+static irqreturn_t wave5_vpu_irq(int irq, void *dev_id)
+{
+ struct vpu_device *dev = dev_id;
- wave5_vpu_clear_interrupt(inst, irq_reason);
+ if (wave5_vdi_read_register(dev, W5_VPU_VPU_INT_STS)) {
+ wave5_vpu_handle_irq(dev);
+ return IRQ_WAKE_THREAD;
}
+
+ return IRQ_HANDLED;
}
static irqreturn_t wave5_vpu_irq_thread(int irq, void *dev_id)
{
struct vpu_device *dev = dev_id;
+ struct vpu_instance *inst, *tmp;
+ int irq_status, ret;
- if (wave5_vdi_read_register(dev, W5_VPU_VPU_INT_STS))
- wave5_vpu_handle_irq(dev);
+ mutex_lock(&dev->irq_lock);
+ list_for_each_entry_safe(inst, tmp, &dev->instances, list) {
+ while (kfifo_len(&inst->irq_status)) {
+ ret = kfifo_out(&inst->irq_status, &irq_status, sizeof(int));
+ if (!ret)
+ break;
+
+ inst->ops->finish_process(inst);
+ }
+ }
+ mutex_unlock(&dev->irq_lock);
return IRQ_HANDLED;
}
@@ -120,6 +156,35 @@ static enum hrtimer_restart wave5_vpu_timer_callback(struct hrtimer *timer)
return HRTIMER_RESTART;
}
+static int irq_thread(void *data)
+{
+ struct vpu_device *dev = (struct vpu_device *)data;
+ struct vpu_instance *inst, *tmp;
+ int irq_status, ret;
+
+ while (!kthread_should_stop()) {
+ if (down_interruptible(&dev->irq_sem))
+ continue;
+
+ if (kthread_should_stop())
+ break;
+
+ mutex_lock(&dev->irq_lock);
+ list_for_each_entry_safe(inst, tmp, &dev->instances, list) {
+ while (kfifo_len(&inst->irq_status)) {
+ ret = kfifo_out(&inst->irq_status, &irq_status, sizeof(int));
+ if (!ret)
+ break;
+
+ inst->ops->finish_process(inst);
+ }
+ }
+ mutex_unlock(&dev->irq_lock);
+ }
+
+ return 0;
+}
+
static int wave5_vpu_load_firmware(struct device *dev, const char *fw_name,
u32 *revision)
{
@@ -184,6 +249,8 @@ static int wave5_vpu_probe(struct platform_device *pdev)
mutex_init(&dev->dev_lock);
mutex_init(&dev->hw_lock);
+ mutex_init(&dev->irq_lock);
+ spin_lock_init(&dev->irq_spinlock);
dev_set_drvdata(&pdev->dev, dev);
dev->dev = &pdev->dev;
@@ -226,9 +293,13 @@ static int wave5_vpu_probe(struct platform_device *pdev)
}
dev->product = wave5_vpu_get_product_id(dev);
+ INIT_LIST_HEAD(&dev->instances);
+
dev->irq = platform_get_irq(pdev, 0);
if (dev->irq < 0) {
dev_err(&pdev->dev, "failed to get irq resource, falling back to polling\n");
+ sema_init(&dev->irq_sem, 1);
+ dev->irq_thread = kthread_run(irq_thread, dev, "irq thread");
hrtimer_init(&dev->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
dev->hrtimer.function = &wave5_vpu_timer_callback;
dev->worker = kthread_create_worker(0, "vpu_irq_thread");
@@ -240,7 +311,7 @@ static int wave5_vpu_probe(struct platform_device *pdev)
dev->vpu_poll_interval = vpu_poll_interval;
kthread_init_work(&dev->work, wave5_vpu_irq_work_fn);
} else {
- ret = devm_request_threaded_irq(&pdev->dev, dev->irq, NULL,
+ ret = devm_request_threaded_irq(&pdev->dev, dev->irq, wave5_vpu_irq,
wave5_vpu_irq_thread, IRQF_ONESHOT, "vpu_irq", dev);
if (ret) {
dev_err(&pdev->dev, "Register interrupt handler, fail: %d\n", ret);
@@ -248,7 +319,6 @@ static int wave5_vpu_probe(struct platform_device *pdev)
}
}
- INIT_LIST_HEAD(&dev->instances);
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret) {
dev_err(&pdev->dev, "v4l2_device_register, fail: %d\n", ret);
@@ -310,6 +380,12 @@ static void wave5_vpu_remove(struct platform_device *pdev)
v4l2_device_unregister(&dev->v4l2_dev);
if (dev->irq < 0) {
+ if (dev->irq_thread) {
+ kthread_stop(dev->irq_thread);
+ up(&dev->irq_sem);
+ dev->irq_thread = NULL;
+ }
+
hrtimer_cancel(&dev->hrtimer);
kthread_cancel_work_sync(&dev->work);
kthread_destroy_worker(dev->worker);
@@ -317,6 +393,7 @@ static void wave5_vpu_remove(struct platform_device *pdev)
mutex_destroy(&dev->dev_lock);
mutex_destroy(&dev->hw_lock);
+ mutex_destroy(&dev->irq_lock);
reset_control_assert(dev->resets);
clk_bulk_disable_unprepare(dev->num_clks, dev->clks);
wave5_vdi_release(&pdev->dev);
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
index 703b2413dafa1..70b8324bbb789 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
@@ -8,6 +8,7 @@
#ifndef VPUAPI_H_INCLUDED
#define VPUAPI_H_INCLUDED
+#include <linux/kfifo.h>
#include <linux/idr.h>
#include <linux/genalloc.h>
#include <media/v4l2-device.h>
@@ -747,6 +748,7 @@ struct vpu_device {
struct video_device *video_dev_enc;
struct mutex dev_lock; /* lock for the src, dst v4l2 queues */
struct mutex hw_lock; /* lock hw configurations */
+ struct mutex irq_lock;
int irq;
enum product_id product;
struct vpu_attr attr;
@@ -764,7 +766,10 @@ struct vpu_device {
struct kthread_worker *worker;
int vpu_poll_interval;
int num_clks;
+ struct task_struct *irq_thread;
+ struct semaphore irq_sem; /* signal to irq_thread when interrupt happens*/
struct reset_control *resets;
+ spinlock_t irq_spinlock; /* protect instances list */
};
struct vpu_instance;
@@ -788,6 +793,7 @@ struct vpu_instance {
enum v4l2_ycbcr_encoding ycbcr_enc;
enum v4l2_quantization quantization;
+ struct kfifo irq_status;
enum vpu_instance_state state;
enum vpu_instance_type type;
const struct vpu_instance_ops *ops;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 248/869] ring-buffer: Fix possible dereference of uninitialized pointer
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (246 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 247/869] media: chips-media: wave5: Fix Null reference while testing fluster Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 249/869] drm: renesas: rz-du: mipi_dsi: fix kernel panic when rebooting for some panels Greg Kroah-Hartman
` (621 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, kernel test robot, Dan Carpenter,
Masami Hiramatsu (Google), Daniil Dulov, Steven Rostedt (Google),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniil Dulov <d.dulov@aladdin.ru>
[ Upstream commit f1547779402c4cd67755c33616b7203baa88420b ]
There is a pointer head_page in rb_meta_validate_events() which is not
initialized at the beginning of a function. This pointer can be dereferenced
if there is a failure during reader page validation. In this case the control
is passed to "invalid" label where the pointer is dereferenced in a loop.
To fix the issue initialize orig_head and head_page before calling
rb_validate_buffer.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Cc: stable@vger.kernel.org
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Link: https://patch.msgid.link/20260213100130.2013839-1-d.dulov@aladdin.ru
Closes: https://lore.kernel.org/r/202406130130.JtTGRf7W-lkp@intel.com/
Fixes: 5f3b6e839f3c ("ring-buffer: Validate boot range memory events")
Signed-off-by: Daniil Dulov <d.dulov@aladdin.ru>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/trace/ring_buffer.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index c54e7e910b436..ca6a4d0f3ef37 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -1888,6 +1888,8 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
if (!meta || !meta->head_buffer)
return;
+ head_page = cpu_buffer->head_page;
+
/* Do the reader page first */
ret = rb_validate_buffer(cpu_buffer->reader_page->page, cpu_buffer->cpu);
if (ret < 0) {
@@ -1898,8 +1900,6 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
entry_bytes += local_read(&cpu_buffer->reader_page->page->commit);
local_set(&cpu_buffer->reader_page->entries, ret);
- head_page = cpu_buffer->head_page;
-
/* If the commit_buffer is the reader page, update the commit page */
if (meta->commit_buffer == (unsigned long)cpu_buffer->reader_page->page) {
cpu_buffer->commit_page = cpu_buffer->reader_page;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 249/869] drm: renesas: rz-du: mipi_dsi: fix kernel panic when rebooting for some panels
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (247 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 248/869] ring-buffer: Fix possible dereference of uninitialized pointer Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 250/869] drm/amdgpu: Skip vcn poison irq release on VF Greg Kroah-Hartman
` (620 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Biju Das, Hugo Villeneuve,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
[ Upstream commit 64aa8b3a60a825134f7d866adf05c024bbe0c24c ]
Since commit 56de5e305d4b ("clk: renesas: r9a07g044: Add MSTOP for RZ/G2L")
we may get the following kernel panic, for some panels, when rebooting:
systemd-shutdown[1]: Rebooting.
Call trace:
...
do_serror+0x28/0x68
el1h_64_error_handler+0x34/0x50
el1h_64_error+0x6c/0x70
rzg2l_mipi_dsi_host_transfer+0x114/0x458 (P)
mipi_dsi_device_transfer+0x44/0x58
mipi_dsi_dcs_set_display_off_multi+0x9c/0xc4
ili9881c_unprepare+0x38/0x88
drm_panel_unprepare+0xbc/0x108
This happens for panels that need to send MIPI-DSI commands in their
unprepare() callback. Since the MIPI-DSI interface is stopped at that
point, rzg2l_mipi_dsi_host_transfer() triggers the kernel panic.
Fix by moving rzg2l_mipi_dsi_stop() to new callback function
rzg2l_mipi_dsi_atomic_post_disable().
With this change we now have the correct power-down/stop sequence:
systemd-shutdown[1]: Rebooting.
rzg2l-mipi-dsi 10850000.dsi: rzg2l_mipi_dsi_atomic_disable(): entry
ili9881c-dsi 10850000.dsi.0: ili9881c_unprepare(): entry
rzg2l-mipi-dsi 10850000.dsi: rzg2l_mipi_dsi_atomic_post_disable(): entry
reboot: Restarting system
Suggested-by: Biju Das <biju.das.jz@bp.renesas.com>
Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Tested-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://patch.msgid.link/20260112154333.655352-1-hugo@hugovil.com
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index a9216a99b2be1..5b8da2b6cbd0f 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -574,6 +574,13 @@ static void rzg2l_mipi_dsi_atomic_disable(struct drm_bridge *bridge,
rzg2l_mipi_dsi_stop_video(dsi);
rzg2l_mipi_dsi_stop_hs_clock(dsi);
+}
+
+static void rzg2l_mipi_dsi_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
+{
+ struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge);
+
rzg2l_mipi_dsi_stop(dsi);
}
@@ -598,6 +605,7 @@ static const struct drm_bridge_funcs rzg2l_mipi_dsi_bridge_ops = {
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_enable = rzg2l_mipi_dsi_atomic_enable,
.atomic_disable = rzg2l_mipi_dsi_atomic_disable,
+ .atomic_post_disable = rzg2l_mipi_dsi_atomic_post_disable,
.mode_valid = rzg2l_mipi_dsi_bridge_mode_valid,
};
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 250/869] drm/amdgpu: Skip vcn poison irq release on VF
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (248 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 249/869] drm: renesas: rz-du: mipi_dsi: fix kernel panic when rebooting for some panels Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 251/869] btrfs: do not ASSERT() when the fs flips RO inside btrfs_repair_io_failure() Greg Kroah-Hartman
` (619 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lijo Lazar, Mangesh Gadre,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lijo Lazar <lijo.lazar@amd.com>
[ Upstream commit 8980be03b3f9a4b58197ef95d3b37efa41a25331 ]
VF doesn't enable VCN poison irq in VCNv2.5. Skip releasing it and avoid
call trace during deinitialization.
[ 71.913601] [drm] clean up the vf2pf work item
[ 71.915088] ------------[ cut here ]------------
[ 71.915092] WARNING: CPU: 3 PID: 1079 at /tmp/amd.aFkFvSQl/amd/amdgpu/amdgpu_irq.c:641 amdgpu_irq_put+0xc6/0xe0 [amdgpu]
[ 71.915355] Modules linked in: amdgpu(OE-) amddrm_ttm_helper(OE) amdttm(OE) amddrm_buddy(OE) amdxcp(OE) amddrm_exec(OE) amd_sched(OE) amdkcl(OE) drm_suballoc_helper drm_display_helper cec rc_core i2c_algo_bit video wmi binfmt_misc nls_iso8859_1 intel_rapl_msr intel_rapl_common input_leds joydev serio_raw mac_hid qemu_fw_cfg sch_fq_codel dm_multipath scsi_dh_rdac scsi_dh_emc scsi_dh_alua efi_pstore ip_tables x_tables autofs4 btrfs blake2b_generic raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 hid_generic crct10dif_pclmul crc32_pclmul polyval_clmulni polyval_generic ghash_clmulni_intel usbhid 8139too sha256_ssse3 sha1_ssse3 hid psmouse bochs i2c_i801 ahci drm_vram_helper libahci i2c_smbus lpc_ich drm_ttm_helper 8139cp mii ttm aesni_intel crypto_simd cryptd
[ 71.915484] CPU: 3 PID: 1079 Comm: rmmod Tainted: G OE 6.8.0-87-generic #88~22.04.1-Ubuntu
[ 71.915489] Hardware name: Red Hat KVM/RHEL, BIOS 1.16.3-2.el9_5.1 04/01/2014
[ 71.915492] RIP: 0010:amdgpu_irq_put+0xc6/0xe0 [amdgpu]
[ 71.915768] Code: 75 84 b8 ea ff ff ff eb d4 44 89 ea 48 89 de 4c 89 e7 e8 fd fc ff ff 5b 41 5c 41 5d 41 5e 5d 31 d2 31 f6 31 ff e9 55 30 3b c7 <0f> 0b eb d4 b8 fe ff ff ff eb a8 e9 b7 3b 8a 00 66 2e 0f 1f 84 00
[ 71.915771] RSP: 0018:ffffcf0800eafa30 EFLAGS: 00010246
[ 71.915775] RAX: 0000000000000000 RBX: ffff891bda4b0668 RCX: 0000000000000000
[ 71.915777] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
[ 71.915779] RBP: ffffcf0800eafa50 R08: 0000000000000000 R09: 0000000000000000
[ 71.915781] R10: 0000000000000000 R11: 0000000000000000 R12: ffff891bda480000
[ 71.915782] R13: 0000000000000000 R14: 0000000000000001 R15: 0000000000000000
[ 71.915792] FS: 000070cff87c4c40(0000) GS:ffff893abfb80000(0000) knlGS:0000000000000000
[ 71.915795] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 71.915797] CR2: 00005fa13073e478 CR3: 000000010d634006 CR4: 0000000000770ef0
[ 71.915800] PKRU: 55555554
[ 71.915802] Call Trace:
[ 71.915805] <TASK>
[ 71.915809] vcn_v2_5_hw_fini+0x19e/0x1e0 [amdgpu]
Signed-off-by: Lijo Lazar <lijo.lazar@amd.com>
Reviewed-by: Mangesh Gadre <Mangesh.Gadre@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index 42edc91f4a78d..20ef8835b12b1 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -402,7 +402,9 @@ static int vcn_v2_5_hw_fini(void *handle)
RREG32_SOC15(VCN, i, mmUVD_STATUS)))
vcn_v2_5_set_powergating_state(adev, AMD_PG_STATE_GATE);
- if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
+ /* VF doesn't enable interrupt operations for RAS */
+ if (!amdgpu_sriov_vf(adev) &&
+ amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
amdgpu_irq_put(adev, &adev->vcn.inst[i].ras_poison_irq, 0);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 251/869] btrfs: do not ASSERT() when the fs flips RO inside btrfs_repair_io_failure()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (249 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 250/869] drm/amdgpu: Skip vcn poison irq release on VF Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 252/869] btrfs: remove reserved argument from btrfs_pin_extent() Greg Kroah-Hartman
` (618 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christoph Hellwig, Qu Wenruo,
David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <wqu@suse.com>
[ Upstream commit 8ceaad6cd6e7fa5f73b0b2796a2e85d75d37e9f3 ]
[BUG]
There is a bug report that when btrfs hits ENOSPC error in a critical
path, btrfs flips RO (this part is expected, although the ENOSPC bug
still needs to be addressed).
The problem is after the RO flip, if there is a read repair pending, we
can hit the ASSERT() inside btrfs_repair_io_failure() like the following:
BTRFS info (device vdc): relocating block group 30408704 flags metadata|raid1
------------[ cut here ]------------
BTRFS: Transaction aborted (error -28)
WARNING: fs/btrfs/extent-tree.c:3235 at __btrfs_free_extent.isra.0+0x453/0xfd0, CPU#1: btrfs/383844
Modules linked in: kvm_intel kvm irqbypass
[...]
---[ end trace 0000000000000000 ]---
BTRFS info (device vdc state EA): 2 enospc errors during balance
BTRFS info (device vdc state EA): balance: ended with status: -30
BTRFS error (device vdc state EA): parent transid verify failed on logical 30556160 mirror 2 wanted 8 found 6
BTRFS error (device vdc state EA): bdev /dev/nvme0n1 errs: wr 0, rd 0, flush 0, corrupt 10, gen 0
[...]
assertion failed: !(fs_info->sb->s_flags & SB_RDONLY) :: 0, in fs/btrfs/bio.c:938
------------[ cut here ]------------
assertion failed: !(fs_info->sb->s_flags & SB_RDONLY) :: 0, in fs/btrfs/bio.c:938
kernel BUG at fs/btrfs/bio.c:938!
Oops: invalid opcode: 0000 [#1] SMP NOPTI
CPU: 0 UID: 0 PID: 868 Comm: kworker/u8:13 Tainted: G W N 6.19.0-rc6+ #4788 PREEMPT(full)
Tainted: [W]=WARN, [N]=TEST
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014
Workqueue: btrfs-endio simple_end_io_work
RIP: 0010:btrfs_repair_io_failure.cold+0xb2/0x120
RSP: 0000:ffffc90001d2bcf0 EFLAGS: 00010246
RAX: 0000000000000051 RBX: 0000000000001000 RCX: 0000000000000000
RDX: 0000000000000000 RSI: ffffffff8305cf42 RDI: 00000000ffffffff
RBP: 0000000000000002 R08: 00000000fffeffff R09: ffffffff837fa988
R10: ffffffff8327a9e0 R11: 6f69747265737361 R12: ffff88813018d310
R13: ffff888168b8a000 R14: ffffc90001d2bd90 R15: ffff88810a169000
FS: 0000000000000000(0000) GS:ffff8885e752c000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
------------[ cut here ]------------
[CAUSE]
The cause of -ENOSPC error during the test case btrfs/124 is still
unknown, although it's known that we still have cases where metadata can
be over-committed but can not be fulfilled correctly, thus if we hit
such ENOSPC error inside a critical path, we have no choice but abort
the current transaction.
This will mark the fs read-only.
The problem is inside the btrfs_repair_io_failure() path that we require
the fs not to be mount read-only. This is normally fine, but if we are
doing a read-repair meanwhile the fs flips RO due to a critical error,
we can enter btrfs_repair_io_failure() with super block set to
read-only, thus triggering the above crash.
[FIX]
Just replace the ASSERT() with a proper return if the fs is already
read-only.
Reported-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/linux-btrfs/20260126045555.GB31641@lst.de/
Tested-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/bio.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c
index 5fd0b39d8c703..6225f9d045efe 100644
--- a/fs/btrfs/bio.c
+++ b/fs/btrfs/bio.c
@@ -812,9 +812,15 @@ int btrfs_repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start,
struct bio bio;
int ret = 0;
- ASSERT(!(fs_info->sb->s_flags & SB_RDONLY));
BUG_ON(!mirror_num);
+ /*
+ * The fs either mounted RO or hit critical errors, no need
+ * to continue repairing.
+ */
+ if (unlikely(sb_rdonly(fs_info->sb)))
+ return 0;
+
if (btrfs_repair_one_zone(fs_info, logical))
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 252/869] btrfs: remove reserved argument from btrfs_pin_extent()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (250 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 251/869] btrfs: do not ASSERT() when the fs flips RO inside btrfs_repair_io_failure() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 253/869] btrfs: dont BUG() on unexpected delayed ref type in run_one_delayed_ref() Greg Kroah-Hartman
` (617 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johannes Thumshirn, Filipe Manana,
David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Filipe Manana <fdmanana@suse.com>
[ Upstream commit 8dcb8e4b110d86aaae2c485622423b6f63a65408 ]
All callers pass a value of 1 (true) to it, so remove it.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Stable-dep-of: c7d1d4ff5674 ("btrfs: don't BUG() on unexpected delayed ref type in run_one_delayed_ref()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/extent-tree.c | 15 +++++++--------
fs/btrfs/extent-tree.h | 3 +--
2 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 399c7e10bc14c..1e760331272a0 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1754,7 +1754,7 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
if (TRANS_ABORTED(trans)) {
if (insert_reserved) {
- btrfs_pin_extent(trans, node->bytenr, node->num_bytes, 1);
+ btrfs_pin_extent(trans, node->bytenr, node->num_bytes);
free_head_ref_squota_rsv(trans->fs_info, href);
}
return 0;
@@ -1773,7 +1773,7 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
else
BUG();
if (ret && insert_reserved)
- btrfs_pin_extent(trans, node->bytenr, node->num_bytes, 1);
+ btrfs_pin_extent(trans, node->bytenr, node->num_bytes);
if (ret < 0)
btrfs_err(trans->fs_info,
"failed to run delayed ref for logical %llu num_bytes %llu type %u action %u ref_mod %d: %d",
@@ -1914,7 +1914,7 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans,
spin_unlock(&delayed_refs->lock);
if (head->must_insert_reserved) {
- btrfs_pin_extent(trans, head->bytenr, head->num_bytes, 1);
+ btrfs_pin_extent(trans, head->bytenr, head->num_bytes);
if (head->is_data) {
struct btrfs_root *csum_root;
@@ -2612,15 +2612,14 @@ static int pin_down_extent(struct btrfs_trans_handle *trans,
return 0;
}
-int btrfs_pin_extent(struct btrfs_trans_handle *trans,
- u64 bytenr, u64 num_bytes, int reserved)
+int btrfs_pin_extent(struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes)
{
struct btrfs_block_group *cache;
cache = btrfs_lookup_block_group(trans->fs_info, bytenr);
BUG_ON(!cache); /* Logic error */
- pin_down_extent(trans, cache, bytenr, num_bytes, reserved);
+ pin_down_extent(trans, cache, bytenr, num_bytes, 1);
btrfs_put_block_group(cache);
return 0;
@@ -3531,7 +3530,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_ref *ref)
* tree, just update pinning info and exit early.
*/
if (ref->ref_root == BTRFS_TREE_LOG_OBJECTID) {
- btrfs_pin_extent(trans, ref->bytenr, ref->num_bytes, 1);
+ btrfs_pin_extent(trans, ref->bytenr, ref->num_bytes);
ret = 0;
} else if (ref->type == BTRFS_REF_METADATA) {
ret = btrfs_add_delayed_tree_ref(trans, ref, NULL);
@@ -5006,7 +5005,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
ret = alloc_reserved_file_extent(trans, 0, root_objectid, 0, owner,
offset, ins, 1, root_objectid);
if (ret)
- btrfs_pin_extent(trans, ins->objectid, ins->offset, 1);
+ btrfs_pin_extent(trans, ins->objectid, ins->offset);
ret = btrfs_record_squota_delta(fs_info, &delta);
btrfs_put_block_group(block_group);
return ret;
diff --git a/fs/btrfs/extent-tree.h b/fs/btrfs/extent-tree.h
index 82c054dbc3691..4eef608c82f0a 100644
--- a/fs/btrfs/extent-tree.h
+++ b/fs/btrfs/extent-tree.h
@@ -110,8 +110,7 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr,
u64 offset, int metadata, u64 *refs, u64 *flags,
u64 *owner_root);
-int btrfs_pin_extent(struct btrfs_trans_handle *trans, u64 bytenr, u64 num,
- int reserved);
+int btrfs_pin_extent(struct btrfs_trans_handle *trans, u64 bytenr, u64 num);
int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,
const struct extent_buffer *eb);
int btrfs_exclude_logged_extents(struct extent_buffer *eb);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 253/869] btrfs: dont BUG() on unexpected delayed ref type in run_one_delayed_ref()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (251 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 252/869] btrfs: remove reserved argument from btrfs_pin_extent() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 254/869] md raid: fix hang when stopping arrays with metadata through dm-raid Greg Kroah-Hartman
` (616 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Boris Burkov, Qu Wenruo,
Filipe Manana, David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Filipe Manana <fdmanana@suse.com>
[ Upstream commit c7d1d4ff56744074e005771aff193b927392d51f ]
There is no need to BUG(), we can just return an error and log an error
message.
Reviewed-by: Boris Burkov <boris@bur.io>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/extent-tree.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 1e760331272a0..a821ea34674f3 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1750,32 +1750,36 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
struct btrfs_delayed_extent_op *extent_op,
bool insert_reserved)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
int ret = 0;
if (TRANS_ABORTED(trans)) {
if (insert_reserved) {
btrfs_pin_extent(trans, node->bytenr, node->num_bytes);
- free_head_ref_squota_rsv(trans->fs_info, href);
+ free_head_ref_squota_rsv(fs_info, href);
}
return 0;
}
if (node->type == BTRFS_TREE_BLOCK_REF_KEY ||
- node->type == BTRFS_SHARED_BLOCK_REF_KEY)
+ node->type == BTRFS_SHARED_BLOCK_REF_KEY) {
ret = run_delayed_tree_ref(trans, href, node, extent_op,
insert_reserved);
- else if (node->type == BTRFS_EXTENT_DATA_REF_KEY ||
- node->type == BTRFS_SHARED_DATA_REF_KEY)
+ } else if (node->type == BTRFS_EXTENT_DATA_REF_KEY ||
+ node->type == BTRFS_SHARED_DATA_REF_KEY) {
ret = run_delayed_data_ref(trans, href, node, extent_op,
insert_reserved);
- else if (node->type == BTRFS_EXTENT_OWNER_REF_KEY)
+ } else if (node->type == BTRFS_EXTENT_OWNER_REF_KEY) {
ret = 0;
- else
- BUG();
+ } else {
+ ret = -EUCLEAN;
+ btrfs_err(fs_info, "unexpected delayed ref node type: %u", node->type);
+ }
+
if (ret && insert_reserved)
btrfs_pin_extent(trans, node->bytenr, node->num_bytes);
if (ret < 0)
- btrfs_err(trans->fs_info,
+ btrfs_err(fs_info,
"failed to run delayed ref for logical %llu num_bytes %llu type %u action %u ref_mod %d: %d",
node->bytenr, node->num_bytes, node->type,
node->action, node->ref_mod, ret);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 254/869] md raid: fix hang when stopping arrays with metadata through dm-raid
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (252 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 253/869] btrfs: dont BUG() on unexpected delayed ref type in run_one_delayed_ref() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 255/869] media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure Greg Kroah-Hartman
` (615 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Heinz Mauelshagen, Yu Kuai,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heinz Mauelshagen <heinzm@redhat.com>
[ Upstream commit cefcb9297fbdb6d94b61787b4f8d84f55b741470 ]
When using device-mapper's dm-raid target, stopping a RAID array can cause
the system to hang under specific conditions.
This occurs when:
- A dm-raid managed device tree is suspended from top to bottom
(the top-level RAID device is suspended first, followed by its
underlying metadata and data devices)
- The top-level RAID device is then removed
Removing the top-level device triggers a hang in the following sequence:
the dm-raid destructor calls md_stop(), which tries to flush the
write-intent bitmap by writing to the metadata sub-devices. However, these
devices are already suspended, making them unable to complete the write-intent
operations and causing an indefinite block.
Fix:
- Prevent bitmap flushing when md_stop() is called from dm-raid
destructor context
and avoid a quiescing/unquescing cycle which could also cause I/O
- Still allow write-intent bitmap flushing when called from dm-raid
suspend context
This ensures that RAID array teardown can complete successfully even when the
underlying devices are in a suspended state.
This second patch uses md_is_rdwr() to distinguish between suspend and
destructor paths as elaborated on above.
Link: https://lore.kernel.org/linux-raid/CAM23VxqYrwkhKEBeQrZeZwQudbiNey2_8B_SEOLqug=pXxaFrA@mail.gmail.com
Signed-off-by: Heinz Mauelshagen <heinzm@redhat.com>
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/md.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index a6f71253511cf..55632055196f0 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -6484,12 +6484,14 @@ static void __md_stop_writes(struct mddev *mddev)
{
del_timer_sync(&mddev->safemode_timer);
- if (mddev->pers && mddev->pers->quiesce) {
- mddev->pers->quiesce(mddev, 1);
- mddev->pers->quiesce(mddev, 0);
- }
+ if (md_is_rdwr(mddev) || !mddev_is_dm(mddev)) {
+ if (mddev->pers && mddev->pers->quiesce) {
+ mddev->pers->quiesce(mddev, 1);
+ mddev->pers->quiesce(mddev, 0);
+ }
- mddev->bitmap_ops->flush(mddev);
+ mddev->bitmap_ops->flush(mddev);
+ }
if (md_is_rdwr(mddev) &&
((!mddev->in_sync && !mddev_is_clustered(mddev)) ||
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 255/869] media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (253 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 254/869] md raid: fix hang when stopping arrays with metadata through dm-raid Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 256/869] media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC Greg Kroah-Hartman
` (614 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ming Qian, Frank Li,
Nicolas Dufresne, Hans Verkuil, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolas Dufresne <nicolas.dufresne@collabora.com>
[ Upstream commit db6b97a4f8041e479be9ef4b8b07022636c96f50 ]
Adding a reference count to the v4l2_m2m_dev structure allow safely
sharing it across multiple hardware nodes. This can be used to prevent
running jobs concurrently on m2m cores that have some internal resource
sharing.
Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
[hverkuil: fix typos in v4l2_m2m_put documentation]
Stable-dep-of: e0203ddf9af7 ("media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/media/v4l2-core/v4l2-mem2mem.c | 23 +++++++++++++++++++++++
include/media/v4l2-mem2mem.h | 21 +++++++++++++++++++++
2 files changed, 44 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index eb22d6172462d..85006fb18f720 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -90,6 +90,7 @@ static const char * const m2m_entity_name[] = {
* @job_work: worker to run queued jobs.
* @job_queue_flags: flags of the queue status, %QUEUE_PAUSED.
* @m2m_ops: driver callbacks
+ * @kref: device reference count
*/
struct v4l2_m2m_dev {
struct v4l2_m2m_ctx *curr_ctx;
@@ -109,6 +110,8 @@ struct v4l2_m2m_dev {
unsigned long job_queue_flags;
const struct v4l2_m2m_ops *m2m_ops;
+
+ struct kref kref;
};
static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
@@ -1210,6 +1213,7 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
INIT_LIST_HEAD(&m2m_dev->job_queue);
spin_lock_init(&m2m_dev->job_spinlock);
INIT_WORK(&m2m_dev->job_work, v4l2_m2m_device_run_work);
+ kref_init(&m2m_dev->kref);
return m2m_dev;
}
@@ -1221,6 +1225,25 @@ void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev)
}
EXPORT_SYMBOL_GPL(v4l2_m2m_release);
+void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev)
+{
+ kref_get(&m2m_dev->kref);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_get);
+
+static void v4l2_m2m_release_from_kref(struct kref *kref)
+{
+ struct v4l2_m2m_dev *m2m_dev = container_of(kref, struct v4l2_m2m_dev, kref);
+
+ v4l2_m2m_release(m2m_dev);
+}
+
+void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev)
+{
+ kref_put(&m2m_dev->kref, v4l2_m2m_release_from_kref);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_put);
+
struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
void *drv_priv,
int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq))
diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
index 2e55a13ed3bb8..1f10f63ef3803 100644
--- a/include/media/v4l2-mem2mem.h
+++ b/include/media/v4l2-mem2mem.h
@@ -544,6 +544,27 @@ v4l2_m2m_register_media_controller(struct v4l2_m2m_dev *m2m_dev,
*/
void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev);
+/**
+ * v4l2_m2m_get() - take a reference to the m2m_dev structure
+ *
+ * @m2m_dev: opaque pointer to the internal data to handle M2M context
+ *
+ * This is used to share the M2M device across multiple devices. This
+ * can be used to avoid scheduling two hardware nodes concurrently.
+ */
+void v4l2_m2m_get(struct v4l2_m2m_dev *m2m_dev);
+
+/**
+ * v4l2_m2m_put() - remove a reference to the m2m_dev structure
+ *
+ * @m2m_dev: opaque pointer to the internal data to handle M2M context
+ *
+ * Once the M2M device has no more references, v4l2_m2m_release() will be
+ * called automatically. Users of this method should never call
+ * v4l2_m2m_release() directly. See v4l2_m2m_get() for more details.
+ */
+void v4l2_m2m_put(struct v4l2_m2m_dev *m2m_dev);
+
/**
* v4l2_m2m_ctx_init() - allocate and initialize a m2m context
*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 256/869] media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (254 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 255/869] media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 257/869] KVM: Export hardware virtualization enabling/disabling functions Greg Kroah-Hartman
` (613 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ming Qian, Frank Li,
Nicolas Dufresne, Hans Verkuil, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Qian <ming.qian@oss.nxp.com>
[ Upstream commit e0203ddf9af7c8e170e1e99ce83b4dc07f0cd765 ]
For the i.MX8MQ platform, there is a hardware limitation: the g1 VPU and
g2 VPU cannot decode simultaneously; otherwise, it will cause below bus
error and produce corrupted pictures, even potentially lead to system hang.
[ 110.527986] hantro-vpu 38310000.video-codec: frame decode timed out.
[ 110.583517] hantro-vpu 38310000.video-codec: bus error detected.
Therefore, it is necessary to ensure that g1 and g2 operate alternately.
This allows for successful multi-instance decoding of H.264 and HEVC.
To achieve this, g1 and g2 share the same v4l2_m2m_dev, and then the
v4l2_m2m_dev can handle the scheduling.
Fixes: cb5dd5a0fa518 ("media: hantro: Introduce G2/HEVC decoder")
Cc: stable@vger.kernel.org
Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Co-developed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/media/platform/verisilicon/hantro.h | 2 +
.../media/platform/verisilicon/hantro_drv.c | 42 +++++++++++++++++--
.../media/platform/verisilicon/imx8m_vpu_hw.c | 8 ++++
3 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
index 811260dc3c777..439f0adb4e816 100644
--- a/drivers/media/platform/verisilicon/hantro.h
+++ b/drivers/media/platform/verisilicon/hantro.h
@@ -77,6 +77,7 @@ struct hantro_irq {
* @double_buffer: core needs double buffering
* @legacy_regs: core uses legacy register set
* @late_postproc: postproc must be set up at the end of the job
+ * @shared_devices: an array of device ids that cannot run concurrently
*/
struct hantro_variant {
unsigned int enc_offset;
@@ -101,6 +102,7 @@ struct hantro_variant {
unsigned int double_buffer : 1;
unsigned int legacy_regs : 1;
unsigned int late_postproc : 1;
+ const struct of_device_id *shared_devices;
};
/**
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index 137ca13eeed7c..01d6ab67a8bf3 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
@@ -1038,6 +1039,41 @@ static int hantro_disable_multicore(struct hantro_dev *vpu)
return 0;
}
+static struct v4l2_m2m_dev *hantro_get_v4l2_m2m_dev(struct hantro_dev *vpu)
+{
+ struct device_node *node;
+ struct hantro_dev *shared_vpu;
+
+ if (!vpu->variant || !vpu->variant->shared_devices)
+ goto init_new_m2m_dev;
+
+ for_each_matching_node(node, vpu->variant->shared_devices) {
+ struct platform_device *pdev;
+ struct v4l2_m2m_dev *m2m_dev;
+
+ pdev = of_find_device_by_node(node);
+ if (!pdev)
+ continue;
+
+ shared_vpu = platform_get_drvdata(pdev);
+ if (IS_ERR_OR_NULL(shared_vpu) || shared_vpu == vpu) {
+ platform_device_put(pdev);
+ continue;
+ }
+
+ v4l2_m2m_get(shared_vpu->m2m_dev);
+ m2m_dev = shared_vpu->m2m_dev;
+ platform_device_put(pdev);
+
+ of_node_put(node);
+
+ return m2m_dev;
+ }
+
+init_new_m2m_dev:
+ return v4l2_m2m_init(&vpu_m2m_ops);
+}
+
static int hantro_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
@@ -1189,7 +1225,7 @@ static int hantro_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, vpu);
- vpu->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops);
+ vpu->m2m_dev = hantro_get_v4l2_m2m_dev(vpu);
if (IS_ERR(vpu->m2m_dev)) {
v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem device\n");
ret = PTR_ERR(vpu->m2m_dev);
@@ -1228,7 +1264,7 @@ static int hantro_probe(struct platform_device *pdev)
hantro_remove_enc_func(vpu);
err_m2m_rel:
media_device_cleanup(&vpu->mdev);
- v4l2_m2m_release(vpu->m2m_dev);
+ v4l2_m2m_put(vpu->m2m_dev);
err_v4l2_unreg:
v4l2_device_unregister(&vpu->v4l2_dev);
err_clk_unprepare:
@@ -1251,7 +1287,7 @@ static void hantro_remove(struct platform_device *pdev)
hantro_remove_dec_func(vpu);
hantro_remove_enc_func(vpu);
media_device_cleanup(&vpu->mdev);
- v4l2_m2m_release(vpu->m2m_dev);
+ v4l2_m2m_put(vpu->m2m_dev);
v4l2_device_unregister(&vpu->v4l2_dev);
clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks);
reset_control_assert(vpu->resets);
diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
index 74fd985a8aad1..cdaac2f18fb54 100644
--- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
@@ -361,6 +361,12 @@ const struct hantro_variant imx8mq_vpu_variant = {
.num_regs = ARRAY_SIZE(imx8mq_reg_names)
};
+static const struct of_device_id imx8mq_vpu_shared_resources[] __initconst = {
+ { .compatible = "nxp,imx8mq-vpu-g1", },
+ { .compatible = "nxp,imx8mq-vpu-g2", },
+ { /* sentinel */ }
+};
+
const struct hantro_variant imx8mq_vpu_g1_variant = {
.dec_fmts = imx8m_vpu_dec_fmts,
.num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts),
@@ -374,6 +380,7 @@ const struct hantro_variant imx8mq_vpu_g1_variant = {
.num_irqs = ARRAY_SIZE(imx8mq_irqs),
.clk_names = imx8mq_g1_clk_names,
.num_clocks = ARRAY_SIZE(imx8mq_g1_clk_names),
+ .shared_devices = imx8mq_vpu_shared_resources,
};
const struct hantro_variant imx8mq_vpu_g2_variant = {
@@ -389,6 +396,7 @@ const struct hantro_variant imx8mq_vpu_g2_variant = {
.num_irqs = ARRAY_SIZE(imx8mq_g2_irqs),
.clk_names = imx8mq_g2_clk_names,
.num_clocks = ARRAY_SIZE(imx8mq_g2_clk_names),
+ .shared_devices = imx8mq_vpu_shared_resources,
};
const struct hantro_variant imx8mm_vpu_g1_variant = {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 257/869] KVM: Export hardware virtualization enabling/disabling functions
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (255 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 256/869] media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 258/869] syscore: Pass context data to callbacks Greg Kroah-Hartman
` (612 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Kai Huang, Paolo Bonzini,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kai Huang <kai.huang@intel.com>
[ Upstream commit 62b1fa69f31969e11d03529d3a80599ddda2d043 ]
To support TDX, KVM will need to enable TDX during KVM module loading
time. Enabling TDX requires enabling hardware virtualization first so
that all online CPUs (and the new CPU going online) are in post-VMXON
state.
KVM by default enables hardware virtualization but that is done in
kvm_init(), which must be the last step after all initialization is done
thus is too late for enabling TDX.
Export functions to enable/disable hardware virtualization so that TDX
code can use them to handle hardware virtualization enabling before
kvm_init().
Signed-off-by: Kai Huang <kai.huang@intel.com>
Message-ID: <dfe17314c0d9978b7bc3b0833dff6f167fbd28f5.1731664295.git.kai.huang@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Stable-dep-of: e6d96073af68 ("soc/tegra: pmc: Fix unsafe generic_handle_irq() call")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/kvm_host.h | 8 ++++++++
virt/kvm/kvm_main.c | 18 ++++--------------
2 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index b4235e99f0a9d..2b7068685ff2a 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -2528,4 +2528,12 @@ long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,
struct kvm_pre_fault_memory *range);
#endif
+#ifdef CONFIG_KVM_GENERIC_HARDWARE_ENABLING
+int kvm_enable_virtualization(void);
+void kvm_disable_virtualization(void);
+#else
+static inline int kvm_enable_virtualization(void) { return 0; }
+static inline void kvm_disable_virtualization(void) { }
+#endif
+
#endif
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 15ad929ec0d0c..b2e76be087121 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -136,8 +136,6 @@ static int kvm_no_compat_open(struct inode *inode, struct file *file)
#define KVM_COMPAT(c) .compat_ioctl = kvm_no_compat_ioctl, \
.open = kvm_no_compat_open
#endif
-static int kvm_enable_virtualization(void);
-static void kvm_disable_virtualization(void);
static void kvm_io_bus_destroy(struct kvm_io_bus *bus);
@@ -5713,7 +5711,7 @@ static struct syscore_ops kvm_syscore_ops = {
.shutdown = kvm_shutdown,
};
-static int kvm_enable_virtualization(void)
+int kvm_enable_virtualization(void)
{
int r;
@@ -5758,8 +5756,9 @@ static int kvm_enable_virtualization(void)
--kvm_usage_count;
return r;
}
+EXPORT_SYMBOL_GPL(kvm_enable_virtualization);
-static void kvm_disable_virtualization(void)
+void kvm_disable_virtualization(void)
{
guard(mutex)(&kvm_usage_lock);
@@ -5770,6 +5769,7 @@ static void kvm_disable_virtualization(void)
cpuhp_remove_state(CPUHP_AP_KVM_ONLINE);
kvm_arch_disable_virtualization();
}
+EXPORT_SYMBOL_GPL(kvm_disable_virtualization);
static int kvm_init_virtualization(void)
{
@@ -5785,21 +5785,11 @@ static void kvm_uninit_virtualization(void)
kvm_disable_virtualization();
}
#else /* CONFIG_KVM_GENERIC_HARDWARE_ENABLING */
-static int kvm_enable_virtualization(void)
-{
- return 0;
-}
-
static int kvm_init_virtualization(void)
{
return 0;
}
-static void kvm_disable_virtualization(void)
-{
-
-}
-
static void kvm_uninit_virtualization(void)
{
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 258/869] syscore: Pass context data to callbacks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (256 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 257/869] KVM: Export hardware virtualization enabling/disabling functions Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 259/869] soc/tegra: pmc: Fix unsafe generic_handle_irq() call Greg Kroah-Hartman
` (611 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rafael J. Wysocki (Intel),
Thierry Reding, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thierry Reding <treding@nvidia.com>
[ Upstream commit a97fbc3ee3e2a536fafaff04f21f45472db71769 ]
Several drivers can benefit from registering per-instance data along
with the syscore operations. To achieve this, move the modifiable fields
out of the syscore_ops structure and into a separate struct syscore that
can be registered with the framework. Add a void * driver data field for
drivers to store contextual data that will be passed to the syscore ops.
Acked-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Stable-dep-of: e6d96073af68 ("soc/tegra: pmc: Fix unsafe generic_handle_irq() call")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm/mach-exynos/mcpm-exynos.c | 12 ++--
arch/arm/mach-exynos/suspend.c | 48 +++++++------
arch/arm/mach-pxa/generic.h | 6 +-
arch/arm/mach-pxa/irq.c | 10 ++-
arch/arm/mach-pxa/mfp-pxa2xx.c | 10 ++-
arch/arm/mach-pxa/mfp-pxa3xx.c | 10 ++-
arch/arm/mach-pxa/pxa25x.c | 4 +-
arch/arm/mach-pxa/pxa27x.c | 4 +-
arch/arm/mach-pxa/pxa3xx.c | 4 +-
arch/arm/mach-pxa/smemc.c | 12 ++--
arch/arm/mach-s3c/irq-pm-s3c64xx.c | 12 ++--
arch/arm/mach-s5pv210/pm.c | 10 ++-
arch/arm/mach-versatile/integrator_ap.c | 12 ++--
arch/arm/mm/cache-b15-rac.c | 12 ++--
arch/loongarch/kernel/smp.c | 12 ++--
arch/mips/alchemy/common/dbdma.c | 12 ++--
arch/mips/alchemy/common/irq.c | 24 ++++---
arch/mips/alchemy/common/usb.c | 12 ++--
arch/mips/pci/pci-alchemy.c | 16 +++--
arch/powerpc/platforms/cell/spu_base.c | 10 ++-
arch/powerpc/platforms/powermac/pic.c | 12 ++--
arch/powerpc/sysdev/fsl_lbc.c | 12 ++--
arch/powerpc/sysdev/fsl_pci.c | 12 ++--
arch/powerpc/sysdev/ipic.c | 12 ++--
arch/powerpc/sysdev/mpic.c | 14 ++--
arch/powerpc/sysdev/mpic_timer.c | 10 ++-
arch/sh/mm/pmb.c | 10 ++-
arch/x86/events/amd/ibs.c | 12 ++--
arch/x86/hyperv/hv_init.c | 12 ++--
arch/x86/kernel/amd_gart_64.c | 10 ++-
arch/x86/kernel/apic/apic.c | 12 ++--
arch/x86/kernel/apic/io_apic.c | 17 +++--
arch/x86/kernel/cpu/aperfmperf.c | 20 +++---
arch/x86/kernel/cpu/intel_epb.c | 16 +++--
arch/x86/kernel/cpu/mce/core.c | 14 ++--
arch/x86/kernel/cpu/microcode/core.c | 15 ++++-
arch/x86/kernel/cpu/mtrr/legacy.c | 12 ++--
arch/x86/kernel/cpu/umwait.c | 10 ++-
arch/x86/kernel/i8237.c | 10 ++-
arch/x86/kernel/i8259.c | 14 ++--
arch/x86/kernel/kvm.c | 12 ++--
drivers/acpi/pci_link.c | 10 ++-
drivers/acpi/sleep.c | 12 ++--
drivers/base/firmware_loader/main.c | 12 ++--
drivers/base/syscore.c | 82 ++++++++++++-----------
drivers/bus/mvebu-mbus.c | 16 +++--
drivers/clk/at91/pmc.c | 12 ++--
drivers/clk/imx/clk-vf610.c | 12 ++--
drivers/clk/ingenic/jz4725b-cgu.c | 2 +-
drivers/clk/ingenic/jz4740-cgu.c | 2 +-
drivers/clk/ingenic/jz4755-cgu.c | 2 +-
drivers/clk/ingenic/jz4760-cgu.c | 2 +-
drivers/clk/ingenic/jz4770-cgu.c | 2 +-
drivers/clk/ingenic/jz4780-cgu.c | 2 +-
drivers/clk/ingenic/pm.c | 14 ++--
drivers/clk/ingenic/pm.h | 2 +-
drivers/clk/ingenic/tcu.c | 12 ++--
drivers/clk/ingenic/x1000-cgu.c | 2 +-
drivers/clk/ingenic/x1830-cgu.c | 2 +-
drivers/clk/mvebu/common.c | 12 ++--
drivers/clk/rockchip/clk-rk3288.c | 12 ++--
drivers/clk/samsung/clk-s5pv210-audss.c | 12 ++--
drivers/clk/samsung/clk.c | 12 ++--
drivers/clk/tegra/clk-tegra210.c | 12 ++--
drivers/clocksource/timer-armada-370-xp.c | 12 ++--
drivers/cpuidle/cpuidle-psci.c | 12 ++--
drivers/gpio/gpio-mxc.c | 12 ++--
drivers/gpio/gpio-pxa.c | 12 ++--
drivers/gpio/gpio-sa1100.c | 12 ++--
drivers/hv/vmbus_drv.c | 14 ++--
drivers/iommu/amd/init.c | 16 +++--
drivers/iommu/intel/iommu.c | 12 ++--
drivers/irqchip/exynos-combiner.c | 14 ++--
drivers/irqchip/irq-armada-370-xp.c | 12 ++--
drivers/irqchip/irq-bcm7038-l1.c | 12 ++--
drivers/irqchip/irq-gic-v3-its.c | 12 ++--
drivers/irqchip/irq-i8259.c | 12 ++--
drivers/irqchip/irq-imx-gpcv2.c | 16 +++--
drivers/irqchip/irq-loongson-eiointc.c | 12 ++--
drivers/irqchip/irq-loongson-htpic.c | 10 ++-
drivers/irqchip/irq-loongson-htvec.c | 12 ++--
drivers/irqchip/irq-loongson-pch-lpc.c | 12 ++--
drivers/irqchip/irq-loongson-pch-pic.c | 12 ++--
drivers/irqchip/irq-mchp-eic.c | 12 ++--
drivers/irqchip/irq-mst-intc.c | 12 ++--
drivers/irqchip/irq-mtk-cirq.c | 12 ++--
drivers/irqchip/irq-renesas-rzg2l.c | 12 ++--
drivers/irqchip/irq-sa11x0.c | 12 ++--
drivers/irqchip/irq-sifive-plic.c | 12 ++--
drivers/irqchip/irq-sun6i-r.c | 18 +++--
drivers/irqchip/irq-tegra.c | 12 ++--
drivers/irqchip/irq-vic.c | 12 ++--
drivers/leds/trigger/ledtrig-cpu.c | 14 ++--
drivers/macintosh/via-pmu.c | 12 ++--
drivers/power/reset/sc27xx-poweroff.c | 10 ++-
drivers/sh/clk/core.c | 10 ++-
drivers/sh/intc/core.c | 12 ++--
drivers/soc/bcm/brcmstb/biuctrl.c | 12 ++--
drivers/soc/tegra/pmc.c | 17 +++--
drivers/thermal/intel/intel_hfi.c | 12 ++--
drivers/xen/xen-acpi-processor.c | 12 ++--
include/linux/syscore_ops.h | 15 +++--
kernel/cpu_pm.c | 12 ++--
kernel/irq/generic-chip.c | 14 ++--
kernel/irq/pm.c | 11 ++-
kernel/printk/printk.c | 11 ++-
kernel/time/sched_clock.c | 22 ++++--
kernel/time/timekeeping.c | 22 ++++--
virt/kvm/kvm_main.c | 18 +++--
109 files changed, 898 insertions(+), 470 deletions(-)
diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
index fd0dbeb93357d..cb7d8a7b14e0d 100644
--- a/arch/arm/mach-exynos/mcpm-exynos.c
+++ b/arch/arm/mach-exynos/mcpm-exynos.c
@@ -215,7 +215,7 @@ static const struct of_device_id exynos_dt_mcpm_match[] = {
{},
};
-static void exynos_mcpm_setup_entry_point(void)
+static void exynos_mcpm_setup_entry_point(void *data)
{
/*
* U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr
@@ -228,10 +228,14 @@ static void exynos_mcpm_setup_entry_point(void)
__raw_writel(__pa_symbol(mcpm_entry_point), ns_sram_base_addr + 8);
}
-static struct syscore_ops exynos_mcpm_syscore_ops = {
+static const struct syscore_ops exynos_mcpm_syscore_ops = {
.resume = exynos_mcpm_setup_entry_point,
};
+static struct syscore exynos_mcpm_syscore = {
+ .ops = &exynos_mcpm_syscore_ops,
+};
+
static int __init exynos_mcpm_init(void)
{
struct device_node *node;
@@ -300,9 +304,9 @@ static int __init exynos_mcpm_init(void)
pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i));
}
- exynos_mcpm_setup_entry_point();
+ exynos_mcpm_setup_entry_point(NULL);
- register_syscore_ops(&exynos_mcpm_syscore_ops);
+ register_syscore(&exynos_mcpm_syscore);
return ret;
}
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c
index cac4e82f6c824..aca767935e20c 100644
--- a/arch/arm/mach-exynos/suspend.c
+++ b/arch/arm/mach-exynos/suspend.c
@@ -53,9 +53,9 @@ struct exynos_pm_data {
void (*pm_prepare)(void);
void (*pm_resume_prepare)(void);
- void (*pm_resume)(void);
- int (*pm_suspend)(void);
int (*cpu_suspend)(unsigned long);
+
+ const struct syscore_ops *syscore_ops;
};
/* Used only on Exynos542x/5800 */
@@ -377,7 +377,7 @@ static void exynos5420_pm_prepare(void)
}
-static int exynos_pm_suspend(void)
+static int exynos_pm_suspend(void *data)
{
exynos_pm_central_suspend();
@@ -391,7 +391,7 @@ static int exynos_pm_suspend(void)
return 0;
}
-static int exynos5420_pm_suspend(void)
+static int exynos5420_pm_suspend(void *data)
{
u32 this_cluster;
@@ -409,7 +409,7 @@ static int exynos5420_pm_suspend(void)
return 0;
}
-static void exynos_pm_resume(void)
+static void exynos_pm_resume(void *data)
{
u32 cpuid = read_cpuid_part();
@@ -430,7 +430,7 @@ static void exynos_pm_resume(void)
exynos_set_delayed_reset_assertion(true);
}
-static void exynos3250_pm_resume(void)
+static void exynos3250_pm_resume(void *data)
{
u32 cpuid = read_cpuid_part();
@@ -474,7 +474,7 @@ static void exynos5420_prepare_pm_resume(void)
}
}
-static void exynos5420_pm_resume(void)
+static void exynos5420_pm_resume(void *data)
{
unsigned long tmp;
@@ -597,41 +597,52 @@ static const struct platform_suspend_ops exynos_suspend_ops = {
.valid = suspend_valid_only_mem,
};
+static const struct syscore_ops exynos3250_syscore_ops = {
+ .suspend = exynos_pm_suspend,
+ .resume = exynos3250_pm_resume,
+};
+
static const struct exynos_pm_data exynos3250_pm_data = {
.wkup_irq = exynos3250_wkup_irq,
.wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
- .pm_suspend = exynos_pm_suspend,
- .pm_resume = exynos3250_pm_resume,
.pm_prepare = exynos3250_pm_prepare,
.cpu_suspend = exynos3250_cpu_suspend,
+ .syscore_ops = &exynos3250_syscore_ops,
+};
+
+static const struct syscore_ops exynos_syscore_ops = {
+ .suspend = exynos_pm_suspend,
+ .resume = exynos_pm_resume,
};
static const struct exynos_pm_data exynos4_pm_data = {
.wkup_irq = exynos4_wkup_irq,
.wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
- .pm_suspend = exynos_pm_suspend,
- .pm_resume = exynos_pm_resume,
.pm_prepare = exynos_pm_prepare,
.cpu_suspend = exynos_cpu_suspend,
+ .syscore_ops = &exynos_syscore_ops,
};
static const struct exynos_pm_data exynos5250_pm_data = {
.wkup_irq = exynos5250_wkup_irq,
.wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
- .pm_suspend = exynos_pm_suspend,
- .pm_resume = exynos_pm_resume,
.pm_prepare = exynos_pm_prepare,
.cpu_suspend = exynos_cpu_suspend,
+ .syscore_ops = &exynos_syscore_ops,
+};
+
+static const struct syscore_ops exynos5420_syscore_ops = {
+ .resume = exynos5420_pm_resume,
+ .suspend = exynos5420_pm_suspend,
};
static const struct exynos_pm_data exynos5420_pm_data = {
.wkup_irq = exynos5250_wkup_irq,
.wake_disable_mask = (0x7F << 7) | (0x1F << 1),
.pm_resume_prepare = exynos5420_prepare_pm_resume,
- .pm_resume = exynos5420_pm_resume,
- .pm_suspend = exynos5420_pm_suspend,
.pm_prepare = exynos5420_pm_prepare,
.cpu_suspend = exynos5420_cpu_suspend,
+ .syscore_ops = &exynos5420_syscore_ops,
};
static const struct of_device_id exynos_pmu_of_device_ids[] __initconst = {
@@ -657,7 +668,7 @@ static const struct of_device_id exynos_pmu_of_device_ids[] __initconst = {
{ /*sentinel*/ },
};
-static struct syscore_ops exynos_pm_syscore_ops;
+static struct syscore exynos_pm_syscore;
void __init exynos_pm_init(void)
{
@@ -685,10 +696,9 @@ void __init exynos_pm_init(void)
tmp |= pm_data->wake_disable_mask;
pmu_raw_writel(tmp, S5P_WAKEUP_MASK);
- exynos_pm_syscore_ops.suspend = pm_data->pm_suspend;
- exynos_pm_syscore_ops.resume = pm_data->pm_resume;
+ exynos_pm_syscore.ops = pm_data->syscore_ops;
- register_syscore_ops(&exynos_pm_syscore_ops);
+ register_syscore(&exynos_pm_syscore);
suspend_set_ops(&exynos_suspend_ops);
/*
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index c9c2c46ecead0..caad4fca8de3e 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -34,9 +34,9 @@ extern void __init pxa27x_map_io(void);
extern void __init pxa3xx_init_irq(void);
extern void __init pxa3xx_map_io(void);
-extern struct syscore_ops pxa_irq_syscore_ops;
-extern struct syscore_ops pxa2xx_mfp_syscore_ops;
-extern struct syscore_ops pxa3xx_mfp_syscore_ops;
+extern struct syscore pxa_irq_syscore;
+extern struct syscore pxa2xx_mfp_syscore;
+extern struct syscore pxa3xx_mfp_syscore;
void __init pxa_set_ffuart_info(void *info);
void __init pxa_set_btuart_info(void *info);
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index a9ef710081472..78992c5d45ea4 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -179,7 +179,7 @@ void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32];
static unsigned long saved_ipr[MAX_INTERNAL_IRQS];
-static int pxa_irq_suspend(void)
+static int pxa_irq_suspend(void *data)
{
int i;
@@ -198,7 +198,7 @@ static int pxa_irq_suspend(void)
return 0;
}
-static void pxa_irq_resume(void)
+static void pxa_irq_resume(void *data)
{
int i;
@@ -220,11 +220,15 @@ static void pxa_irq_resume(void)
#define pxa_irq_resume NULL
#endif
-struct syscore_ops pxa_irq_syscore_ops = {
+static const struct syscore_ops pxa_irq_syscore_ops = {
.suspend = pxa_irq_suspend,
.resume = pxa_irq_resume,
};
+struct syscore pxa_irq_syscore = {
+ .ops = &pxa_irq_syscore_ops,
+};
+
#ifdef CONFIG_OF
static const struct of_device_id intc_ids[] __initconst = {
{ .compatible = "marvell,pxa-intc", },
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c
index f5a3d890f682e..d1347055fbe4f 100644
--- a/arch/arm/mach-pxa/mfp-pxa2xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa2xx.c
@@ -346,7 +346,7 @@ static unsigned long saved_gpdr[4];
static unsigned long saved_gplr[4];
static unsigned long saved_pgsr[4];
-static int pxa2xx_mfp_suspend(void)
+static int pxa2xx_mfp_suspend(void *data)
{
int i;
@@ -385,7 +385,7 @@ static int pxa2xx_mfp_suspend(void)
return 0;
}
-static void pxa2xx_mfp_resume(void)
+static void pxa2xx_mfp_resume(void *data)
{
int i;
@@ -404,11 +404,15 @@ static void pxa2xx_mfp_resume(void)
#define pxa2xx_mfp_resume NULL
#endif
-struct syscore_ops pxa2xx_mfp_syscore_ops = {
+static const struct syscore_ops pxa2xx_mfp_syscore_ops = {
.suspend = pxa2xx_mfp_suspend,
.resume = pxa2xx_mfp_resume,
};
+struct syscore pxa2xx_mfp_syscore = {
+ .ops = &pxa2xx_mfp_syscore_ops,
+};
+
static int __init pxa2xx_mfp_init(void)
{
int i;
diff --git a/arch/arm/mach-pxa/mfp-pxa3xx.c b/arch/arm/mach-pxa/mfp-pxa3xx.c
index d16ab7451efef..fe7498fbb62b3 100644
--- a/arch/arm/mach-pxa/mfp-pxa3xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa3xx.c
@@ -27,13 +27,13 @@
* a pull-down mode if they're an active low chip select, and we're
* just entering standby.
*/
-static int pxa3xx_mfp_suspend(void)
+static int pxa3xx_mfp_suspend(void *data)
{
mfp_config_lpm();
return 0;
}
-static void pxa3xx_mfp_resume(void)
+static void pxa3xx_mfp_resume(void *data)
{
mfp_config_run();
@@ -49,7 +49,11 @@ static void pxa3xx_mfp_resume(void)
#define pxa3xx_mfp_resume NULL
#endif
-struct syscore_ops pxa3xx_mfp_syscore_ops = {
+static const struct syscore_ops pxa3xx_mfp_syscore_ops = {
.suspend = pxa3xx_mfp_suspend,
.resume = pxa3xx_mfp_resume,
};
+
+struct syscore pxa3xx_mfp_syscore = {
+ .ops = &pxa3xx_mfp_syscore_ops,
+};
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 03e34841fc004..70509a5998142 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -235,8 +235,8 @@ static int __init pxa25x_init(void)
pxa25x_init_pm();
- register_syscore_ops(&pxa_irq_syscore_ops);
- register_syscore_ops(&pxa2xx_mfp_syscore_ops);
+ register_syscore(&pxa_irq_syscore);
+ register_syscore(&pxa2xx_mfp_syscore);
if (!of_have_populated_dt()) {
software_node_register(&pxa2xx_gpiochip_node);
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index f8382477d629e..ff63619790383 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -337,8 +337,8 @@ static int __init pxa27x_init(void)
pxa27x_init_pm();
- register_syscore_ops(&pxa_irq_syscore_ops);
- register_syscore_ops(&pxa2xx_mfp_syscore_ops);
+ register_syscore(&pxa_irq_syscore);
+ register_syscore(&pxa2xx_mfp_syscore);
if (!of_have_populated_dt()) {
software_node_register(&pxa2xx_gpiochip_node);
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 1d1e5713464dc..06c578ea658e3 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -424,8 +424,8 @@ static int __init pxa3xx_init(void)
if (cpu_is_pxa320())
enable_irq_wake(IRQ_WAKEUP1);
- register_syscore_ops(&pxa_irq_syscore_ops);
- register_syscore_ops(&pxa3xx_mfp_syscore_ops);
+ register_syscore(&pxa_irq_syscore);
+ register_syscore(&pxa3xx_mfp_syscore);
}
return ret;
diff --git a/arch/arm/mach-pxa/smemc.c b/arch/arm/mach-pxa/smemc.c
index 2d2a321d82f81..fb93a8f28356e 100644
--- a/arch/arm/mach-pxa/smemc.c
+++ b/arch/arm/mach-pxa/smemc.c
@@ -18,7 +18,7 @@ static unsigned long msc[2];
static unsigned long sxcnfg, memclkcfg;
static unsigned long csadrcfg[4];
-static int pxa3xx_smemc_suspend(void)
+static int pxa3xx_smemc_suspend(void *data)
{
msc[0] = __raw_readl(MSC0);
msc[1] = __raw_readl(MSC1);
@@ -32,7 +32,7 @@ static int pxa3xx_smemc_suspend(void)
return 0;
}
-static void pxa3xx_smemc_resume(void)
+static void pxa3xx_smemc_resume(void *data)
{
__raw_writel(msc[0], MSC0);
__raw_writel(msc[1], MSC1);
@@ -46,11 +46,15 @@ static void pxa3xx_smemc_resume(void)
__raw_writel(0x2, CSMSADRCFG);
}
-static struct syscore_ops smemc_syscore_ops = {
+static const struct syscore_ops smemc_syscore_ops = {
.suspend = pxa3xx_smemc_suspend,
.resume = pxa3xx_smemc_resume,
};
+static struct syscore smemc_syscore = {
+ .ops = &smemc_syscore_ops,
+};
+
static int __init smemc_init(void)
{
if (cpu_is_pxa3xx()) {
@@ -64,7 +68,7 @@ static int __init smemc_init(void)
*/
__raw_writel(0x2, CSMSADRCFG);
- register_syscore_ops(&smemc_syscore_ops);
+ register_syscore(&smemc_syscore);
}
return 0;
diff --git a/arch/arm/mach-s3c/irq-pm-s3c64xx.c b/arch/arm/mach-s3c/irq-pm-s3c64xx.c
index 4a1e935bada19..ab726c595001d 100644
--- a/arch/arm/mach-s3c/irq-pm-s3c64xx.c
+++ b/arch/arm/mach-s3c/irq-pm-s3c64xx.c
@@ -58,7 +58,7 @@ static struct irq_grp_save {
static u32 irq_uart_mask[SERIAL_SAMSUNG_UARTS];
-static int s3c64xx_irq_pm_suspend(void)
+static int s3c64xx_irq_pm_suspend(void *data)
{
struct irq_grp_save *grp = eint_grp_save;
int i;
@@ -79,7 +79,7 @@ static int s3c64xx_irq_pm_suspend(void)
return 0;
}
-static void s3c64xx_irq_pm_resume(void)
+static void s3c64xx_irq_pm_resume(void *data)
{
struct irq_grp_save *grp = eint_grp_save;
int i;
@@ -100,18 +100,22 @@ static void s3c64xx_irq_pm_resume(void)
S3C_PMDBG("%s: IRQ configuration restored\n", __func__);
}
-static struct syscore_ops s3c64xx_irq_syscore_ops = {
+static const struct syscore_ops s3c64xx_irq_syscore_ops = {
.suspend = s3c64xx_irq_pm_suspend,
.resume = s3c64xx_irq_pm_resume,
};
+static struct syscore s3c64xx_irq_syscore = {
+ .ops = &s3c64xx_irq_syscore_ops,
+};
+
static __init int s3c64xx_syscore_init(void)
{
/* Appropriate drivers (pinctrl, uart) handle this when using DT. */
if (of_have_populated_dt() || !soc_is_s3c64xx())
return 0;
- register_syscore_ops(&s3c64xx_irq_syscore_ops);
+ register_syscore(&s3c64xx_irq_syscore);
return 0;
}
diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c
index 6fa70f787df4e..fa270750364cf 100644
--- a/arch/arm/mach-s5pv210/pm.c
+++ b/arch/arm/mach-s5pv210/pm.c
@@ -195,20 +195,24 @@ static const struct platform_suspend_ops s5pv210_suspend_ops = {
/*
* Syscore operations used to delay restore of certain registers.
*/
-static void s5pv210_pm_resume(void)
+static void s5pv210_pm_resume(void *data)
{
s3c_pm_do_restore_core(s5pv210_core_save, ARRAY_SIZE(s5pv210_core_save));
}
-static struct syscore_ops s5pv210_pm_syscore_ops = {
+static const struct syscore_ops s5pv210_pm_syscore_ops = {
.resume = s5pv210_pm_resume,
};
+static struct syscore s5pv210_pm_syscore = {
+ .ops = &s5pv210_pm_syscore_ops,
+};
+
/*
* Initialization entry point.
*/
void __init s5pv210_pm_init(void)
{
- register_syscore_ops(&s5pv210_pm_syscore_ops);
+ register_syscore(&s5pv210_pm_syscore);
suspend_set_ops(&s5pv210_suspend_ops);
}
diff --git a/arch/arm/mach-versatile/integrator_ap.c b/arch/arm/mach-versatile/integrator_ap.c
index 4bd6712e9f525..ee90d6619d0db 100644
--- a/arch/arm/mach-versatile/integrator_ap.c
+++ b/arch/arm/mach-versatile/integrator_ap.c
@@ -63,13 +63,13 @@ static void __init ap_map_io(void)
#ifdef CONFIG_PM
static unsigned long ic_irq_enable;
-static int irq_suspend(void)
+static int irq_suspend(void *data)
{
ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE);
return 0;
}
-static void irq_resume(void)
+static void irq_resume(void *data)
{
/* disable all irq sources */
cm_clear_irqs();
@@ -83,14 +83,18 @@ static void irq_resume(void)
#define irq_resume NULL
#endif
-static struct syscore_ops irq_syscore_ops = {
+static const struct syscore_ops irq_syscore_ops = {
.suspend = irq_suspend,
.resume = irq_resume,
};
+static struct syscore irq_syscore = {
+ .ops = &irq_syscore_ops,
+};
+
static int __init irq_syscore_init(void)
{
- register_syscore_ops(&irq_syscore_ops);
+ register_syscore(&irq_syscore);
return 0;
}
diff --git a/arch/arm/mm/cache-b15-rac.c b/arch/arm/mm/cache-b15-rac.c
index 6f63b90f9e1ac..e7807356dfab0 100644
--- a/arch/arm/mm/cache-b15-rac.c
+++ b/arch/arm/mm/cache-b15-rac.c
@@ -256,7 +256,7 @@ static int b15_rac_dead_cpu(unsigned int cpu)
return 0;
}
-static int b15_rac_suspend(void)
+static int b15_rac_suspend(void *data)
{
/* Suspend the read-ahead cache oeprations, forcing our cache
* implementation to fallback to the regular ARMv7 calls.
@@ -271,7 +271,7 @@ static int b15_rac_suspend(void)
return 0;
}
-static void b15_rac_resume(void)
+static void b15_rac_resume(void *data)
{
/* Coming out of a S3 suspend/resume cycle, the read-ahead cache
* register RAC_CONFIG0_REG will be restored to its default value, make
@@ -282,11 +282,15 @@ static void b15_rac_resume(void)
clear_bit(RAC_SUSPENDED, &b15_rac_flags);
}
-static struct syscore_ops b15_rac_syscore_ops = {
+static const struct syscore_ops b15_rac_syscore_ops = {
.suspend = b15_rac_suspend,
.resume = b15_rac_resume,
};
+static struct syscore b15_rac_syscore = {
+ .ops = &b15_rac_syscore_ops,
+};
+
static int __init b15_rac_init(void)
{
struct device_node *dn, *cpu_dn;
@@ -347,7 +351,7 @@ static int __init b15_rac_init(void)
}
if (IS_ENABLED(CONFIG_PM_SLEEP))
- register_syscore_ops(&b15_rac_syscore_ops);
+ register_syscore(&b15_rac_syscore);
spin_lock(&rac_lock);
reg = __raw_readl(b15_rac_base + RAC_CONFIG0_REG);
diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
index 780abcd86ca32..e3c3ff251dcbd 100644
--- a/arch/loongarch/kernel/smp.c
+++ b/arch/loongarch/kernel/smp.c
@@ -499,28 +499,32 @@ int hibernate_resume_nonboot_cpu_disable(void)
*/
#ifdef CONFIG_PM
-static int loongson_ipi_suspend(void)
+static int loongson_ipi_suspend(void *data)
{
return 0;
}
-static void loongson_ipi_resume(void)
+static void loongson_ipi_resume(void *data)
{
iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_EN);
}
-static struct syscore_ops loongson_ipi_syscore_ops = {
+static const struct syscore_ops loongson_ipi_syscore_ops = {
.resume = loongson_ipi_resume,
.suspend = loongson_ipi_suspend,
};
+static struct syscore loongson_ipi_syscore = {
+ .ops = &loongson_ipi_syscore_ops,
+};
+
/*
* Enable boot cpu ipi before enabling nonboot cpus
* during syscore_resume.
*/
static int __init ipi_pm_init(void)
{
- register_syscore_ops(&loongson_ipi_syscore_ops);
+ register_syscore(&loongson_ipi_syscore);
return 0;
}
diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c
index 6a3c890f7bbfe..6c2c2010bbaee 100644
--- a/arch/mips/alchemy/common/dbdma.c
+++ b/arch/mips/alchemy/common/dbdma.c
@@ -982,7 +982,7 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr)
static unsigned long alchemy_dbdma_pm_data[NUM_DBDMA_CHANS + 1][6];
-static int alchemy_dbdma_suspend(void)
+static int alchemy_dbdma_suspend(void *data)
{
int i;
void __iomem *addr;
@@ -1019,7 +1019,7 @@ static int alchemy_dbdma_suspend(void)
return 0;
}
-static void alchemy_dbdma_resume(void)
+static void alchemy_dbdma_resume(void *data)
{
int i;
void __iomem *addr;
@@ -1044,11 +1044,15 @@ static void alchemy_dbdma_resume(void)
}
}
-static struct syscore_ops alchemy_dbdma_syscore_ops = {
+static const struct syscore_ops alchemy_dbdma_syscore_ops = {
.suspend = alchemy_dbdma_suspend,
.resume = alchemy_dbdma_resume,
};
+static struct syscore alchemy_dbdma_syscore = {
+ .ops = &alchemy_dbdma_syscore_ops,
+};
+
static int __init dbdma_setup(unsigned int irq, dbdev_tab_t *idtable)
{
int ret;
@@ -1071,7 +1075,7 @@ static int __init dbdma_setup(unsigned int irq, dbdev_tab_t *idtable)
printk(KERN_ERR "Cannot grab DBDMA interrupt!\n");
else {
dbdma_initialized = 1;
- register_syscore_ops(&alchemy_dbdma_syscore_ops);
+ register_syscore(&alchemy_dbdma_syscore);
}
return ret;
diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index da9f9220048fc..2403afcd2fb95 100644
--- a/arch/mips/alchemy/common/irq.c
+++ b/arch/mips/alchemy/common/irq.c
@@ -758,7 +758,7 @@ static inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d)
wmb();
}
-static int alchemy_ic_suspend(void)
+static int alchemy_ic_suspend(void *data)
{
alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR),
alchemy_gpic_pmdata);
@@ -767,7 +767,7 @@ static int alchemy_ic_suspend(void)
return 0;
}
-static void alchemy_ic_resume(void)
+static void alchemy_ic_resume(void *data)
{
alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR),
&alchemy_gpic_pmdata[7]);
@@ -775,7 +775,7 @@ static void alchemy_ic_resume(void)
alchemy_gpic_pmdata);
}
-static int alchemy_gpic_suspend(void)
+static int alchemy_gpic_suspend(void *data)
{
void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR);
int i;
@@ -806,7 +806,7 @@ static int alchemy_gpic_suspend(void)
return 0;
}
-static void alchemy_gpic_resume(void)
+static void alchemy_gpic_resume(void *data)
{
void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR);
int i;
@@ -837,16 +837,24 @@ static void alchemy_gpic_resume(void)
wmb();
}
-static struct syscore_ops alchemy_ic_pmops = {
+static const struct syscore_ops alchemy_ic_pmops = {
.suspend = alchemy_ic_suspend,
.resume = alchemy_ic_resume,
};
-static struct syscore_ops alchemy_gpic_pmops = {
+static struct syscore alchemy_ic_pm = {
+ .ops = &alchemy_ic_pmops,
+};
+
+static const struct syscore_ops alchemy_gpic_pmops = {
.suspend = alchemy_gpic_suspend,
.resume = alchemy_gpic_resume,
};
+static struct syscore alchemy_gpic_pm = {
+ .ops = &alchemy_gpic_pmops,
+};
+
/******************************************************************************/
/* create chained handlers for the 4 IC requests to the MIPS IRQ ctrl */
@@ -880,7 +888,7 @@ static void __init au1000_init_irq(struct alchemy_irqmap *map)
ic_init((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR));
ic_init((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR));
- register_syscore_ops(&alchemy_ic_pmops);
+ register_syscore(&alchemy_ic_pm);
mips_cpu_irq_init();
/* register all 64 possible IC0+IC1 irq sources as type "none".
@@ -925,7 +933,7 @@ static void __init alchemy_gpic_init_irq(const struct alchemy_irqmap *dints)
int i;
void __iomem *bank_base;
- register_syscore_ops(&alchemy_gpic_pmops);
+ register_syscore(&alchemy_gpic_pm);
mips_cpu_irq_init();
/* disable & ack all possible interrupt sources */
diff --git a/arch/mips/alchemy/common/usb.c b/arch/mips/alchemy/common/usb.c
index 5d618547ebf01..a55f32bf517cd 100644
--- a/arch/mips/alchemy/common/usb.c
+++ b/arch/mips/alchemy/common/usb.c
@@ -580,22 +580,26 @@ static void alchemy_usb_pm(int susp)
}
}
-static int alchemy_usb_suspend(void)
+static int alchemy_usb_suspend(void *data)
{
alchemy_usb_pm(1);
return 0;
}
-static void alchemy_usb_resume(void)
+static void alchemy_usb_resume(void *data)
{
alchemy_usb_pm(0);
}
-static struct syscore_ops alchemy_usb_pm_ops = {
+static const struct syscore_ops alchemy_usb_pm_syscore_ops = {
.suspend = alchemy_usb_suspend,
.resume = alchemy_usb_resume,
};
+static struct syscore alchemy_usb_pm_syscore = {
+ .ops = &alchemy_usb_pm_syscore_ops,
+};
+
static int __init alchemy_usb_init(void)
{
int ret = 0;
@@ -620,7 +624,7 @@ static int __init alchemy_usb_init(void)
}
if (!ret)
- register_syscore_ops(&alchemy_usb_pm_ops);
+ register_syscore(&alchemy_usb_pm_syscore);
return ret;
}
diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c
index 58625d1b64658..6bfee0f71803e 100644
--- a/arch/mips/pci/pci-alchemy.c
+++ b/arch/mips/pci/pci-alchemy.c
@@ -304,7 +304,7 @@ static int alchemy_pci_def_idsel(unsigned int devsel, int assert)
}
/* save PCI controller register contents. */
-static int alchemy_pci_suspend(void)
+static int alchemy_pci_suspend(void *data)
{
struct alchemy_pci_context *ctx = __alchemy_pci_ctx;
if (!ctx)
@@ -326,7 +326,7 @@ static int alchemy_pci_suspend(void)
return 0;
}
-static void alchemy_pci_resume(void)
+static void alchemy_pci_resume(void *data)
{
struct alchemy_pci_context *ctx = __alchemy_pci_ctx;
if (!ctx)
@@ -354,9 +354,13 @@ static void alchemy_pci_resume(void)
alchemy_pci_wired_entry(ctx); /* install it */
}
-static struct syscore_ops alchemy_pci_pmops = {
- .suspend = alchemy_pci_suspend,
- .resume = alchemy_pci_resume,
+static const struct syscore_ops alchemy_pci_syscore_ops = {
+ .suspend = alchemy_pci_suspend,
+ .resume = alchemy_pci_resume,
+};
+
+static struct syscore alchemy_pci_syscore = {
+ .ops = &alchemy_pci_syscore_ops,
};
static int alchemy_pci_probe(struct platform_device *pdev)
@@ -478,7 +482,7 @@ static int alchemy_pci_probe(struct platform_device *pdev)
__alchemy_pci_ctx = ctx;
platform_set_drvdata(pdev, ctx);
- register_syscore_ops(&alchemy_pci_pmops);
+ register_syscore(&alchemy_pci_syscore);
register_pci_controller(&ctx->alchemy_pci_ctrl);
dev_info(&pdev->dev, "PCI controller at %ld MHz\n",
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index dea6f0f258974..bbd3603206806 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -727,7 +727,7 @@ static inline void crash_register_spus(struct list_head *list)
}
#endif
-static void spu_shutdown(void)
+static void spu_shutdown(void *data)
{
struct spu *spu;
@@ -739,10 +739,14 @@ static void spu_shutdown(void)
mutex_unlock(&spu_full_list_mutex);
}
-static struct syscore_ops spu_syscore_ops = {
+static const struct syscore_ops spu_syscore_ops = {
.shutdown = spu_shutdown,
};
+static struct syscore spu_syscore = {
+ .ops = &spu_syscore_ops,
+};
+
static int __init init_spu_base(void)
{
int i, ret = 0;
@@ -776,7 +780,7 @@ static int __init init_spu_base(void)
crash_register_spus(&spu_full_list);
mutex_unlock(&spu_full_list_mutex);
spu_add_dev_attr(&dev_attr_stat);
- register_syscore_ops(&spu_syscore_ops);
+ register_syscore(&spu_syscore);
spu_init_affinity();
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 2202bf77c7a31..582ff2aafc5d8 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -599,7 +599,7 @@ static int pmacpic_find_viaint(void)
return viaint;
}
-static int pmacpic_suspend(void)
+static int pmacpic_suspend(void *data)
{
int viaint = pmacpic_find_viaint();
@@ -620,7 +620,7 @@ static int pmacpic_suspend(void)
return 0;
}
-static void pmacpic_resume(void)
+static void pmacpic_resume(void *data)
{
int i;
@@ -633,15 +633,19 @@ static void pmacpic_resume(void)
pmac_unmask_irq(irq_get_irq_data(i));
}
-static struct syscore_ops pmacpic_syscore_ops = {
+static const struct syscore_ops pmacpic_syscore_ops = {
.suspend = pmacpic_suspend,
.resume = pmacpic_resume,
};
+static struct syscore pmacpic_syscore = {
+ .ops = &pmacpic_syscore_ops,
+};
+
static int __init init_pmacpic_syscore(void)
{
if (pmac_irq_hw[0])
- register_syscore_ops(&pmacpic_syscore_ops);
+ register_syscore(&pmacpic_syscore);
return 0;
}
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
index 217cea150987d..7ed07232a69a4 100644
--- a/arch/powerpc/sysdev/fsl_lbc.c
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -350,7 +350,7 @@ static int fsl_lbc_ctrl_probe(struct platform_device *dev)
#ifdef CONFIG_SUSPEND
/* save lbc registers */
-static int fsl_lbc_syscore_suspend(void)
+static int fsl_lbc_syscore_suspend(void *data)
{
struct fsl_lbc_ctrl *ctrl;
struct fsl_lbc_regs __iomem *lbc;
@@ -374,7 +374,7 @@ static int fsl_lbc_syscore_suspend(void)
}
/* restore lbc registers */
-static void fsl_lbc_syscore_resume(void)
+static void fsl_lbc_syscore_resume(void *data)
{
struct fsl_lbc_ctrl *ctrl;
struct fsl_lbc_regs __iomem *lbc;
@@ -408,10 +408,14 @@ static const struct of_device_id fsl_lbc_match[] = {
};
#ifdef CONFIG_SUSPEND
-static struct syscore_ops lbc_syscore_pm_ops = {
+static const struct syscore_ops lbc_syscore_pm_ops = {
.suspend = fsl_lbc_syscore_suspend,
.resume = fsl_lbc_syscore_resume,
};
+
+static struct syscore lbc_syscore_pm = {
+ .ops = &lbc_syscore_pm_ops,
+};
#endif
static struct platform_driver fsl_lbc_ctrl_driver = {
@@ -425,7 +429,7 @@ static struct platform_driver fsl_lbc_ctrl_driver = {
static int __init fsl_lbc_init(void)
{
#ifdef CONFIG_SUSPEND
- register_syscore_ops(&lbc_syscore_pm_ops);
+ register_syscore(&lbc_syscore_pm);
#endif
return platform_driver_register(&fsl_lbc_ctrl_driver);
}
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index ef7707ea0db7b..4e501654cb41b 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -1258,7 +1258,7 @@ static void fsl_pci_syscore_do_suspend(struct pci_controller *hose)
send_pme_turnoff_message(hose);
}
-static int fsl_pci_syscore_suspend(void)
+static int fsl_pci_syscore_suspend(void *data)
{
struct pci_controller *hose, *tmp;
@@ -1291,7 +1291,7 @@ static void fsl_pci_syscore_do_resume(struct pci_controller *hose)
setup_pci_atmu(hose);
}
-static void fsl_pci_syscore_resume(void)
+static void fsl_pci_syscore_resume(void *data)
{
struct pci_controller *hose, *tmp;
@@ -1299,10 +1299,14 @@ static void fsl_pci_syscore_resume(void)
fsl_pci_syscore_do_resume(hose);
}
-static struct syscore_ops pci_syscore_pm_ops = {
+static const struct syscore_ops pci_syscore_pm_ops = {
.suspend = fsl_pci_syscore_suspend,
.resume = fsl_pci_syscore_resume,
};
+
+static struct syscore pci_syscore_pm = {
+ .ops = &pci_syscore_pm_ops,
+};
#endif
void fsl_pcibios_fixup_phb(struct pci_controller *phb)
@@ -1359,7 +1363,7 @@ static struct platform_driver fsl_pci_driver = {
static int __init fsl_pci_init(void)
{
#ifdef CONFIG_PM_SLEEP
- register_syscore_ops(&pci_syscore_pm_ops);
+ register_syscore(&pci_syscore_pm);
#endif
return platform_driver_register(&fsl_pci_driver);
}
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index 5f69e2d50f268..d7b2db9926f68 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -817,7 +817,7 @@ static struct {
u32 sercr;
} ipic_saved_state;
-static int ipic_suspend(void)
+static int ipic_suspend(void *data)
{
struct ipic *ipic = primary_ipic;
@@ -848,7 +848,7 @@ static int ipic_suspend(void)
return 0;
}
-static void ipic_resume(void)
+static void ipic_resume(void *data)
{
struct ipic *ipic = primary_ipic;
@@ -870,18 +870,22 @@ static void ipic_resume(void)
#define ipic_resume NULL
#endif
-static struct syscore_ops ipic_syscore_ops = {
+static const struct syscore_ops ipic_syscore_ops = {
.suspend = ipic_suspend,
.resume = ipic_resume,
};
+static struct syscore ipic_syscore = {
+ .ops = &ipic_syscore_ops,
+};
+
static int __init init_ipic_syscore(void)
{
if (!primary_ipic || !primary_ipic->regs)
return -ENODEV;
printk(KERN_DEBUG "Registering ipic system core operations\n");
- register_syscore_ops(&ipic_syscore_ops);
+ register_syscore(&ipic_syscore);
return 0;
}
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index d94cf36b0f658..479dca1d7d44f 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -1943,7 +1943,7 @@ static void mpic_suspend_one(struct mpic *mpic)
}
}
-static int mpic_suspend(void)
+static int mpic_suspend(void *data)
{
struct mpic *mpic = mpics;
@@ -1985,7 +1985,7 @@ static void mpic_resume_one(struct mpic *mpic)
} /* end for loop */
}
-static void mpic_resume(void)
+static void mpic_resume(void *data)
{
struct mpic *mpic = mpics;
@@ -1995,19 +1995,23 @@ static void mpic_resume(void)
}
}
-static struct syscore_ops mpic_syscore_ops = {
+static const struct syscore_ops mpic_syscore_ops = {
.resume = mpic_resume,
.suspend = mpic_suspend,
};
+static struct syscore mpic_syscore = {
+ .ops = &mpic_syscore_ops,
+};
+
static int mpic_init_sys(void)
{
int rc;
- register_syscore_ops(&mpic_syscore_ops);
+ register_syscore(&mpic_syscore);
rc = subsys_system_register(&mpic_subsys, NULL);
if (rc) {
- unregister_syscore_ops(&mpic_syscore_ops);
+ unregister_syscore(&mpic_syscore);
pr_err("mpic: Failed to register subsystem!\n");
return rc;
}
diff --git a/arch/powerpc/sysdev/mpic_timer.c b/arch/powerpc/sysdev/mpic_timer.c
index 7166e2e0baaf6..60f5b3934b511 100644
--- a/arch/powerpc/sysdev/mpic_timer.c
+++ b/arch/powerpc/sysdev/mpic_timer.c
@@ -519,7 +519,7 @@ static void __init timer_group_init(struct device_node *np)
kfree(priv);
}
-static void mpic_timer_resume(void)
+static void mpic_timer_resume(void *data)
{
struct timer_group_priv *priv;
@@ -535,10 +535,14 @@ static const struct of_device_id mpic_timer_ids[] = {
{},
};
-static struct syscore_ops mpic_timer_syscore_ops = {
+static const struct syscore_ops mpic_timer_syscore_ops = {
.resume = mpic_timer_resume,
};
+static struct syscore mpic_timer_syscore = {
+ .ops = &mpic_timer_syscore_ops,
+};
+
static int __init mpic_timer_init(void)
{
struct device_node *np = NULL;
@@ -546,7 +550,7 @@ static int __init mpic_timer_init(void)
for_each_matching_node(np, mpic_timer_ids)
timer_group_init(np);
- register_syscore_ops(&mpic_timer_syscore_ops);
+ register_syscore(&mpic_timer_syscore);
if (list_empty(&timer_group_list))
return -ENODEV;
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index 68eb7cc6e5643..482eec50f404e 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -857,7 +857,7 @@ static int __init pmb_debugfs_init(void)
subsys_initcall(pmb_debugfs_init);
#ifdef CONFIG_PM
-static void pmb_syscore_resume(void)
+static void pmb_syscore_resume(void *data)
{
struct pmb_entry *pmbe;
int i;
@@ -874,13 +874,17 @@ static void pmb_syscore_resume(void)
read_unlock(&pmb_rwlock);
}
-static struct syscore_ops pmb_syscore_ops = {
+static const struct syscore_ops pmb_syscore_ops = {
.resume = pmb_syscore_resume,
};
+static struct syscore pmb_syscore = {
+ .ops = &pmb_syscore_ops,
+};
+
static int __init pmb_sysdev_init(void)
{
- register_syscore_ops(&pmb_syscore_ops);
+ register_syscore(&pmb_syscore);
return 0;
}
subsys_initcall(pmb_sysdev_init);
diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c
index 1022d1dcbe447..5dde66bd94bdd 100644
--- a/arch/x86/events/amd/ibs.c
+++ b/arch/x86/events/amd/ibs.c
@@ -1488,26 +1488,30 @@ static int x86_pmu_amd_ibs_starting_cpu(unsigned int cpu)
#ifdef CONFIG_PM
-static int perf_ibs_suspend(void)
+static int perf_ibs_suspend(void *data)
{
clear_APIC_ibs();
return 0;
}
-static void perf_ibs_resume(void)
+static void perf_ibs_resume(void *data)
{
ibs_eilvt_setup();
setup_APIC_ibs();
}
-static struct syscore_ops perf_ibs_syscore_ops = {
+static const struct syscore_ops perf_ibs_syscore_ops = {
.resume = perf_ibs_resume,
.suspend = perf_ibs_suspend,
};
+static struct syscore perf_ibs_syscore = {
+ .ops = &perf_ibs_syscore_ops,
+};
+
static void perf_ibs_pm_init(void)
{
- register_syscore_ops(&perf_ibs_syscore_ops);
+ register_syscore(&perf_ibs_syscore);
}
#else
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
index 239f612816e6d..5d7e5b53e33ea 100644
--- a/arch/x86/hyperv/hv_init.c
+++ b/arch/x86/hyperv/hv_init.c
@@ -316,7 +316,7 @@ static int __init hv_pci_init(void)
return 1;
}
-static int hv_suspend(void)
+static int hv_suspend(void *data)
{
union hv_x64_msr_hypercall_contents hypercall_msr;
int ret;
@@ -343,7 +343,7 @@ static int hv_suspend(void)
return ret;
}
-static void hv_resume(void)
+static void hv_resume(void *data)
{
union hv_x64_msr_hypercall_contents hypercall_msr;
int ret;
@@ -370,11 +370,15 @@ static void hv_resume(void)
}
/* Note: when the ops are called, only CPU0 is online and IRQs are disabled. */
-static struct syscore_ops hv_syscore_ops = {
+static const struct syscore_ops hv_syscore_ops = {
.suspend = hv_suspend,
.resume = hv_resume,
};
+static struct syscore hv_syscore = {
+ .ops = &hv_syscore_ops,
+};
+
static void (* __initdata old_setup_percpu_clockev)(void);
static void __init hv_stimer_setup_percpu_clockev(void)
@@ -604,7 +608,7 @@ void __init hyperv_init(void)
x86_init.pci.arch_init = hv_pci_init;
- register_syscore_ops(&hv_syscore_ops);
+ register_syscore(&hv_syscore);
if (cpuid_ebx(HYPERV_CPUID_FEATURES) & HV_ACCESS_PARTITION_ID)
hv_get_partition_id();
diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c
index c884deca839b2..30a1916b0c4e5 100644
--- a/arch/x86/kernel/amd_gart_64.c
+++ b/arch/x86/kernel/amd_gart_64.c
@@ -591,7 +591,7 @@ static void gart_fixup_northbridges(void)
}
}
-static void gart_resume(void)
+static void gart_resume(void *data)
{
pr_info("PCI-DMA: Resuming GART IOMMU\n");
@@ -600,11 +600,15 @@ static void gart_resume(void)
enable_gart_translations();
}
-static struct syscore_ops gart_syscore_ops = {
+static const struct syscore_ops gart_syscore_ops = {
.resume = gart_resume,
};
+static struct syscore gart_syscore = {
+ .ops = &gart_syscore_ops,
+};
+
/*
* Private Northbridge GATT initialization in case we cannot use the
* AGP driver for some reason.
@@ -650,7 +654,7 @@ static __init int init_amd_gatt(struct agp_kern_info *info)
agp_gatt_table = gatt;
- register_syscore_ops(&gart_syscore_ops);
+ register_syscore(&gart_syscore);
flush_gart();
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 21dc37cca20ea..65c521d74ab84 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -2379,7 +2379,7 @@ static struct {
unsigned int apic_cmci;
} apic_pm_state;
-static int lapic_suspend(void)
+static int lapic_suspend(void *data)
{
unsigned long flags;
int maxlvt;
@@ -2427,7 +2427,7 @@ static int lapic_suspend(void)
return 0;
}
-static void lapic_resume(void)
+static void lapic_resume(void *data)
{
unsigned int l, h;
unsigned long flags;
@@ -2507,11 +2507,15 @@ static void lapic_resume(void)
* are needed on every CPU up until machine_halt/restart/poweroff.
*/
-static struct syscore_ops lapic_syscore_ops = {
+static const struct syscore_ops lapic_syscore_ops = {
.resume = lapic_resume,
.suspend = lapic_suspend,
};
+static struct syscore lapic_syscore = {
+ .ops = &lapic_syscore_ops,
+};
+
static void apic_pm_activate(void)
{
apic_pm_state.active = 1;
@@ -2521,7 +2525,7 @@ static int __init init_lapic_sysfs(void)
{
/* XXX: remove suspend/resume procs if !apic_pm_state.active? */
if (boot_cpu_has(X86_FEATURE_APIC))
- register_syscore_ops(&lapic_syscore_ops);
+ register_syscore(&lapic_syscore);
return 0;
}
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 1029ea4ac8ba3..2f478d8ef5624 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -2308,7 +2308,12 @@ static void resume_ioapic_id(int ioapic_idx)
}
}
-static void ioapic_resume(void)
+static int ioapic_suspend(void *data)
+{
+ return save_ioapic_entries();
+}
+
+static void ioapic_resume(void *data)
{
int ioapic_idx;
@@ -2318,14 +2323,18 @@ static void ioapic_resume(void)
restore_ioapic_entries();
}
-static struct syscore_ops ioapic_syscore_ops = {
- .suspend = save_ioapic_entries,
+static const struct syscore_ops ioapic_syscore_ops = {
+ .suspend = ioapic_suspend,
.resume = ioapic_resume,
};
+static struct syscore ioapic_syscore = {
+ .ops = &ioapic_syscore_ops,
+};
+
static int __init ioapic_init_ops(void)
{
- register_syscore_ops(&ioapic_syscore_ops);
+ register_syscore(&ioapic_syscore);
return 0;
}
diff --git a/arch/x86/kernel/cpu/aperfmperf.c b/arch/x86/kernel/cpu/aperfmperf.c
index f642de2ebdac8..e7c7b42459df9 100644
--- a/arch/x86/kernel/cpu/aperfmperf.c
+++ b/arch/x86/kernel/cpu/aperfmperf.c
@@ -36,7 +36,7 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(struct aperfmperf, cpu_samples) = {
.seq = SEQCNT_ZERO(cpu_samples.seq)
};
-static void init_counter_refs(void)
+static void init_counter_refs(void *data)
{
u64 aperf, mperf;
@@ -288,16 +288,20 @@ static bool __init intel_set_max_freq_ratio(void)
}
#ifdef CONFIG_PM_SLEEP
-static struct syscore_ops freq_invariance_syscore_ops = {
+static const struct syscore_ops freq_invariance_syscore_ops = {
.resume = init_counter_refs,
};
-static void register_freq_invariance_syscore_ops(void)
+static struct syscore freq_invariance_syscore = {
+ .ops = &freq_invariance_syscore_ops,
+};
+
+static void register_freq_invariance_syscore(void)
{
- register_syscore_ops(&freq_invariance_syscore_ops);
+ register_syscore(&freq_invariance_syscore);
}
#else
-static inline void register_freq_invariance_syscore_ops(void) {}
+static inline void register_freq_invariance_syscore(void) {}
#endif
static void freq_invariance_enable(void)
@@ -307,7 +311,7 @@ static void freq_invariance_enable(void)
return;
}
static_branch_enable_cpuslocked(&arch_scale_freq_key);
- register_freq_invariance_syscore_ops();
+ register_freq_invariance_syscore();
pr_info("Estimated ratio of average max frequency by base frequency (times 1024): %llu\n", arch_max_freq_ratio);
}
@@ -534,7 +538,7 @@ static int __init bp_init_aperfmperf(void)
if (!cpu_feature_enabled(X86_FEATURE_APERFMPERF))
return 0;
- init_counter_refs();
+ init_counter_refs(NULL);
bp_init_freq_invariance();
return 0;
}
@@ -543,5 +547,5 @@ early_initcall(bp_init_aperfmperf);
void ap_init_aperfmperf(void)
{
if (cpu_feature_enabled(X86_FEATURE_APERFMPERF))
- init_counter_refs();
+ init_counter_refs(NULL);
}
diff --git a/arch/x86/kernel/cpu/intel_epb.c b/arch/x86/kernel/cpu/intel_epb.c
index 30b1d63b97f3a..91b9020d08b6a 100644
--- a/arch/x86/kernel/cpu/intel_epb.c
+++ b/arch/x86/kernel/cpu/intel_epb.c
@@ -75,7 +75,7 @@ static u8 energ_perf_values[] = {
[EPB_INDEX_POWERSAVE] = ENERGY_PERF_BIAS_POWERSAVE,
};
-static int intel_epb_save(void)
+static int intel_epb_save(void *data)
{
u64 epb;
@@ -89,7 +89,7 @@ static int intel_epb_save(void)
return 0;
}
-static void intel_epb_restore(void)
+static void intel_epb_restore(void *data)
{
u64 val = this_cpu_read(saved_epb);
u64 epb;
@@ -114,11 +114,15 @@ static void intel_epb_restore(void)
wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, (epb & ~EPB_MASK) | val);
}
-static struct syscore_ops intel_epb_syscore_ops = {
+static const struct syscore_ops intel_epb_syscore_ops = {
.suspend = intel_epb_save,
.resume = intel_epb_restore,
};
+static struct syscore intel_epb_syscore = {
+ .ops = &intel_epb_syscore_ops,
+};
+
static const char * const energy_perf_strings[] = {
[EPB_INDEX_PERFORMANCE] = "performance",
[EPB_INDEX_BALANCE_PERFORMANCE] = "balance-performance",
@@ -185,7 +189,7 @@ static int intel_epb_online(unsigned int cpu)
{
struct device *cpu_dev = get_cpu_device(cpu);
- intel_epb_restore();
+ intel_epb_restore(NULL);
if (!cpuhp_tasks_frozen)
sysfs_merge_group(&cpu_dev->kobj, &intel_epb_attr_group);
@@ -199,7 +203,7 @@ static int intel_epb_offline(unsigned int cpu)
if (!cpuhp_tasks_frozen)
sysfs_unmerge_group(&cpu_dev->kobj, &intel_epb_attr_group);
- intel_epb_save();
+ intel_epb_save(NULL);
return 0;
}
@@ -230,7 +234,7 @@ static __init int intel_epb_init(void)
if (ret < 0)
goto err_out_online;
- register_syscore_ops(&intel_epb_syscore_ops);
+ register_syscore(&intel_epb_syscore);
return 0;
err_out_online:
diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c
index 7be30b3775785..6e6cb9dec9a74 100644
--- a/arch/x86/kernel/cpu/mce/core.c
+++ b/arch/x86/kernel/cpu/mce/core.c
@@ -2396,13 +2396,13 @@ static void vendor_disable_error_reporting(void)
mce_disable_error_reporting();
}
-static int mce_syscore_suspend(void)
+static int mce_syscore_suspend(void *data)
{
vendor_disable_error_reporting();
return 0;
}
-static void mce_syscore_shutdown(void)
+static void mce_syscore_shutdown(void *data)
{
vendor_disable_error_reporting();
}
@@ -2412,7 +2412,7 @@ static void mce_syscore_shutdown(void)
* Only one CPU is active at this time, the others get re-added later using
* CPU hotplug:
*/
-static void mce_syscore_resume(void)
+static void mce_syscore_resume(void *data)
{
__mcheck_cpu_init_generic();
__mcheck_cpu_init_vendor(raw_cpu_ptr(&cpu_info));
@@ -2420,12 +2420,16 @@ static void mce_syscore_resume(void)
cr4_set_bits(X86_CR4_MCE);
}
-static struct syscore_ops mce_syscore_ops = {
+static const struct syscore_ops mce_syscore_ops = {
.suspend = mce_syscore_suspend,
.shutdown = mce_syscore_shutdown,
.resume = mce_syscore_resume,
};
+static struct syscore mce_syscore = {
+ .ops = &mce_syscore_ops,
+};
+
/*
* mce_device: Sysfs support
*/
@@ -2826,7 +2830,7 @@ static __init int mcheck_init_device(void)
if (err < 0)
goto err_out_online;
- register_syscore_ops(&mce_syscore_ops);
+ register_syscore(&mce_syscore);
return 0;
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index e8021d3e58824..7809380e81a99 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -774,8 +774,17 @@ void microcode_bsp_resume(void)
reload_early_microcode(cpu);
}
-static struct syscore_ops mc_syscore_ops = {
- .resume = microcode_bsp_resume,
+static void microcode_bsp_syscore_resume(void *data)
+{
+ microcode_bsp_resume();
+}
+
+static const struct syscore_ops mc_syscore_ops = {
+ .resume = microcode_bsp_syscore_resume,
+};
+
+static struct syscore mc_syscore = {
+ .ops = &mc_syscore_ops,
};
static int mc_cpu_online(unsigned int cpu)
@@ -854,7 +863,7 @@ static int __init microcode_init(void)
}
}
- register_syscore_ops(&mc_syscore_ops);
+ register_syscore(&mc_syscore);
cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/microcode:online",
mc_cpu_online, mc_cpu_down_prep);
diff --git a/arch/x86/kernel/cpu/mtrr/legacy.c b/arch/x86/kernel/cpu/mtrr/legacy.c
index d25882fcf181d..2415ffaaf02c0 100644
--- a/arch/x86/kernel/cpu/mtrr/legacy.c
+++ b/arch/x86/kernel/cpu/mtrr/legacy.c
@@ -41,7 +41,7 @@ struct mtrr_value {
static struct mtrr_value *mtrr_value;
-static int mtrr_save(void)
+static int mtrr_save(void *data)
{
int i;
@@ -56,7 +56,7 @@ static int mtrr_save(void)
return 0;
}
-static void mtrr_restore(void)
+static void mtrr_restore(void *data)
{
int i;
@@ -69,11 +69,15 @@ static void mtrr_restore(void)
}
}
-static struct syscore_ops mtrr_syscore_ops = {
+static const struct syscore_ops mtrr_syscore_ops = {
.suspend = mtrr_save,
.resume = mtrr_restore,
};
+static struct syscore mtrr_syscore = {
+ .ops = &mtrr_syscore_ops,
+};
+
void mtrr_register_syscore(void)
{
mtrr_value = kcalloc(num_var_ranges, sizeof(*mtrr_value), GFP_KERNEL);
@@ -86,5 +90,5 @@ void mtrr_register_syscore(void)
* TBD: is there any system with such CPU which supports
* suspend/resume? If no, we should remove the code.
*/
- register_syscore_ops(&mtrr_syscore_ops);
+ register_syscore(&mtrr_syscore);
}
diff --git a/arch/x86/kernel/cpu/umwait.c b/arch/x86/kernel/cpu/umwait.c
index 2293efd6ffa69..66ed3802bd137 100644
--- a/arch/x86/kernel/cpu/umwait.c
+++ b/arch/x86/kernel/cpu/umwait.c
@@ -86,15 +86,19 @@ static int umwait_cpu_offline(unsigned int cpu)
* trust the firmware nor does it matter if the same value is written
* again.
*/
-static void umwait_syscore_resume(void)
+static void umwait_syscore_resume(void *data)
{
umwait_update_control_msr(NULL);
}
-static struct syscore_ops umwait_syscore_ops = {
+static const struct syscore_ops umwait_syscore_ops = {
.resume = umwait_syscore_resume,
};
+static struct syscore umwait_syscore = {
+ .ops = &umwait_syscore_ops,
+};
+
/* sysfs interface */
/*
@@ -226,7 +230,7 @@ static int __init umwait_init(void)
return ret;
}
- register_syscore_ops(&umwait_syscore_ops);
+ register_syscore(&umwait_syscore);
/*
* Add umwait control interface. Ignore failure, so at least the
diff --git a/arch/x86/kernel/i8237.c b/arch/x86/kernel/i8237.c
index 2cd124ad9380c..896d46b442848 100644
--- a/arch/x86/kernel/i8237.c
+++ b/arch/x86/kernel/i8237.c
@@ -19,7 +19,7 @@
* in asm/dma.h.
*/
-static void i8237A_resume(void)
+static void i8237A_resume(void *data)
{
unsigned long flags;
int i;
@@ -41,10 +41,14 @@ static void i8237A_resume(void)
release_dma_lock(flags);
}
-static struct syscore_ops i8237_syscore_ops = {
+static const struct syscore_ops i8237_syscore_ops = {
.resume = i8237A_resume,
};
+static struct syscore i8237_syscore = {
+ .ops = &i8237_syscore_ops,
+};
+
static int __init i8237A_init_ops(void)
{
/*
@@ -70,7 +74,7 @@ static int __init i8237A_init_ops(void)
if (x86_pnpbios_disabled() && dmi_get_bios_year() >= 2017)
return -ENODEV;
- register_syscore_ops(&i8237_syscore_ops);
+ register_syscore(&i8237_syscore);
return 0;
}
device_initcall(i8237A_init_ops);
diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c
index c20d1832c4812..73200f492e11c 100644
--- a/arch/x86/kernel/i8259.c
+++ b/arch/x86/kernel/i8259.c
@@ -246,19 +246,19 @@ static void save_ELCR(char *trigger)
trigger[1] = inb(PIC_ELCR2) & 0xDE;
}
-static void i8259A_resume(void)
+static void i8259A_resume(void *data)
{
init_8259A(i8259A_auto_eoi);
restore_ELCR(irq_trigger);
}
-static int i8259A_suspend(void)
+static int i8259A_suspend(void *data)
{
save_ELCR(irq_trigger);
return 0;
}
-static void i8259A_shutdown(void)
+static void i8259A_shutdown(void *data)
{
/* Put the i8259A into a quiescent state that
* the kernel initialization code can get it
@@ -268,12 +268,16 @@ static void i8259A_shutdown(void)
outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */
}
-static struct syscore_ops i8259_syscore_ops = {
+static const struct syscore_ops i8259_syscore_ops = {
.suspend = i8259A_suspend,
.resume = i8259A_resume,
.shutdown = i8259A_shutdown,
};
+static struct syscore i8259_syscore = {
+ .ops = &i8259_syscore_ops,
+};
+
static void mask_8259A(void)
{
unsigned long flags;
@@ -443,7 +447,7 @@ EXPORT_SYMBOL(legacy_pic);
static int __init i8259A_init_ops(void)
{
if (legacy_pic == &default_legacy_pic)
- register_syscore_ops(&i8259_syscore_ops);
+ register_syscore(&i8259_syscore);
return 0;
}
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 46887d60348ef..a4c78026eea0b 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -720,7 +720,7 @@ static int kvm_cpu_down_prepare(unsigned int cpu)
#endif
-static int kvm_suspend(void)
+static int kvm_suspend(void *data)
{
u64 val = 0;
@@ -734,7 +734,7 @@ static int kvm_suspend(void)
return 0;
}
-static void kvm_resume(void)
+static void kvm_resume(void *data)
{
kvm_cpu_online(raw_smp_processor_id());
@@ -744,11 +744,15 @@ static void kvm_resume(void)
#endif
}
-static struct syscore_ops kvm_syscore_ops = {
+static const struct syscore_ops kvm_syscore_ops = {
.suspend = kvm_suspend,
.resume = kvm_resume,
};
+static struct syscore kvm_syscore = {
+ .ops = &kvm_syscore_ops,
+};
+
static void kvm_pv_guest_cpu_reboot(void *unused)
{
kvm_guest_cpu_offline(true);
@@ -859,7 +863,7 @@ static void __init kvm_guest_init(void)
machine_ops.crash_shutdown = kvm_crash_shutdown;
#endif
- register_syscore_ops(&kvm_syscore_ops);
+ register_syscore(&kvm_syscore);
/*
* Hard lockup detection is enabled by default. Disable it, as guests
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index b727db968f334..ce022799e1b33 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -761,7 +761,7 @@ static int acpi_pci_link_resume(struct acpi_pci_link *link)
return 0;
}
-static void irqrouter_resume(void)
+static void irqrouter_resume(void *data)
{
struct acpi_pci_link *link;
@@ -888,10 +888,14 @@ static int __init acpi_irq_balance_set(char *str)
__setup("acpi_irq_balance", acpi_irq_balance_set);
-static struct syscore_ops irqrouter_syscore_ops = {
+static const struct syscore_ops irqrouter_syscore_ops = {
.resume = irqrouter_resume,
};
+static struct syscore irqrouter_syscore = {
+ .ops = &irqrouter_syscore_ops,
+};
+
void __init acpi_pci_link_init(void)
{
if (acpi_noirq)
@@ -904,6 +908,6 @@ void __init acpi_pci_link_init(void)
else
acpi_irq_balance = 0;
}
- register_syscore_ops(&irqrouter_syscore_ops);
+ register_syscore(&irqrouter_syscore);
acpi_scan_add_handler(&pci_link_handler);
}
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 0b7fa4a8c379c..1b9579bb97c27 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -892,13 +892,13 @@ bool acpi_s2idle_wakeup(void)
#ifdef CONFIG_PM_SLEEP
static u32 saved_bm_rld;
-static int acpi_save_bm_rld(void)
+static int acpi_save_bm_rld(void *data)
{
acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &saved_bm_rld);
return 0;
}
-static void acpi_restore_bm_rld(void)
+static void acpi_restore_bm_rld(void *data)
{
u32 resumed_bm_rld = 0;
@@ -909,14 +909,18 @@ static void acpi_restore_bm_rld(void)
acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld);
}
-static struct syscore_ops acpi_sleep_syscore_ops = {
+static const struct syscore_ops acpi_sleep_syscore_ops = {
.suspend = acpi_save_bm_rld,
.resume = acpi_restore_bm_rld,
};
+static struct syscore acpi_sleep_syscore = {
+ .ops = &acpi_sleep_syscore_ops,
+};
+
static void acpi_sleep_syscore_init(void)
{
- register_syscore_ops(&acpi_sleep_syscore_ops);
+ register_syscore(&acpi_sleep_syscore);
}
#else
static inline void acpi_sleep_syscore_init(void) {}
diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c
index b4c4a53295707..b894687b059ca 100644
--- a/drivers/base/firmware_loader/main.c
+++ b/drivers/base/firmware_loader/main.c
@@ -1621,16 +1621,20 @@ static int fw_pm_notify(struct notifier_block *notify_block,
}
/* stop caching firmware once syscore_suspend is reached */
-static int fw_suspend(void)
+static int fw_suspend(void *data)
{
fw_cache.state = FW_LOADER_NO_CACHE;
return 0;
}
-static struct syscore_ops fw_syscore_ops = {
+static const struct syscore_ops fw_syscore_ops = {
.suspend = fw_suspend,
};
+static struct syscore fw_syscore = {
+ .ops = &fw_syscore_ops,
+};
+
static int __init register_fw_pm_ops(void)
{
int ret;
@@ -1646,14 +1650,14 @@ static int __init register_fw_pm_ops(void)
if (ret)
return ret;
- register_syscore_ops(&fw_syscore_ops);
+ register_syscore(&fw_syscore);
return ret;
}
static inline void unregister_fw_pm_ops(void)
{
- unregister_syscore_ops(&fw_syscore_ops);
+ unregister_syscore(&fw_syscore);
unregister_pm_notifier(&fw_cache.pm_notify);
}
#else
diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c
index 13db1f78d2ce9..483adb796654f 100644
--- a/drivers/base/syscore.c
+++ b/drivers/base/syscore.c
@@ -11,32 +11,32 @@
#include <linux/suspend.h>
#include <trace/events/power.h>
-static LIST_HEAD(syscore_ops_list);
-static DEFINE_MUTEX(syscore_ops_lock);
+static LIST_HEAD(syscore_list);
+static DEFINE_MUTEX(syscore_lock);
/**
- * register_syscore_ops - Register a set of system core operations.
- * @ops: System core operations to register.
+ * register_syscore - Register a set of system core operations.
+ * @syscore: System core operations to register.
*/
-void register_syscore_ops(struct syscore_ops *ops)
+void register_syscore(struct syscore *syscore)
{
- mutex_lock(&syscore_ops_lock);
- list_add_tail(&ops->node, &syscore_ops_list);
- mutex_unlock(&syscore_ops_lock);
+ mutex_lock(&syscore_lock);
+ list_add_tail(&syscore->node, &syscore_list);
+ mutex_unlock(&syscore_lock);
}
-EXPORT_SYMBOL_GPL(register_syscore_ops);
+EXPORT_SYMBOL_GPL(register_syscore);
/**
- * unregister_syscore_ops - Unregister a set of system core operations.
- * @ops: System core operations to unregister.
+ * unregister_syscore - Unregister a set of system core operations.
+ * @syscore: System core operations to unregister.
*/
-void unregister_syscore_ops(struct syscore_ops *ops)
+void unregister_syscore(struct syscore *syscore)
{
- mutex_lock(&syscore_ops_lock);
- list_del(&ops->node);
- mutex_unlock(&syscore_ops_lock);
+ mutex_lock(&syscore_lock);
+ list_del(&syscore->node);
+ mutex_unlock(&syscore_lock);
}
-EXPORT_SYMBOL_GPL(unregister_syscore_ops);
+EXPORT_SYMBOL_GPL(unregister_syscore);
#ifdef CONFIG_PM_SLEEP
/**
@@ -46,7 +46,7 @@ EXPORT_SYMBOL_GPL(unregister_syscore_ops);
*/
int syscore_suspend(void)
{
- struct syscore_ops *ops;
+ struct syscore *syscore;
int ret = 0;
trace_suspend_resume(TPS("syscore_suspend"), 0, true);
@@ -59,25 +59,27 @@ int syscore_suspend(void)
WARN_ONCE(!irqs_disabled(),
"Interrupts enabled before system core suspend.\n");
- list_for_each_entry_reverse(ops, &syscore_ops_list, node)
- if (ops->suspend) {
- pm_pr_dbg("Calling %pS\n", ops->suspend);
- ret = ops->suspend();
+ list_for_each_entry_reverse(syscore, &syscore_list, node)
+ if (syscore->ops->suspend) {
+ pm_pr_dbg("Calling %pS\n", syscore->ops->suspend);
+ ret = syscore->ops->suspend(syscore->data);
if (ret)
goto err_out;
WARN_ONCE(!irqs_disabled(),
- "Interrupts enabled after %pS\n", ops->suspend);
+ "Interrupts enabled after %pS\n",
+ syscore->ops->suspend);
}
trace_suspend_resume(TPS("syscore_suspend"), 0, false);
return 0;
err_out:
- pr_err("PM: System core suspend callback %pS failed.\n", ops->suspend);
+ pr_err("PM: System core suspend callback %pS failed.\n",
+ syscore->ops->suspend);
- list_for_each_entry_continue(ops, &syscore_ops_list, node)
- if (ops->resume)
- ops->resume();
+ list_for_each_entry_continue(syscore, &syscore_list, node)
+ if (syscore->ops->resume)
+ syscore->ops->resume(syscore->data);
return ret;
}
@@ -90,18 +92,19 @@ EXPORT_SYMBOL_GPL(syscore_suspend);
*/
void syscore_resume(void)
{
- struct syscore_ops *ops;
+ struct syscore *syscore;
trace_suspend_resume(TPS("syscore_resume"), 0, true);
WARN_ONCE(!irqs_disabled(),
"Interrupts enabled before system core resume.\n");
- list_for_each_entry(ops, &syscore_ops_list, node)
- if (ops->resume) {
- pm_pr_dbg("Calling %pS\n", ops->resume);
- ops->resume();
+ list_for_each_entry(syscore, &syscore_list, node)
+ if (syscore->ops->resume) {
+ pm_pr_dbg("Calling %pS\n", syscore->ops->resume);
+ syscore->ops->resume(syscore->data);
WARN_ONCE(!irqs_disabled(),
- "Interrupts enabled after %pS\n", ops->resume);
+ "Interrupts enabled after %pS\n",
+ syscore->ops->resume);
}
trace_suspend_resume(TPS("syscore_resume"), 0, false);
}
@@ -113,16 +116,17 @@ EXPORT_SYMBOL_GPL(syscore_resume);
*/
void syscore_shutdown(void)
{
- struct syscore_ops *ops;
+ struct syscore *syscore;
- mutex_lock(&syscore_ops_lock);
+ mutex_lock(&syscore_lock);
- list_for_each_entry_reverse(ops, &syscore_ops_list, node)
- if (ops->shutdown) {
+ list_for_each_entry_reverse(syscore, &syscore_list, node)
+ if (syscore->ops->shutdown) {
if (initcall_debug)
- pr_info("PM: Calling %pS\n", ops->shutdown);
- ops->shutdown();
+ pr_info("PM: Calling %pS\n",
+ syscore->ops->shutdown);
+ syscore->ops->shutdown(syscore->data);
}
- mutex_unlock(&syscore_ops_lock);
+ mutex_unlock(&syscore_lock);
}
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 00cb792bda18b..dd94145c9b222 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -1006,7 +1006,7 @@ static __init int mvebu_mbus_debugfs_init(void)
}
fs_initcall(mvebu_mbus_debugfs_init);
-static int mvebu_mbus_suspend(void)
+static int mvebu_mbus_suspend(void *data)
{
struct mvebu_mbus_state *s = &mbus_state;
int win;
@@ -1040,7 +1040,7 @@ static int mvebu_mbus_suspend(void)
return 0;
}
-static void mvebu_mbus_resume(void)
+static void mvebu_mbus_resume(void *data)
{
struct mvebu_mbus_state *s = &mbus_state;
int win;
@@ -1069,9 +1069,13 @@ static void mvebu_mbus_resume(void)
}
}
-static struct syscore_ops mvebu_mbus_syscore_ops = {
- .suspend = mvebu_mbus_suspend,
- .resume = mvebu_mbus_resume,
+static const struct syscore_ops mvebu_mbus_syscore_ops = {
+ .suspend = mvebu_mbus_suspend,
+ .resume = mvebu_mbus_resume,
+};
+
+static struct syscore mvebu_mbus_syscore = {
+ .ops = &mvebu_mbus_syscore_ops,
};
static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
@@ -1118,7 +1122,7 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
writel(UNIT_SYNC_BARRIER_ALL,
mbus->mbuswins_base + UNIT_SYNC_BARRIER_OFF);
- register_syscore_ops(&mvebu_mbus_syscore_ops);
+ register_syscore(&mvebu_mbus_syscore);
return 0;
}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 40bdc1c80ab08..3d5c2085fc9e5 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -115,7 +115,7 @@ struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
/* Address in SECURAM that say if we suspend to backup mode. */
static void __iomem *at91_pmc_backup_suspend;
-static int at91_pmc_suspend(void)
+static int at91_pmc_suspend(void *data)
{
unsigned int backup;
@@ -129,7 +129,7 @@ static int at91_pmc_suspend(void)
return clk_save_context();
}
-static void at91_pmc_resume(void)
+static void at91_pmc_resume(void *data)
{
unsigned int backup;
@@ -143,11 +143,15 @@ static void at91_pmc_resume(void)
clk_restore_context();
}
-static struct syscore_ops pmc_syscore_ops = {
+static const struct syscore_ops pmc_syscore_ops = {
.suspend = at91_pmc_suspend,
.resume = at91_pmc_resume,
};
+static struct syscore pmc_syscore = {
+ .ops = &pmc_syscore_ops,
+};
+
static const struct of_device_id pmc_dt_ids[] = {
{ .compatible = "atmel,sama5d2-pmc" },
{ .compatible = "microchip,sama7g5-pmc", },
@@ -184,7 +188,7 @@ static int __init pmc_register_ops(void)
return -ENOMEM;
}
- register_syscore_ops(&pmc_syscore_ops);
+ register_syscore(&pmc_syscore);
return 0;
}
diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c
index 9e11f1c7c397e..41eb38552a9c7 100644
--- a/drivers/clk/imx/clk-vf610.c
+++ b/drivers/clk/imx/clk-vf610.c
@@ -139,7 +139,7 @@ static struct clk * __init vf610_get_fixed_clock(
return clk;
};
-static int vf610_clk_suspend(void)
+static int vf610_clk_suspend(void *data)
{
int i;
@@ -156,7 +156,7 @@ static int vf610_clk_suspend(void)
return 0;
}
-static void vf610_clk_resume(void)
+static void vf610_clk_resume(void *data)
{
int i;
@@ -171,11 +171,15 @@ static void vf610_clk_resume(void)
writel_relaxed(ccgr[i], CCM_CCGRx(i));
}
-static struct syscore_ops vf610_clk_syscore_ops = {
+static const struct syscore_ops vf610_clk_syscore_ops = {
.suspend = vf610_clk_suspend,
.resume = vf610_clk_resume,
};
+static struct syscore vf610_clk_syscore = {
+ .ops = &vf610_clk_syscore_ops,
+};
+
static void __init vf610_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
@@ -462,7 +466,7 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clk[clks_init_on[i]]);
- register_syscore_ops(&vf610_clk_syscore_ops);
+ register_syscore(&vf610_clk_syscore);
/* Add the clocks to provider list */
clk_data.clks = clk;
diff --git a/drivers/clk/ingenic/jz4725b-cgu.c b/drivers/clk/ingenic/jz4725b-cgu.c
index 590e9c85cb25b..94cee44c854f9 100644
--- a/drivers/clk/ingenic/jz4725b-cgu.c
+++ b/drivers/clk/ingenic/jz4725b-cgu.c
@@ -268,6 +268,6 @@ static void __init jz4725b_cgu_init(struct device_node *np)
if (retval)
pr_err("%s: failed to register CGU Clocks\n", __func__);
- ingenic_cgu_register_syscore_ops(cgu);
+ ingenic_cgu_register_syscore(cgu);
}
CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init);
diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c
index 3e0a30574ebb3..2def3aedc8dd2 100644
--- a/drivers/clk/ingenic/jz4740-cgu.c
+++ b/drivers/clk/ingenic/jz4740-cgu.c
@@ -266,6 +266,6 @@ static void __init jz4740_cgu_init(struct device_node *np)
if (retval)
pr_err("%s: failed to register CGU Clocks\n", __func__);
- ingenic_cgu_register_syscore_ops(cgu);
+ ingenic_cgu_register_syscore(cgu);
}
CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init);
diff --git a/drivers/clk/ingenic/jz4755-cgu.c b/drivers/clk/ingenic/jz4755-cgu.c
index f2c2d848dab7a..17cf5dcaece99 100644
--- a/drivers/clk/ingenic/jz4755-cgu.c
+++ b/drivers/clk/ingenic/jz4755-cgu.c
@@ -337,7 +337,7 @@ static void __init jz4755_cgu_init(struct device_node *np)
if (retval)
pr_err("%s: failed to register CGU Clocks\n", __func__);
- ingenic_cgu_register_syscore_ops(cgu);
+ ingenic_cgu_register_syscore(cgu);
}
/*
* CGU has some children devices, this is useful for probing children devices
diff --git a/drivers/clk/ingenic/jz4760-cgu.c b/drivers/clk/ingenic/jz4760-cgu.c
index e407f00bd5942..372fe4b079927 100644
--- a/drivers/clk/ingenic/jz4760-cgu.c
+++ b/drivers/clk/ingenic/jz4760-cgu.c
@@ -436,7 +436,7 @@ static void __init jz4760_cgu_init(struct device_node *np)
if (retval)
pr_err("%s: failed to register CGU Clocks\n", __func__);
- ingenic_cgu_register_syscore_ops(cgu);
+ ingenic_cgu_register_syscore(cgu);
}
/* We only probe via devicetree, no need for a platform driver */
diff --git a/drivers/clk/ingenic/jz4770-cgu.c b/drivers/clk/ingenic/jz4770-cgu.c
index 6ae1740367f9e..58f1d3bad6774 100644
--- a/drivers/clk/ingenic/jz4770-cgu.c
+++ b/drivers/clk/ingenic/jz4770-cgu.c
@@ -456,7 +456,7 @@ static void __init jz4770_cgu_init(struct device_node *np)
if (retval)
pr_err("%s: failed to register CGU Clocks\n", __func__);
- ingenic_cgu_register_syscore_ops(cgu);
+ ingenic_cgu_register_syscore(cgu);
}
/* We only probe via devicetree, no need for a platform driver */
diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c
index b1dadc0a5e755..a3fb27298bbeb 100644
--- a/drivers/clk/ingenic/jz4780-cgu.c
+++ b/drivers/clk/ingenic/jz4780-cgu.c
@@ -803,6 +803,6 @@ static void __init jz4780_cgu_init(struct device_node *np)
return;
}
- ingenic_cgu_register_syscore_ops(cgu);
+ ingenic_cgu_register_syscore(cgu);
}
CLK_OF_DECLARE_DRIVER(jz4780_cgu, "ingenic,jz4780-cgu", jz4780_cgu_init);
diff --git a/drivers/clk/ingenic/pm.c b/drivers/clk/ingenic/pm.c
index 341752b640d2b..206d5cf2872f6 100644
--- a/drivers/clk/ingenic/pm.c
+++ b/drivers/clk/ingenic/pm.c
@@ -15,7 +15,7 @@
static void __iomem * __maybe_unused ingenic_cgu_base;
-static int __maybe_unused ingenic_cgu_pm_suspend(void)
+static int __maybe_unused ingenic_cgu_pm_suspend(void *data)
{
u32 val = readl(ingenic_cgu_base + CGU_REG_LCR);
@@ -24,22 +24,26 @@ static int __maybe_unused ingenic_cgu_pm_suspend(void)
return 0;
}
-static void __maybe_unused ingenic_cgu_pm_resume(void)
+static void __maybe_unused ingenic_cgu_pm_resume(void *data)
{
u32 val = readl(ingenic_cgu_base + CGU_REG_LCR);
writel(val & ~LCR_LOW_POWER_MODE, ingenic_cgu_base + CGU_REG_LCR);
}
-static struct syscore_ops __maybe_unused ingenic_cgu_pm_ops = {
+static const struct syscore_ops __maybe_unused ingenic_cgu_pm_ops = {
.suspend = ingenic_cgu_pm_suspend,
.resume = ingenic_cgu_pm_resume,
};
-void ingenic_cgu_register_syscore_ops(struct ingenic_cgu *cgu)
+static struct syscore __maybe_unused ingenic_cgu_pm = {
+ .ops = &ingenic_cgu_pm_ops,
+};
+
+void ingenic_cgu_register_syscore(struct ingenic_cgu *cgu)
{
if (IS_ENABLED(CONFIG_PM_SLEEP)) {
ingenic_cgu_base = cgu->base;
- register_syscore_ops(&ingenic_cgu_pm_ops);
+ register_syscore(&ingenic_cgu_pm);
}
}
diff --git a/drivers/clk/ingenic/pm.h b/drivers/clk/ingenic/pm.h
index fa7540407b6b7..0dcb57dc64cb4 100644
--- a/drivers/clk/ingenic/pm.h
+++ b/drivers/clk/ingenic/pm.h
@@ -7,6 +7,6 @@
struct ingenic_cgu;
-void ingenic_cgu_register_syscore_ops(struct ingenic_cgu *cgu);
+void ingenic_cgu_register_syscore(struct ingenic_cgu *cgu);
#endif /* DRIVERS_CLK_INGENIC_PM_H */
diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c
index 7d04ef40b7cf9..bc6a51da20725 100644
--- a/drivers/clk/ingenic/tcu.c
+++ b/drivers/clk/ingenic/tcu.c
@@ -455,7 +455,7 @@ static int __init ingenic_tcu_probe(struct device_node *np)
return ret;
}
-static int __maybe_unused tcu_pm_suspend(void)
+static int __maybe_unused tcu_pm_suspend(void *data)
{
struct ingenic_tcu *tcu = ingenic_tcu;
@@ -465,7 +465,7 @@ static int __maybe_unused tcu_pm_suspend(void)
return 0;
}
-static void __maybe_unused tcu_pm_resume(void)
+static void __maybe_unused tcu_pm_resume(void *data)
{
struct ingenic_tcu *tcu = ingenic_tcu;
@@ -473,11 +473,15 @@ static void __maybe_unused tcu_pm_resume(void)
clk_enable(tcu->clk);
}
-static struct syscore_ops __maybe_unused tcu_pm_ops = {
+static const struct syscore_ops __maybe_unused tcu_pm_ops = {
.suspend = tcu_pm_suspend,
.resume = tcu_pm_resume,
};
+static struct syscore __maybe_unused tcu_pm = {
+ .ops = &tcu_pm_ops,
+};
+
static void __init ingenic_tcu_init(struct device_node *np)
{
int ret = ingenic_tcu_probe(np);
@@ -486,7 +490,7 @@ static void __init ingenic_tcu_init(struct device_node *np)
pr_crit("Failed to initialize TCU clocks: %d\n", ret);
if (IS_ENABLED(CONFIG_PM_SLEEP))
- register_syscore_ops(&tcu_pm_ops);
+ register_syscore(&tcu_pm);
}
CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-tcu", ingenic_tcu_init);
diff --git a/drivers/clk/ingenic/x1000-cgu.c b/drivers/clk/ingenic/x1000-cgu.c
index feb03eed4fe8c..98f7da93e0137 100644
--- a/drivers/clk/ingenic/x1000-cgu.c
+++ b/drivers/clk/ingenic/x1000-cgu.c
@@ -555,7 +555,7 @@ static void __init x1000_cgu_init(struct device_node *np)
return;
}
- ingenic_cgu_register_syscore_ops(cgu);
+ ingenic_cgu_register_syscore(cgu);
}
/*
* CGU has some children devices, this is useful for probing children devices
diff --git a/drivers/clk/ingenic/x1830-cgu.c b/drivers/clk/ingenic/x1830-cgu.c
index 0fd46e50a513f..acf856e5009e0 100644
--- a/drivers/clk/ingenic/x1830-cgu.c
+++ b/drivers/clk/ingenic/x1830-cgu.c
@@ -463,7 +463,7 @@ static void __init x1830_cgu_init(struct device_node *np)
return;
}
- ingenic_cgu_register_syscore_ops(cgu);
+ ingenic_cgu_register_syscore(cgu);
}
/*
* CGU has some children devices, this is useful for probing children devices
diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c
index 785dbede48354..5adbbd91a6db3 100644
--- a/drivers/clk/mvebu/common.c
+++ b/drivers/clk/mvebu/common.c
@@ -215,22 +215,26 @@ static struct clk *clk_gating_get_src(
return ERR_PTR(-ENODEV);
}
-static int mvebu_clk_gating_suspend(void)
+static int mvebu_clk_gating_suspend(void *data)
{
ctrl->saved_reg = readl(ctrl->base);
return 0;
}
-static void mvebu_clk_gating_resume(void)
+static void mvebu_clk_gating_resume(void *data)
{
writel(ctrl->saved_reg, ctrl->base);
}
-static struct syscore_ops clk_gate_syscore_ops = {
+static const struct syscore_ops clk_gate_syscore_ops = {
.suspend = mvebu_clk_gating_suspend,
.resume = mvebu_clk_gating_resume,
};
+static struct syscore clk_gate_syscore = {
+ .ops = &clk_gate_syscore_ops,
+};
+
void __init mvebu_clk_gating_setup(struct device_node *np,
const struct clk_gating_soc_desc *desc)
{
@@ -284,7 +288,7 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
of_clk_add_provider(np, clk_gating_get_src, ctrl);
- register_syscore_ops(&clk_gate_syscore_ops);
+ register_syscore(&clk_gate_syscore);
return;
gates_out:
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 90d329216064a..9e64fa5321a2c 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -871,7 +871,7 @@ static const int rk3288_saved_cru_reg_ids[] = {
static u32 rk3288_saved_cru_regs[ARRAY_SIZE(rk3288_saved_cru_reg_ids)];
-static int rk3288_clk_suspend(void)
+static int rk3288_clk_suspend(void *data)
{
int i, reg_id;
@@ -906,7 +906,7 @@ static int rk3288_clk_suspend(void)
return 0;
}
-static void rk3288_clk_resume(void)
+static void rk3288_clk_resume(void *data)
{
int i, reg_id;
@@ -923,11 +923,15 @@ static void rk3288_clk_shutdown(void)
writel_relaxed(0xf3030000, rk3288_cru_base + RK3288_MODE_CON);
}
-static struct syscore_ops rk3288_clk_syscore_ops = {
+static const struct syscore_ops rk3288_clk_syscore_ops = {
.suspend = rk3288_clk_suspend,
.resume = rk3288_clk_resume,
};
+static struct syscore rk3288_clk_syscore = {
+ .ops = &rk3288_clk_syscore_ops,
+};
+
static void __init rk3288_common_init(struct device_node *np,
enum rk3288_variant soc)
{
@@ -976,7 +980,7 @@ static void __init rk3288_common_init(struct device_node *np,
rockchip_register_restart_notifier(ctx, RK3288_GLB_SRST_FST,
rk3288_clk_shutdown);
- register_syscore_ops(&rk3288_clk_syscore_ops);
+ register_syscore(&rk3288_clk_syscore);
rockchip_clk_of_add_provider(np, ctx);
}
diff --git a/drivers/clk/samsung/clk-s5pv210-audss.c b/drivers/clk/samsung/clk-s5pv210-audss.c
index b31c00ea331f3..75c7721e4e4e4 100644
--- a/drivers/clk/samsung/clk-s5pv210-audss.c
+++ b/drivers/clk/samsung/clk-s5pv210-audss.c
@@ -35,7 +35,7 @@ static unsigned long reg_save[][2] = {
{ASS_CLK_GATE, 0},
};
-static int s5pv210_audss_clk_suspend(void)
+static int s5pv210_audss_clk_suspend(void *data)
{
int i;
@@ -45,7 +45,7 @@ static int s5pv210_audss_clk_suspend(void)
return 0;
}
-static void s5pv210_audss_clk_resume(void)
+static void s5pv210_audss_clk_resume(void *data)
{
int i;
@@ -53,10 +53,14 @@ static void s5pv210_audss_clk_resume(void)
writel(reg_save[i][1], reg_base + reg_save[i][0]);
}
-static struct syscore_ops s5pv210_audss_clk_syscore_ops = {
+static const struct syscore_ops s5pv210_audss_clk_syscore_ops = {
.suspend = s5pv210_audss_clk_suspend,
.resume = s5pv210_audss_clk_resume,
};
+
+static struct syscore s5pv210_audss_clk_syscore = {
+ .ops = &s5pv210_audss_clk_syscore_ops,
+};
#endif /* CONFIG_PM_SLEEP */
/* register s5pv210_audss clocks */
@@ -174,7 +178,7 @@ static int s5pv210_audss_clk_probe(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
- register_syscore_ops(&s5pv210_audss_clk_syscore_ops);
+ register_syscore(&s5pv210_audss_clk_syscore);
#endif
return 0;
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index e6533513f8ac2..47ae261decd69 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -271,7 +271,7 @@ void __init samsung_clk_of_register_fixed_ext(struct samsung_clk_provider *ctx,
}
#ifdef CONFIG_PM_SLEEP
-static int samsung_clk_suspend(void)
+static int samsung_clk_suspend(void *data)
{
struct samsung_clock_reg_cache *reg_cache;
@@ -284,7 +284,7 @@ static int samsung_clk_suspend(void)
return 0;
}
-static void samsung_clk_resume(void)
+static void samsung_clk_resume(void *data)
{
struct samsung_clock_reg_cache *reg_cache;
@@ -293,11 +293,15 @@ static void samsung_clk_resume(void)
reg_cache->rd_num);
}
-static struct syscore_ops samsung_clk_syscore_ops = {
+static const struct syscore_ops samsung_clk_syscore_ops = {
.suspend = samsung_clk_suspend,
.resume = samsung_clk_resume,
};
+static struct syscore samsung_clk_syscore = {
+ .ops = &samsung_clk_syscore_ops,
+};
+
void samsung_clk_extended_sleep_init(void __iomem *reg_base,
const unsigned long *rdump,
unsigned long nr_rdump,
@@ -316,7 +320,7 @@ void samsung_clk_extended_sleep_init(void __iomem *reg_base,
panic("could not allocate register dump storage.\n");
if (list_empty(&clock_reg_cache_list))
- register_syscore_ops(&samsung_clk_syscore_ops);
+ register_syscore(&samsung_clk_syscore);
reg_cache->reg_base = reg_base;
reg_cache->rd_num = nr_rdump;
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index a3488aaac3f78..8a411fc580b46 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -3444,7 +3444,7 @@ static void tegra210_disable_cpu_clock(u32 cpu)
static u32 spare_reg_ctx, misc_clk_enb_ctx, clk_msk_arm_ctx;
static u32 cpu_softrst_ctx[3];
-static int tegra210_clk_suspend(void)
+static int tegra210_clk_suspend(void *data)
{
unsigned int i;
@@ -3465,7 +3465,7 @@ static int tegra210_clk_suspend(void)
return 0;
}
-static void tegra210_clk_resume(void)
+static void tegra210_clk_resume(void *data)
{
unsigned int i;
@@ -3523,13 +3523,17 @@ static void tegra210_cpu_clock_resume(void)
}
#endif
-static struct syscore_ops tegra_clk_syscore_ops = {
+static const struct syscore_ops tegra_clk_syscore_ops = {
#ifdef CONFIG_PM_SLEEP
.suspend = tegra210_clk_suspend,
.resume = tegra210_clk_resume,
#endif
};
+static struct syscore tegra_clk_syscore = {
+ .ops = &tegra_clk_syscore_ops,
+};
+
static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
.wait_for_reset = tegra210_wait_cpu_in_reset,
.disable_clock = tegra210_disable_cpu_clock,
@@ -3813,6 +3817,6 @@ static void __init tegra210_clock_init(struct device_node *np)
tegra_cpu_car_ops = &tegra210_cpu_car_ops;
- register_syscore_ops(&tegra_clk_syscore_ops);
+ register_syscore(&tegra_clk_syscore);
}
CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init);
diff --git a/drivers/clocksource/timer-armada-370-xp.c b/drivers/clocksource/timer-armada-370-xp.c
index 49735ced52bb8..5db0cbecbf6d5 100644
--- a/drivers/clocksource/timer-armada-370-xp.c
+++ b/drivers/clocksource/timer-armada-370-xp.c
@@ -208,14 +208,14 @@ static int armada_370_xp_timer_dying_cpu(unsigned int cpu)
static u32 timer0_ctrl_reg, timer0_local_ctrl_reg;
-static int armada_370_xp_timer_suspend(void)
+static int armada_370_xp_timer_suspend(void *data)
{
timer0_ctrl_reg = readl(timer_base + TIMER_CTRL_OFF);
timer0_local_ctrl_reg = readl(local_base + TIMER_CTRL_OFF);
return 0;
}
-static void armada_370_xp_timer_resume(void)
+static void armada_370_xp_timer_resume(void *data)
{
writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
@@ -223,11 +223,15 @@ static void armada_370_xp_timer_resume(void)
writel(timer0_local_ctrl_reg, local_base + TIMER_CTRL_OFF);
}
-static struct syscore_ops armada_370_xp_timer_syscore_ops = {
+static const struct syscore_ops armada_370_xp_timer_syscore_ops = {
.suspend = armada_370_xp_timer_suspend,
.resume = armada_370_xp_timer_resume,
};
+static struct syscore armada_370_xp_timer_syscore = {
+ .ops = &armada_370_xp_timer_syscore_ops,
+};
+
static unsigned long armada_370_delay_timer_read(void)
{
return ~readl(timer_base + TIMER0_VAL_OFF);
@@ -325,7 +329,7 @@ static int __init armada_370_xp_timer_common_init(struct device_node *np)
return res;
}
- register_syscore_ops(&armada_370_xp_timer_syscore_ops);
+ register_syscore(&armada_370_xp_timer_syscore);
return 0;
}
diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c
index f3c30037dc8ef..4ad8d614acf69 100644
--- a/drivers/cpuidle/cpuidle-psci.c
+++ b/drivers/cpuidle/cpuidle-psci.c
@@ -158,26 +158,30 @@ static void psci_idle_syscore_switch(bool suspend)
}
}
-static int psci_idle_syscore_suspend(void)
+static int psci_idle_syscore_suspend(void *data)
{
psci_idle_syscore_switch(true);
return 0;
}
-static void psci_idle_syscore_resume(void)
+static void psci_idle_syscore_resume(void *data)
{
psci_idle_syscore_switch(false);
}
-static struct syscore_ops psci_idle_syscore_ops = {
+static const struct syscore_ops psci_idle_syscore_ops = {
.suspend = psci_idle_syscore_suspend,
.resume = psci_idle_syscore_resume,
};
+static struct syscore psci_idle_syscore = {
+ .ops = &psci_idle_syscore_ops,
+};
+
static void psci_idle_init_syscore(void)
{
if (psci_cpuidle_use_syscore)
- register_syscore_ops(&psci_idle_syscore_ops);
+ register_syscore(&psci_idle_syscore);
}
static void psci_idle_init_cpuhp(void)
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index a8ab78ae7fa30..a61bc17b27081 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -667,7 +667,7 @@ static const struct dev_pm_ops mxc_gpio_dev_pm_ops = {
RUNTIME_PM_OPS(mxc_gpio_runtime_suspend, mxc_gpio_runtime_resume, NULL)
};
-static int mxc_gpio_syscore_suspend(void)
+static int mxc_gpio_syscore_suspend(void *data)
{
struct mxc_gpio_port *port;
int ret;
@@ -684,7 +684,7 @@ static int mxc_gpio_syscore_suspend(void)
return 0;
}
-static void mxc_gpio_syscore_resume(void)
+static void mxc_gpio_syscore_resume(void *data)
{
struct mxc_gpio_port *port;
int ret;
@@ -701,11 +701,15 @@ static void mxc_gpio_syscore_resume(void)
}
}
-static struct syscore_ops mxc_gpio_syscore_ops = {
+static const struct syscore_ops mxc_gpio_syscore_ops = {
.suspend = mxc_gpio_syscore_suspend,
.resume = mxc_gpio_syscore_resume,
};
+static struct syscore mxc_gpio_syscore = {
+ .ops = &mxc_gpio_syscore_ops,
+};
+
static struct platform_driver mxc_gpio_driver = {
.driver = {
.name = "gpio-mxc",
@@ -718,7 +722,7 @@ static struct platform_driver mxc_gpio_driver = {
static int __init gpio_mxc_init(void)
{
- register_syscore_ops(&mxc_gpio_syscore_ops);
+ register_syscore(&mxc_gpio_syscore);
return platform_driver_register(&mxc_gpio_driver);
}
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index 91cea97255fa6..b8c49967e0934 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -746,7 +746,7 @@ static int __init pxa_gpio_dt_init(void)
device_initcall(pxa_gpio_dt_init);
#ifdef CONFIG_PM
-static int pxa_gpio_suspend(void)
+static int pxa_gpio_suspend(void *data)
{
struct pxa_gpio_chip *pchip = pxa_gpio_chip;
struct pxa_gpio_bank *c;
@@ -767,7 +767,7 @@ static int pxa_gpio_suspend(void)
return 0;
}
-static void pxa_gpio_resume(void)
+static void pxa_gpio_resume(void *data)
{
struct pxa_gpio_chip *pchip = pxa_gpio_chip;
struct pxa_gpio_bank *c;
@@ -791,14 +791,18 @@ static void pxa_gpio_resume(void)
#define pxa_gpio_resume NULL
#endif
-static struct syscore_ops pxa_gpio_syscore_ops = {
+static const struct syscore_ops pxa_gpio_syscore_ops = {
.suspend = pxa_gpio_suspend,
.resume = pxa_gpio_resume,
};
+static struct syscore pxa_gpio_syscore = {
+ .ops = &pxa_gpio_syscore_ops,
+};
+
static int __init pxa_gpio_sysinit(void)
{
- register_syscore_ops(&pxa_gpio_syscore_ops);
+ register_syscore(&pxa_gpio_syscore);
return 0;
}
postcore_initcall(pxa_gpio_sysinit);
diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c
index 242dad763ac4d..9e3a1199f51b8 100644
--- a/drivers/gpio/gpio-sa1100.c
+++ b/drivers/gpio/gpio-sa1100.c
@@ -253,7 +253,7 @@ static void sa1100_gpio_handler(struct irq_desc *desc)
} while (mask);
}
-static int sa1100_gpio_suspend(void)
+static int sa1100_gpio_suspend(void *data)
{
struct sa1100_gpio_chip *sgc = &sa1100_gpio_chip;
@@ -272,19 +272,23 @@ static int sa1100_gpio_suspend(void)
return 0;
}
-static void sa1100_gpio_resume(void)
+static void sa1100_gpio_resume(void *data)
{
sa1100_update_edge_regs(&sa1100_gpio_chip);
}
-static struct syscore_ops sa1100_gpio_syscore_ops = {
+static const struct syscore_ops sa1100_gpio_syscore_ops = {
.suspend = sa1100_gpio_suspend,
.resume = sa1100_gpio_resume,
};
+static struct syscore sa1100_gpio_syscore = {
+ .ops = &sa1100_gpio_syscore_ops,
+};
+
static int __init sa1100_gpio_init_devicefs(void)
{
- register_syscore_ops(&sa1100_gpio_syscore_ops);
+ register_syscore(&sa1100_gpio_syscore);
return 0;
}
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index db1c71832f2a8..4d3c78c388418 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -2776,7 +2776,7 @@ static void hv_crash_handler(struct pt_regs *regs)
hv_synic_disable_regs(cpu);
};
-static int hv_synic_suspend(void)
+static int hv_synic_suspend(void *data)
{
/*
* When we reach here, all the non-boot CPUs have been offlined.
@@ -2803,7 +2803,7 @@ static int hv_synic_suspend(void)
return 0;
}
-static void hv_synic_resume(void)
+static void hv_synic_resume(void *data)
{
hv_synic_enable_regs(0);
@@ -2815,11 +2815,15 @@ static void hv_synic_resume(void)
}
/* The callbacks run only on CPU0, with irqs_disabled. */
-static struct syscore_ops hv_synic_syscore_ops = {
+static const struct syscore_ops hv_synic_syscore_ops = {
.suspend = hv_synic_suspend,
.resume = hv_synic_resume,
};
+static struct syscore hv_synic_syscore = {
+ .ops = &hv_synic_syscore_ops,
+};
+
static int __init hv_acpi_init(void)
{
int ret;
@@ -2862,7 +2866,7 @@ static int __init hv_acpi_init(void)
hv_setup_kexec_handler(hv_kexec_handler);
hv_setup_crash_handler(hv_crash_handler);
- register_syscore_ops(&hv_synic_syscore_ops);
+ register_syscore(&hv_synic_syscore);
return 0;
@@ -2876,7 +2880,7 @@ static void __exit vmbus_exit(void)
{
int cpu;
- unregister_syscore_ops(&hv_synic_syscore_ops);
+ unregister_syscore(&hv_synic_syscore);
hv_remove_kexec_handler();
hv_remove_crash_handler();
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 804b731957db2..57d0e37f6c2bd 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -2917,7 +2917,7 @@ static void disable_iommus(void)
* disable suspend until real resume implemented
*/
-static void amd_iommu_resume(void)
+static void amd_iommu_resume(void *data)
{
struct amd_iommu *iommu;
@@ -2931,7 +2931,7 @@ static void amd_iommu_resume(void)
amd_iommu_enable_interrupts();
}
-static int amd_iommu_suspend(void)
+static int amd_iommu_suspend(void *data)
{
/* disable IOMMUs to go out of the way for BIOS */
disable_iommus();
@@ -2939,11 +2939,15 @@ static int amd_iommu_suspend(void)
return 0;
}
-static struct syscore_ops amd_iommu_syscore_ops = {
+static const struct syscore_ops amd_iommu_syscore_ops = {
.suspend = amd_iommu_suspend,
.resume = amd_iommu_resume,
};
+static struct syscore amd_iommu_syscore = {
+ .ops = &amd_iommu_syscore_ops,
+};
+
static void __init free_iommu_resources(void)
{
kmem_cache_destroy(amd_iommu_irq_cache);
@@ -3349,7 +3353,7 @@ static int __init state_next(void)
init_state = IOMMU_ENABLED;
break;
case IOMMU_ENABLED:
- register_syscore_ops(&amd_iommu_syscore_ops);
+ register_syscore(&amd_iommu_syscore);
iommu_snp_enable();
amd_iommu_apply_erratum_snp();
@@ -3463,12 +3467,12 @@ int __init amd_iommu_enable(void)
void amd_iommu_disable(void)
{
- amd_iommu_suspend();
+ amd_iommu_suspend(NULL);
}
int amd_iommu_reenable(int mode)
{
- amd_iommu_resume();
+ amd_iommu_resume(NULL);
return 0;
}
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 6c1e33b84bd56..39742525e1a89 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -2504,7 +2504,7 @@ static void iommu_flush_all(void)
}
}
-static int iommu_suspend(void)
+static int iommu_suspend(void *data)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu = NULL;
@@ -2531,7 +2531,7 @@ static int iommu_suspend(void)
return 0;
}
-static void iommu_resume(void)
+static void iommu_resume(void *data)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu = NULL;
@@ -2562,14 +2562,18 @@ static void iommu_resume(void)
}
}
-static struct syscore_ops iommu_syscore_ops = {
+static const struct syscore_ops iommu_syscore_ops = {
.resume = iommu_resume,
.suspend = iommu_suspend,
};
+static struct syscore iommu_syscore = {
+ .ops = &iommu_syscore_ops,
+};
+
static void __init init_iommu_pm_ops(void)
{
- register_syscore_ops(&iommu_syscore_ops);
+ register_syscore(&iommu_syscore);
}
#else
diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c
index 552aa04ff0631..87403f180fb4e 100644
--- a/drivers/irqchip/exynos-combiner.c
+++ b/drivers/irqchip/exynos-combiner.c
@@ -200,12 +200,13 @@ static void __init combiner_init(void __iomem *combiner_base,
/**
* combiner_suspend - save interrupt combiner state before suspend
+ * @data: syscore context
*
* Save the interrupt enable set register for all combiner groups since
* the state is lost when the system enters into a sleep state.
*
*/
-static int combiner_suspend(void)
+static int combiner_suspend(void *data)
{
int i;
@@ -218,12 +219,13 @@ static int combiner_suspend(void)
/**
* combiner_resume - restore interrupt combiner state after resume
+ * @data: syscore context
*
* Restore the interrupt enable set register for all combiner groups since
* the state is lost when the system enters into a sleep state on suspend.
*
*/
-static void combiner_resume(void)
+static void combiner_resume(void *data)
{
int i;
@@ -240,11 +242,15 @@ static void combiner_resume(void)
#define combiner_resume NULL
#endif
-static struct syscore_ops combiner_syscore_ops = {
+static const struct syscore_ops combiner_syscore_ops = {
.suspend = combiner_suspend,
.resume = combiner_resume,
};
+static struct syscore combiner_syscore = {
+ .ops = &combiner_syscore_ops,
+};
+
static int __init combiner_of_init(struct device_node *np,
struct device_node *parent)
{
@@ -264,7 +270,7 @@ static int __init combiner_of_init(struct device_node *np,
combiner_init(combiner_base, np);
- register_syscore_ops(&combiner_syscore_ops);
+ register_syscore(&combiner_syscore);
return 0;
}
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index d7c5ef2484744..fd6ae54dfb97c 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -724,7 +724,7 @@ static void __exception_irq_entry mpic_handle_irq(struct pt_regs *regs)
} while (1);
}
-static int mpic_suspend(void)
+static int mpic_suspend(void *data)
{
struct mpic *mpic = mpic_data;
@@ -733,7 +733,7 @@ static int mpic_suspend(void)
return 0;
}
-static void mpic_resume(void)
+static void mpic_resume(void *data)
{
struct mpic *mpic = mpic_data;
bool src0, src1;
@@ -786,11 +786,15 @@ static void mpic_resume(void)
mpic_ipi_resume(mpic);
}
-static struct syscore_ops mpic_syscore_ops = {
+static const struct syscore_ops mpic_syscore_ops = {
.suspend = mpic_suspend,
.resume = mpic_resume,
};
+static struct syscore mpic_syscore = {
+ .ops = &mpic_syscore_ops,
+};
+
static int __init mpic_map_region(struct device_node *np, int index,
void __iomem **base, phys_addr_t *phys_base)
{
@@ -903,7 +907,7 @@ static int __init mpic_of_init(struct device_node *node, struct device_node *par
mpic_handle_cascade_irq, mpic);
}
- register_syscore_ops(&mpic_syscore_ops);
+ register_syscore(&mpic_syscore);
return 0;
}
diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c
index bca43fa99c8f2..ecd7738663111 100644
--- a/drivers/irqchip/irq-bcm7038-l1.c
+++ b/drivers/irqchip/irq-bcm7038-l1.c
@@ -291,7 +291,7 @@ static int bcm7038_l1_init_one(struct device_node *dn, unsigned int idx,
static LIST_HEAD(bcm7038_l1_intcs_list);
static DEFINE_RAW_SPINLOCK(bcm7038_l1_intcs_lock);
-static int bcm7038_l1_suspend(void)
+static int bcm7038_l1_suspend(void *data)
{
struct bcm7038_l1_chip *intc;
int boot_cpu, word;
@@ -317,7 +317,7 @@ static int bcm7038_l1_suspend(void)
return 0;
}
-static void bcm7038_l1_resume(void)
+static void bcm7038_l1_resume(void *data)
{
struct bcm7038_l1_chip *intc;
int boot_cpu, word;
@@ -338,11 +338,15 @@ static void bcm7038_l1_resume(void)
}
}
-static struct syscore_ops bcm7038_l1_syscore_ops = {
+static const struct syscore_ops bcm7038_l1_syscore_ops = {
.suspend = bcm7038_l1_suspend,
.resume = bcm7038_l1_resume,
};
+static struct syscore bcm7038_l1_syscore = {
+ .ops = &bcm7038_l1_syscore_ops,
+};
+
static int bcm7038_l1_set_wake(struct irq_data *d, unsigned int on)
{
struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
@@ -429,7 +433,7 @@ static int bcm7038_l1_of_init(struct device_node *dn, struct device_node *parent
raw_spin_unlock(&bcm7038_l1_intcs_lock);
if (list_is_singular(&bcm7038_l1_intcs_list))
- register_syscore_ops(&bcm7038_l1_syscore_ops);
+ register_syscore(&bcm7038_l1_syscore);
#endif
pr_info("registered BCM7038 L1 intc (%pOF, IRQs: %d)\n",
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 299134fd02c61..fdf8f1bd157ea 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -4894,7 +4894,7 @@ static void its_enable_quirks(struct its_node *its)
its_quirks, its);
}
-static int its_save_disable(void)
+static int its_save_disable(void *data)
{
struct its_node *its;
int err = 0;
@@ -4930,7 +4930,7 @@ static int its_save_disable(void)
return err;
}
-static void its_restore_enable(void)
+static void its_restore_enable(void *data)
{
struct its_node *its;
int ret;
@@ -4990,11 +4990,15 @@ static void its_restore_enable(void)
raw_spin_unlock(&its_lock);
}
-static struct syscore_ops its_syscore_ops = {
+static const struct syscore_ops its_syscore_ops = {
.suspend = its_save_disable,
.resume = its_restore_enable,
};
+static struct syscore its_syscore = {
+ .ops = &its_syscore_ops,
+};
+
static void __init __iomem *its_map_one(struct resource *res, int *err)
{
void __iomem *its_base;
@@ -5772,7 +5776,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
}
}
- register_syscore_ops(&its_syscore_ops);
+ register_syscore(&its_syscore);
return 0;
}
diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c
index 115bdcffab248..f133f6176a12f 100644
--- a/drivers/irqchip/irq-i8259.c
+++ b/drivers/irqchip/irq-i8259.c
@@ -202,13 +202,13 @@ static void mask_and_ack_8259A(struct irq_data *d)
}
}
-static void i8259A_resume(void)
+static void i8259A_resume(void *data)
{
if (i8259A_auto_eoi >= 0)
init_8259A(i8259A_auto_eoi);
}
-static void i8259A_shutdown(void)
+static void i8259A_shutdown(void *data)
{
/* Put the i8259A into a quiescent state that
* the kernel initialization code can get it
@@ -220,11 +220,15 @@ static void i8259A_shutdown(void)
}
}
-static struct syscore_ops i8259_syscore_ops = {
+static const struct syscore_ops i8259_syscore_ops = {
.resume = i8259A_resume,
.shutdown = i8259A_shutdown,
};
+static struct syscore i8259_syscore = {
+ .ops = &i8259_syscore_ops,
+};
+
static void init_8259A(int auto_eoi)
{
unsigned long flags;
@@ -320,7 +324,7 @@ struct irq_domain * __init __init_i8259_irqs(struct device_node *node)
if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade", NULL))
pr_err("Failed to register cascade interrupt\n");
- register_syscore_ops(&i8259_syscore_ops);
+ register_syscore(&i8259_syscore);
return domain;
}
diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c
index 8a0e82067924e..2107729cf0ddc 100644
--- a/drivers/irqchip/irq-imx-gpcv2.c
+++ b/drivers/irqchip/irq-imx-gpcv2.c
@@ -33,7 +33,7 @@ static void __iomem *gpcv2_idx_to_reg(struct gpcv2_irqchip_data *cd, int i)
return cd->gpc_base + cd->cpu2wakeup + i * 4;
}
-static int gpcv2_wakeup_source_save(void)
+static int gpcv2_wakeup_source_save(void *data)
{
struct gpcv2_irqchip_data *cd;
void __iomem *reg;
@@ -52,7 +52,7 @@ static int gpcv2_wakeup_source_save(void)
return 0;
}
-static void gpcv2_wakeup_source_restore(void)
+static void gpcv2_wakeup_source_restore(void *data)
{
struct gpcv2_irqchip_data *cd;
int i;
@@ -65,9 +65,13 @@ static void gpcv2_wakeup_source_restore(void)
writel_relaxed(cd->saved_irq_mask[i], gpcv2_idx_to_reg(cd, i));
}
-static struct syscore_ops imx_gpcv2_syscore_ops = {
- .suspend = gpcv2_wakeup_source_save,
- .resume = gpcv2_wakeup_source_restore,
+static const struct syscore_ops gpcv2_syscore_ops = {
+ .suspend = gpcv2_wakeup_source_save,
+ .resume = gpcv2_wakeup_source_restore,
+};
+
+static struct syscore gpcv2_syscore = {
+ .ops = &gpcv2_syscore_ops,
};
static int imx_gpcv2_irq_set_wake(struct irq_data *d, unsigned int on)
@@ -276,7 +280,7 @@ static int __init imx_gpcv2_irqchip_init(struct device_node *node,
writel_relaxed(~0x1, cd->gpc_base + cd->cpu2wakeup);
imx_gpcv2_instance = cd;
- register_syscore_ops(&imx_gpcv2_syscore_ops);
+ register_syscore(&gpcv2_syscore);
/*
* Clear the OF_POPULATED flag set in of_irq_init so that
diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
index e24db71a8783c..e3b49d018a5e7 100644
--- a/drivers/irqchip/irq-loongson-eiointc.c
+++ b/drivers/irqchip/irq-loongson-eiointc.c
@@ -306,21 +306,25 @@ static struct irq_domain *acpi_get_vec_parent(int node, struct acpi_vector_group
return NULL;
}
-static int eiointc_suspend(void)
+static int eiointc_suspend(void *data)
{
return 0;
}
-static void eiointc_resume(void)
+static void eiointc_resume(void *data)
{
eiointc_router_init(0);
}
-static struct syscore_ops eiointc_syscore_ops = {
+static const struct syscore_ops eiointc_syscore_ops = {
.suspend = eiointc_suspend,
.resume = eiointc_resume,
};
+static struct syscore eiointc_syscore = {
+ .ops = &eiointc_syscore_ops,
+};
+
static int __init pch_pic_parse_madt(union acpi_subtable_headers *header,
const unsigned long end)
{
@@ -400,7 +404,7 @@ static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq,
irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv);
if (nr_pics == 1) {
- register_syscore_ops(&eiointc_syscore_ops);
+ register_syscore(&eiointc_syscore);
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_EIOINTC_STARTING,
"irqchip/loongarch/eiointc:starting",
eiointc_router_init, NULL);
diff --git a/drivers/irqchip/irq-loongson-htpic.c b/drivers/irqchip/irq-loongson-htpic.c
index f4abdf156de71..1c691c4be9894 100644
--- a/drivers/irqchip/irq-loongson-htpic.c
+++ b/drivers/irqchip/irq-loongson-htpic.c
@@ -71,15 +71,19 @@ static void htpic_reg_init(void)
writel(0xffff, htpic->base + HTINT_EN_OFF);
}
-static void htpic_resume(void)
+static void htpic_resume(void *data)
{
htpic_reg_init();
}
-struct syscore_ops htpic_syscore_ops = {
+static const struct syscore_ops htpic_syscore_ops = {
.resume = htpic_resume,
};
+static struct syscore htpic_syscore = {
+ .ops = &htpic_syscore_ops,
+};
+
static int __init htpic_of_init(struct device_node *node, struct device_node *parent)
{
unsigned int parent_irq[4];
@@ -130,7 +134,7 @@ static int __init htpic_of_init(struct device_node *node, struct device_node *pa
htpic_irq_dispatch, htpic);
}
- register_syscore_ops(&htpic_syscore_ops);
+ register_syscore(&htpic_syscore);
return 0;
diff --git a/drivers/irqchip/irq-loongson-htvec.c b/drivers/irqchip/irq-loongson-htvec.c
index 5da02c7ad0b30..52952cca7c18c 100644
--- a/drivers/irqchip/irq-loongson-htvec.c
+++ b/drivers/irqchip/irq-loongson-htvec.c
@@ -159,7 +159,7 @@ static void htvec_reset(struct htvec *priv)
}
}
-static int htvec_suspend(void)
+static int htvec_suspend(void *data)
{
int i;
@@ -169,7 +169,7 @@ static int htvec_suspend(void)
return 0;
}
-static void htvec_resume(void)
+static void htvec_resume(void *data)
{
int i;
@@ -177,11 +177,15 @@ static void htvec_resume(void)
writel(htvec_priv->saved_vec_en[i], htvec_priv->base + HTVEC_EN_OFF + 4 * i);
}
-static struct syscore_ops htvec_syscore_ops = {
+static const struct syscore_ops htvec_syscore_ops = {
.suspend = htvec_suspend,
.resume = htvec_resume,
};
+static struct syscore htvec_syscore = {
+ .ops = &htvec_syscore_ops,
+};
+
static int htvec_init(phys_addr_t addr, unsigned long size,
int num_parents, int parent_irq[], struct fwnode_handle *domain_handle)
{
@@ -214,7 +218,7 @@ static int htvec_init(phys_addr_t addr, unsigned long size,
htvec_priv = priv;
- register_syscore_ops(&htvec_syscore_ops);
+ register_syscore(&htvec_syscore);
return 0;
diff --git a/drivers/irqchip/irq-loongson-pch-lpc.c b/drivers/irqchip/irq-loongson-pch-lpc.c
index 912bf50a5c7ca..3a125f3e42873 100644
--- a/drivers/irqchip/irq-loongson-pch-lpc.c
+++ b/drivers/irqchip/irq-loongson-pch-lpc.c
@@ -151,7 +151,7 @@ static int pch_lpc_disabled(struct pch_lpc *priv)
(readl(priv->base + LPC_INT_STS) == 0xffffffff);
}
-static int pch_lpc_suspend(void)
+static int pch_lpc_suspend(void *data)
{
pch_lpc_priv->saved_reg_ctl = readl(pch_lpc_priv->base + LPC_INT_CTL);
pch_lpc_priv->saved_reg_ena = readl(pch_lpc_priv->base + LPC_INT_ENA);
@@ -159,18 +159,22 @@ static int pch_lpc_suspend(void)
return 0;
}
-static void pch_lpc_resume(void)
+static void pch_lpc_resume(void *data)
{
writel(pch_lpc_priv->saved_reg_ctl, pch_lpc_priv->base + LPC_INT_CTL);
writel(pch_lpc_priv->saved_reg_ena, pch_lpc_priv->base + LPC_INT_ENA);
writel(pch_lpc_priv->saved_reg_pol, pch_lpc_priv->base + LPC_INT_POL);
}
-static struct syscore_ops pch_lpc_syscore_ops = {
+static const struct syscore_ops pch_lpc_syscore_ops = {
.suspend = pch_lpc_suspend,
.resume = pch_lpc_resume,
};
+static struct syscore pch_lpc_syscore = {
+ .ops = &pch_lpc_syscore_ops,
+};
+
int __init pch_lpc_acpi_init(struct irq_domain *parent,
struct acpi_madt_lpc_pic *acpi_pchlpc)
{
@@ -222,7 +226,7 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent,
pch_lpc_priv = priv;
pch_lpc_handle = irq_handle;
- register_syscore_ops(&pch_lpc_syscore_ops);
+ register_syscore(&pch_lpc_syscore);
return 0;
diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c
index 69efda35a8e78..75a256e83c5e9 100644
--- a/drivers/irqchip/irq-loongson-pch-pic.c
+++ b/drivers/irqchip/irq-loongson-pch-pic.c
@@ -278,7 +278,7 @@ static void pch_pic_reset(struct pch_pic *priv)
}
}
-static int pch_pic_suspend(void)
+static int pch_pic_suspend(void *data)
{
int i, j;
@@ -296,7 +296,7 @@ static int pch_pic_suspend(void)
return 0;
}
-static void pch_pic_resume(void)
+static void pch_pic_resume(void *data)
{
int i, j;
@@ -313,11 +313,15 @@ static void pch_pic_resume(void)
}
}
-static struct syscore_ops pch_pic_syscore_ops = {
+static const struct syscore_ops pch_pic_syscore_ops = {
.suspend = pch_pic_suspend,
.resume = pch_pic_resume,
};
+static struct syscore pch_pic_syscore = {
+ .ops = &pch_pic_syscore_ops,
+};
+
static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
struct irq_domain *parent_domain, struct fwnode_handle *domain_handle,
u32 gsi_base)
@@ -356,7 +360,7 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
pch_pic_priv[nr_pics++] = priv;
if (nr_pics == 1)
- register_syscore_ops(&pch_pic_syscore_ops);
+ register_syscore(&pch_pic_syscore);
return 0;
diff --git a/drivers/irqchip/irq-mchp-eic.c b/drivers/irqchip/irq-mchp-eic.c
index 8a5baa0987a4b..2ad3c1d02d523 100644
--- a/drivers/irqchip/irq-mchp-eic.c
+++ b/drivers/irqchip/irq-mchp-eic.c
@@ -109,7 +109,7 @@ static int mchp_eic_irq_set_wake(struct irq_data *d, unsigned int on)
return 0;
}
-static int mchp_eic_irq_suspend(void)
+static int mchp_eic_irq_suspend(void *data)
{
unsigned int hwirq;
@@ -123,7 +123,7 @@ static int mchp_eic_irq_suspend(void)
return 0;
}
-static void mchp_eic_irq_resume(void)
+static void mchp_eic_irq_resume(void *data)
{
unsigned int hwirq;
@@ -135,11 +135,15 @@ static void mchp_eic_irq_resume(void)
MCHP_EIC_SCFG(hwirq));
}
-static struct syscore_ops mchp_eic_syscore_ops = {
+static const struct syscore_ops mchp_eic_syscore_ops = {
.suspend = mchp_eic_irq_suspend,
.resume = mchp_eic_irq_resume,
};
+static struct syscore mchp_eic_syscore = {
+ .ops = &mchp_eic_syscore_ops,
+};
+
static struct irq_chip mchp_eic_chip = {
.name = "eic",
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SET_TYPE_MASKED,
@@ -256,7 +260,7 @@ static int mchp_eic_init(struct device_node *node, struct device_node *parent)
goto clk_unprepare;
}
- register_syscore_ops(&mchp_eic_syscore_ops);
+ register_syscore(&mchp_eic_syscore);
pr_info("%pOF: EIC registered, nr_irqs %u\n", node, MCHP_EIC_NIRQ);
diff --git a/drivers/irqchip/irq-mst-intc.c b/drivers/irqchip/irq-mst-intc.c
index f6133ae281556..d771eb0346128 100644
--- a/drivers/irqchip/irq-mst-intc.c
+++ b/drivers/irqchip/irq-mst-intc.c
@@ -143,7 +143,7 @@ static void mst_intc_polarity_restore(struct mst_intc_chip_data *cd)
writew_relaxed(cd->saved_polarity_conf[i], addr + i * 4);
}
-static void mst_irq_resume(void)
+static void mst_irq_resume(void *data)
{
struct mst_intc_chip_data *cd;
@@ -151,7 +151,7 @@ static void mst_irq_resume(void)
mst_intc_polarity_restore(cd);
}
-static int mst_irq_suspend(void)
+static int mst_irq_suspend(void *data)
{
struct mst_intc_chip_data *cd;
@@ -160,14 +160,18 @@ static int mst_irq_suspend(void)
return 0;
}
-static struct syscore_ops mst_irq_syscore_ops = {
+static const struct syscore_ops mst_irq_syscore_ops = {
.suspend = mst_irq_suspend,
.resume = mst_irq_resume,
};
+static struct syscore mst_irq_syscore = {
+ .ops = &mst_irq_syscore_ops,
+};
+
static int __init mst_irq_pm_init(void)
{
- register_syscore_ops(&mst_irq_syscore_ops);
+ register_syscore(&mst_irq_syscore);
return 0;
}
late_initcall(mst_irq_pm_init);
diff --git a/drivers/irqchip/irq-mtk-cirq.c b/drivers/irqchip/irq-mtk-cirq.c
index 76bc0283e3b96..889f014f0451a 100644
--- a/drivers/irqchip/irq-mtk-cirq.c
+++ b/drivers/irqchip/irq-mtk-cirq.c
@@ -199,7 +199,7 @@ static const struct irq_domain_ops cirq_domain_ops = {
};
#ifdef CONFIG_PM_SLEEP
-static int mtk_cirq_suspend(void)
+static int mtk_cirq_suspend(void *data)
{
void __iomem *reg;
u32 value, mask;
@@ -257,7 +257,7 @@ static int mtk_cirq_suspend(void)
return 0;
}
-static void mtk_cirq_resume(void)
+static void mtk_cirq_resume(void *data)
{
void __iomem *reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL);
u32 value;
@@ -272,14 +272,18 @@ static void mtk_cirq_resume(void)
writel_relaxed(value, reg);
}
-static struct syscore_ops mtk_cirq_syscore_ops = {
+static const struct syscore_ops mtk_cirq_syscore_ops = {
.suspend = mtk_cirq_suspend,
.resume = mtk_cirq_resume,
};
+static struct syscore mtk_cirq_syscore = {
+ .ops = &mtk_cirq_syscore_ops,
+};
+
static void mtk_cirq_syscore_init(void)
{
- register_syscore_ops(&mtk_cirq_syscore_ops);
+ register_syscore(&mtk_cirq_syscore);
}
#else
static inline void mtk_cirq_syscore_init(void) {}
diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c
index ac88d5aa46c22..72944e6a16589 100644
--- a/drivers/irqchip/irq-renesas-rzg2l.c
+++ b/drivers/irqchip/irq-renesas-rzg2l.c
@@ -399,7 +399,7 @@ static int rzg2l_irqc_set_type(struct irq_data *d, unsigned int type)
return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
}
-static int rzg2l_irqc_irq_suspend(void)
+static int rzg2l_irqc_irq_suspend(void *data)
{
struct rzg2l_irqc_reg_cache *cache = &rzg2l_irqc_data->cache;
void __iomem *base = rzg2l_irqc_data->base;
@@ -411,7 +411,7 @@ static int rzg2l_irqc_irq_suspend(void)
return 0;
}
-static void rzg2l_irqc_irq_resume(void)
+static void rzg2l_irqc_irq_resume(void *data)
{
struct rzg2l_irqc_reg_cache *cache = &rzg2l_irqc_data->cache;
void __iomem *base = rzg2l_irqc_data->base;
@@ -426,11 +426,15 @@ static void rzg2l_irqc_irq_resume(void)
writel_relaxed(cache->iitsr, base + IITSR);
}
-static struct syscore_ops rzg2l_irqc_syscore_ops = {
+static const struct syscore_ops rzg2l_irqc_syscore_ops = {
.suspend = rzg2l_irqc_irq_suspend,
.resume = rzg2l_irqc_irq_resume,
};
+static struct syscore rzg2l_irqc_syscore = {
+ .ops = &rzg2l_irqc_syscore_ops,
+};
+
static const struct irq_chip rzg2l_irqc_chip = {
.name = "rzg2l-irqc",
.irq_eoi = rzg2l_irqc_eoi,
@@ -590,7 +594,7 @@ static int rzg2l_irqc_common_init(struct device_node *node, struct device_node *
goto pm_put;
}
- register_syscore_ops(&rzg2l_irqc_syscore_ops);
+ register_syscore(&rzg2l_irqc_syscore);
/*
* Prevent the cleanup function from invoking put_device by assigning
diff --git a/drivers/irqchip/irq-sa11x0.c b/drivers/irqchip/irq-sa11x0.c
index 9d0b80271949d..141c3601d8a54 100644
--- a/drivers/irqchip/irq-sa11x0.c
+++ b/drivers/irqchip/irq-sa11x0.c
@@ -85,7 +85,7 @@ static struct sa1100irq_state {
unsigned int iccr;
} sa1100irq_state;
-static int sa1100irq_suspend(void)
+static int sa1100irq_suspend(void *data)
{
struct sa1100irq_state *st = &sa1100irq_state;
@@ -102,7 +102,7 @@ static int sa1100irq_suspend(void)
return 0;
}
-static void sa1100irq_resume(void)
+static void sa1100irq_resume(void *data)
{
struct sa1100irq_state *st = &sa1100irq_state;
@@ -114,14 +114,18 @@ static void sa1100irq_resume(void)
}
}
-static struct syscore_ops sa1100irq_syscore_ops = {
+static const struct syscore_ops sa1100irq_syscore_ops = {
.suspend = sa1100irq_suspend,
.resume = sa1100irq_resume,
};
+static struct syscore sa1100irq_syscore = {
+ .ops = &sa1100irq_syscore_ops,
+};
+
static int __init sa1100irq_init_devicefs(void)
{
- register_syscore_ops(&sa1100irq_syscore_ops);
+ register_syscore(&sa1100irq_syscore);
return 0;
}
diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
index b58b3cd807d40..d57e9b25d0b4d 100644
--- a/drivers/irqchip/irq-sifive-plic.c
+++ b/drivers/irqchip/irq-sifive-plic.c
@@ -250,7 +250,7 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type)
return IRQ_SET_MASK_OK;
}
-static int plic_irq_suspend(void)
+static int plic_irq_suspend(void *data)
{
unsigned int i, cpu;
unsigned long flags;
@@ -282,7 +282,7 @@ static int plic_irq_suspend(void)
return 0;
}
-static void plic_irq_resume(void)
+static void plic_irq_resume(void *data)
{
unsigned int i, index, cpu;
unsigned long flags;
@@ -313,11 +313,15 @@ static void plic_irq_resume(void)
}
}
-static struct syscore_ops plic_irq_syscore_ops = {
+static const struct syscore_ops plic_irq_syscore_ops = {
.suspend = plic_irq_suspend,
.resume = plic_irq_resume,
};
+static struct syscore plic_irq_syscore = {
+ .ops = &plic_irq_syscore_ops,
+};
+
static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq)
{
@@ -683,7 +687,7 @@ static int plic_probe(struct fwnode_handle *fwnode)
cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
"irqchip/sifive/plic:starting",
plic_starting_cpu, plic_dying_cpu);
- register_syscore_ops(&plic_irq_syscore_ops);
+ register_syscore(&plic_irq_syscore);
plic_global_setup_done = true;
}
}
diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
index 99958d470d626..81e8342d1c9f2 100644
--- a/drivers/irqchip/irq-sun6i-r.c
+++ b/drivers/irqchip/irq-sun6i-r.c
@@ -268,7 +268,7 @@ static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
.free = irq_domain_free_irqs_common,
};
-static int sun6i_r_intc_suspend(void)
+static int sun6i_r_intc_suspend(void *data)
{
u32 buf[BITS_TO_U32(MAX(SUN6I_NR_TOP_LEVEL_IRQS, SUN6I_NR_MUX_BITS))];
int i;
@@ -284,7 +284,7 @@ static int sun6i_r_intc_suspend(void)
return 0;
}
-static void sun6i_r_intc_resume(void)
+static void sun6i_r_intc_resume(void *data)
{
int i;
@@ -294,17 +294,21 @@ static void sun6i_r_intc_resume(void)
writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));
}
-static void sun6i_r_intc_shutdown(void)
+static void sun6i_r_intc_shutdown(void *data)
{
- sun6i_r_intc_suspend();
+ sun6i_r_intc_suspend(data);
}
-static struct syscore_ops sun6i_r_intc_syscore_ops = {
+static const struct syscore_ops sun6i_r_intc_syscore_ops = {
.suspend = sun6i_r_intc_suspend,
.resume = sun6i_r_intc_resume,
.shutdown = sun6i_r_intc_shutdown,
};
+static struct syscore sun6i_r_intc_syscore = {
+ .ops = &sun6i_r_intc_syscore_ops,
+};
+
static int __init sun6i_r_intc_init(struct device_node *node,
struct device_node *parent,
const struct sun6i_r_intc_variant *v)
@@ -346,10 +350,10 @@ static int __init sun6i_r_intc_init(struct device_node *node,
return -ENOMEM;
}
- register_syscore_ops(&sun6i_r_intc_syscore_ops);
+ register_syscore(&sun6i_r_intc_syscore);
sun6i_r_intc_ack_nmi();
- sun6i_r_intc_resume();
+ sun6i_r_intc_resume(NULL);
return 0;
}
diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c
index ad3e2c1b3c87b..70ab4dc8f476a 100644
--- a/drivers/irqchip/irq-tegra.c
+++ b/drivers/irqchip/irq-tegra.c
@@ -132,7 +132,7 @@ static int tegra_set_wake(struct irq_data *d, unsigned int enable)
return 0;
}
-static int tegra_ictlr_suspend(void)
+static int tegra_ictlr_suspend(void *data)
{
unsigned long flags;
unsigned int i;
@@ -161,7 +161,7 @@ static int tegra_ictlr_suspend(void)
return 0;
}
-static void tegra_ictlr_resume(void)
+static void tegra_ictlr_resume(void *data)
{
unsigned long flags;
unsigned int i;
@@ -184,14 +184,18 @@ static void tegra_ictlr_resume(void)
local_irq_restore(flags);
}
-static struct syscore_ops tegra_ictlr_syscore_ops = {
+static const struct syscore_ops tegra_ictlr_syscore_ops = {
.suspend = tegra_ictlr_suspend,
.resume = tegra_ictlr_resume,
};
+static struct syscore tegra_ictlr_syscore = {
+ .ops = &tegra_ictlr_syscore_ops,
+};
+
static void tegra_ictlr_syscore_init(void)
{
- register_syscore_ops(&tegra_ictlr_syscore_ops);
+ register_syscore(&tegra_ictlr_syscore);
}
#else
#define tegra_set_wake NULL
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index ea93e7236c4ac..e2076ea885cfa 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -120,7 +120,7 @@ static void resume_one_vic(struct vic_device *vic)
writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR);
}
-static void vic_resume(void)
+static void vic_resume(void *data)
{
int id;
@@ -146,7 +146,7 @@ static void suspend_one_vic(struct vic_device *vic)
writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR);
}
-static int vic_suspend(void)
+static int vic_suspend(void *data)
{
int id;
@@ -156,11 +156,15 @@ static int vic_suspend(void)
return 0;
}
-static struct syscore_ops vic_syscore_ops = {
+static const struct syscore_ops vic_syscore_ops = {
.suspend = vic_suspend,
.resume = vic_resume,
};
+static struct syscore vic_syscore = {
+ .ops = &vic_syscore_ops,
+};
+
/**
* vic_pm_init - initcall to register VIC pm
*
@@ -171,7 +175,7 @@ static struct syscore_ops vic_syscore_ops = {
static int __init vic_pm_init(void)
{
if (vic_id > 0)
- register_syscore_ops(&vic_syscore_ops);
+ register_syscore(&vic_syscore);
return 0;
}
diff --git a/drivers/leds/trigger/ledtrig-cpu.c b/drivers/leds/trigger/ledtrig-cpu.c
index 05848a2fecff6..679323c2ccda0 100644
--- a/drivers/leds/trigger/ledtrig-cpu.c
+++ b/drivers/leds/trigger/ledtrig-cpu.c
@@ -94,28 +94,32 @@ void ledtrig_cpu(enum cpu_led_event ledevt)
}
EXPORT_SYMBOL(ledtrig_cpu);
-static int ledtrig_cpu_syscore_suspend(void)
+static int ledtrig_cpu_syscore_suspend(void *data)
{
ledtrig_cpu(CPU_LED_STOP);
return 0;
}
-static void ledtrig_cpu_syscore_resume(void)
+static void ledtrig_cpu_syscore_resume(void *data)
{
ledtrig_cpu(CPU_LED_START);
}
-static void ledtrig_cpu_syscore_shutdown(void)
+static void ledtrig_cpu_syscore_shutdown(void *data)
{
ledtrig_cpu(CPU_LED_HALTED);
}
-static struct syscore_ops ledtrig_cpu_syscore_ops = {
+static const struct syscore_ops ledtrig_cpu_syscore_ops = {
.shutdown = ledtrig_cpu_syscore_shutdown,
.suspend = ledtrig_cpu_syscore_suspend,
.resume = ledtrig_cpu_syscore_resume,
};
+static struct syscore ledtrig_cpu_syscore = {
+ .ops = &ledtrig_cpu_syscore_ops,
+};
+
static int ledtrig_online_cpu(unsigned int cpu)
{
ledtrig_cpu(CPU_LED_START);
@@ -157,7 +161,7 @@ static int __init ledtrig_cpu_init(void)
led_trigger_register_simple(trig->name, &trig->_trig);
}
- register_syscore_ops(&ledtrig_cpu_syscore_ops);
+ register_syscore(&ledtrig_cpu_syscore);
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "leds/trigger:starting",
ledtrig_online_cpu, ledtrig_prepare_down_cpu);
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index b0f09c70f1ff8..5fe47e784d437 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -2600,7 +2600,7 @@ void pmu_blink(int n)
#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
int pmu_sys_suspended;
-static int pmu_syscore_suspend(void)
+static int pmu_syscore_suspend(void *data)
{
/* Suspend PMU event interrupts */
pmu_suspend();
@@ -2614,7 +2614,7 @@ static int pmu_syscore_suspend(void)
return 0;
}
-static void pmu_syscore_resume(void)
+static void pmu_syscore_resume(void *data)
{
struct adb_request req;
@@ -2634,14 +2634,18 @@ static void pmu_syscore_resume(void)
pmu_sys_suspended = 0;
}
-static struct syscore_ops pmu_syscore_ops = {
+static const struct syscore_ops pmu_syscore_ops = {
.suspend = pmu_syscore_suspend,
.resume = pmu_syscore_resume,
};
+static struct syscore pmu_syscore = {
+ .ops = &pmu_syscore_ops,
+};
+
static int pmu_syscore_register(void)
{
- register_syscore_ops(&pmu_syscore_ops);
+ register_syscore(&pmu_syscore);
return 0;
}
diff --git a/drivers/power/reset/sc27xx-poweroff.c b/drivers/power/reset/sc27xx-poweroff.c
index 90287c31992c4..393bd1c33b73b 100644
--- a/drivers/power/reset/sc27xx-poweroff.c
+++ b/drivers/power/reset/sc27xx-poweroff.c
@@ -28,7 +28,7 @@ static struct regmap *regmap;
* taking cpus down to avoid racing regmap or spi mutex lock when poweroff
* system through PMIC.
*/
-static void sc27xx_poweroff_shutdown(void)
+static void sc27xx_poweroff_shutdown(void *data)
{
#ifdef CONFIG_HOTPLUG_CPU
int cpu;
@@ -40,10 +40,14 @@ static void sc27xx_poweroff_shutdown(void)
#endif
}
-static struct syscore_ops poweroff_syscore_ops = {
+static const struct syscore_ops poweroff_syscore_ops = {
.shutdown = sc27xx_poweroff_shutdown,
};
+static struct syscore poweroff_syscore = {
+ .ops = &poweroff_syscore_ops,
+};
+
static void sc27xx_poweroff_do_poweroff(void)
{
/* Disable the external subsys connection's power firstly */
@@ -62,7 +66,7 @@ static int sc27xx_poweroff_probe(struct platform_device *pdev)
return -ENODEV;
pm_power_off = sc27xx_poweroff_do_poweroff;
- register_syscore_ops(&poweroff_syscore_ops);
+ register_syscore(&poweroff_syscore);
return 0;
}
diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c
index 7a73f5e4a1fc7..f02e12dfa5f64 100644
--- a/drivers/sh/clk/core.c
+++ b/drivers/sh/clk/core.c
@@ -569,7 +569,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
EXPORT_SYMBOL_GPL(clk_round_rate);
#ifdef CONFIG_PM
-static void clks_core_resume(void)
+static void clks_core_resume(void *data)
{
struct clk *clkp;
@@ -588,13 +588,17 @@ static void clks_core_resume(void)
}
}
-static struct syscore_ops clks_syscore_ops = {
+static const struct syscore_ops clks_syscore_ops = {
.resume = clks_core_resume,
};
+static struct syscore clks_syscore = {
+ .ops = &clks_syscore_ops,
+};
+
static int __init clk_syscore_init(void)
{
- register_syscore_ops(&clks_syscore_ops);
+ register_syscore(&clks_syscore);
return 0;
}
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c
index ea571eeb30787..3dde703b77668 100644
--- a/drivers/sh/intc/core.c
+++ b/drivers/sh/intc/core.c
@@ -394,7 +394,7 @@ int __init register_intc_controller(struct intc_desc *desc)
return -ENOMEM;
}
-static int intc_suspend(void)
+static int intc_suspend(void *data)
{
struct intc_desc_int *d;
@@ -420,7 +420,7 @@ static int intc_suspend(void)
return 0;
}
-static void intc_resume(void)
+static void intc_resume(void *data)
{
struct intc_desc_int *d;
@@ -450,11 +450,15 @@ static void intc_resume(void)
}
}
-struct syscore_ops intc_syscore_ops = {
+static const struct syscore_ops intc_syscore_ops = {
.suspend = intc_suspend,
.resume = intc_resume,
};
+static struct syscore intc_syscore = {
+ .ops = &intc_syscore_ops,
+};
+
const struct bus_type intc_subsys = {
.name = "intc",
.dev_name = "intc",
@@ -477,7 +481,7 @@ static int __init register_intc_devs(void)
struct intc_desc_int *d;
int error;
- register_syscore_ops(&intc_syscore_ops);
+ register_syscore(&intc_syscore);
error = subsys_system_register(&intc_subsys, NULL);
if (!error) {
diff --git a/drivers/soc/bcm/brcmstb/biuctrl.c b/drivers/soc/bcm/brcmstb/biuctrl.c
index 364ddbe365c24..bd830649b60dd 100644
--- a/drivers/soc/bcm/brcmstb/biuctrl.c
+++ b/drivers/soc/bcm/brcmstb/biuctrl.c
@@ -298,7 +298,7 @@ static int __init setup_hifcpubiuctrl_regs(struct device_node *np)
#ifdef CONFIG_PM_SLEEP
static u32 cpubiuctrl_reg_save[NUM_CPU_BIUCTRL_REGS];
-static int brcmstb_cpu_credit_reg_suspend(void)
+static int brcmstb_cpu_credit_reg_suspend(void *data)
{
unsigned int i;
@@ -311,7 +311,7 @@ static int brcmstb_cpu_credit_reg_suspend(void)
return 0;
}
-static void brcmstb_cpu_credit_reg_resume(void)
+static void brcmstb_cpu_credit_reg_resume(void *data)
{
unsigned int i;
@@ -322,10 +322,14 @@ static void brcmstb_cpu_credit_reg_resume(void)
cbc_writel(cpubiuctrl_reg_save[i], i);
}
-static struct syscore_ops brcmstb_cpu_credit_syscore_ops = {
+static const struct syscore_ops brcmstb_cpu_credit_syscore_ops = {
.suspend = brcmstb_cpu_credit_reg_suspend,
.resume = brcmstb_cpu_credit_reg_resume,
};
+
+static struct syscore brcmstb_cpu_credit_syscore = {
+ .ops = &brcmstb_cpu_credit_syscore_ops,
+};
#endif
@@ -354,7 +358,7 @@ static int __init brcmstb_biuctrl_init(void)
a72_b53_rac_enable_all(np);
mcp_a72_b53_set();
#ifdef CONFIG_PM_SLEEP
- register_syscore_ops(&brcmstb_cpu_credit_syscore_ops);
+ register_syscore(&brcmstb_cpu_credit_syscore);
#endif
ret = 0;
out_put:
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 0fdccd7362094..bed58b78d13dc 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -467,7 +467,7 @@ struct tegra_pmc {
unsigned long *wake_type_dual_edge_map;
unsigned long *wake_sw_status_map;
unsigned long *wake_cntrl_level_map;
- struct syscore_ops syscore;
+ struct syscore syscore;
};
static struct tegra_pmc *pmc = &(struct tegra_pmc) {
@@ -3148,7 +3148,7 @@ static void tegra186_pmc_process_wake_events(struct tegra_pmc *pmc, unsigned int
}
}
-static void tegra186_pmc_wake_syscore_resume(void)
+static void tegra186_pmc_wake_syscore_resume(void *data)
{
u32 status, mask;
unsigned int i;
@@ -3161,7 +3161,7 @@ static void tegra186_pmc_wake_syscore_resume(void)
}
}
-static int tegra186_pmc_wake_syscore_suspend(void)
+static int tegra186_pmc_wake_syscore_suspend(void *data)
{
wke_read_sw_wake_status(pmc);
@@ -3180,6 +3180,11 @@ static int tegra186_pmc_wake_syscore_suspend(void)
return 0;
}
+static const struct syscore_ops tegra186_pmc_wake_syscore_ops = {
+ .suspend = tegra186_pmc_wake_syscore_suspend,
+ .resume = tegra186_pmc_wake_syscore_resume,
+};
+
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
static int tegra_pmc_suspend(struct device *dev)
{
@@ -3830,10 +3835,8 @@ static const struct tegra_pmc_regs tegra186_pmc_regs = {
static void tegra186_pmc_init(struct tegra_pmc *pmc)
{
- pmc->syscore.suspend = tegra186_pmc_wake_syscore_suspend;
- pmc->syscore.resume = tegra186_pmc_wake_syscore_resume;
-
- register_syscore_ops(&pmc->syscore);
+ pmc->syscore.ops = &tegra186_pmc_wake_syscore_ops;
+ register_syscore(&pmc->syscore);
}
static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
diff --git a/drivers/thermal/intel/intel_hfi.c b/drivers/thermal/intel/intel_hfi.c
index 5b18a46a10b06..e71cc0a11d01b 100644
--- a/drivers/thermal/intel/intel_hfi.c
+++ b/drivers/thermal/intel/intel_hfi.c
@@ -592,7 +592,7 @@ static void hfi_disable_instance(void *ptr)
hfi_disable();
}
-static void hfi_syscore_resume(void)
+static void hfi_syscore_resume(void *data)
{
/* This code runs only on the boot CPU. */
struct hfi_cpu_info *info = &per_cpu(hfi_cpu_info, 0);
@@ -603,7 +603,7 @@ static void hfi_syscore_resume(void)
hfi_enable_instance(hfi_instance);
}
-static int hfi_syscore_suspend(void)
+static int hfi_syscore_suspend(void *data)
{
/* No locking needed. There is no concurrency with CPU offline. */
hfi_disable();
@@ -611,11 +611,15 @@ static int hfi_syscore_suspend(void)
return 0;
}
-static struct syscore_ops hfi_pm_ops = {
+static const struct syscore_ops hfi_pm_ops = {
.resume = hfi_syscore_resume,
.suspend = hfi_syscore_suspend,
};
+static struct syscore hfi_pm = {
+ .ops = &hfi_pm_ops,
+};
+
static int hfi_thermal_notify(struct notifier_block *nb, unsigned long state,
void *_notify)
{
@@ -710,7 +714,7 @@ void __init intel_hfi_init(void)
if (thermal_genl_register_notifier(&hfi_thermal_nb))
goto err_nl_notif;
- register_syscore_ops(&hfi_pm_ops);
+ register_syscore(&hfi_pm);
return;
diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c
index 520756159d3d3..8d1860bd5d578 100644
--- a/drivers/xen/xen-acpi-processor.c
+++ b/drivers/xen/xen-acpi-processor.c
@@ -492,7 +492,7 @@ static void xen_acpi_processor_resume_worker(struct work_struct *dummy)
pr_info("ACPI data upload failed, error = %d\n", rc);
}
-static void xen_acpi_processor_resume(void)
+static void xen_acpi_processor_resume(void *data)
{
static DECLARE_WORK(wq, xen_acpi_processor_resume_worker);
@@ -506,10 +506,14 @@ static void xen_acpi_processor_resume(void)
schedule_work(&wq);
}
-static struct syscore_ops xap_syscore_ops = {
+static const struct syscore_ops xap_syscore_ops = {
.resume = xen_acpi_processor_resume,
};
+static struct syscore xap_syscore = {
+ .ops = &xap_syscore_ops,
+};
+
static int __init xen_acpi_processor_init(void)
{
int i;
@@ -560,7 +564,7 @@ static int __init xen_acpi_processor_init(void)
if (rc)
goto err_unregister;
- register_syscore_ops(&xap_syscore_ops);
+ register_syscore(&xap_syscore);
return 0;
err_unregister:
@@ -577,7 +581,7 @@ static void __exit xen_acpi_processor_exit(void)
{
int i;
- unregister_syscore_ops(&xap_syscore_ops);
+ unregister_syscore(&xap_syscore);
bitmap_free(acpi_ids_done);
bitmap_free(acpi_id_present);
bitmap_free(acpi_id_cst_present);
diff --git a/include/linux/syscore_ops.h b/include/linux/syscore_ops.h
index ae4d48e4c970a..ac6d71be5c382 100644
--- a/include/linux/syscore_ops.h
+++ b/include/linux/syscore_ops.h
@@ -11,14 +11,19 @@
#include <linux/list.h>
struct syscore_ops {
+ int (*suspend)(void *data);
+ void (*resume)(void *data);
+ void (*shutdown)(void *data);
+};
+
+struct syscore {
struct list_head node;
- int (*suspend)(void);
- void (*resume)(void);
- void (*shutdown)(void);
+ const struct syscore_ops *ops;
+ void *data;
};
-extern void register_syscore_ops(struct syscore_ops *ops);
-extern void unregister_syscore_ops(struct syscore_ops *ops);
+extern void register_syscore(struct syscore *syscore);
+extern void unregister_syscore(struct syscore *syscore);
#ifdef CONFIG_PM_SLEEP
extern int syscore_suspend(void);
extern void syscore_resume(void);
diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c
index b0f0d15085db1..7481fbb947d32 100644
--- a/kernel/cpu_pm.c
+++ b/kernel/cpu_pm.c
@@ -173,7 +173,7 @@ int cpu_cluster_pm_exit(void)
EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit);
#ifdef CONFIG_PM
-static int cpu_pm_suspend(void)
+static int cpu_pm_suspend(void *data)
{
int ret;
@@ -185,20 +185,24 @@ static int cpu_pm_suspend(void)
return ret;
}
-static void cpu_pm_resume(void)
+static void cpu_pm_resume(void *data)
{
cpu_cluster_pm_exit();
cpu_pm_exit();
}
-static struct syscore_ops cpu_pm_syscore_ops = {
+static const struct syscore_ops cpu_pm_syscore_ops = {
.suspend = cpu_pm_suspend,
.resume = cpu_pm_resume,
};
+static struct syscore cpu_pm_syscore = {
+ .ops = &cpu_pm_syscore_ops,
+};
+
static int cpu_pm_init(void)
{
- register_syscore_ops(&cpu_pm_syscore_ops);
+ register_syscore(&cpu_pm_syscore);
return 0;
}
core_initcall(cpu_pm_init);
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c
index 32ffcbb87fa12..a083f497fb0d3 100644
--- a/kernel/irq/generic-chip.c
+++ b/kernel/irq/generic-chip.c
@@ -664,7 +664,7 @@ static struct irq_data *irq_gc_get_irq_data(struct irq_chip_generic *gc)
}
#ifdef CONFIG_PM
-static int irq_gc_suspend(void)
+static int irq_gc_suspend(void *data)
{
struct irq_chip_generic *gc;
@@ -684,7 +684,7 @@ static int irq_gc_suspend(void)
return 0;
}
-static void irq_gc_resume(void)
+static void irq_gc_resume(void *data)
{
struct irq_chip_generic *gc;
@@ -707,7 +707,7 @@ static void irq_gc_resume(void)
#define irq_gc_resume NULL
#endif
-static void irq_gc_shutdown(void)
+static void irq_gc_shutdown(void *data)
{
struct irq_chip_generic *gc;
@@ -723,15 +723,19 @@ static void irq_gc_shutdown(void)
}
}
-static struct syscore_ops irq_gc_syscore_ops = {
+static const struct syscore_ops irq_gc_syscore_ops = {
.suspend = irq_gc_suspend,
.resume = irq_gc_resume,
.shutdown = irq_gc_shutdown,
};
+static struct syscore irq_gc_syscore = {
+ .ops = &irq_gc_syscore_ops,
+};
+
static int __init irq_gc_init_ops(void)
{
- register_syscore_ops(&irq_gc_syscore_ops);
+ register_syscore(&irq_gc_syscore);
return 0;
}
device_initcall(irq_gc_init_ops);
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index c556bc49d2137..6337997411315 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -227,21 +227,26 @@ void rearm_wake_irq(unsigned int irq)
/**
* irq_pm_syscore_resume - enable interrupt lines early
+ * @data: syscore context
*
* Enable all interrupt lines with %IRQF_EARLY_RESUME set.
*/
-static void irq_pm_syscore_resume(void)
+static void irq_pm_syscore_resume(void *data)
{
resume_irqs(true);
}
-static struct syscore_ops irq_pm_syscore_ops = {
+static const struct syscore_ops irq_pm_syscore_ops = {
.resume = irq_pm_syscore_resume,
};
+static struct syscore irq_pm_syscore = {
+ .ops = &irq_pm_syscore_ops,
+};
+
static int __init irq_pm_init_ops(void)
{
- register_syscore_ops(&irq_pm_syscore_ops);
+ register_syscore(&irq_pm_syscore);
return 0;
}
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 37f1d4637d90c..1c5c26168cefd 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3656,12 +3656,13 @@ static bool legacy_kthread_create(void)
/**
* printk_kthreads_shutdown - shutdown all threaded printers
+ * @data: syscore context
*
* On system shutdown all threaded printers are stopped. This allows printk
* to transition back to atomic printing, thus providing a robust mechanism
* for the final shutdown/reboot messages to be output.
*/
-static void printk_kthreads_shutdown(void)
+static void printk_kthreads_shutdown(void *data)
{
struct console *con;
@@ -3683,10 +3684,14 @@ static void printk_kthreads_shutdown(void)
console_list_unlock();
}
-static struct syscore_ops printk_syscore_ops = {
+static const struct syscore_ops printk_syscore_ops = {
.shutdown = printk_kthreads_shutdown,
};
+static struct syscore printk_syscore = {
+ .ops = &printk_syscore_ops,
+};
+
/*
* If appropriate, start nbcon kthreads and set @printk_kthreads_running.
* If any kthreads fail to start, those consoles are unregistered.
@@ -3753,7 +3758,7 @@ static void printk_kthreads_check_locked(void)
static int __init printk_set_kthreads_ready(void)
{
- register_syscore_ops(&printk_syscore_ops);
+ register_syscore(&printk_syscore);
console_list_lock();
printk_kthreads_ready = true;
diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c
index 68d6c1190ac7f..8aacdbde3a10b 100644
--- a/kernel/time/sched_clock.c
+++ b/kernel/time/sched_clock.c
@@ -283,6 +283,11 @@ int sched_clock_suspend(void)
return 0;
}
+static int sched_clock_syscore_suspend(void *data)
+{
+ return sched_clock_suspend();
+}
+
void sched_clock_resume(void)
{
struct clock_read_data *rd = &cd.read_data[0];
@@ -292,14 +297,23 @@ void sched_clock_resume(void)
rd->read_sched_clock = cd.actual_read_sched_clock;
}
-static struct syscore_ops sched_clock_ops = {
- .suspend = sched_clock_suspend,
- .resume = sched_clock_resume,
+static void sched_clock_syscore_resume(void *data)
+{
+ sched_clock_resume();
+}
+
+static const struct syscore_ops sched_clock_syscore_ops = {
+ .suspend = sched_clock_syscore_suspend,
+ .resume = sched_clock_syscore_resume,
+};
+
+static struct syscore sched_clock_syscore = {
+ .ops = &sched_clock_syscore_ops,
};
static int __init sched_clock_syscore_init(void)
{
- register_syscore_ops(&sched_clock_ops);
+ register_syscore(&sched_clock_syscore);
return 0;
}
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 4d8927aeca974..626fbb2a1a8cf 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1868,6 +1868,11 @@ void timekeeping_resume(void)
timerfd_resume();
}
+static void timekeeping_syscore_resume(void *data)
+{
+ timekeeping_resume();
+}
+
int timekeeping_suspend(void)
{
struct timekeeper *tk = &tk_core.timekeeper;
@@ -1937,15 +1942,24 @@ int timekeeping_suspend(void)
return 0;
}
+static int timekeeping_syscore_suspend(void *data)
+{
+ return timekeeping_suspend();
+}
+
/* sysfs resume/suspend bits for timekeeping */
-static struct syscore_ops timekeeping_syscore_ops = {
- .resume = timekeeping_resume,
- .suspend = timekeeping_suspend,
+static const struct syscore_ops timekeeping_syscore_ops = {
+ .resume = timekeeping_syscore_resume,
+ .suspend = timekeeping_syscore_suspend,
+};
+
+static struct syscore timekeeping_syscore = {
+ .ops = &timekeeping_syscore_ops,
};
static int __init timekeeping_init_ops(void)
{
- register_syscore_ops(&timekeeping_syscore_ops);
+ register_syscore(&timekeeping_syscore);
return 0;
}
device_initcall(timekeeping_init_ops);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index b2e76be087121..55ec5956c28b6 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -5662,7 +5662,7 @@ static int kvm_offline_cpu(unsigned int cpu)
return 0;
}
-static void kvm_shutdown(void)
+static void kvm_shutdown(void *data)
{
/*
* Disable hardware virtualization and set kvm_rebooting to indicate
@@ -5680,7 +5680,7 @@ static void kvm_shutdown(void)
on_each_cpu(kvm_disable_virtualization_cpu, NULL, 1);
}
-static int kvm_suspend(void)
+static int kvm_suspend(void *data)
{
/*
* Secondary CPUs and CPU hotplug are disabled across the suspend/resume
@@ -5697,7 +5697,7 @@ static int kvm_suspend(void)
return 0;
}
-static void kvm_resume(void)
+static void kvm_resume(void *data)
{
lockdep_assert_not_held(&kvm_usage_lock);
lockdep_assert_irqs_disabled();
@@ -5705,12 +5705,16 @@ static void kvm_resume(void)
WARN_ON_ONCE(kvm_enable_virtualization_cpu());
}
-static struct syscore_ops kvm_syscore_ops = {
+static const struct syscore_ops kvm_syscore_ops = {
.suspend = kvm_suspend,
.resume = kvm_resume,
.shutdown = kvm_shutdown,
};
+static struct syscore kvm_syscore = {
+ .ops = &kvm_syscore_ops,
+};
+
int kvm_enable_virtualization(void)
{
int r;
@@ -5727,7 +5731,7 @@ int kvm_enable_virtualization(void)
if (r)
goto err_cpuhp;
- register_syscore_ops(&kvm_syscore_ops);
+ register_syscore(&kvm_syscore);
/*
* Undo virtualization enabling and bail if the system is going down.
@@ -5749,7 +5753,7 @@ int kvm_enable_virtualization(void)
return 0;
err_rebooting:
- unregister_syscore_ops(&kvm_syscore_ops);
+ unregister_syscore(&kvm_syscore);
cpuhp_remove_state(CPUHP_AP_KVM_ONLINE);
err_cpuhp:
kvm_arch_disable_virtualization();
@@ -5765,7 +5769,7 @@ void kvm_disable_virtualization(void)
if (--kvm_usage_count)
return;
- unregister_syscore_ops(&kvm_syscore_ops);
+ unregister_syscore(&kvm_syscore);
cpuhp_remove_state(CPUHP_AP_KVM_ONLINE);
kvm_arch_disable_virtualization();
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 259/869] soc/tegra: pmc: Fix unsafe generic_handle_irq() call
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (257 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 258/869] syscore: Pass context data to callbacks Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 260/869] wifi: iwlwifi: mvm: dont send a 6E related command when not supported Greg Kroah-Hartman
` (610 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Petlozu Pravareshwar,
Prathamesh Shete, Jon Hunter, Thierry Reding, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prathamesh Shete <pshete@nvidia.com>
[ Upstream commit e6d96073af681780820c94079b978474a8a44413 ]
Currently, when resuming from system suspend on Tegra platforms,
the following warning is observed:
WARNING: CPU: 0 PID: 14459 at kernel/irq/irqdesc.c:666
Call trace:
handle_irq_desc+0x20/0x58 (P)
tegra186_pmc_wake_syscore_resume+0xe4/0x15c
syscore_resume+0x3c/0xb8
suspend_devices_and_enter+0x510/0x540
pm_suspend+0x16c/0x1d8
The warning occurs because generic_handle_irq() is being called from
a non-interrupt context which is considered as unsafe.
Fix this warning by deferring generic_handle_irq() call to an IRQ work
which gets executed in hard IRQ context where generic_handle_irq()
can be called safely.
When PREEMPT_RT kernels are used, regular IRQ work (initialized with
init_irq_work) is deferred to run in per-CPU kthreads in preemptible
context rather than hard IRQ context. Hence, use the IRQ_WORK_INIT_HARD
variant so that with PREEMPT_RT kernels, the IRQ work is processed in
hardirq context instead of being deferred to a thread which is required
for calling generic_handle_irq().
On non-PREEMPT_RT kernels, both init_irq_work() and IRQ_WORK_INIT_HARD()
execute in IRQ context, so this change has no functional impact for
standard kernel configurations.
Signed-off-by: Petlozu Pravareshwar <petlozup@nvidia.com>
Signed-off-by: Prathamesh Shete <pshete@nvidia.com>
Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
Tested-by: Jon Hunter <jonathanh@nvidia.com>
[treding@nvidia.com: miscellaneous cleanups]
Signed-off-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/soc/tegra/pmc.c | 104 ++++++++++++++++++++++++++++------------
1 file changed, 74 insertions(+), 30 deletions(-)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index bed58b78d13dc..0cca72e18437d 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -28,6 +28,7 @@
#include <linux/iopoll.h>
#include <linux/irqdomain.h>
#include <linux/irq.h>
+#include <linux/irq_work.h>
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/of_clk.h>
@@ -468,6 +469,10 @@ struct tegra_pmc {
unsigned long *wake_sw_status_map;
unsigned long *wake_cntrl_level_map;
struct syscore syscore;
+
+ /* Pending wake IRQ processing */
+ struct irq_work wake_work;
+ u32 *wake_status;
};
static struct tegra_pmc *pmc = &(struct tegra_pmc) {
@@ -1905,6 +1910,50 @@ static int tegra_pmc_parse_dt(struct tegra_pmc *pmc, struct device_node *np)
return 0;
}
+/* translate sc7 wake sources back into IRQs to catch edge triggered wakeups */
+static void tegra186_pmc_wake_handler(struct irq_work *work)
+{
+ struct tegra_pmc *pmc = container_of(work, struct tegra_pmc, wake_work);
+ unsigned int i, wake;
+
+ for (i = 0; i < pmc->soc->max_wake_vectors; i++) {
+ unsigned long status = pmc->wake_status[i];
+
+ for_each_set_bit(wake, &status, 32) {
+ irq_hw_number_t hwirq = wake + (i * 32);
+ struct irq_desc *desc;
+ unsigned int irq;
+
+ irq = irq_find_mapping(pmc->domain, hwirq);
+ if (!irq) {
+ dev_warn(pmc->dev,
+ "No IRQ found for WAKE#%lu!\n",
+ hwirq);
+ continue;
+ }
+
+ dev_dbg(pmc->dev,
+ "Resume caused by WAKE#%lu mapped to IRQ#%u\n",
+ hwirq, irq);
+
+ desc = irq_to_desc(irq);
+ if (!desc) {
+ dev_warn(pmc->dev,
+ "No descriptor found for IRQ#%u\n",
+ irq);
+ continue;
+ }
+
+ if (!desc->action || !desc->action->name)
+ continue;
+
+ generic_handle_irq(irq);
+ }
+
+ pmc->wake_status[i] = 0;
+ }
+}
+
static int tegra_pmc_init(struct tegra_pmc *pmc)
{
if (pmc->soc->max_wake_events > 0) {
@@ -1923,6 +1972,18 @@ static int tegra_pmc_init(struct tegra_pmc *pmc)
pmc->wake_cntrl_level_map = bitmap_zalloc(pmc->soc->max_wake_events, GFP_KERNEL);
if (!pmc->wake_cntrl_level_map)
return -ENOMEM;
+
+ pmc->wake_status = kcalloc(pmc->soc->max_wake_vectors, sizeof(u32), GFP_KERNEL);
+ if (!pmc->wake_status)
+ return -ENOMEM;
+
+ /*
+ * Initialize IRQ work for processing wake IRQs. Must use
+ * HARD_IRQ variant to run in hard IRQ context on PREEMPT_RT
+ * because we call generic_handle_irq() which requires hard
+ * IRQ context.
+ */
+ pmc->wake_work = IRQ_WORK_INIT_HARD(tegra186_pmc_wake_handler);
}
if (pmc->soc->init)
@@ -3122,47 +3183,30 @@ static void wke_clear_wake_status(struct tegra_pmc *pmc)
}
}
-/* translate sc7 wake sources back into IRQs to catch edge triggered wakeups */
-static void tegra186_pmc_process_wake_events(struct tegra_pmc *pmc, unsigned int index,
- unsigned long status)
-{
- unsigned int wake;
-
- dev_dbg(pmc->dev, "Wake[%d:%d] status=%#lx\n", (index * 32) + 31, index * 32, status);
-
- for_each_set_bit(wake, &status, 32) {
- irq_hw_number_t hwirq = wake + 32 * index;
- struct irq_desc *desc;
- unsigned int irq;
-
- irq = irq_find_mapping(pmc->domain, hwirq);
-
- desc = irq_to_desc(irq);
- if (!desc || !desc->action || !desc->action->name) {
- dev_dbg(pmc->dev, "Resume caused by WAKE%ld, IRQ %d\n", hwirq, irq);
- continue;
- }
-
- dev_dbg(pmc->dev, "Resume caused by WAKE%ld, %s\n", hwirq, desc->action->name);
- generic_handle_irq(irq);
- }
-}
-
static void tegra186_pmc_wake_syscore_resume(void *data)
{
- u32 status, mask;
unsigned int i;
+ u32 mask;
for (i = 0; i < pmc->soc->max_wake_vectors; i++) {
mask = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(i));
- status = readl(pmc->wake + WAKE_AOWAKE_STATUS_R(i)) & mask;
-
- tegra186_pmc_process_wake_events(pmc, i, status);
+ pmc->wake_status[i] = readl(pmc->wake + WAKE_AOWAKE_STATUS_R(i)) & mask;
}
+
+ /* Schedule IRQ work to process wake IRQs (if any) */
+ irq_work_queue(&pmc->wake_work);
}
static int tegra186_pmc_wake_syscore_suspend(void *data)
{
+ unsigned int i;
+
+ /* Check if there are unhandled wake IRQs */
+ for (i = 0; i < pmc->soc->max_wake_vectors; i++)
+ if (pmc->wake_status[i])
+ dev_warn(pmc->dev,
+ "Unhandled wake IRQs pending vector[%u]: 0x%x\n",
+ i, pmc->wake_status[i]);
wke_read_sw_wake_status(pmc);
/* flip the wakeup trigger for dual-edge triggered pads
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 260/869] wifi: iwlwifi: mvm: dont send a 6E related command when not supported
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (258 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 259/869] soc/tegra: pmc: Fix unsafe generic_handle_irq() call Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 261/869] drm/amd/display: Fix NULL pointer dereference in dcn401_init_hw() Greg Kroah-Hartman
` (609 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Emmanuel Grumbach, Johannes Berg,
Miri Korenblit, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
[ Upstream commit 323156c3541e23da7e582008a7ac30cd51b60acd ]
MCC_ALLOWED_AP_TYPE_CMD is related to 6E support. Do not send it if the
device doesn't support 6E.
Apparently, the firmware is mistakenly advertising support for this
command even on AX201 which does not support 6E and then the firmware
crashes.
Fixes: 0d2fc8821a7d ("wifi: iwlwifi: nvm: parse the VLP/AFC bit from regulatory")
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220804
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260324113316.e171f0163f2a.I0c444d1f82d1773054e7ffc391ad49697d58f44e@changeid
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 4bad012472e1e..968cb35d6408c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -490,7 +490,8 @@ static void iwl_mvm_uats_init(struct iwl_mvm *mvm)
.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
};
- if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
+ if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210 ||
+ !mvm->trans->cfg->uhb_supported) {
IWL_DEBUG_RADIO(mvm, "UATS feature is not supported\n");
return;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 261/869] drm/amd/display: Fix NULL pointer dereference in dcn401_init_hw()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (259 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 260/869] wifi: iwlwifi: mvm: dont send a 6E related command when not supported Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 262/869] ice: ptp: dont WARN when controlling PF is unavailable Greg Kroah-Hartman
` (608 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Daniel Sa, Alvin Lee, Roman Li,
Alex Hung, Tom Chung, Dan Carpenter, Aurabindo Pillai,
Srinivasan Shanmugam, Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
[ Upstream commit e927b36ae18b66b49219eaa9f46edc7b4fdbb25e ]
dcn401_init_hw() assumes that update_bw_bounding_box() is valid when
entering the update path. However, the existing condition:
((!fams2_enable && update_bw_bounding_box) || freq_changed)
does not guarantee this, as the freq_changed branch can evaluate to true
independently of the callback pointer.
This can result in calling update_bw_bounding_box() when it is NULL.
Fix this by separating the update condition from the pointer checks and
ensuring the callback, dc->clk_mgr, and bw_params are validated before
use.
Fixes the below:
../dc/hwss/dcn401/dcn401_hwseq.c:367 dcn401_init_hw() error: we previously assumed 'dc->res_pool->funcs->update_bw_bounding_box' could be null (see line 362)
Fixes: ca0fb243c3bb ("drm/amd/display: Underflow Seen on DCN401 eGPU")
Cc: Daniel Sa <Daniel.Sa@amd.com>
Cc: Alvin Lee <alvin.lee2@amd.com>
Cc: Roman Li <roman.li@amd.com>
Cc: Alex Hung <alex.hung@amd.com>
Cc: Tom Chung <chiahsuan.chung@amd.com>
Cc: Dan Carpenter <dan.carpenter@linaro.org>
Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 86117c5ab42f21562fedb0a64bffea3ee5fcd477)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index 768b756d427c7..be99798cf6ee1 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -225,6 +225,7 @@ void dcn401_init_hw(struct dc *dc)
int edp_num;
uint32_t backlight = MAX_BACKLIGHT_LEVEL;
uint32_t user_level = MAX_BACKLIGHT_LEVEL;
+ bool dchub_ref_freq_changed;
int current_dchub_ref_freq = 0;
if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) {
@@ -445,12 +446,14 @@ void dcn401_init_hw(struct dc *dc)
dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0;
dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
dc->debug.fams2_config.bits.enable &= dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver == 2;
- if ((!dc->debug.fams2_config.bits.enable && dc->res_pool->funcs->update_bw_bounding_box)
- || res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq) {
+ dchub_ref_freq_changed =
+ res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq;
+ if ((!dc->debug.fams2_config.bits.enable || dchub_ref_freq_changed) &&
+ dc->res_pool->funcs->update_bw_bounding_box &&
+ dc->clk_mgr && dc->clk_mgr->bw_params) {
/* update bounding box if FAMS2 disabled, or if dchub clk has changed */
- if (dc->clk_mgr)
- dc->res_pool->funcs->update_bw_bounding_box(dc,
- dc->clk_mgr->bw_params);
+ dc->res_pool->funcs->update_bw_bounding_box(dc,
+ dc->clk_mgr->bw_params);
}
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 262/869] ice: ptp: dont WARN when controlling PF is unavailable
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (260 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 261/869] drm/amd/display: Fix NULL pointer dereference in dcn401_init_hw() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 263/869] i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue Greg Kroah-Hartman
` (607 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kohei Enju, Aleksandr Loktionov,
Tony Nguyen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kohei Enju <kohei@enjuk.jp>
[ Upstream commit bb3f21edc7056cdf44a7f7bd7ba65af40741838c ]
In VFIO passthrough setups, it is possible to pass through only a PF
which doesn't own the source timer. In that case the PTP controlling PF
(adapter->ctrl_pf) is never initialized in the VM, so ice_get_ctrl_ptp()
returns NULL and triggers WARN_ON() in ice_ptp_setup_pf().
Since this is an expected behavior in that configuration, replace
WARN_ON() with an informational message and return -EOPNOTSUPP.
Fixes: e800654e85b5 ("ice: Use ice_adapter for PTP shared data instead of auxdev")
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/ice/ice_ptp.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index ca0d4ba2b63b2..f0dab91ce831e 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -2936,7 +2936,13 @@ static int ice_ptp_setup_pf(struct ice_pf *pf)
struct ice_ptp *ctrl_ptp = ice_get_ctrl_ptp(pf);
struct ice_ptp *ptp = &pf->ptp;
- if (WARN_ON(!ctrl_ptp) || ice_get_phy_model(&pf->hw) == ICE_PHY_UNSUP)
+ if (!ctrl_ptp) {
+ dev_info(ice_pf_to_dev(pf),
+ "PTP unavailable: no controlling PF\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (ice_get_phy_model(&pf->hw) == ICE_PHY_UNSUP)
return -ENODEV;
INIT_LIST_HEAD(&ptp->port.list_node);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 263/869] i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (261 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 262/869] ice: ptp: dont WARN when controlling PF is unavailable Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 264/869] i3c: mipi-i3c-hci: Fix race in DMA ring dequeue Greg Kroah-Hartman
` (606 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Adrian Hunter, Frank Li,
Alexandre Belloni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <adrian.hunter@intel.com>
[ Upstream commit b795e68bf3073d67bebbb5a44d93f49efc5b8cc7 ]
The logic used to abort the DMA ring contains several flaws:
1. The driver unconditionally issues a ring abort even when the ring has
already stopped.
2. The completion used to wait for abort completion is never
re-initialized, resulting in incorrect wait behavior.
3. The abort sequence unintentionally clears RING_CTRL_ENABLE, which
resets hardware ring pointers and disrupts the controller state.
4. If the ring is already stopped, the abort operation should be
considered successful without attempting further action.
Fix the abort handling by checking whether the ring is running before
issuing an abort, re-initializing the completion when needed, ensuring that
RING_CTRL_ENABLE remains asserted during abort, and treating an already
stopped ring as a successful condition.
Fixes: 9ad9a52cce282 ("i3c/master: introduce the mipi-i3c-hci driver")
Cc: stable@vger.kernel.org
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260306072451.11131-9-adrian.hunter@intel.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/i3c/master/mipi-i3c-hci/dma.c | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index 09bc109c4ab1e..8788eefcbb5be 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -457,16 +457,23 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci,
struct hci_rh_data *rh = &rings->headers[xfer_list[0].ring_number];
unsigned int i;
bool did_unqueue = false;
-
- /* stop the ring */
- rh_reg_write(RING_CONTROL, RING_CTRL_ABORT);
- if (wait_for_completion_timeout(&rh->op_done, HZ) == 0) {
- /*
- * We're deep in it if ever this condition is ever met.
- * Hardware might still be writing to memory, etc.
- */
- dev_crit(&hci->master.dev, "unable to abort the ring\n");
- WARN_ON(1);
+ u32 ring_status;
+
+ ring_status = rh_reg_read(RING_STATUS);
+ if (ring_status & RING_STATUS_RUNNING) {
+ /* stop the ring */
+ reinit_completion(&rh->op_done);
+ rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_ABORT);
+ wait_for_completion_timeout(&rh->op_done, HZ);
+ ring_status = rh_reg_read(RING_STATUS);
+ if (ring_status & RING_STATUS_RUNNING) {
+ /*
+ * We're deep in it if ever this condition is ever met.
+ * Hardware might still be writing to memory, etc.
+ */
+ dev_crit(&hci->master.dev, "unable to abort the ring\n");
+ WARN_ON(1);
+ }
}
for (i = 0; i < n; i++) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 264/869] i3c: mipi-i3c-hci: Fix race in DMA ring dequeue
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (262 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 263/869] i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 265/869] scsi: qla2xxx: Completely fix fcport double free Greg Kroah-Hartman
` (605 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Adrian Hunter, Frank Li,
Alexandre Belloni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <adrian.hunter@intel.com>
[ Upstream commit 1dca8aee80eea76d2aae21265de5dd64f6ba0f09 ]
The HCI DMA dequeue path (hci_dma_dequeue_xfer()) may be invoked for
multiple transfers that timeout around the same time. However, the
function is not serialized and can race with itself.
When a timeout occurs, hci_dma_dequeue_xfer() stops the ring, processes
incomplete transfers, and then restarts the ring. If another timeout
triggers a parallel call into the same function, the two instances may
interfere with each other - stopping or restarting the ring at unexpected
times.
Add a mutex so that hci_dma_dequeue_xfer() is serialized with respect to
itself.
Fixes: 9ad9a52cce282 ("i3c/master: introduce the mipi-i3c-hci driver")
Cc: stable@vger.kernel.org
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260306072451.11131-7-adrian.hunter@intel.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/i3c/master/mipi-i3c-hci/core.c | 1 +
drivers/i3c/master/mipi-i3c-hci/dma.c | 2 ++
drivers/i3c/master/mipi-i3c-hci/hci.h | 1 +
3 files changed, 4 insertions(+)
diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 51780354be3b3..73a620144c7e1 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -804,6 +804,7 @@ static int i3c_hci_probe(struct platform_device *pdev)
hci = devm_kzalloc(&pdev->dev, sizeof(*hci), GFP_KERNEL);
if (!hci)
return -ENOMEM;
+ mutex_init(&hci->control_mutex);
hci->base_regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hci->base_regs))
return PTR_ERR(hci->base_regs);
diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index 8788eefcbb5be..845feecc0211f 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -459,6 +459,8 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci,
bool did_unqueue = false;
u32 ring_status;
+ guard(mutex)(&hci->control_mutex);
+
ring_status = rh_reg_read(RING_STATUS);
if (ring_status & RING_STATUS_RUNNING) {
/* stop the ring */
diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h
index aaa47ac473814..24e6dd22cf0e4 100644
--- a/drivers/i3c/master/mipi-i3c-hci/hci.h
+++ b/drivers/i3c/master/mipi-i3c-hci/hci.h
@@ -48,6 +48,7 @@ struct i3c_hci {
const struct hci_io_ops *io;
void *io_data;
const struct hci_cmd_ops *cmd;
+ struct mutex control_mutex;
atomic_t next_cmd_tid;
u32 caps;
unsigned int quirks;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 265/869] scsi: qla2xxx: Completely fix fcport double free
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (263 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 264/869] i3c: mipi-i3c-hci: Fix race in DMA ring dequeue Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 266/869] ASoC: amd: acp-mach-common: Add missing error check for clock acquisition Greg Kroah-Hartman
` (604 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vladimir Riabchun, Farhat Abbas,
Martin K. Petersen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Riabchun <ferr.lambarginio@gmail.com>
[ Upstream commit c0b7da13a04bd70ef6070bfb9ea85f582294560a ]
In qla24xx_els_dcmd_iocb() sp->free is set to qla2x00_els_dcmd_sp_free().
When an error happens, this function is called by qla2x00_sp_release(),
when kref_put() releases the first and the last reference.
qla2x00_els_dcmd_sp_free() frees fcport by calling qla2x00_free_fcport().
Doing it one more time after kref_put() is a bad idea.
Fixes: 82f522ae0d97 ("scsi: qla2xxx: Fix double free of fcport")
Fixes: 4895009c4bb7 ("scsi: qla2xxx: Prevent command send on chip reset")
Signed-off-by: Vladimir Riabchun <ferr.lambarginio@gmail.com>
Signed-off-by: Farhat Abbas <fabbas@cloudlinux.com>
Link: https://patch.msgid.link/aYsDln9NFQQsPDgg@vova-pc
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/scsi/qla2xxx/qla_iocb.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 17231a8dab988..c8a44969a6c30 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2758,7 +2758,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
if (!elsio->u.els_logo.els_logo_pyld) {
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
- qla2x00_free_fcport(fcport);
return QLA_FUNCTION_FAILED;
}
@@ -2783,7 +2782,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
if (rval != QLA_SUCCESS) {
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
- qla2x00_free_fcport(fcport);
return QLA_FUNCTION_FAILED;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 266/869] ASoC: amd: acp-mach-common: Add missing error check for clock acquisition
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (264 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 265/869] scsi: qla2xxx: Completely fix fcport double free Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 267/869] rxrpc: kdoc: Update function descriptions and add link from rxrpc.rst Greg Kroah-Hartman
` (603 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Chen Ni, Mark Brown, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Ni <nichen@iscas.ac.cn>
[ Upstream commit 30c64fb9839949f085c8eb55b979cbd8a4c51f00 ]
The acp_card_rt5682_init() and acp_card_rt5682s_init() functions did not
check the return values of clk_get(). This could lead to a kernel crash
when the invalid pointers are later dereferenced by clock core
functions.
Fix this by:
1. Changing clk_get() to the device-managed devm_clk_get().
2. Adding IS_ERR() checks immediately after each clock acquisition.
Fixes: 8b7256266848 ("ASoC: amd: acp: Add support for RT5682-VS codec")
Fixes: d4c750f2c7d4 ("ASoC: amd: acp: Add generic machine driver support for ACP cards")
Signed-off-by: Chen Ni <nichen@iscas.ac.cn>
Link: https://patch.msgid.link/20260310044327.2582018-1-nichen@iscas.ac.cn
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/soc/amd/acp/acp-mach-common.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index 6c0a92d76b54d..75143f24a5cea 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -133,8 +133,13 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
if (drvdata->hs_codec_id != RT5682)
return -EINVAL;
- drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
- drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
+ drvdata->wclk = devm_clk_get(component->dev, "rt5682-dai-wclk");
+ if (IS_ERR(drvdata->wclk))
+ return PTR_ERR(drvdata->wclk);
+
+ drvdata->bclk = devm_clk_get(component->dev, "rt5682-dai-bclk");
+ if (IS_ERR(drvdata->bclk))
+ return PTR_ERR(drvdata->bclk);
ret = snd_soc_dapm_new_controls(&card->dapm, rt5682_widgets,
ARRAY_SIZE(rt5682_widgets));
@@ -375,8 +380,13 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
return -EINVAL;
if (!drvdata->soc_mclk) {
- drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
- drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
+ drvdata->wclk = devm_clk_get(component->dev, "rt5682-dai-wclk");
+ if (IS_ERR(drvdata->wclk))
+ return PTR_ERR(drvdata->wclk);
+
+ drvdata->bclk = devm_clk_get(component->dev, "rt5682-dai-bclk");
+ if (IS_ERR(drvdata->bclk))
+ return PTR_ERR(drvdata->bclk);
}
ret = snd_soc_dapm_new_controls(&card->dapm, rt5682s_widgets,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 267/869] rxrpc: kdoc: Update function descriptions and add link from rxrpc.rst
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (265 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 266/869] ASoC: amd: acp-mach-common: Add missing error check for clock acquisition Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 268/869] rxrpc, afs: Fix missing error pointer check after rxrpc_kernel_lookup_peer() Greg Kroah-Hartman
` (602 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Marc Dionne,
Simon Horman, linux-afs, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit 28a79fc9b03e4ed89b65e5300091e7ed55e13192 ]
Update the kerneldoc function descriptions to add "Return:" sections for
AF_RXRPC exported functions that have return values to stop the kdoc
builder from throwing warnings.
Also add links from the rxrpc.rst API doc to add a function API reference
at the end. (Note that the API doc really needs updating, but that's
beyond this patchset).
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
Link: https://patch.msgid.link/20250411095303.2316168-2-dhowells@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 4245a79003ad ("rxrpc, afs: Fix missing error pointer check after rxrpc_kernel_lookup_peer()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
Documentation/networking/rxrpc.rst | 11 +++++++++++
net/rxrpc/af_rxrpc.c | 21 +++++++++++++++++----
net/rxrpc/key.c | 2 ++
net/rxrpc/peer_object.c | 22 ++++++++++++++++++----
net/rxrpc/recvmsg.c | 12 ++++++------
net/rxrpc/sendmsg.c | 7 +++++--
net/rxrpc/server_key.c | 2 ++
7 files changed, 61 insertions(+), 16 deletions(-)
diff --git a/Documentation/networking/rxrpc.rst b/Documentation/networking/rxrpc.rst
index e807e18ba32ac..2680abd1cb269 100644
--- a/Documentation/networking/rxrpc.rst
+++ b/Documentation/networking/rxrpc.rst
@@ -1172,3 +1172,14 @@ adjusted through sysctls in /proc/net/rxrpc/:
header plus exactly 1412 bytes of data. The terminal packet must contain
a four byte header plus any amount of data. In any event, a jumbo packet
may not exceed rxrpc_rx_mtu in size.
+
+
+API Function Reference
+======================
+
+.. kernel-doc:: net/rxrpc/af_rxrpc.c
+.. kernel-doc:: net/rxrpc/key.c
+.. kernel-doc:: net/rxrpc/peer_object.c
+.. kernel-doc:: net/rxrpc/recvmsg.c
+.. kernel-doc:: net/rxrpc/sendmsg.c
+.. kernel-doc:: net/rxrpc/server_key.c
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index ec4fe6af218f0..edb5a94110783 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -265,7 +265,10 @@ static int rxrpc_listen(struct socket *sock, int backlog)
* @gfp: Allocation flags
*
* Lookup or create a remote transport endpoint record for the specified
- * address and return it with a ref held.
+ * address.
+ *
+ * Return: The peer record found with a reference, %NULL if no record is found
+ * or a negative error code if the address is invalid or unsupported.
*/
struct rxrpc_peer *rxrpc_kernel_lookup_peer(struct socket *sock,
struct sockaddr_rxrpc *srx, gfp_t gfp)
@@ -283,9 +286,11 @@ EXPORT_SYMBOL(rxrpc_kernel_lookup_peer);
/**
* rxrpc_kernel_get_peer - Get a reference on a peer
- * @peer: The peer to get a reference on.
+ * @peer: The peer to get a reference on (may be NULL).
+ *
+ * Get a reference for a remote peer record (if not NULL).
*
- * Get a record for the remote peer in a call.
+ * Return: The @peer argument.
*/
struct rxrpc_peer *rxrpc_kernel_get_peer(struct rxrpc_peer *peer)
{
@@ -296,6 +301,8 @@ EXPORT_SYMBOL(rxrpc_kernel_get_peer);
/**
* rxrpc_kernel_put_peer - Allow a kernel app to drop a peer reference
* @peer: The peer to drop a ref on
+ *
+ * Drop a reference on a peer record.
*/
void rxrpc_kernel_put_peer(struct rxrpc_peer *peer)
{
@@ -320,10 +327,12 @@ EXPORT_SYMBOL(rxrpc_kernel_put_peer);
*
* Allow a kernel service to begin a call on the nominated socket. This just
* sets up all the internal tracking structures and allocates connection and
- * call IDs as appropriate. The call to be used is returned.
+ * call IDs as appropriate.
*
* The default socket destination address and security may be overridden by
* supplying @srx and @key.
+ *
+ * Return: The new call or an error code.
*/
struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
struct rxrpc_peer *peer,
@@ -437,6 +446,8 @@ EXPORT_SYMBOL(rxrpc_kernel_put_call);
*
* Allow a kernel service to find out whether a call is still alive - whether
* it has completed successfully and all received data has been consumed.
+ *
+ * Return: %true if the call is still ongoing and %false if it has completed.
*/
bool rxrpc_kernel_check_life(const struct socket *sock,
const struct rxrpc_call *call)
@@ -456,6 +467,8 @@ EXPORT_SYMBOL(rxrpc_kernel_check_life);
*
* Allow a kernel service to retrieve the epoch value from a service call to
* see if the client at the other end rebooted.
+ *
+ * Return: The epoch of the call's connection.
*/
u32 rxrpc_kernel_get_epoch(struct socket *sock, struct rxrpc_call *call)
{
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index 73659197edffa..1dbf7851f0fcf 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -536,6 +536,8 @@ EXPORT_SYMBOL(rxrpc_get_server_data_key);
*
* Generate a null RxRPC key that can be used to indicate anonymous security is
* required for a particular domain.
+ *
+ * Return: The new key or a negative error code.
*/
struct key *rxrpc_get_null_key(const char *keyname)
{
diff --git a/net/rxrpc/peer_object.c b/net/rxrpc/peer_object.c
index 3af39fc67d34b..e329be68434d9 100644
--- a/net/rxrpc/peer_object.c
+++ b/net/rxrpc/peer_object.c
@@ -463,6 +463,8 @@ void rxrpc_destroy_all_peers(struct rxrpc_net *rxnet)
* @call: The call to query
*
* Get a record for the remote peer in a call.
+ *
+ * Return: The call's peer record.
*/
struct rxrpc_peer *rxrpc_kernel_get_call_peer(struct socket *sock, struct rxrpc_call *call)
{
@@ -474,7 +476,9 @@ EXPORT_SYMBOL(rxrpc_kernel_get_call_peer);
* rxrpc_kernel_get_srtt - Get a call's peer smoothed RTT
* @peer: The peer to query
*
- * Get the call's peer smoothed RTT in uS or UINT_MAX if we have no samples.
+ * Get the call's peer smoothed RTT.
+ *
+ * Return: The RTT in uS or %UINT_MAX if we have no samples.
*/
unsigned int rxrpc_kernel_get_srtt(const struct rxrpc_peer *peer)
{
@@ -487,7 +491,10 @@ EXPORT_SYMBOL(rxrpc_kernel_get_srtt);
* @peer: The peer to query
*
* Get a pointer to the address from a peer record. The caller is responsible
- * for making sure that the address is not deallocated.
+ * for making sure that the address is not deallocated. A fake address will be
+ * substituted if %peer in NULL.
+ *
+ * Return: The rxrpc address record or a fake record.
*/
const struct sockaddr_rxrpc *rxrpc_kernel_remote_srx(const struct rxrpc_peer *peer)
{
@@ -500,7 +507,10 @@ EXPORT_SYMBOL(rxrpc_kernel_remote_srx);
* @peer: The peer to query
*
* Get a pointer to the transport address from a peer record. The caller is
- * responsible for making sure that the address is not deallocated.
+ * responsible for making sure that the address is not deallocated. A fake
+ * address will be substituted if %peer in NULL.
+ *
+ * Return: The transport address record or a fake record.
*/
const struct sockaddr *rxrpc_kernel_remote_addr(const struct rxrpc_peer *peer)
{
@@ -515,7 +525,9 @@ EXPORT_SYMBOL(rxrpc_kernel_remote_addr);
* @app_data: The data to set
*
* Set the app-specific data on a peer. AF_RXRPC makes no effort to retain
- * anything the data might refer to. The previous app_data is returned.
+ * anything the data might refer to.
+ *
+ * Return: The previous app_data.
*/
unsigned long rxrpc_kernel_set_peer_data(struct rxrpc_peer *peer, unsigned long app_data)
{
@@ -528,6 +540,8 @@ EXPORT_SYMBOL(rxrpc_kernel_set_peer_data);
* @peer: The peer to query
*
* Retrieve the app-specific data from a peer.
+ *
+ * Return: The peer's app data.
*/
unsigned long rxrpc_kernel_get_peer_data(const struct rxrpc_peer *peer)
{
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index beb0eb426592a..bb140d7005c7c 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -546,14 +546,14 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
* @_service: Where to store the actual service ID (may be upgraded)
*
* Allow a kernel service to receive data and pick up information about the
- * state of a call. Returns 0 if got what was asked for and there's more
- * available, 1 if we got what was asked for and we're at the end of the data
- * and -EAGAIN if we need more data.
+ * state of a call. Note that *@_abort should also be initialised to %0.
*
- * Note that we may return -EAGAIN to drain empty packets at the end of the
- * data, even if we've already copied over the requested data.
+ * Note that we may return %-EAGAIN to drain empty packets at the end
+ * of the data, even if we've already copied over the requested data.
*
- * *_abort should also be initialised to 0.
+ * Return: %0 if got what was asked for and there's more available, %1
+ * if we got what was asked for and we're at the end of the data and
+ * %-EAGAIN if we need more data.
*/
int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,
struct iov_iter *iter, size_t *_len,
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index 1d8065468e90a..c9b85848e825b 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -745,6 +745,8 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
* appropriate to sending data. No control data should be supplied in @msg,
* nor should an address be supplied. MSG_MORE should be flagged if there's
* more data to come, otherwise this data will end the transmission phase.
+ *
+ * Return: %0 if successful and a negative error code otherwise.
*/
int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
struct msghdr *msg, size_t len,
@@ -780,8 +782,9 @@ EXPORT_SYMBOL(rxrpc_kernel_send_data);
* @error: Local error value
* @why: Indication as to why.
*
- * Allow a kernel service to abort a call, if it's still in an abortable state
- * and return true if the call was aborted, false if it was already complete.
+ * Allow a kernel service to abort a call if it's still in an abortable state.
+ *
+ * Return: %true if the call was aborted, %false if it was already complete.
*/
bool rxrpc_kernel_abort_call(struct socket *sock, struct rxrpc_call *call,
u32 abort_code, int error, enum rxrpc_abort_reason why)
diff --git a/net/rxrpc/server_key.c b/net/rxrpc/server_key.c
index 9d95a6055b707..7501fc7b38b85 100644
--- a/net/rxrpc/server_key.c
+++ b/net/rxrpc/server_key.c
@@ -155,6 +155,8 @@ int rxrpc_server_keyring(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
*
* Set the server security keyring on an rxrpc socket. This is used to provide
* the encryption keys for a kernel service.
+ *
+ * Return: %0 if successful and a negative error code otherwise.
*/
int rxrpc_sock_set_security_keyring(struct sock *sk, struct key *keyring)
{
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 268/869] rxrpc, afs: Fix missing error pointer check after rxrpc_kernel_lookup_peer()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (266 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 267/869] rxrpc: kdoc: Update function descriptions and add link from rxrpc.rst Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 269/869] net/mlx5e: RX, Fix XDP multi-buf frag counting for legacy RQ Greg Kroah-Hartman
` (601 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Miaoqian Lin, David Howells,
Marc Dionne, Simon Horman, linux-afs, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miaoqian Lin <linmq006@gmail.com>
[ Upstream commit 4245a79003adf30e67f8e9060915bd05cb31d142 ]
rxrpc_kernel_lookup_peer() can also return error pointers in addition to
NULL, so just checking for NULL is not sufficient.
Fix this by:
(1) Changing rxrpc_kernel_lookup_peer() to return -ENOMEM rather than NULL
on allocation failure.
(2) Making the callers in afs use IS_ERR() and PTR_ERR() to pass on the
error code returned.
Fixes: 72904d7b9bfb ("rxrpc, afs: Allow afs to pin rxrpc_peer objects")
Signed-off-by: Miaoqian Lin <linmq006@gmail.com>
Co-developed-by: David Howells <dhowells@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
Link: https://patch.msgid.link/368272.1772713861@warthog.procyon.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/afs/addr_list.c | 8 ++++----
net/rxrpc/af_rxrpc.c | 8 +++++---
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c
index f2361a1351076..48d68f5aa7b43 100644
--- a/fs/afs/addr_list.c
+++ b/fs/afs/addr_list.c
@@ -298,8 +298,8 @@ int afs_merge_fs_addr4(struct afs_net *net, struct afs_addr_list *alist,
srx.transport.sin.sin_addr.s_addr = xdr;
peer = rxrpc_kernel_lookup_peer(net->socket, &srx, GFP_KERNEL);
- if (!peer)
- return -ENOMEM;
+ if (IS_ERR(peer))
+ return PTR_ERR(peer);
for (i = 0; i < alist->nr_ipv4; i++) {
if (peer == alist->addrs[i].peer) {
@@ -342,8 +342,8 @@ int afs_merge_fs_addr6(struct afs_net *net, struct afs_addr_list *alist,
memcpy(&srx.transport.sin6.sin6_addr, xdr, 16);
peer = rxrpc_kernel_lookup_peer(net->socket, &srx, GFP_KERNEL);
- if (!peer)
- return -ENOMEM;
+ if (IS_ERR(peer))
+ return PTR_ERR(peer);
for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) {
if (peer == alist->addrs[i].peer) {
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index edb5a94110783..0d86c7c37754a 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -267,12 +267,13 @@ static int rxrpc_listen(struct socket *sock, int backlog)
* Lookup or create a remote transport endpoint record for the specified
* address.
*
- * Return: The peer record found with a reference, %NULL if no record is found
- * or a negative error code if the address is invalid or unsupported.
+ * Return: The peer record found with a reference or a negative error code if
+ * the address is invalid or unsupported.
*/
struct rxrpc_peer *rxrpc_kernel_lookup_peer(struct socket *sock,
struct sockaddr_rxrpc *srx, gfp_t gfp)
{
+ struct rxrpc_peer *peer;
struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
int ret;
@@ -280,7 +281,8 @@ struct rxrpc_peer *rxrpc_kernel_lookup_peer(struct socket *sock,
if (ret < 0)
return ERR_PTR(ret);
- return rxrpc_lookup_peer(rx->local, srx, gfp);
+ peer = rxrpc_lookup_peer(rx->local, srx, gfp);
+ return peer ?: ERR_PTR(-ENOMEM);
}
EXPORT_SYMBOL(rxrpc_kernel_lookup_peer);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 269/869] net/mlx5e: RX, Fix XDP multi-buf frag counting for legacy RQ
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (267 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 268/869] rxrpc, afs: Fix missing error pointer check after rxrpc_kernel_lookup_peer() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 270/869] net/mlx5e: RX, Fix XDP multi-buf frag counting for striding RQ Greg Kroah-Hartman
` (600 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dragos Tatulea, Tariq Toukan,
Amery Hung, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dragos Tatulea <dtatulea@nvidia.com>
[ Upstream commit a6413e6f6c9d9bb9833324cb3753582f7bc0f2fa ]
XDP multi-buf programs can modify the layout of the XDP buffer when the
program calls bpf_xdp_pull_data() or bpf_xdp_adjust_tail(). The
referenced commit in the fixes tag corrected the assumption in the mlx5
driver that the XDP buffer layout doesn't change during a program
execution. However, this fix introduced another issue: the dropped
fragments still need to be counted on the driver side to avoid page
fragment reference counting issues.
Such issue can be observed with the
test_xdp_native_adjst_tail_shrnk_data selftest when using a payload of
3600 and shrinking by 256 bytes (an upcoming selftest patch): the last
fragment gets released by the XDP code but doesn't get tracked by the
driver. This results in a negative pp_ref_count during page release and
the following splat:
WARNING: include/net/page_pool/helpers.h:297 at mlx5e_page_release_fragmented.isra.0+0x4a/0x50 [mlx5_core], CPU#12: ip/3137
Modules linked in: [...]
CPU: 12 UID: 0 PID: 3137 Comm: ip Not tainted 6.19.0-rc3+ #12 NONE
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
RIP: 0010:mlx5e_page_release_fragmented.isra.0+0x4a/0x50 [mlx5_core]
[...]
Call Trace:
<TASK>
mlx5e_dealloc_rx_wqe+0xcb/0x1a0 [mlx5_core]
mlx5e_free_rx_descs+0x7f/0x110 [mlx5_core]
mlx5e_close_rq+0x50/0x60 [mlx5_core]
mlx5e_close_queues+0x36/0x2c0 [mlx5_core]
mlx5e_close_channel+0x1c/0x50 [mlx5_core]
mlx5e_close_channels+0x45/0x80 [mlx5_core]
mlx5e_safe_switch_params+0x1a5/0x230 [mlx5_core]
mlx5e_change_mtu+0xf3/0x2f0 [mlx5_core]
netif_set_mtu_ext+0xf1/0x230
do_setlink.isra.0+0x219/0x1180
rtnl_newlink+0x79f/0xb60
rtnetlink_rcv_msg+0x213/0x3a0
netlink_rcv_skb+0x48/0xf0
netlink_unicast+0x24a/0x350
netlink_sendmsg+0x1ee/0x410
__sock_sendmsg+0x38/0x60
____sys_sendmsg+0x232/0x280
___sys_sendmsg+0x78/0xb0
__sys_sendmsg+0x5f/0xb0
[...]
do_syscall_64+0x57/0xc50
This patch fixes the issue by doing page frag counting on all the
original XDP buffer fragments for all relevant XDP actions (XDP_TX ,
XDP_REDIRECT and XDP_PASS). This is basically reverting to the original
counting before the commit in the fixes tag.
As frag_page is still pointing to the original tail, the nr_frags
parameter to xdp_update_skb_frags_info() needs to be calculated
in a different way to reflect the new nr_frags.
Fixes: afd5ba577c10 ("net/mlx5e: RX, Fix generating skb from non-linear xdp_buff for legacy RQ")
Signed-off-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Reviewed-by: Amery Hung <ameryhung@gmail.com>
Link: https://patch.msgid.link/20260305142634.1813208-6-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 3fb3d9299528d..148cc8445afab 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -1732,6 +1732,7 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
struct skb_shared_info *sinfo;
u32 frag_consumed_bytes;
struct bpf_prog *prog;
+ u8 nr_frags_free = 0;
struct sk_buff *skb;
dma_addr_t addr;
u32 truesize;
@@ -1774,15 +1775,13 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
prog = rcu_dereference(rq->xdp_prog);
if (prog) {
- u8 nr_frags_free, old_nr_frags = sinfo->nr_frags;
+ u8 old_nr_frags = sinfo->nr_frags;
if (mlx5e_xdp_handle(rq, prog, mxbuf)) {
if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT,
rq->flags)) {
struct mlx5e_wqe_frag_info *pwi;
- wi -= old_nr_frags - sinfo->nr_frags;
-
for (pwi = head_wi; pwi < wi; pwi++)
pwi->frag_page->frags++;
}
@@ -1790,10 +1789,8 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
}
nr_frags_free = old_nr_frags - sinfo->nr_frags;
- if (unlikely(nr_frags_free)) {
- wi -= nr_frags_free;
+ if (unlikely(nr_frags_free))
truesize -= nr_frags_free * frag_info->frag_stride;
- }
}
skb = mlx5e_build_linear_skb(
@@ -1809,7 +1806,7 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
if (xdp_buff_has_frags(&mxbuf->xdp)) {
/* sinfo->nr_frags is reset by build_skb, calculate again. */
- xdp_update_skb_shared_info(skb, wi - head_wi - 1,
+ xdp_update_skb_shared_info(skb, wi - head_wi - nr_frags_free - 1,
sinfo->xdp_frags_size, truesize,
xdp_buff_is_frag_pfmemalloc(
&mxbuf->xdp));
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 270/869] net/mlx5e: RX, Fix XDP multi-buf frag counting for striding RQ
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (268 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 269/869] net/mlx5e: RX, Fix XDP multi-buf frag counting for legacy RQ Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 271/869] nouveau/gsp: drop WARN_ON in ACPI probes Greg Kroah-Hartman
` (599 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dragos Tatulea, Amery Hung,
Nimrod Oren, Tariq Toukan, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dragos Tatulea <dtatulea@nvidia.com>
[ Upstream commit db25c42c2e1f9c0d136420fff5e5700f7e771a6f ]
XDP multi-buf programs can modify the layout of the XDP buffer when the
program calls bpf_xdp_pull_data() or bpf_xdp_adjust_tail(). The
referenced commit in the fixes tag corrected the assumption in the mlx5
driver that the XDP buffer layout doesn't change during a program
execution. However, this fix introduced another issue: the dropped
fragments still need to be counted on the driver side to avoid page
fragment reference counting issues.
The issue was discovered by the drivers/net/xdp.py selftest,
more specifically the test_xdp_native_tx_mb:
- The mlx5 driver allocates a page_pool page and initializes it with
a frag counter of 64 (pp_ref_count=64) and the internal frag counter
to 0.
- The test sends one packet with no payload.
- On RX (mlx5e_skb_from_cqe_mpwrq_nonlinear()), mlx5 configures the XDP
buffer with the packet data starting in the first fragment which is the
page mentioned above.
- The XDP program runs and calls bpf_xdp_pull_data() which moves the
header into the linear part of the XDP buffer. As the packet doesn't
contain more data, the program drops the tail fragment since it no
longer contains any payload (pp_ref_count=63).
- mlx5 device skips counting this fragment. Internal frag counter
remains 0.
- mlx5 releases all 64 fragments of the page but page pp_ref_count is
63 => negative reference counting error.
Resulting splat during the test:
WARNING: CPU: 0 PID: 188225 at ./include/net/page_pool/helpers.h:297 mlx5e_page_release_fragmented.isra.0+0xbd/0xe0 [mlx5_core]
Modules linked in: [...]
CPU: 0 UID: 0 PID: 188225 Comm: ip Not tainted 6.18.0-rc7_for_upstream_min_debug_2025_12_08_11_44 #1 NONE
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014
RIP: 0010:mlx5e_page_release_fragmented.isra.0+0xbd/0xe0 [mlx5_core]
[...]
Call Trace:
<TASK>
mlx5e_free_rx_mpwqe+0x20a/0x250 [mlx5_core]
mlx5e_dealloc_rx_mpwqe+0x37/0xb0 [mlx5_core]
mlx5e_free_rx_descs+0x11a/0x170 [mlx5_core]
mlx5e_close_rq+0x78/0xa0 [mlx5_core]
mlx5e_close_queues+0x46/0x2a0 [mlx5_core]
mlx5e_close_channel+0x24/0x90 [mlx5_core]
mlx5e_close_channels+0x5d/0xf0 [mlx5_core]
mlx5e_safe_switch_params+0x2ec/0x380 [mlx5_core]
mlx5e_change_mtu+0x11d/0x490 [mlx5_core]
mlx5e_change_nic_mtu+0x19/0x30 [mlx5_core]
netif_set_mtu_ext+0xfc/0x240
do_setlink.isra.0+0x226/0x1100
rtnl_newlink+0x7a9/0xba0
rtnetlink_rcv_msg+0x220/0x3c0
netlink_rcv_skb+0x4b/0xf0
netlink_unicast+0x255/0x380
netlink_sendmsg+0x1f3/0x420
__sock_sendmsg+0x38/0x60
____sys_sendmsg+0x1e8/0x240
___sys_sendmsg+0x7c/0xb0
[...]
__sys_sendmsg+0x5f/0xb0
do_syscall_64+0x55/0xc70
The problem applies for XDP_PASS as well which is handled in a different
code path in the driver.
This patch fixes the issue by doing page frag counting on all the
original XDP buffer fragments for all relevant XDP actions (XDP_TX ,
XDP_REDIRECT and XDP_PASS). This is basically reverting to the original
counting before the commit in the fixes tag.
As frag_page is still pointing to the original tail, the nr_frags
parameter to xdp_update_skb_frags_info() needs to be calculated
in a different way to reflect the new nr_frags.
Fixes: 87bcef158ac1 ("net/mlx5e: RX, Fix generating skb from non-linear xdp_buff for striding RQ")
Signed-off-by: Dragos Tatulea <dtatulea@nvidia.com>
Cc: Amery Hung <ameryhung@gmail.com>
Reviewed-by: Nimrod Oren <noren@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/20260305142634.1813208-5-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 148cc8445afab..71f0519be09de 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -2088,14 +2088,13 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
if (prog) {
u8 nr_frags_free, old_nr_frags = sinfo->nr_frags;
+ u8 new_nr_frags;
u32 len;
if (mlx5e_xdp_handle(rq, prog, mxbuf)) {
if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
struct mlx5e_frag_page *pfp;
- frag_page -= old_nr_frags - sinfo->nr_frags;
-
for (pfp = head_page; pfp < frag_page; pfp++)
pfp->frags++;
@@ -2105,13 +2104,12 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
return NULL; /* page/packet was consumed by XDP */
}
- nr_frags_free = old_nr_frags - sinfo->nr_frags;
- if (unlikely(nr_frags_free)) {
- frag_page -= nr_frags_free;
+ new_nr_frags = sinfo->nr_frags;
+ nr_frags_free = old_nr_frags - new_nr_frags;
+ if (unlikely(nr_frags_free))
truesize -= (nr_frags_free - 1) * page_size +
ALIGN(pg_consumed_bytes,
BIT(rq->mpwqe.log_stride_sz));
- }
len = mxbuf->xdp.data_end - mxbuf->xdp.data;
@@ -2132,7 +2130,7 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
struct mlx5e_frag_page *pagep;
/* sinfo->nr_frags is reset by build_skb, calculate again. */
- xdp_update_skb_shared_info(skb, frag_page - head_page,
+ xdp_update_skb_shared_info(skb, new_nr_frags,
sinfo->xdp_frags_size, truesize,
xdp_buff_is_frag_pfmemalloc(
&mxbuf->xdp));
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 271/869] nouveau/gsp: drop WARN_ON in ACPI probes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (269 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 270/869] net/mlx5e: RX, Fix XDP multi-buf frag counting for striding RQ Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 272/869] bpf: Fix tcx/netkit detach permissions when prog fd isnt given Greg Kroah-Hartman
` (598 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dave Airlie, Danilo Krummrich,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Airlie <airlied@redhat.com>
[ Upstream commit 9478c166c46934160135e197b049b5a05753f2ad ]
These WARN_ONs seem to trigger a lot, and we don't seem to have a
plan to fix them, so just drop them, as they are most likely
harmless.
Cc: stable@vger.kernel.org
Fixes: 176fdcbddfd2 ("drm/nouveau/gsp/r535: add support for booting GSP-RM")
Signed-off-by: Dave Airlie <airlied@redhat.com>
Link: https://patch.msgid.link/20241121014601.229391-1-airlied@gmail.com
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
index 801b0bc676ab2..5952f0abc070c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
@@ -1476,8 +1476,8 @@ r535_gsp_acpi_caps(acpi_handle handle, CAPS_METHOD_DATA *caps)
if (!obj)
goto done;
- if (WARN_ON(obj->type != ACPI_TYPE_BUFFER) ||
- WARN_ON(obj->buffer.length != 4))
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length != 4)
goto done;
caps->status = 0;
@@ -1512,8 +1512,8 @@ r535_gsp_acpi_jt(acpi_handle handle, JT_METHOD_DATA *jt)
if (!obj)
goto done;
- if (WARN_ON(obj->type != ACPI_TYPE_BUFFER) ||
- WARN_ON(obj->buffer.length != 4))
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length != 4)
goto done;
jt->status = 0;
@@ -1600,8 +1600,8 @@ r535_gsp_acpi_dod(acpi_handle handle, DOD_METHOD_DATA *dod)
_DOD = output.pointer;
- if (WARN_ON(_DOD->type != ACPI_TYPE_PACKAGE) ||
- WARN_ON(_DOD->package.count > ARRAY_SIZE(dod->acpiIdList)))
+ if (_DOD->type != ACPI_TYPE_PACKAGE ||
+ _DOD->package.count > ARRAY_SIZE(dod->acpiIdList))
return;
for (int i = 0; i < _DOD->package.count; i++) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 272/869] bpf: Fix tcx/netkit detach permissions when prog fd isnt given
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (270 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 271/869] nouveau/gsp: drop WARN_ON in ACPI probes Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 273/869] btrfs: fix EEXIST abort due to non-consecutive gaps in chunk allocation Greg Kroah-Hartman
` (597 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Guillaume Gonnet, Alexei Starovoitov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guillaume Gonnet <ggonnet.linux@gmail.com>
[ Upstream commit ae23bc81ddf7c17b663c4ed1b21e35527b0a7131 ]
This commit fixes a security issue where BPF_PROG_DETACH on tcx or
netkit devices could be executed by any user when no program fd was
provided, bypassing permission checks. The fix adds a capability
check for CAP_NET_ADMIN or CAP_SYS_ADMIN in this case.
Fixes: e420bed02507 ("bpf: Add fd-based tcx multi-prog infra with link support")
Signed-off-by: Guillaume Gonnet <ggonnet.linux@gmail.com>
Link: https://lore.kernel.org/r/20260127160200.10395-1-ggonnet.linux@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/bpf.h | 5 +++++
include/linux/bpf_mprog.h | 10 ++++++++++
kernel/bpf/syscall.c | 7 ++-----
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index a63fd54ac6b4f..8bdb4ba4df7ee 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -2999,6 +2999,11 @@ static inline void bpf_dynptr_set_rdonly(struct bpf_dynptr_kern *ptr)
}
#endif /* CONFIG_BPF_SYSCALL */
+static inline bool bpf_net_capable(void)
+{
+ return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
+}
+
static __always_inline int
bpf_probe_read_kernel_common(void *dst, u32 size, const void *unsafe_ptr)
{
diff --git a/include/linux/bpf_mprog.h b/include/linux/bpf_mprog.h
index 929225f7b0959..0b9f4caeeb0a3 100644
--- a/include/linux/bpf_mprog.h
+++ b/include/linux/bpf_mprog.h
@@ -340,4 +340,14 @@ static inline bool bpf_mprog_supported(enum bpf_prog_type type)
return false;
}
}
+
+static inline bool bpf_mprog_detach_empty(enum bpf_prog_type type)
+{
+ switch (type) {
+ case BPF_PROG_TYPE_SCHED_CLS:
+ return bpf_net_capable();
+ default:
+ return false;
+ }
+}
#endif /* __BPF_MPROG_H */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 857285a48d433..43081a7fb283a 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1206,11 +1206,6 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
return ret;
}
-static bool bpf_net_capable(void)
-{
- return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
-}
-
#define BPF_MAP_CREATE_LAST_FIELD map_token_fd
/* called via syscall */
static int map_create(union bpf_attr *attr)
@@ -4177,6 +4172,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
if (IS_ERR(prog))
return PTR_ERR(prog);
+ } else if (!bpf_mprog_detach_empty(ptype)) {
+ return -EPERM;
}
} else if (is_cgroup_prog_type(ptype, 0, false)) {
if (attr->attach_flags || attr->relative_fd)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 273/869] btrfs: fix EEXIST abort due to non-consecutive gaps in chunk allocation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (271 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 272/869] bpf: Fix tcx/netkit detach permissions when prog fd isnt given Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 274/869] net: stmmac: fix oops when split header is enabled Greg Kroah-Hartman
` (596 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dimitrios Apostolou, Qu Wenruo,
Boris Burkov, David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boris Burkov <boris@bur.io>
[ Upstream commit b14c5e04bd0f722ed631845599d52d03fcae1bc1 ]
I have been observing a number of systems aborting at
insert_dev_extents() in btrfs_create_pending_block_groups(). The
following is a sample stack trace of such an abort coming from forced
chunk allocation (typically behind CONFIG_BTRFS_EXPERIMENTAL) but this
can theoretically happen to any DUP chunk allocation.
[81.801] ------------[ cut here ]------------
[81.801] BTRFS: Transaction aborted (error -17)
[81.801] WARNING: fs/btrfs/block-group.c:2876 at btrfs_create_pending_block_groups+0x721/0x770 [btrfs], CPU#1: bash/319
[81.802] Modules linked in: virtio_net btrfs xor zstd_compress raid6_pq null_blk
[81.803] CPU: 1 UID: 0 PID: 319 Comm: bash Kdump: loaded Not tainted 6.19.0-rc6+ #319 NONE
[81.803] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.17.0-2-2 04/01/2014
[81.804] RIP: 0010:btrfs_create_pending_block_groups+0x723/0x770 [btrfs]
[81.806] RSP: 0018:ffffa36241a6bce8 EFLAGS: 00010282
[81.806] RAX: 000000000000000d RBX: ffff8e699921e400 RCX: 0000000000000000
[81.807] RDX: 0000000002040001 RSI: 00000000ffffffef RDI: ffffffffc0608bf0
[81.807] RBP: 00000000ffffffef R08: ffff8e69830f6000 R09: 0000000000000007
[81.808] R10: ffff8e699921e5e8 R11: 0000000000000000 R12: ffff8e6999228000
[81.808] R13: ffff8e6984d82000 R14: ffff8e69966a69c0 R15: ffff8e69aa47b000
[81.809] FS: 00007fec6bdd9740(0000) GS:ffff8e6b1b379000(0000) knlGS:0000000000000000
[81.809] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[81.810] CR2: 00005604833670f0 CR3: 0000000116679000 CR4: 00000000000006f0
[81.810] Call Trace:
[81.810] <TASK>
[81.810] __btrfs_end_transaction+0x3e/0x2b0 [btrfs]
[81.811] btrfs_force_chunk_alloc_store+0xcd/0x140 [btrfs]
[81.811] kernfs_fop_write_iter+0x15f/0x240
[81.812] vfs_write+0x264/0x500
[81.812] ksys_write+0x6c/0xe0
[81.812] do_syscall_64+0x66/0x770
[81.812] entry_SYSCALL_64_after_hwframe+0x76/0x7e
[81.813] RIP: 0033:0x7fec6be66197
[81.814] RSP: 002b:00007fffb159dd30 EFLAGS: 00000202 ORIG_RAX: 0000000000000001
[81.815] RAX: ffffffffffffffda RBX: 00007fec6bdd9740 RCX: 00007fec6be66197
[81.815] RDX: 0000000000000002 RSI: 0000560483374f80 RDI: 0000000000000001
[81.816] RBP: 0000560483374f80 R08: 0000000000000000 R09: 0000000000000000
[81.816] R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000002
[81.817] R13: 00007fec6bfb85c0 R14: 00007fec6bfb5ee0 R15: 00005604833729c0
[81.817] </TASK>
[81.817] irq event stamp: 20039
[81.818] hardirqs last enabled at (20047): [<ffffffff99a68302>] __up_console_sem+0x52/0x60
[81.818] hardirqs last disabled at (20056): [<ffffffff99a682e7>] __up_console_sem+0x37/0x60
[81.819] softirqs last enabled at (19470): [<ffffffff999d2b46>] __irq_exit_rcu+0x96/0xc0
[81.819] softirqs last disabled at (19463): [<ffffffff999d2b46>] __irq_exit_rcu+0x96/0xc0
[81.820] ---[ end trace 0000000000000000 ]---
[81.820] BTRFS: error (device dm-7 state A) in btrfs_create_pending_block_groups:2876: errno=-17 Object already exists
Inspecting these aborts with drgn, I observed a pattern of overlapping
chunk_maps. Note how stripe 1 of the first chunk overlaps in physical
address with stripe 0 of the second chunk.
Physical Start Physical End Length Logical Type Stripe
----------------------------------------------------------------------------------------------------
0x0000000102500000 0x0000000142500000 1.0G 0x0000000641d00000 META|DUP 0/2
0x0000000142500000 0x0000000182500000 1.0G 0x0000000641d00000 META|DUP 1/2
0x0000000142500000 0x0000000182500000 1.0G 0x0000000601d00000 META|DUP 0/2
0x0000000182500000 0x00000001c2500000 1.0G 0x0000000601d00000 META|DUP 1/2
Now how could this possibly happen? All chunk allocation is protected by
the chunk_mutex so racing allocations should see a consistent view of
the CHUNK_ALLOCATED bit in the chunk allocation extent-io-tree
(device->alloc_state as set by chunk_map_device_set_bits()) The tree
itself is protected by a spin lock, and clearing/setting the bits is
always protected by fs_info->mapping_tree_lock, so no race is apparent.
It turns out that there is a subtle bug in the logic regarding chunk
allocations that have happened in the current transaction, known as
"pending extents". The chunk allocation as defined in
find_free_dev_extent() is a loop which searches the commit root of the
dev_root and looks for gaps between DEV_EXTENT items. For those gaps, it
then checks alloc_state bitmap for any pending extents and adjusts the
hole that it finds accordingly. However, the logic in that adjustment
assumes that the first pending extent is the only one in that range.
e.g., given a layout with two non-consecutive pending extents in a hole
passed to dev_extent_hole_check() via *hole_start and *hole_size:
|----pending A----| real hole |----pending B----|
| candidate hole |
*hole_start *hole_start + *hole_size
the code incorrectly returns a "hole" from the end of pending extent A
until the passed in hole end, failing to account for pending B.
However, it is not entirely obvious that it is actually possible to
produce such a layout. I was able to reproduce it, but with some
contortions: I continued to use the force chunk allocation sysfs file
and I introduced a long delay (10 seconds) into the start of the cleaner
thread. I also prevented the unused bgs cleaning logic from ever
deleting metadata bgs. These help make it easier to deterministically
produce the condition but shouldn't really matter if you imagine the
conditions happening by race/luck. Allocations/frees can happen
concurrently with the cleaner thread preparing to process an unused
extent and both create some used chunks with an unused chunk
interleaved, all during one transaction. Then btrfs_delete_unused_bgs()
sees the unused one and clears it, leaving a range with several pending
chunk allocations and a gap in the middle.
The basic idea is that the unused_bgs cleanup work happens on a worker
so if we allocate 3 block groups in one transaction, then the cleaner
work kicked off by the previous transaction comes through and deletes
the middle one of the 3, then the commit root shows no dev extents and
we have the bad pattern in the extent-io-tree. One final consideration
is that the code happens to loop to the next hole if there are no more
extents at all, so we need one more dev extent way past the area we are
working in. Something like the following demonstrates the technique:
# push the BG frontier out to 20G
fallocate -l 20G $mnt/foo
# allocate one more that will prevent the "no more dev extents" luck
fallocate -l 1G $mnt/sticky
# sync
sync
# clear out the allocation area
rm $mnt/foo
sync
_cleaner
# let everything quiesce
sleep 20
sync
# dev tree should have one bg 20G out and the rest at the beginning..
# sort of like an empty FS but with a random sticky chunk.
# kick off the cleaner in the background, remember it will sleep 10s
# before doing interesting work
_cleaner &
sleep 3
# create 3 trivial block groups, all empty, all immediately marked as unused.
echo 1 > "$(_btrfs_sysfs_space_info $dev metadata)/force_chunk_alloc"
echo 1 > "$(_btrfs_sysfs_space_info $dev data)/force_chunk_alloc"
echo 1 > "$(_btrfs_sysfs_space_info $dev metadata)/force_chunk_alloc"
# let the cleaner thread definitely finish, it will remove the data bg
sleep 10
# this allocation sees the non-consecutive pending metadata chunks with
# data chunk gap of 1G and allocates a 2G extent in that hole. ENOSPC!
echo 1 > "$(_btrfs_sysfs_space_info $dev metadata)/force_chunk_alloc"
As for the fix, it is not that obvious. I could not see a trivial way to
do it even by adding backup loops into find_free_dev_extent(), so I
opted to change the semantics of dev_extent_hole_check() to not stop
looping until it finds a sufficiently big hole. For clarity, this also
required changing the helper function contains_pending_extent() into two
new helpers which find the first pending extent and the first suitable
hole in a range.
I attempted to clean up the documentation and range calculations to be
as consistent and clear as possible for the future.
I also looked at the zoned case and concluded that the loop there is
different and not to be unified with this one. As far as I can tell, the
zoned check will only further constrain the hole so looping back to find
more holes is acceptable. Though given that zoned really only appends, I
find it highly unlikely that it is susceptible to this bug.
Fixes: 1b9845081633 ("Btrfs: fix find_free_dev_extent() malfunction in case device tree has hole")
Reported-by: Dimitrios Apostolou <jimis@gmx.net>
Closes: https://lore.kernel.org/linux-btrfs/q7760374-q1p4-029o-5149-26p28421s468@tzk.arg/
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Boris Burkov <boris@bur.io>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/volumes.c | 241 ++++++++++++++++++++++++++++++++++-----------
1 file changed, 182 insertions(+), 59 deletions(-)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index de0d9a450c3cc..6d9df90de9387 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1483,30 +1483,158 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
}
/*
- * Try to find a chunk that intersects [start, start + len] range and when one
- * such is found, record the end of it in *start
+ * Find the first pending extent intersecting a range.
+ *
+ * @device: the device to search
+ * @start: start of the range to check
+ * @len: length of the range to check
+ * @pending_start: output pointer for the start of the found pending extent
+ * @pending_end: output pointer for the end of the found pending extent (inclusive)
+ *
+ * Search for a pending chunk allocation that intersects the half-open range
+ * [start, start + len).
+ *
+ * Return: true if a pending extent was found, false otherwise.
+ * If the return value is true, store the first pending extent in
+ * [*pending_start, *pending_end]. Otherwise, the two output variables
+ * may still be modified, to something outside the range and should not
+ * be used.
*/
-static bool contains_pending_extent(struct btrfs_device *device, u64 *start,
- u64 len)
+static bool first_pending_extent(struct btrfs_device *device, u64 start, u64 len,
+ u64 *pending_start, u64 *pending_end)
{
- u64 physical_start, physical_end;
-
lockdep_assert_held(&device->fs_info->chunk_mutex);
- if (find_first_extent_bit(&device->alloc_state, *start,
- &physical_start, &physical_end,
+ if (find_first_extent_bit(&device->alloc_state, start,
+ pending_start, pending_end,
CHUNK_ALLOCATED, NULL)) {
- if (in_range(physical_start, *start, len) ||
- in_range(*start, physical_start,
- physical_end + 1 - physical_start)) {
- *start = physical_end + 1;
+ if (in_range(*pending_start, start, len) ||
+ in_range(start, *pending_start, *pending_end + 1 - *pending_start)) {
return true;
}
}
return false;
}
+/*
+ * Find the first real hole accounting for pending extents.
+ *
+ * @device: the device containing the candidate hole
+ * @start: input/output pointer for the hole start position
+ * @len: input/output pointer for the hole length
+ * @min_hole_size: the size of hole we are looking for
+ *
+ * Given a potential hole specified by [*start, *start + *len), check for pending
+ * chunk allocations within that range. If pending extents are found, the hole is
+ * adjusted to represent the first true free space that is large enough when
+ * accounting for pending chunks.
+ *
+ * Note that this function must handle various cases involving non consecutive
+ * pending extents.
+ *
+ * Returns: true if a suitable hole was found and false otherwise.
+ * If the return value is true, then *start and *len are set to represent the hole.
+ * If the return value is false, then *start is set to the largest hole we
+ * found and *len is set to its length.
+ * If there are no holes at all, then *start is set to the end of the range and
+ * *len is set to 0.
+ */
+static bool find_hole_in_pending_extents(struct btrfs_device *device, u64 *start,
+ u64 *len, u64 min_hole_size)
+{
+ u64 pending_start, pending_end;
+ u64 end;
+ u64 max_hole_start = 0;
+ u64 max_hole_len = 0;
+
+ lockdep_assert_held(&device->fs_info->chunk_mutex);
+
+ if (*len == 0)
+ return false;
+
+ end = *start + *len - 1;
+
+ /*
+ * Loop until we either see a large enough hole or check every pending
+ * extent overlapping the candidate hole.
+ * At every hole that we observe, record it if it is the new max.
+ * At the end of the iteration, set the output variables to the max hole.
+ */
+ while (true) {
+ if (first_pending_extent(device, *start, *len, &pending_start, &pending_end)) {
+ /*
+ * Case 1: the pending extent overlaps the start of
+ * candidate hole. That means the true hole is after the
+ * pending extent, but we need to find the next pending
+ * extent to properly size the hole. In the next loop,
+ * we will reduce to case 2 or 3.
+ * e.g.,
+ *
+ * |----pending A----| real hole |----pending B----|
+ * | candidate hole |
+ * *start end
+ */
+ if (pending_start <= *start) {
+ *start = pending_end + 1;
+ goto next;
+ }
+ /*
+ * Case 2: The pending extent starts after *start (and overlaps
+ * [*start, end), so the first hole just goes up to the start
+ * of the pending extent.
+ * e.g.,
+ *
+ * | real hole |----pending A----|
+ * | candidate hole |
+ * *start end
+ */
+ *len = pending_start - *start;
+ if (*len > max_hole_len) {
+ max_hole_start = *start;
+ max_hole_len = *len;
+ }
+ if (*len >= min_hole_size)
+ break;
+ /*
+ * If the hole wasn't big enough, then we advance past
+ * the pending extent and keep looking.
+ */
+ *start = pending_end + 1;
+ goto next;
+ } else {
+ /*
+ * Case 3: There is no pending extent overlapping the
+ * range [*start, *start + *len - 1], so the only remaining
+ * hole is the remaining range.
+ * e.g.,
+ *
+ * | candidate hole |
+ * | real hole |
+ * *start end
+ */
+
+ if (*len > max_hole_len) {
+ max_hole_start = *start;
+ max_hole_len = *len;
+ }
+ break;
+ }
+next:
+ if (*start > end)
+ break;
+ *len = end - *start + 1;
+ }
+ if (max_hole_len) {
+ *start = max_hole_start;
+ *len = max_hole_len;
+ } else {
+ *start = end + 1;
+ *len = 0;
+ }
+ return max_hole_len >= min_hole_size;
+}
+
static u64 dev_extent_search_start(struct btrfs_device *device)
{
switch (device->fs_devices->chunk_alloc_policy) {
@@ -1569,58 +1697,56 @@ static bool dev_extent_hole_check_zoned(struct btrfs_device *device,
}
/*
- * Check if specified hole is suitable for allocation.
+ * Validate and adjust a hole for chunk allocation
*
- * @device: the device which we have the hole
- * @hole_start: starting position of the hole
- * @hole_size: the size of the hole
- * @num_bytes: the size of the free space that we need
+ * @device: the device containing the candidate hole
+ * @hole_start: input/output pointer for the hole start position
+ * @hole_size: input/output pointer for the hole size
+ * @num_bytes: minimum allocation size required
*
- * This function may modify @hole_start and @hole_size to reflect the suitable
- * position for allocation. Returns 1 if hole position is updated, 0 otherwise.
+ * Check if the specified hole is suitable for allocation and adjust it if
+ * necessary. The hole may be modified to skip over pending chunk allocations
+ * and to satisfy stricter zoned requirements on zoned filesystems.
+ *
+ * For regular (non-zoned) allocation, if the hole after adjustment is smaller
+ * than @num_bytes, the search continues past additional pending extents until
+ * either a sufficiently large hole is found or no more pending extents exist.
+ *
+ * Return: true if a suitable hole was found and false otherwise.
+ * If the return value is true, then *hole_start and *hole_size are set to
+ * represent the hole we found.
+ * If the return value is false, then *hole_start is set to the largest
+ * hole we found and *hole_size is set to its length.
+ * If there are no holes at all, then *hole_start is set to the end of the range
+ * and *hole_size is set to 0.
*/
static bool dev_extent_hole_check(struct btrfs_device *device, u64 *hole_start,
u64 *hole_size, u64 num_bytes)
{
- bool changed = false;
- u64 hole_end = *hole_start + *hole_size;
+ bool found = false;
+ const u64 hole_end = *hole_start + *hole_size - 1;
- for (;;) {
- /*
- * Check before we set max_hole_start, otherwise we could end up
- * sending back this offset anyway.
- */
- if (contains_pending_extent(device, hole_start, *hole_size)) {
- if (hole_end >= *hole_start)
- *hole_size = hole_end - *hole_start;
- else
- *hole_size = 0;
- changed = true;
- }
+ ASSERT(*hole_size > 0);
- switch (device->fs_devices->chunk_alloc_policy) {
- case BTRFS_CHUNK_ALLOC_REGULAR:
- /* No extra check */
- break;
- case BTRFS_CHUNK_ALLOC_ZONED:
- if (dev_extent_hole_check_zoned(device, hole_start,
- hole_size, num_bytes)) {
- changed = true;
- /*
- * The changed hole can contain pending extent.
- * Loop again to check that.
- */
- continue;
- }
- break;
- default:
- BUG();
- }
+again:
+ *hole_size = hole_end - *hole_start + 1;
+ found = find_hole_in_pending_extents(device, hole_start, hole_size, num_bytes);
+ if (!found)
+ return found;
+ ASSERT(*hole_size >= num_bytes);
+ switch (device->fs_devices->chunk_alloc_policy) {
+ case BTRFS_CHUNK_ALLOC_REGULAR:
+ return found;
+ case BTRFS_CHUNK_ALLOC_ZONED:
+ if (dev_extent_hole_check_zoned(device, hole_start, hole_size, num_bytes))
+ goto again;
break;
+ default:
+ BUG();
}
- return changed;
+ return found;
}
/*
@@ -1679,7 +1805,7 @@ static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
ret = -ENOMEM;
goto out;
}
-again:
+
if (search_start >= search_end ||
test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) {
ret = -ENOSPC;
@@ -1766,11 +1892,7 @@ static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
*/
if (search_end > search_start) {
hole_size = search_end - search_start;
- if (dev_extent_hole_check(device, &search_start, &hole_size,
- num_bytes)) {
- btrfs_release_path(path);
- goto again;
- }
+ dev_extent_hole_check(device, &search_start, &hole_size, num_bytes);
if (hole_size > max_hole_size) {
max_hole_start = search_start;
@@ -4870,6 +4992,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
u64 diff;
u64 start;
u64 free_diff = 0;
+ u64 pending_start, pending_end;
new_size = round_down(new_size, fs_info->sectorsize);
start = new_size;
@@ -4915,7 +5038,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
* in-memory chunks are synced to disk so that the loop below sees them
* and relocates them accordingly.
*/
- if (contains_pending_extent(device, &start, diff)) {
+ if (first_pending_extent(device, start, diff, &pending_start, &pending_end)) {
mutex_unlock(&fs_info->chunk_mutex);
ret = btrfs_commit_transaction(trans);
if (ret)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 274/869] net: stmmac: fix oops when split header is enabled
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (272 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 273/869] btrfs: fix EEXIST abort due to non-consecutive gaps in chunk allocation Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 275/869] drm/exynos: vidi: use priv->vidi_dev for ctx lookup in vidi_connection_ioctl() Greg Kroah-Hartman
` (595 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jacob Keller, Jie Zhang,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jie Zhang <jzhang918@gmail.com>
[ Upstream commit babab1b42ed68877ef669a08384becf281ad2582 ]
For GMAC4, when split header is enabled, in some rare cases, the
hardware does not fill buf2 of the first descriptor with payload.
Thus we cannot assume buf2 is always fully filled if it is not
the last descriptor. Otherwise, the length of buf2 of the second
descriptor will be calculated wrong and cause an oops:
Unable to handle kernel paging request at virtual address ffff00019246bfc0
...
x2 : 0000000000000040 x1 : ffff00019246bfc0 x0 : ffff00009246c000
Call trace:
dcache_inval_poc+0x28/0x58 (P)
dma_direct_sync_single_for_cpu+0x38/0x6c
__dma_sync_single_for_cpu+0x34/0x6c
stmmac_napi_poll_rx+0x8f0/0xb60
__napi_poll.constprop.0+0x30/0x144
net_rx_action+0x160/0x274
handle_softirqs+0x1b8/0x1fc
...
To fix this, the PL bit-field in RDES3 register is used for all
descriptors, whether it is the last descriptor or not.
Fixes: ec222003bd94 ("net: stmmac: Prepare to add Split Header support")
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Jie Zhang <jie.zhang@analog.com>
Link: https://patch.msgid.link/20260209225037.589130-1-jie.zhang@analog.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 20 ++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 91c07c04435f2..dfab95896adde 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4903,13 +4903,27 @@ static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv,
if (!priv->sph)
return 0;
- /* Not last descriptor */
- if (status & rx_not_ls)
+ /* For GMAC4, when split header is enabled, in some rare cases, the
+ * hardware does not fill buf2 of the first descriptor with payload.
+ * Thus we cannot assume buf2 is always fully filled if it is not
+ * the last descriptor. Otherwise, the length of buf2 of the second
+ * descriptor will be calculated wrong and cause an oops.
+ *
+ * If this is the last descriptor, 'plen' is the length of the
+ * received packet that was transferred to system memory.
+ * Otherwise, it is the accumulated number of bytes that have been
+ * transferred for the current packet.
+ *
+ * Thus 'plen - len' always gives the correct length of buf2.
+ */
+
+ /* Not GMAC4 and not last descriptor */
+ if (!priv->plat->has_gmac4 && (status & rx_not_ls))
return priv->dma_conf.dma_buf_sz;
+ /* GMAC4 or last descriptor */
plen = stmmac_get_rx_frame_len(priv, p, coe);
- /* Last descriptor */
return plen - len;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 275/869] drm/exynos: vidi: use priv->vidi_dev for ctx lookup in vidi_connection_ioctl()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (273 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 274/869] net: stmmac: fix oops when split header is enabled Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 276/869] gfs2: fix memory leaks in gfs2_fill_super error path Greg Kroah-Hartman
` (594 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeongjun Park, Inki Dae, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeongjun Park <aha310510@gmail.com>
[ Upstream commit d3968a0d85b211e197f2f4f06268a7031079e0d0 ]
vidi_connection_ioctl() retrieves the driver_data from drm_dev->dev to
obtain a struct vidi_context pointer. However, drm_dev->dev is the
exynos-drm master device, and the driver_data contained therein is not
the vidi component device, but a completely different device.
This can lead to various bugs, ranging from null pointer dereferences and
garbage value accesses to, in unlucky cases, out-of-bounds errors,
use-after-free errors, and more.
To resolve this issue, we need to store/delete the vidi device pointer in
exynos_drm_private->vidi_dev during bind/unbind, and then read this
exynos_drm_private->vidi_dev within ioctl() to obtain the correct
struct vidi_context pointer.
Cc: <stable@vger.kernel.org>
Signed-off-by: Jeongjun Park <aha310510@gmail.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 +
drivers/gpu/drm/exynos/exynos_drm_vidi.c | 14 +++++++++++++-
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 23646e55f142c..06c29ff2aac0e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -199,6 +199,7 @@ struct drm_exynos_file_private {
struct exynos_drm_private {
struct device *g2d_dev;
struct device *dma_dev;
+ struct device *vidi_dev;
void *mapping;
/* for atomic commit */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 8400330dfe3eb..684170f44989e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -231,9 +231,14 @@ ATTRIBUTE_GROUPS(vidi);
int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
struct drm_file *file_priv)
{
- struct vidi_context *ctx = dev_get_drvdata(drm_dev->dev);
+ struct exynos_drm_private *priv = drm_dev->dev_private;
+ struct device *dev = priv ? priv->vidi_dev : NULL;
+ struct vidi_context *ctx = dev ? dev_get_drvdata(dev) : NULL;
struct drm_exynos_vidi_connection *vidi = data;
+ if (!ctx)
+ return -ENODEV;
+
if (!vidi) {
DRM_DEV_DEBUG_KMS(ctx->dev,
"user data for vidi is null.\n");
@@ -407,6 +412,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
{
struct vidi_context *ctx = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
+ struct exynos_drm_private *priv = drm_dev->dev_private;
struct drm_encoder *encoder = &ctx->encoder;
struct exynos_drm_plane *exynos_plane;
struct exynos_drm_plane_config plane_config = { 0 };
@@ -414,6 +420,8 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
int ret;
ctx->drm_dev = drm_dev;
+ if (priv)
+ priv->vidi_dev = dev;
plane_config.pixel_formats = formats;
plane_config.num_pixel_formats = ARRAY_SIZE(formats);
@@ -459,8 +467,12 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
static void vidi_unbind(struct device *dev, struct device *master, void *data)
{
struct vidi_context *ctx = dev_get_drvdata(dev);
+ struct drm_device *drm_dev = data;
+ struct exynos_drm_private *priv = drm_dev->dev_private;
del_timer_sync(&ctx->timer);
+ if (priv)
+ priv->vidi_dev = NULL;
}
static const struct component_ops vidi_component_ops = {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 276/869] gfs2: fix memory leaks in gfs2_fill_super error path
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (274 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 275/869] drm/exynos: vidi: use priv->vidi_dev for ctx lookup in vidi_connection_ioctl() Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 277/869] KVM: SVM: Add missing save/restore handling of LBR MSRs Greg Kroah-Hartman
` (593 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+aac438d7a1c44071e04b,
Deepanshu Kartikey, Andreas Gruenbacher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Deepanshu Kartikey <kartikey406@gmail.com>
[ Upstream commit da6f5bbc2e7902f578b503f2a4c3d8d09ca4b102 ]
Fix two memory leaks in the gfs2_fill_super() error handling path when
transitioning a filesystem to read-write mode fails.
First leak: kthread objects (thread_struct, task_struct, etc.)
When gfs2_freeze_lock_shared() fails after init_threads() succeeds, the
created kernel threads (logd and quotad) are never destroyed. This
occurs because the fail_per_node label doesn't call
gfs2_destroy_threads().
Second leak: quota bitmap buffer (8192 bytes)
When gfs2_make_fs_rw() fails after gfs2_quota_init() succeeds but
before other operations complete, the allocated quota bitmap is never
freed.
The fix moves thread cleanup to the fail_per_node label to handle all
error paths uniformly. gfs2_destroy_threads() is safe to call
unconditionally as it checks for NULL pointers. Quota cleanup is added
in gfs2_make_fs_rw() to properly handle the withdrawal case where
quota initialization succeeds but the filesystem is then withdrawn.
Thread leak backtrace (gfs2_freeze_lock_shared failure):
unreferenced object 0xffff88801d7bca80 (size 4480):
copy_process+0x3a1/0x4670 kernel/fork.c:2422
kernel_clone+0xf3/0x6e0 kernel/fork.c:2779
kthread_create_on_node+0x100/0x150 kernel/kthread.c:478
init_threads+0xab/0x350 fs/gfs2/ops_fstype.c:611
gfs2_fill_super+0xe5c/0x1240 fs/gfs2/ops_fstype.c:1265
Quota leak backtrace (gfs2_make_fs_rw failure):
unreferenced object 0xffff88812de7c000 (size 8192):
gfs2_quota_init+0xe5/0x820 fs/gfs2/quota.c:1409
gfs2_make_fs_rw+0x7a/0xe0 fs/gfs2/super.c:149
gfs2_fill_super+0xfbb/0x1240 fs/gfs2/ops_fstype.c:1275
Reported-by: syzbot+aac438d7a1c44071e04b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=aac438d7a1c44071e04b
Fixes: 6c7410f44961 ("gfs2: gfs2_freeze_lock_shared cleanup")
Fixes: b66f723bb552 ("gfs2: Improve gfs2_make_fs_rw error handling")
Link: https://lore.kernel.org/all/20260131062509.77974-1-kartikey406@gmail.com/T/ [v1]
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/gfs2/ops_fstype.c | 2 +-
fs/gfs2/super.c | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 4c6d1f15a6a84..243971150973c 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1281,7 +1281,6 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
if (error) {
gfs2_freeze_unlock(sdp);
- gfs2_destroy_threads(sdp);
fs_err(sdp, "can't make FS RW: %d\n", error);
goto fail_per_node;
}
@@ -1291,6 +1290,7 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
fail_per_node:
init_per_node(sdp, UNDO);
+ gfs2_destroy_threads(sdp);
fail_inodes:
init_inodes(sdp, UNDO);
fail_sb:
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 3d5d4b8446214..8628121c1ab14 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -157,8 +157,10 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
gfs2_log_pointers_init(sdp, head.lh_blkno);
error = gfs2_quota_init(sdp);
- if (!error && gfs2_withdrawing_or_withdrawn(sdp))
+ if (!error && gfs2_withdrawing_or_withdrawn(sdp)) {
+ gfs2_quota_cleanup(sdp);
error = -EIO;
+ }
if (!error)
set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
return error;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 277/869] KVM: SVM: Add missing save/restore handling of LBR MSRs
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (275 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 276/869] gfs2: fix memory leaks in gfs2_fill_super error path Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 278/869] ipmi:ssif: Clean up kthread on errors Greg Kroah-Hartman
` (592 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jim Mattson, Yosry Ahmed,
Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yosry Ahmed <yosry@kernel.org>
[ Upstream commit 3700f0788da6acf73b2df56690f4b201aa4aefd2 ]
MSR_IA32_DEBUGCTLMSR and LBR MSRs are currently not enumerated by
KVM_GET_MSR_INDEX_LIST, and LBR MSRs cannot be set with KVM_SET_MSRS. So
save/restore is completely broken.
Fix it by adding the MSRs to msrs_to_save_base, and allowing writes to
LBR MSRs from userspace only (as they are read-only MSRs) if LBR
virtualization is enabled. Additionally, to correctly restore L1's LBRs
while L2 is running, make sure the LBRs are copied from the captured
VMCB01 save area in svm_copy_vmrun_state().
Note, for VMX, this also fixes a flaw where MSR_IA32_DEBUGCTLMSR isn't
reported as an MSR to save/restore.
Note #2, over-reporting MSR_IA32_LASTxxx on Intel is ok, as KVM already
handles unsupported reads and writes thanks to commit b5e2fec0ebc3 ("KVM:
Ignore DEBUGCTL MSRs with no effect") (kvm_do_msr_access() will morph the
unsupported userspace write into a nop).
Fixes: 24e09cbf480a ("KVM: SVM: enable LBR virtualization")
Cc: stable@vger.kernel.org
Reported-by: Jim Mattson <jmattson@google.com>
Signed-off-by: Yosry Ahmed <yosry@kernel.org>
Link: https://patch.msgid.link/20260303003421.2185681-4-yosry@kernel.org
[sean: guard with lbrv checks, massage changelog]
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/svm/nested.c | 8 ++++++++
arch/x86/kvm/svm/svm.c | 42 ++++++++++++++++++++++++++++++++++-----
arch/x86/kvm/x86.c | 3 +++
3 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index 2d81f1cb4ca7b..95698c1da833d 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -959,6 +959,14 @@ void svm_copy_vmrun_state(struct vmcb_save_area *to_save,
to_save->rsp = from_save->rsp;
to_save->rip = from_save->rip;
to_save->cpl = 0;
+
+ if (kvm_cpu_cap_has(X86_FEATURE_LBRV)) {
+ to_save->dbgctl = from_save->dbgctl & ~DEBUGCTL_RESERVED_BITS;
+ to_save->br_from = from_save->br_from;
+ to_save->br_to = from_save->br_to;
+ to_save->last_excp_from = from_save->last_excp_from;
+ to_save->last_excp_to = from_save->last_excp_to;
+ }
}
void svm_copy_vmloadsave_state(struct vmcb *to_vmcb, struct vmcb *from_vmcb)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 9408ab965aeaa..21f74cea2b05b 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -2966,19 +2966,19 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
msr_info->data = svm->tsc_aux;
break;
case MSR_IA32_DEBUGCTLMSR:
- msr_info->data = svm->vmcb->save.dbgctl;
+ msr_info->data = lbrv ? svm->vmcb->save.dbgctl : 0;
break;
case MSR_IA32_LASTBRANCHFROMIP:
- msr_info->data = svm->vmcb->save.br_from;
+ msr_info->data = lbrv ? svm->vmcb->save.br_from : 0;
break;
case MSR_IA32_LASTBRANCHTOIP:
- msr_info->data = svm->vmcb->save.br_to;
+ msr_info->data = lbrv ? svm->vmcb->save.br_to : 0;
break;
case MSR_IA32_LASTINTFROMIP:
- msr_info->data = svm->vmcb->save.last_excp_from;
+ msr_info->data = lbrv ? svm->vmcb->save.last_excp_from : 0;
break;
case MSR_IA32_LASTINTTOIP:
- msr_info->data = svm->vmcb->save.last_excp_to;
+ msr_info->data = lbrv ? svm->vmcb->save.last_excp_to : 0;
break;
case MSR_VM_HSAVE_PA:
msr_info->data = svm->nested.hsave_msr;
@@ -3258,6 +3258,38 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
svm_update_lbrv(vcpu);
break;
+ case MSR_IA32_LASTBRANCHFROMIP:
+ if (!lbrv)
+ return KVM_MSR_RET_UNSUPPORTED;
+ if (!msr->host_initiated)
+ return 1;
+ svm->vmcb->save.br_from = data;
+ vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
+ break;
+ case MSR_IA32_LASTBRANCHTOIP:
+ if (!lbrv)
+ return KVM_MSR_RET_UNSUPPORTED;
+ if (!msr->host_initiated)
+ return 1;
+ svm->vmcb->save.br_to = data;
+ vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
+ break;
+ case MSR_IA32_LASTINTFROMIP:
+ if (!lbrv)
+ return KVM_MSR_RET_UNSUPPORTED;
+ if (!msr->host_initiated)
+ return 1;
+ svm->vmcb->save.last_excp_from = data;
+ vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
+ break;
+ case MSR_IA32_LASTINTTOIP:
+ if (!lbrv)
+ return KVM_MSR_RET_UNSUPPORTED;
+ if (!msr->host_initiated)
+ return 1;
+ svm->vmcb->save.last_excp_to = data;
+ vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
+ break;
case MSR_VM_HSAVE_PA:
/*
* Old kernels did not validate the value written to
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 99549df4c633d..842e4af926302 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -320,6 +320,9 @@ static const u32 msrs_to_save_base[] = {
MSR_IA32_UMWAIT_CONTROL,
MSR_IA32_XFD, MSR_IA32_XFD_ERR,
+ MSR_IA32_DEBUGCTLMSR,
+ MSR_IA32_LASTBRANCHFROMIP, MSR_IA32_LASTBRANCHTOIP,
+ MSR_IA32_LASTINTFROMIP, MSR_IA32_LASTINTTOIP,
};
static const u32 msrs_to_save_pmu[] = {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 278/869] ipmi:ssif: Clean up kthread on errors
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (276 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 277/869] KVM: SVM: Add missing save/restore handling of LBR MSRs Greg Kroah-Hartman
@ 2026-10-17 15:51 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 279/869] KVM: x86: Rename "governed features" helpers to use "guest_cpu_cap" Greg Kroah-Hartman
` (591 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:51 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Li Xiao, Corey Minyard, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Corey Minyard <corey@minyard.net>
[ Upstream commit 75c486cb1bcaa1a3ec3a6438498176a3a4998ae4 ]
If an error occurs after the ssif kthread is created, but before the
main IPMI code starts the ssif interface, the ssif kthread will not
be stopped.
So make sure the kthread is stopped on an error condition if it is
running.
Fixes: 259307074bfc ("ipmi: Add SMBus interface driver (SSIF)")
Reported-by: Li Xiao <<252270051@hdu.edu.cn>
Cc: stable@vger.kernel.org
Reviewed-by: Li Xiao <252270051@hdu.edu.cn>
Signed-off-by: Corey Minyard <corey@minyard.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/char/ipmi/ipmi_ssif.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 7950f13c1ef76..a19184151323c 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -1292,6 +1292,7 @@ static void shutdown_ssif(void *send_info)
if (ssif_info->thread) {
complete(&ssif_info->wake_thread);
kthread_stop(ssif_info->thread);
+ ssif_info->thread = NULL;
}
}
@@ -1936,6 +1937,25 @@ static int ssif_probe(struct i2c_client *client)
out:
if (rv) {
+ /*
+ * If ipmi_register_smi() starts the interface, it will
+ * call shutdown and that will free the thread and set
+ * it to NULL. Otherwise it must be freed here.
+ */
+ if (ssif_info->thread) {
+ struct task_struct *thread = ssif_info->thread;
+
+ /*
+ * The thread exits on its own once it sees
+ * stopping, so hold a reference across the stop.
+ */
+ get_task_struct(thread);
+ ssif_info->stopping = true;
+ complete(&ssif_info->wake_thread);
+ kthread_stop(thread);
+ put_task_struct(thread);
+ ssif_info->thread = NULL;
+ }
if (addr_info)
addr_info->client = NULL;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 279/869] KVM: x86: Rename "governed features" helpers to use "guest_cpu_cap"
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (277 preceding siblings ...)
2026-10-17 15:51 ` [PATCH 6.12 278/869] ipmi:ssif: Clean up kthread on errors Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 280/869] KVM: nSVM: Always use NextRIP as vmcb02s NextRIP after first L2 VMRUN Greg Kroah-Hartman
` (590 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Maxim Levitsky, Binbin Wu,
Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <seanjc@google.com>
[ Upstream commit 2c5e168e5ce154592667a8e384012117c917d790 ]
As the first step toward replacing KVM's so-called "governed features"
framework with a more comprehensive, less poorly named implementation,
replace the "kvm_governed_feature" function prefix with "guest_cpu_cap"
and rename guest_can_use() to guest_cpu_cap_has().
The "guest_cpu_cap" naming scheme mirrors that of "kvm_cpu_cap", and
provides a more clear distinction between guest capabilities, which are
KVM controlled (heh, or one might say "governed"), and guest CPUID, which
with few exceptions is fully userspace controlled.
Opportunistically rewrite the comment about XSS passthrough for SEV-ES
guests to avoid referencing so many functions, as such comments are prone
to becoming stale (case in point...).
No functional change intended.
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
Link: https://lore.kernel.org/r/20241128013424.4096668-40-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Stable-dep-of: 8d397582f6b5 ("KVM: nSVM: Always use NextRIP as vmcb02's NextRIP after first L2 VMRUN")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/cpuid.c | 2 +-
arch/x86/kvm/cpuid.h | 16 ++++++++--------
arch/x86/kvm/mmu.h | 2 +-
arch/x86/kvm/mmu/mmu.c | 4 ++--
arch/x86/kvm/svm/nested.c | 20 ++++++++++----------
arch/x86/kvm/svm/sev.c | 17 ++++++++---------
arch/x86/kvm/svm/svm.c | 26 +++++++++++++-------------
arch/x86/kvm/svm/svm.h | 4 ++--
arch/x86/kvm/vmx/nested.c | 6 +++---
arch/x86/kvm/vmx/vmx.c | 16 ++++++++--------
arch/x86/kvm/x86.c | 4 ++--
11 files changed, 58 insertions(+), 59 deletions(-)
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index a7a1486ce2704..e2b55b7f64971 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -392,7 +392,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
allow_gbpages = tdp_enabled ? boot_cpu_has(X86_FEATURE_GBPAGES) :
guest_cpuid_has(vcpu, X86_FEATURE_GBPAGES);
if (allow_gbpages)
- kvm_governed_feature_set(vcpu, X86_FEATURE_GBPAGES);
+ guest_cpu_cap_set(vcpu, X86_FEATURE_GBPAGES);
best = kvm_find_cpuid_entry(vcpu, 1);
if (best && apic) {
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index f16a7b2c2adcf..1a8cc377d2563 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -241,8 +241,8 @@ static __always_inline bool kvm_is_governed_feature(unsigned int x86_feature)
return kvm_governed_feature_index(x86_feature) >= 0;
}
-static __always_inline void kvm_governed_feature_set(struct kvm_vcpu *vcpu,
- unsigned int x86_feature)
+static __always_inline void guest_cpu_cap_set(struct kvm_vcpu *vcpu,
+ unsigned int x86_feature)
{
BUILD_BUG_ON(!kvm_is_governed_feature(x86_feature));
@@ -250,15 +250,15 @@ static __always_inline void kvm_governed_feature_set(struct kvm_vcpu *vcpu,
vcpu->arch.governed_features.enabled);
}
-static __always_inline void kvm_governed_feature_check_and_set(struct kvm_vcpu *vcpu,
- unsigned int x86_feature)
+static __always_inline void guest_cpu_cap_check_and_set(struct kvm_vcpu *vcpu,
+ unsigned int x86_feature)
{
if (kvm_cpu_cap_has(x86_feature) && guest_cpuid_has(vcpu, x86_feature))
- kvm_governed_feature_set(vcpu, x86_feature);
+ guest_cpu_cap_set(vcpu, x86_feature);
}
-static __always_inline bool guest_can_use(struct kvm_vcpu *vcpu,
- unsigned int x86_feature)
+static __always_inline bool guest_cpu_cap_has(struct kvm_vcpu *vcpu,
+ unsigned int x86_feature)
{
BUILD_BUG_ON(!kvm_is_governed_feature(x86_feature));
@@ -268,7 +268,7 @@ static __always_inline bool guest_can_use(struct kvm_vcpu *vcpu,
static inline bool kvm_vcpu_is_legal_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
{
- if (guest_can_use(vcpu, X86_FEATURE_LAM))
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_LAM))
cr3 &= ~(X86_CR3_LAM_U48 | X86_CR3_LAM_U57);
return kvm_vcpu_is_legal_gpa(vcpu, cr3);
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 1d9c919c92320..838893f166634 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -126,7 +126,7 @@ static inline unsigned long kvm_get_active_pcid(struct kvm_vcpu *vcpu)
static inline unsigned long kvm_get_active_cr3_lam_bits(struct kvm_vcpu *vcpu)
{
- if (!guest_can_use(vcpu, X86_FEATURE_LAM))
+ if (!guest_cpu_cap_has(vcpu, X86_FEATURE_LAM))
return 0;
return kvm_read_cr3(vcpu) & (X86_CR3_LAM_U48 | X86_CR3_LAM_U57);
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 1a4d5fa11922d..ab6d3f565b0a1 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -5110,7 +5110,7 @@ static void reset_guest_rsvds_bits_mask(struct kvm_vcpu *vcpu,
__reset_rsvds_bits_mask(&context->guest_rsvd_check,
vcpu->arch.reserved_gpa_bits,
context->cpu_role.base.level, is_efer_nx(context),
- guest_can_use(vcpu, X86_FEATURE_GBPAGES),
+ guest_cpu_cap_has(vcpu, X86_FEATURE_GBPAGES),
is_cr4_pse(context),
guest_cpuid_is_amd_compatible(vcpu));
}
@@ -5187,7 +5187,7 @@ static void reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu,
__reset_rsvds_bits_mask(shadow_zero_check, reserved_hpa_bits(),
context->root_role.level,
context->root_role.efer_nx,
- guest_can_use(vcpu, X86_FEATURE_GBPAGES),
+ guest_cpu_cap_has(vcpu, X86_FEATURE_GBPAGES),
is_pse, is_amd);
if (!shadow_me_mask)
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index 95698c1da833d..08274463ad867 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -111,7 +111,7 @@ static void nested_svm_uninit_mmu_context(struct kvm_vcpu *vcpu)
static bool nested_vmcb_needs_vls_intercept(struct vcpu_svm *svm)
{
- if (!guest_can_use(&svm->vcpu, X86_FEATURE_V_VMSAVE_VMLOAD))
+ if (!guest_cpu_cap_has(&svm->vcpu, X86_FEATURE_V_VMSAVE_VMLOAD))
return true;
if (!nested_npt_enabled(svm))
@@ -610,7 +610,7 @@ static void nested_vmcb02_prepare_save(struct vcpu_svm *svm, struct vmcb *vmcb12
vmcb_mark_dirty(vmcb02, VMCB_DR);
}
- if (unlikely(guest_can_use(vcpu, X86_FEATURE_LBRV) &&
+ if (unlikely(guest_cpu_cap_has(vcpu, X86_FEATURE_LBRV) &&
(svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK))) {
/*
* Reserved bits of DEBUGCTL are ignored. Be consistent with
@@ -671,7 +671,7 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
* exit_int_info, exit_int_info_err, next_rip, insn_len, insn_bytes.
*/
- if (guest_can_use(vcpu, X86_FEATURE_VGIF) &&
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_VGIF) &&
(svm->nested.ctl.int_ctl & V_GIF_ENABLE_MASK))
int_ctl_vmcb12_bits |= (V_GIF_MASK | V_GIF_ENABLE_MASK);
else
@@ -710,7 +710,7 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
vmcb02->control.tsc_offset = vcpu->arch.tsc_offset;
- if (guest_can_use(vcpu, X86_FEATURE_TSCRATEMSR) &&
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_TSCRATEMSR) &&
svm->tsc_ratio_msr != kvm_caps.default_tsc_scaling_ratio)
nested_svm_update_tsc_ratio_msr(vcpu);
@@ -731,7 +731,7 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
* what a nrips=0 CPU would do (L1 is responsible for advancing RIP
* prior to injecting the event).
*/
- if (guest_can_use(vcpu, X86_FEATURE_NRIPS))
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS))
vmcb02->control.next_rip = svm->nested.ctl.next_rip;
else if (boot_cpu_has(X86_FEATURE_NRIPS))
vmcb02->control.next_rip = vmcb12_rip;
@@ -741,7 +741,7 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
svm->soft_int_injected = true;
svm->soft_int_csbase = vmcb12_csbase;
svm->soft_int_old_rip = vmcb12_rip;
- if (guest_can_use(vcpu, X86_FEATURE_NRIPS))
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS))
svm->soft_int_next_rip = svm->nested.ctl.next_rip;
else
svm->soft_int_next_rip = vmcb12_rip;
@@ -752,11 +752,11 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
if (!nested_vmcb_needs_vls_intercept(svm))
vmcb02->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
- if (guest_can_use(vcpu, X86_FEATURE_PAUSEFILTER))
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_PAUSEFILTER))
pause_count12 = svm->nested.ctl.pause_filter_count;
else
pause_count12 = 0;
- if (guest_can_use(vcpu, X86_FEATURE_PFTHRESHOLD))
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_PFTHRESHOLD))
pause_thresh12 = svm->nested.ctl.pause_filter_thresh;
else
pause_thresh12 = 0;
@@ -1043,7 +1043,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
if (vmcb12->control.exit_code != SVM_EXIT_ERR)
nested_save_pending_event_to_vmcb12(svm, vmcb12);
- if (guest_can_use(vcpu, X86_FEATURE_NRIPS))
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS))
vmcb12->control.next_rip = vmcb02->control.next_rip;
vmcb12->control.event_inj = 0;
@@ -1082,7 +1082,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
if (!nested_exit_on_intr(svm))
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
- if (unlikely(guest_can_use(vcpu, X86_FEATURE_LBRV) &&
+ if (unlikely(guest_cpu_cap_has(vcpu, X86_FEATURE_LBRV) &&
(svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK)))
svm_copy_lbrs(vmcb12, vmcb02);
else
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 1a766b3d95f23..02d2bd78f8e7b 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -4569,16 +4569,15 @@ static void sev_es_vcpu_after_set_cpuid(struct vcpu_svm *svm)
* For SEV-ES, accesses to MSR_IA32_XSS should not be intercepted if
* the host/guest supports its use.
*
- * guest_can_use() checks a number of requirements on the host/guest to
- * ensure that MSR_IA32_XSS is available, but it might report true even
- * if X86_FEATURE_XSAVES isn't configured in the guest to ensure host
- * MSR_IA32_XSS is always properly restored. For SEV-ES, it is better
- * to further check that the guest CPUID actually supports
- * X86_FEATURE_XSAVES so that accesses to MSR_IA32_XSS by misbehaved
- * guests will still get intercepted and caught in the normal
- * kvm_emulate_rdmsr()/kvm_emulated_wrmsr() paths.
+ * KVM treats the guest as being capable of using XSAVES even if XSAVES
+ * isn't enabled in guest CPUID as there is no intercept for XSAVES,
+ * i.e. the guest can use XSAVES/XRSTOR to read/write XSS if XSAVE is
+ * exposed to the guest and XSAVES is supported in hardware. Condition
+ * full XSS passthrough on the guest being able to use XSAVES *and*
+ * XSAVES being exposed to the guest so that KVM can at least honor
+ * guest CPUID for RDMSR and WRMSR.
*/
- if (guest_can_use(vcpu, X86_FEATURE_XSAVES) &&
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_XSAVES) &&
guest_cpuid_has(vcpu, X86_FEATURE_XSAVES))
set_msr_interception(vcpu, svm->msrpm, MSR_IA32_XSS, 1, 1);
else
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 21f74cea2b05b..3e2af127a4e27 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1040,7 +1040,7 @@ void svm_update_lbrv(struct kvm_vcpu *vcpu)
struct vcpu_svm *svm = to_svm(vcpu);
bool current_enable_lbrv = svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK;
bool enable_lbrv = (svm->vmcb->save.dbgctl & DEBUGCTLMSR_LBR) ||
- (is_guest_mode(vcpu) && guest_can_use(vcpu, X86_FEATURE_LBRV) &&
+ (is_guest_mode(vcpu) && guest_cpu_cap_has(vcpu, X86_FEATURE_LBRV) &&
(svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK));
if (enable_lbrv && !current_enable_lbrv)
@@ -2922,7 +2922,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
switch (msr_info->index) {
case MSR_AMD64_TSC_RATIO:
if (!msr_info->host_initiated &&
- !guest_can_use(vcpu, X86_FEATURE_TSCRATEMSR))
+ !guest_cpu_cap_has(vcpu, X86_FEATURE_TSCRATEMSR))
return 1;
msr_info->data = svm->tsc_ratio_msr;
break;
@@ -3082,7 +3082,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
switch (ecx) {
case MSR_AMD64_TSC_RATIO:
- if (!guest_can_use(vcpu, X86_FEATURE_TSCRATEMSR)) {
+ if (!guest_cpu_cap_has(vcpu, X86_FEATURE_TSCRATEMSR)) {
if (!msr->host_initiated)
return 1;
@@ -3104,7 +3104,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
svm->tsc_ratio_msr = data;
- if (guest_can_use(vcpu, X86_FEATURE_TSCRATEMSR) &&
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_TSCRATEMSR) &&
is_guest_mode(vcpu))
nested_svm_update_tsc_ratio_msr(vcpu);
@@ -4574,11 +4574,11 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
if (boot_cpu_has(X86_FEATURE_XSAVE) &&
boot_cpu_has(X86_FEATURE_XSAVES) &&
guest_cpuid_has(vcpu, X86_FEATURE_XSAVE))
- kvm_governed_feature_set(vcpu, X86_FEATURE_XSAVES);
+ guest_cpu_cap_set(vcpu, X86_FEATURE_XSAVES);
- kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_NRIPS);
- kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_TSCRATEMSR);
- kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_LBRV);
+ guest_cpu_cap_check_and_set(vcpu, X86_FEATURE_NRIPS);
+ guest_cpu_cap_check_and_set(vcpu, X86_FEATURE_TSCRATEMSR);
+ guest_cpu_cap_check_and_set(vcpu, X86_FEATURE_LBRV);
/*
* Intercept VMLOAD if the vCPU model is Intel in order to emulate that
@@ -4586,12 +4586,12 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
* SVM on Intel is bonkers and extremely unlikely to work).
*/
if (!guest_cpuid_is_intel_compatible(vcpu))
- kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
+ guest_cpu_cap_check_and_set(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
- kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_PAUSEFILTER);
- kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_PFTHRESHOLD);
- kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_VGIF);
- kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_VNMI);
+ guest_cpu_cap_check_and_set(vcpu, X86_FEATURE_PAUSEFILTER);
+ guest_cpu_cap_check_and_set(vcpu, X86_FEATURE_PFTHRESHOLD);
+ guest_cpu_cap_check_and_set(vcpu, X86_FEATURE_VGIF);
+ guest_cpu_cap_check_and_set(vcpu, X86_FEATURE_VNMI);
svm_recalc_instruction_intercepts(vcpu, svm);
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 93ad26f3b1a1a..19da3ce2b7668 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -510,7 +510,7 @@ static inline bool svm_is_intercept(struct vcpu_svm *svm, int bit)
static inline bool nested_vgif_enabled(struct vcpu_svm *svm)
{
- return guest_can_use(&svm->vcpu, X86_FEATURE_VGIF) &&
+ return guest_cpu_cap_has(&svm->vcpu, X86_FEATURE_VGIF) &&
(svm->nested.ctl.int_ctl & V_GIF_ENABLE_MASK);
}
@@ -562,7 +562,7 @@ static inline bool nested_npt_enabled(struct vcpu_svm *svm)
static inline bool nested_vnmi_enabled(struct vcpu_svm *svm)
{
- return guest_can_use(&svm->vcpu, X86_FEATURE_VNMI) &&
+ return guest_cpu_cap_has(&svm->vcpu, X86_FEATURE_VNMI) &&
(svm->nested.ctl.int_ctl & V_NMI_ENABLE_MASK);
}
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index abda07f41b4a1..b2a0e36de0d32 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -6671,7 +6671,7 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
vmx = to_vmx(vcpu);
vmcs12 = get_vmcs12(vcpu);
- if (guest_can_use(vcpu, X86_FEATURE_VMX) &&
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_VMX) &&
(vmx->nested.vmxon || vmx->nested.smm.vmxon)) {
kvm_state.hdr.vmx.vmxon_pa = vmx->nested.vmxon_ptr;
kvm_state.hdr.vmx.vmcs12_pa = vmx->nested.current_vmptr;
@@ -6812,7 +6812,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
if (kvm_state->flags & ~KVM_STATE_NESTED_EVMCS)
return -EINVAL;
} else {
- if (!guest_can_use(vcpu, X86_FEATURE_VMX))
+ if (!guest_cpu_cap_has(vcpu, X86_FEATURE_VMX))
return -EINVAL;
if (!page_address_valid(vcpu, kvm_state->hdr.vmx.vmxon_pa))
@@ -6846,7 +6846,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
return -EINVAL;
if ((kvm_state->flags & KVM_STATE_NESTED_EVMCS) &&
- (!guest_can_use(vcpu, X86_FEATURE_VMX) ||
+ (!guest_cpu_cap_has(vcpu, X86_FEATURE_VMX) ||
!vmx->nested.enlightened_vmcs_enabled))
return -EINVAL;
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 84420bfbcb1bd..7e098fb60bbf7 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -2103,7 +2103,7 @@ int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
[msr_info->index - MSR_IA32_SGXLEPUBKEYHASH0];
break;
case KVM_FIRST_EMULATED_VMX_MSR ... KVM_LAST_EMULATED_VMX_MSR:
- if (!guest_can_use(vcpu, X86_FEATURE_VMX))
+ if (!guest_cpu_cap_has(vcpu, X86_FEATURE_VMX))
return 1;
if (vmx_get_vmx_msr(&vmx->nested.msrs, msr_info->index,
&msr_info->data))
@@ -2422,7 +2422,7 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case KVM_FIRST_EMULATED_VMX_MSR ... KVM_LAST_EMULATED_VMX_MSR:
if (!msr_info->host_initiated)
return 1; /* they are read-only */
- if (!guest_can_use(vcpu, X86_FEATURE_VMX))
+ if (!guest_cpu_cap_has(vcpu, X86_FEATURE_VMX))
return 1;
return vmx_set_vmx_msr(vcpu, msr_index, data);
case MSR_IA32_RTIT_CTL:
@@ -4608,7 +4608,7 @@ vmx_adjust_secondary_exec_control(struct vcpu_vmx *vmx, u32 *exec_control,
\
if (cpu_has_vmx_##name()) { \
if (kvm_is_governed_feature(X86_FEATURE_##feat_name)) \
- __enabled = guest_can_use(__vcpu, X86_FEATURE_##feat_name); \
+ __enabled = guest_cpu_cap_has(__vcpu, X86_FEATURE_##feat_name); \
else \
__enabled = guest_cpuid_has(__vcpu, X86_FEATURE_##feat_name); \
vmx_adjust_secondary_exec_control(vmx, exec_control, SECONDARY_EXEC_##ctrl_name,\
@@ -7832,10 +7832,10 @@ void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
*/
if (boot_cpu_has(X86_FEATURE_XSAVE) &&
guest_cpuid_has(vcpu, X86_FEATURE_XSAVE))
- kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_XSAVES);
+ guest_cpu_cap_check_and_set(vcpu, X86_FEATURE_XSAVES);
- kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_VMX);
- kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_LAM);
+ guest_cpu_cap_check_and_set(vcpu, X86_FEATURE_VMX);
+ guest_cpu_cap_check_and_set(vcpu, X86_FEATURE_LAM);
vmx_setup_uret_msrs(vmx);
@@ -7843,7 +7843,7 @@ void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
vmcs_set_secondary_exec_control(vmx,
vmx_secondary_exec_control(vmx));
- if (guest_can_use(vcpu, X86_FEATURE_VMX))
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_VMX))
vmx->msr_ia32_feature_control_valid_bits |=
FEAT_CTL_VMX_ENABLED_INSIDE_SMX |
FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX;
@@ -7852,7 +7852,7 @@ void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
~(FEAT_CTL_VMX_ENABLED_INSIDE_SMX |
FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX);
- if (guest_can_use(vcpu, X86_FEATURE_VMX))
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_VMX))
nested_vmx_cr_fixed1_bits_update(vcpu);
if (boot_cpu_has(X86_FEATURE_INTEL_PT) &&
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 842e4af926302..0a28c6346a96a 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1032,7 +1032,7 @@ void kvm_load_guest_xsave_state(struct kvm_vcpu *vcpu)
if (vcpu->arch.xcr0 != kvm_host.xcr0)
xsetbv(XCR_XFEATURE_ENABLED_MASK, vcpu->arch.xcr0);
- if (guest_can_use(vcpu, X86_FEATURE_XSAVES) &&
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_XSAVES) &&
vcpu->arch.ia32_xss != kvm_host.xss)
wrmsrl(MSR_IA32_XSS, vcpu->arch.ia32_xss);
}
@@ -1063,7 +1063,7 @@ void kvm_load_host_xsave_state(struct kvm_vcpu *vcpu)
if (vcpu->arch.xcr0 != kvm_host.xcr0)
xsetbv(XCR_XFEATURE_ENABLED_MASK, kvm_host.xcr0);
- if (guest_can_use(vcpu, X86_FEATURE_XSAVES) &&
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_XSAVES) &&
vcpu->arch.ia32_xss != kvm_host.xss)
wrmsrl(MSR_IA32_XSS, kvm_host.xss);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 280/869] KVM: nSVM: Always use NextRIP as vmcb02s NextRIP after first L2 VMRUN
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (278 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 279/869] KVM: x86: Rename "governed features" helpers to use "guest_cpu_cap" Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 281/869] ceph: Remove call to PagePrivate2() Greg Kroah-Hartman
` (589 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yosry Ahmed, Sean Christopherson,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yosry Ahmed <yosry@kernel.org>
[ Upstream commit 8d397582f6b5e9fbcf09781c7c934b4910e94a50 ]
For guests with NRIPS disabled, L1 does not provide NextRIP when running
an L2 with an injected soft interrupt, instead it advances the current RIP
before running it. KVM uses the current RIP as the NextRIP in vmcb02 to
emulate a CPU without NRIPS.
However, after L2 runs the first time, NextRIP will be updated by the CPU
and/or KVM, and the current RIP is no longer the correct value to use in
vmcb02. Hence, after save/restore, use the current RIP if and only if a
nested run is pending, otherwise use NextRIP. Give soft_int_next_rip the
same treatment, as it's the same logic, just for a narrower use case.
Fixes: cc440cdad5b7 ("KVM: nSVM: implement KVM_GET_NESTED_STATE and KVM_SET_NESTED_STATE")
CC: stable@vger.kernel.org
Signed-off-by: Yosry Ahmed <yosry@kernel.org>
Link: https://patch.msgid.link/20260225005950.3739782-6-yosry@kernel.org
[sean: give soft_int_next_rip the same treatment]
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/svm/nested.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index 08274463ad867..2f98a90537d28 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -724,24 +724,32 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
vmcb02->control.event_inj_err = svm->nested.ctl.event_inj_err;
/*
- * next_rip is consumed on VMRUN as the return address pushed on the
+ * NextRIP is consumed on VMRUN as the return address pushed on the
* stack for injected soft exceptions/interrupts. If nrips is exposed
- * to L1, take it verbatim from vmcb12. If nrips is supported in
- * hardware but not exposed to L1, stuff the actual L2 RIP to emulate
- * what a nrips=0 CPU would do (L1 is responsible for advancing RIP
- * prior to injecting the event).
+ * to L1, take it verbatim from vmcb12.
+ *
+ * If nrips is supported in hardware but not exposed to L1, stuff the
+ * actual L2 RIP to emulate what a nrips=0 CPU would do (L1 is
+ * responsible for advancing RIP prior to injecting the event). This is
+ * only the case for the first L2 run after VMRUN. After that (e.g.
+ * during save/restore), NextRIP is updated by the CPU and/or KVM, and
+ * the value of the L2 RIP from vmcb12 should not be used.
*/
- if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS))
- vmcb02->control.next_rip = svm->nested.ctl.next_rip;
- else if (boot_cpu_has(X86_FEATURE_NRIPS))
- vmcb02->control.next_rip = vmcb12_rip;
+ if (boot_cpu_has(X86_FEATURE_NRIPS)) {
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS) ||
+ !svm->nested.nested_run_pending)
+ vmcb02->control.next_rip = svm->nested.ctl.next_rip;
+ else
+ vmcb02->control.next_rip = vmcb12_rip;
+ }
svm->nmi_l1_to_l2 = is_evtinj_nmi(vmcb02->control.event_inj);
if (is_evtinj_soft(vmcb02->control.event_inj)) {
svm->soft_int_injected = true;
svm->soft_int_csbase = vmcb12_csbase;
svm->soft_int_old_rip = vmcb12_rip;
- if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS))
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS) ||
+ !svm->nested.nested_run_pending)
svm->soft_int_next_rip = svm->nested.ctl.next_rip;
else
svm->soft_int_next_rip = vmcb12_rip;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 281/869] ceph: Remove call to PagePrivate2()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (279 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 280/869] KVM: nSVM: Always use NextRIP as vmcb02s NextRIP after first L2 VMRUN Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 282/869] ceph: extend ceph_writeback_ctl for ceph_writepages_start() refactoring Greg Kroah-Hartman
` (588 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Matthew Wilcox (Oracle),
Christian Brauner, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Wilcox (Oracle) <willy@infradead.org>
[ Upstream commit fd15ba4cb00a43fb4df42e1f95f94857ad122eea ]
Use the folio that we already have to call folio_test_private_2()
instead. This is the last call to PagePrivate2(), so replace its
PAGEFLAG() definition with FOLIO_FLAG().
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Link: https://lore.kernel.org/r/20241002040111.1023018-6-willy@infradead.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: a0d9555bf9ea ("ceph: fix num_ops off-by-one when crypto allocation fails")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ceph/addr.c | 20 ++++++++++----------
include/linux/page-flags.h | 2 +-
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index e5ea8fb6d9a6f..674aa886a66e3 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -1052,7 +1052,9 @@ static int ceph_writepages_start(struct address_space *mapping,
if (!nr_folios && !locked_pages)
break;
for (i = 0; i < nr_folios && locked_pages < max_pages; i++) {
- page = &fbatch.folios[i]->page;
+ struct folio *folio = fbatch.folios[i];
+
+ page = &folio->page;
doutc(cl, "? %p idx %lu\n", page, page->index);
if (locked_pages == 0)
lock_page(page); /* first page */
@@ -1079,8 +1081,6 @@ static int ceph_writepages_start(struct address_space *mapping,
continue;
}
if (page_offset(page) >= ceph_wbc.i_size) {
- struct folio *folio = page_folio(page);
-
doutc(cl, "folio at %lu beyond eof %llu\n",
folio->index, ceph_wbc.i_size);
if ((ceph_wbc.size_stable ||
@@ -1096,16 +1096,16 @@ static int ceph_writepages_start(struct address_space *mapping,
unlock_page(page);
break;
}
- if (PageWriteback(page) ||
- PagePrivate2(page) /* [DEPRECATED] */) {
+ if (folio_test_writeback(folio) ||
+ folio_test_private_2(folio) /* [DEPRECATED] */) {
if (wbc->sync_mode == WB_SYNC_NONE) {
- doutc(cl, "%p under writeback\n", page);
- unlock_page(page);
+ doutc(cl, "%p under writeback\n", folio);
+ folio_unlock(folio);
continue;
}
- doutc(cl, "waiting on writeback %p\n", page);
- wait_on_page_writeback(page);
- folio_wait_private_2(page_folio(page)); /* [DEPRECATED] */
+ doutc(cl, "waiting on writeback %p\n", folio);
+ folio_wait_writeback(folio);
+ folio_wait_private_2(folio); /* [DEPRECATED] */
}
if (!clear_page_dirty_for_io(page)) {
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 4e8c6d0511c56..53171d714ac6d 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -543,7 +543,7 @@ FOLIO_FLAG(swapbacked, FOLIO_HEAD_PAGE)
* - PG_private and PG_private_2 cause release_folio() and co to be invoked
*/
PAGEFLAG(Private, private, PF_ANY)
-PAGEFLAG(Private2, private_2, PF_ANY) TESTSCFLAG(Private2, private_2, PF_ANY)
+FOLIO_FLAG(private_2, FOLIO_HEAD_PAGE)
/* owner_2 can be set on tail pages for anon memory */
FOLIO_FLAG(owner_2, FOLIO_HEAD_PAGE)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 282/869] ceph: extend ceph_writeback_ctl for ceph_writepages_start() refactoring
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (280 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 281/869] ceph: Remove call to PagePrivate2() Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 283/869] ceph: introduce ceph_process_folio_batch() method Greg Kroah-Hartman
` (587 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Viacheslav Dubeyko, David Howells,
Christian Brauner, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
[ Upstream commit f08068df4aa411465319bfb796dc6a2228131bc5 ]
The ceph_writepages_start() has unreasonably huge size and
complex logic that makes this method hard to understand.
Current state of the method's logic makes bug fix really
hard task. This patch extends the struct ceph_writeback_ctl
with the goal to make ceph_writepages_start() method
more compact and easy to understand by means of deep refactoring.
Signed-off-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Link: https://lore.kernel.org/r/20250205000249.123054-2-slava@dubeyko.com
Tested-by: David Howells <dhowells@redhat.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: a0d9555bf9ea ("ceph: fix num_ops off-by-one when crypto allocation fails")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ceph/addr.c | 487 ++++++++++++++++++++++++++++++-------------------
1 file changed, 302 insertions(+), 185 deletions(-)
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 674aa886a66e3..9ca7fe3da6bce 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -572,7 +572,36 @@ struct ceph_writeback_ctl
u64 truncate_size;
u32 truncate_seq;
bool size_stable;
+
bool head_snapc;
+ struct ceph_snap_context *snapc;
+ struct ceph_snap_context *last_snapc;
+
+ bool done;
+ bool should_loop;
+ bool range_whole;
+ pgoff_t start_index;
+ pgoff_t index;
+ pgoff_t end;
+ xa_mark_t tag;
+
+ pgoff_t strip_unit_end;
+ unsigned int wsize;
+ unsigned int nr_folios;
+ unsigned int max_pages;
+ unsigned int locked_pages;
+
+ int op_idx;
+ int num_ops;
+ u64 offset;
+ u64 len;
+
+ struct folio_batch fbatch;
+ unsigned int processed_in_fbatch;
+
+ bool from_pool;
+ struct page **pages;
+ struct page **data_pages;
};
/*
@@ -937,6 +966,74 @@ static void writepages_finish(struct ceph_osd_request *req)
ceph_dec_osd_stopping_blocker(fsc->mdsc);
}
+static inline
+unsigned int ceph_define_write_size(struct address_space *mapping)
+{
+ struct inode *inode = mapping->host;
+ struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
+ unsigned int wsize = i_blocksize(inode);
+
+ if (fsc->mount_options->wsize < wsize)
+ wsize = fsc->mount_options->wsize;
+
+ return wsize;
+}
+
+static inline
+void ceph_folio_batch_init(struct ceph_writeback_ctl *ceph_wbc)
+{
+ folio_batch_init(&ceph_wbc->fbatch);
+ ceph_wbc->processed_in_fbatch = 0;
+}
+
+static inline
+void ceph_folio_batch_reinit(struct ceph_writeback_ctl *ceph_wbc)
+{
+ folio_batch_release(&ceph_wbc->fbatch);
+ ceph_folio_batch_init(ceph_wbc);
+}
+
+static inline
+void ceph_init_writeback_ctl(struct address_space *mapping,
+ struct writeback_control *wbc,
+ struct ceph_writeback_ctl *ceph_wbc)
+{
+ ceph_wbc->snapc = NULL;
+ ceph_wbc->last_snapc = NULL;
+
+ ceph_wbc->strip_unit_end = 0;
+ ceph_wbc->wsize = ceph_define_write_size(mapping);
+
+ ceph_wbc->nr_folios = 0;
+ ceph_wbc->max_pages = 0;
+ ceph_wbc->locked_pages = 0;
+
+ ceph_wbc->done = false;
+ ceph_wbc->should_loop = false;
+ ceph_wbc->range_whole = false;
+
+ ceph_wbc->start_index = wbc->range_cyclic ? mapping->writeback_index : 0;
+ ceph_wbc->index = ceph_wbc->start_index;
+ ceph_wbc->end = -1;
+
+ if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages) {
+ ceph_wbc->tag = PAGECACHE_TAG_TOWRITE;
+ } else {
+ ceph_wbc->tag = PAGECACHE_TAG_DIRTY;
+ }
+
+ ceph_wbc->op_idx = -1;
+ ceph_wbc->num_ops = 0;
+ ceph_wbc->offset = 0;
+ ceph_wbc->len = 0;
+ ceph_wbc->from_pool = false;
+
+ ceph_folio_batch_init(ceph_wbc);
+
+ ceph_wbc->pages = NULL;
+ ceph_wbc->data_pages = NULL;
+}
+
/*
* initiate async writeback
*/
@@ -948,17 +1045,11 @@ static int ceph_writepages_start(struct address_space *mapping,
struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
struct ceph_client *cl = fsc->client;
struct ceph_vino vino = ceph_vino(inode);
- pgoff_t index, start_index, end = -1;
- struct ceph_snap_context *snapc = NULL, *last_snapc = NULL, *pgsnapc;
- struct folio_batch fbatch;
- int rc = 0;
- unsigned int wsize = i_blocksize(inode);
- struct ceph_osd_request *req = NULL;
+ struct ceph_snap_context *pgsnapc;
struct ceph_writeback_ctl ceph_wbc;
- bool should_loop, range_whole = false;
- bool done = false;
+ struct ceph_osd_request *req = NULL;
+ int rc = 0;
bool caching = ceph_is_cache_enabled(inode);
- xa_mark_t tag;
if (wbc->sync_mode == WB_SYNC_NONE &&
fsc->write_congested)
@@ -977,86 +1068,78 @@ static int ceph_writepages_start(struct address_space *mapping,
mapping_set_error(mapping, -EIO);
return -EIO; /* we're in a forced umount, don't write! */
}
- if (fsc->mount_options->wsize < wsize)
- wsize = fsc->mount_options->wsize;
- folio_batch_init(&fbatch);
+ ceph_init_writeback_ctl(mapping, wbc, &ceph_wbc);
- start_index = wbc->range_cyclic ? mapping->writeback_index : 0;
- index = start_index;
-
- if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages) {
- tag = PAGECACHE_TAG_TOWRITE;
- } else {
- tag = PAGECACHE_TAG_DIRTY;
- }
retry:
/* find oldest snap context with dirty data */
- snapc = get_oldest_context(inode, &ceph_wbc, NULL);
- if (!snapc) {
+ ceph_wbc.snapc = get_oldest_context(inode, &ceph_wbc, NULL);
+ if (!ceph_wbc.snapc) {
/* hmm, why does writepages get called when there
is no dirty data? */
doutc(cl, " no snap context with dirty data?\n");
goto out;
}
- doutc(cl, " oldest snapc is %p seq %lld (%d snaps)\n", snapc,
- snapc->seq, snapc->num_snaps);
+ doutc(cl, " oldest snapc is %p seq %lld (%d snaps)\n",
+ ceph_wbc.snapc, ceph_wbc.snapc->seq,
+ ceph_wbc.snapc->num_snaps);
- should_loop = false;
- if (ceph_wbc.head_snapc && snapc != last_snapc) {
+ ceph_wbc.should_loop = false;
+ if (ceph_wbc.head_snapc && ceph_wbc.snapc != ceph_wbc.last_snapc) {
/* where to start/end? */
if (wbc->range_cyclic) {
- index = start_index;
- end = -1;
- if (index > 0)
- should_loop = true;
- doutc(cl, " cyclic, start at %lu\n", index);
+ ceph_wbc.index = ceph_wbc.start_index;
+ ceph_wbc.end = -1;
+ if (ceph_wbc.index > 0)
+ ceph_wbc.should_loop = true;
+ doutc(cl, " cyclic, start at %lu\n", ceph_wbc.index);
} else {
- index = wbc->range_start >> PAGE_SHIFT;
- end = wbc->range_end >> PAGE_SHIFT;
+ ceph_wbc.index = wbc->range_start >> PAGE_SHIFT;
+ ceph_wbc.end = wbc->range_end >> PAGE_SHIFT;
if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
- range_whole = true;
- doutc(cl, " not cyclic, %lu to %lu\n", index, end);
+ ceph_wbc.range_whole = true;
+ doutc(cl, " not cyclic, %lu to %lu\n",
+ ceph_wbc.index, ceph_wbc.end);
}
} else if (!ceph_wbc.head_snapc) {
/* Do not respect wbc->range_{start,end}. Dirty pages
* in that range can be associated with newer snapc.
* They are not writeable until we write all dirty pages
* associated with 'snapc' get written */
- if (index > 0)
- should_loop = true;
+ if (ceph_wbc.index > 0)
+ ceph_wbc.should_loop = true;
doutc(cl, " non-head snapc, range whole\n");
}
if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
- tag_pages_for_writeback(mapping, index, end);
+ tag_pages_for_writeback(mapping, ceph_wbc.index, ceph_wbc.end);
- ceph_put_snap_context(last_snapc);
- last_snapc = snapc;
+ ceph_put_snap_context(ceph_wbc.last_snapc);
+ ceph_wbc.last_snapc = ceph_wbc.snapc;
- while (!done && index <= end) {
- int num_ops = 0, op_idx;
- unsigned i, nr_folios, max_pages, locked_pages = 0;
- struct page **pages = NULL, **data_pages;
+ while (!ceph_wbc.done && ceph_wbc.index <= ceph_wbc.end) {
+ unsigned i;
struct page *page;
- pgoff_t strip_unit_end = 0;
- u64 offset = 0, len = 0;
- bool from_pool = false;
- max_pages = wsize >> PAGE_SHIFT;
+ ceph_wbc.max_pages = ceph_wbc.wsize >> PAGE_SHIFT;
get_more_pages:
- nr_folios = filemap_get_folios_tag(mapping, &index,
- end, tag, &fbatch);
- doutc(cl, "pagevec_lookup_range_tag got %d\n", nr_folios);
- if (!nr_folios && !locked_pages)
+ ceph_wbc.nr_folios = filemap_get_folios_tag(mapping,
+ &ceph_wbc.index,
+ ceph_wbc.end,
+ ceph_wbc.tag,
+ &ceph_wbc.fbatch);
+ doutc(cl, "pagevec_lookup_range_tag got %d\n",
+ ceph_wbc.nr_folios);
+ if (!ceph_wbc.nr_folios && !ceph_wbc.locked_pages)
break;
- for (i = 0; i < nr_folios && locked_pages < max_pages; i++) {
- struct folio *folio = fbatch.folios[i];
+ for (i = 0; i < ceph_wbc.nr_folios &&
+ ceph_wbc.locked_pages < ceph_wbc.max_pages; i++) {
+ struct folio *folio = ceph_wbc.fbatch.folios[i];
page = &folio->page;
doutc(cl, "? %p idx %lu\n", page, page->index);
- if (locked_pages == 0)
+ if (ceph_wbc.locked_pages == 0)
lock_page(page); /* first page */
else if (!trylock_page(page))
break;
@@ -1070,13 +1153,14 @@ static int ceph_writepages_start(struct address_space *mapping,
}
/* only if matching snap context */
pgsnapc = page_snap_context(page);
- if (pgsnapc != snapc) {
+ if (pgsnapc != ceph_wbc.snapc) {
doutc(cl, "page snapc %p %lld != oldest %p %lld\n",
- pgsnapc, pgsnapc->seq, snapc, snapc->seq);
- if (!should_loop &&
+ pgsnapc, pgsnapc->seq,
+ ceph_wbc.snapc, ceph_wbc.snapc->seq);
+ if (!ceph_wbc.should_loop &&
!ceph_wbc.head_snapc &&
wbc->sync_mode != WB_SYNC_NONE)
- should_loop = true;
+ ceph_wbc.should_loop = true;
unlock_page(page);
continue;
}
@@ -1091,7 +1175,8 @@ static int ceph_writepages_start(struct address_space *mapping,
folio_unlock(folio);
continue;
}
- if (strip_unit_end && (page->index > strip_unit_end)) {
+ if (ceph_wbc.strip_unit_end &&
+ (page->index > ceph_wbc.strip_unit_end)) {
doutc(cl, "end of strip unit %p\n", page);
unlock_page(page);
break;
@@ -1120,47 +1205,52 @@ static int ceph_writepages_start(struct address_space *mapping,
* calculate max possinle write size and
* allocate a page array
*/
- if (locked_pages == 0) {
+ if (ceph_wbc.locked_pages == 0) {
u64 objnum;
u64 objoff;
u32 xlen;
/* prepare async write request */
- offset = (u64)page_offset(page);
+ ceph_wbc.offset = (u64)page_offset(page);
ceph_calc_file_object_mapping(&ci->i_layout,
- offset, wsize,
+ ceph_wbc.offset,
+ ceph_wbc.wsize,
&objnum, &objoff,
&xlen);
- len = xlen;
+ ceph_wbc.len = xlen;
- num_ops = 1;
- strip_unit_end = page->index +
- ((len - 1) >> PAGE_SHIFT);
+ ceph_wbc.num_ops = 1;
+ ceph_wbc.strip_unit_end = page->index +
+ ((ceph_wbc.len - 1) >> PAGE_SHIFT);
- BUG_ON(pages);
- max_pages = calc_pages_for(0, (u64)len);
- pages = kmalloc_array(max_pages,
- sizeof(*pages),
+ BUG_ON(ceph_wbc.pages);
+ ceph_wbc.max_pages =
+ calc_pages_for(0, (u64)ceph_wbc.len);
+ ceph_wbc.pages = kmalloc_array(ceph_wbc.max_pages,
+ sizeof(*ceph_wbc.pages),
GFP_NOFS);
- if (!pages) {
- from_pool = true;
- pages = mempool_alloc(ceph_wb_pagevec_pool, GFP_NOFS);
- BUG_ON(!pages);
+ if (!ceph_wbc.pages) {
+ ceph_wbc.from_pool = true;
+ ceph_wbc.pages =
+ mempool_alloc(ceph_wb_pagevec_pool,
+ GFP_NOFS);
+ BUG_ON(!ceph_wbc.pages);
}
- len = 0;
+ ceph_wbc.len = 0;
} else if (page->index !=
- (offset + len) >> PAGE_SHIFT) {
- if (num_ops >= (from_pool ? CEPH_OSD_SLAB_OPS :
+ (ceph_wbc.offset + ceph_wbc.len) >> PAGE_SHIFT) {
+ if (ceph_wbc.num_ops >=
+ (ceph_wbc.from_pool ? CEPH_OSD_SLAB_OPS :
CEPH_OSD_MAX_OPS)) {
redirty_page_for_writepage(wbc, page);
unlock_page(page);
break;
}
- num_ops++;
- offset = (u64)page_offset(page);
- len = 0;
+ ceph_wbc.num_ops++;
+ ceph_wbc.offset = (u64)page_offset(page);
+ ceph_wbc.len = 0;
}
/* note position of first page in fbatch */
@@ -1173,78 +1263,85 @@ static int ceph_writepages_start(struct address_space *mapping,
fsc->write_congested = true;
if (IS_ENCRYPTED(inode)) {
- pages[locked_pages] =
+ ceph_wbc.pages[ceph_wbc.locked_pages] =
fscrypt_encrypt_pagecache_blocks(page,
PAGE_SIZE, 0,
- locked_pages ? GFP_NOWAIT : GFP_NOFS);
- if (IS_ERR(pages[locked_pages])) {
- if (PTR_ERR(pages[locked_pages]) == -EINVAL)
+ ceph_wbc.locked_pages ?
+ GFP_NOWAIT : GFP_NOFS);
+ if (IS_ERR(ceph_wbc.pages[ceph_wbc.locked_pages])) {
+ if (PTR_ERR(ceph_wbc.pages[ceph_wbc.locked_pages]) == -EINVAL)
pr_err_client(cl,
"inode->i_blkbits=%hhu\n",
inode->i_blkbits);
/* better not fail on first page! */
- BUG_ON(locked_pages == 0);
- pages[locked_pages] = NULL;
+ BUG_ON(ceph_wbc.locked_pages == 0);
+ ceph_wbc.pages[ceph_wbc.locked_pages] = NULL;
redirty_page_for_writepage(wbc, page);
unlock_page(page);
break;
}
- ++locked_pages;
+ ++ceph_wbc.locked_pages;
} else {
- pages[locked_pages++] = page;
+ ceph_wbc.pages[ceph_wbc.locked_pages++] = page;
}
- fbatch.folios[i] = NULL;
- len += thp_size(page);
+ ceph_wbc.fbatch.folios[i] = NULL;
+ ceph_wbc.len += thp_size(page);
}
/* did we get anything? */
- if (!locked_pages)
+ if (!ceph_wbc.locked_pages)
goto release_folios;
if (i) {
unsigned j, n = 0;
/* shift unused page to beginning of fbatch */
- for (j = 0; j < nr_folios; j++) {
- if (!fbatch.folios[j])
+ for (j = 0; j < ceph_wbc.nr_folios; j++) {
+ if (!ceph_wbc.fbatch.folios[j])
continue;
- if (n < j)
- fbatch.folios[n] = fbatch.folios[j];
+ if (n < j) {
+ ceph_wbc.fbatch.folios[n] =
+ ceph_wbc.fbatch.folios[j];
+ }
n++;
}
- fbatch.nr = n;
+ ceph_wbc.fbatch.nr = n;
- if (nr_folios && i == nr_folios &&
- locked_pages < max_pages) {
+ if (ceph_wbc.nr_folios && i == ceph_wbc.nr_folios &&
+ ceph_wbc.locked_pages < ceph_wbc.max_pages) {
doutc(cl, "reached end fbatch, trying for more\n");
- folio_batch_release(&fbatch);
+ folio_batch_release(&ceph_wbc.fbatch);
goto get_more_pages;
}
}
new_request:
- offset = ceph_fscrypt_page_offset(pages[0]);
- len = wsize;
+ ceph_wbc.offset = ceph_fscrypt_page_offset(ceph_wbc.pages[0]);
+ ceph_wbc.len = ceph_wbc.wsize;
req = ceph_osdc_new_request(&fsc->client->osdc,
&ci->i_layout, vino,
- offset, &len, 0, num_ops,
+ ceph_wbc.offset, &ceph_wbc.len,
+ 0, ceph_wbc.num_ops,
CEPH_OSD_OP_WRITE, CEPH_OSD_FLAG_WRITE,
- snapc, ceph_wbc.truncate_seq,
+ ceph_wbc.snapc, ceph_wbc.truncate_seq,
ceph_wbc.truncate_size, false);
if (IS_ERR(req)) {
req = ceph_osdc_new_request(&fsc->client->osdc,
&ci->i_layout, vino,
- offset, &len, 0,
- min(num_ops,
+ ceph_wbc.offset, &ceph_wbc.len,
+ 0, min(ceph_wbc.num_ops,
CEPH_OSD_SLAB_OPS),
CEPH_OSD_OP_WRITE,
CEPH_OSD_FLAG_WRITE,
- snapc, ceph_wbc.truncate_seq,
+ ceph_wbc.snapc,
+ ceph_wbc.truncate_seq,
ceph_wbc.truncate_size, true);
BUG_ON(IS_ERR(req));
}
- BUG_ON(len < ceph_fscrypt_page_offset(pages[locked_pages - 1]) +
- thp_size(pages[locked_pages - 1]) - offset);
+ BUG_ON(ceph_wbc.len <
+ ceph_fscrypt_page_offset(ceph_wbc.pages[ceph_wbc.locked_pages - 1]) +
+ thp_size(ceph_wbc.pages[ceph_wbc.locked_pages - 1]) -
+ ceph_wbc.offset);
if (!ceph_inc_osd_stopping_blocker(fsc->mdsc)) {
rc = -EIO;
@@ -1254,100 +1351,118 @@ static int ceph_writepages_start(struct address_space *mapping,
req->r_inode = inode;
/* Format the osd request message and submit the write */
- len = 0;
- data_pages = pages;
- op_idx = 0;
- for (i = 0; i < locked_pages; i++) {
- struct page *page = ceph_fscrypt_pagecache_page(pages[i]);
+ ceph_wbc.len = 0;
+ ceph_wbc.data_pages = ceph_wbc.pages;
+ ceph_wbc.op_idx = 0;
+ for (i = 0; i < ceph_wbc.locked_pages; i++) {
+ struct page *page =
+ ceph_fscrypt_pagecache_page(ceph_wbc.pages[i]);
u64 cur_offset = page_offset(page);
/*
* Discontinuity in page range? Ceph can handle that by just passing
* multiple extents in the write op.
*/
- if (offset + len != cur_offset) {
+ if (ceph_wbc.offset + ceph_wbc.len != cur_offset) {
/* If it's full, stop here */
- if (op_idx + 1 == req->r_num_ops)
+ if (ceph_wbc.op_idx + 1 == req->r_num_ops)
break;
/* Kick off an fscache write with what we have so far. */
- ceph_fscache_write_to_cache(inode, offset, len, caching);
+ ceph_fscache_write_to_cache(inode, ceph_wbc.offset,
+ ceph_wbc.len, caching);
/* Start a new extent */
- osd_req_op_extent_dup_last(req, op_idx,
- cur_offset - offset);
- doutc(cl, "got pages at %llu~%llu\n", offset,
- len);
- osd_req_op_extent_osd_data_pages(req, op_idx,
- data_pages, len, 0,
- from_pool, false);
- osd_req_op_extent_update(req, op_idx, len);
-
- len = 0;
- offset = cur_offset;
- data_pages = pages + i;
- op_idx++;
+ osd_req_op_extent_dup_last(req, ceph_wbc.op_idx,
+ cur_offset -
+ ceph_wbc.offset);
+ doutc(cl, "got pages at %llu~%llu\n",
+ ceph_wbc.offset,
+ ceph_wbc.len);
+ osd_req_op_extent_osd_data_pages(req,
+ ceph_wbc.op_idx,
+ ceph_wbc.data_pages,
+ ceph_wbc.len, 0,
+ ceph_wbc.from_pool, false);
+ osd_req_op_extent_update(req, ceph_wbc.op_idx,
+ ceph_wbc.len);
+
+ ceph_wbc.len = 0;
+ ceph_wbc.offset = cur_offset;
+ ceph_wbc.data_pages = ceph_wbc.pages + i;
+ ceph_wbc.op_idx++;
}
set_page_writeback(page);
if (caching)
ceph_set_page_fscache(page);
- len += thp_size(page);
+ ceph_wbc.len += thp_size(page);
}
- ceph_fscache_write_to_cache(inode, offset, len, caching);
+ ceph_fscache_write_to_cache(inode, ceph_wbc.offset,
+ ceph_wbc.len, caching);
if (ceph_wbc.size_stable) {
- len = min(len, ceph_wbc.i_size - offset);
- } else if (i == locked_pages) {
+ ceph_wbc.len = min(ceph_wbc.len,
+ ceph_wbc.i_size - ceph_wbc.offset);
+ } else if (i == ceph_wbc.locked_pages) {
/* writepages_finish() clears writeback pages
* according to the data length, so make sure
* data length covers all locked pages */
- u64 min_len = len + 1 - thp_size(page);
- len = get_writepages_data_length(inode, pages[i - 1],
- offset);
- len = max(len, min_len);
+ u64 min_len = ceph_wbc.len + 1 - thp_size(page);
+ ceph_wbc.len =
+ get_writepages_data_length(inode,
+ ceph_wbc.pages[i - 1],
+ ceph_wbc.offset);
+ ceph_wbc.len = max(ceph_wbc.len, min_len);
+ }
+ if (IS_ENCRYPTED(inode)) {
+ ceph_wbc.len = round_up(ceph_wbc.len,
+ CEPH_FSCRYPT_BLOCK_SIZE);
}
- if (IS_ENCRYPTED(inode))
- len = round_up(len, CEPH_FSCRYPT_BLOCK_SIZE);
- doutc(cl, "got pages at %llu~%llu\n", offset, len);
+ doutc(cl, "got pages at %llu~%llu\n",
+ ceph_wbc.offset, ceph_wbc.len);
if (IS_ENCRYPTED(inode) &&
- ((offset | len) & ~CEPH_FSCRYPT_BLOCK_MASK))
+ ((ceph_wbc.offset | ceph_wbc.len) & ~CEPH_FSCRYPT_BLOCK_MASK))
pr_warn_client(cl,
"bad encrypted write offset=%lld len=%llu\n",
- offset, len);
+ ceph_wbc.offset, ceph_wbc.len);
- osd_req_op_extent_osd_data_pages(req, op_idx, data_pages, len,
- 0, from_pool, false);
- osd_req_op_extent_update(req, op_idx, len);
+ osd_req_op_extent_osd_data_pages(req, ceph_wbc.op_idx,
+ ceph_wbc.data_pages,
+ ceph_wbc.len,
+ 0, ceph_wbc.from_pool, false);
+ osd_req_op_extent_update(req, ceph_wbc.op_idx, ceph_wbc.len);
- BUG_ON(op_idx + 1 != req->r_num_ops);
+ BUG_ON(ceph_wbc.op_idx + 1 != req->r_num_ops);
- from_pool = false;
- if (i < locked_pages) {
- BUG_ON(num_ops <= req->r_num_ops);
- num_ops -= req->r_num_ops;
- locked_pages -= i;
+ ceph_wbc.from_pool = false;
+ if (i < ceph_wbc.locked_pages) {
+ BUG_ON(ceph_wbc.num_ops <= req->r_num_ops);
+ ceph_wbc.num_ops -= req->r_num_ops;
+ ceph_wbc.locked_pages -= i;
/* allocate new pages array for next request */
- data_pages = pages;
- pages = kmalloc_array(locked_pages, sizeof(*pages),
- GFP_NOFS);
- if (!pages) {
- from_pool = true;
- pages = mempool_alloc(ceph_wb_pagevec_pool, GFP_NOFS);
- BUG_ON(!pages);
+ ceph_wbc.data_pages = ceph_wbc.pages;
+ ceph_wbc.pages = kmalloc_array(ceph_wbc.locked_pages,
+ sizeof(*ceph_wbc.pages),
+ GFP_NOFS);
+ if (!ceph_wbc.pages) {
+ ceph_wbc.from_pool = true;
+ ceph_wbc.pages =
+ mempool_alloc(ceph_wb_pagevec_pool, GFP_NOFS);
+ BUG_ON(!ceph_wbc.pages);
}
- memcpy(pages, data_pages + i,
- locked_pages * sizeof(*pages));
- memset(data_pages + i, 0,
- locked_pages * sizeof(*pages));
+ memcpy(ceph_wbc.pages, ceph_wbc.data_pages + i,
+ ceph_wbc.locked_pages * sizeof(*ceph_wbc.pages));
+ memset(ceph_wbc.data_pages + i, 0,
+ ceph_wbc.locked_pages * sizeof(*ceph_wbc.pages));
} else {
- BUG_ON(num_ops != req->r_num_ops);
- index = pages[i - 1]->index + 1;
+ BUG_ON(ceph_wbc.num_ops != req->r_num_ops);
+ ceph_wbc.index = ceph_wbc.pages[i - 1]->index + 1;
/* request message now owns the pages array */
- pages = NULL;
+ ceph_wbc.pages = NULL;
}
req->r_mtime = inode_get_mtime(inode);
@@ -1355,7 +1470,7 @@ static int ceph_writepages_start(struct address_space *mapping,
req = NULL;
wbc->nr_to_write -= i;
- if (pages)
+ if (ceph_wbc.pages)
goto new_request;
/*
@@ -1365,54 +1480,56 @@ static int ceph_writepages_start(struct address_space *mapping,
* we tagged for writeback prior to entering this loop.
*/
if (wbc->nr_to_write <= 0 && wbc->sync_mode == WB_SYNC_NONE)
- done = true;
+ ceph_wbc.done = true;
release_folios:
doutc(cl, "folio_batch release on %d folios (%p)\n",
- (int)fbatch.nr, fbatch.nr ? fbatch.folios[0] : NULL);
- folio_batch_release(&fbatch);
+ (int)ceph_wbc.fbatch.nr,
+ ceph_wbc.fbatch.nr ? ceph_wbc.fbatch.folios[0] : NULL);
+ folio_batch_release(&ceph_wbc.fbatch);
}
- if (should_loop && !done) {
+ if (ceph_wbc.should_loop && !ceph_wbc.done) {
/* more to do; loop back to beginning of file */
doutc(cl, "looping back to beginning of file\n");
- end = start_index - 1; /* OK even when start_index == 0 */
+ ceph_wbc.end = ceph_wbc.start_index - 1; /* OK even when start_index == 0 */
/* to write dirty pages associated with next snapc,
* we need to wait until current writes complete */
if (wbc->sync_mode != WB_SYNC_NONE &&
- start_index == 0 && /* all dirty pages were checked */
+ ceph_wbc.start_index == 0 && /* all dirty pages were checked */
!ceph_wbc.head_snapc) {
struct page *page;
unsigned i, nr;
- index = 0;
- while ((index <= end) &&
- (nr = filemap_get_folios_tag(mapping, &index,
+ ceph_wbc.index = 0;
+ while ((ceph_wbc.index <= ceph_wbc.end) &&
+ (nr = filemap_get_folios_tag(mapping,
+ &ceph_wbc.index,
(pgoff_t)-1,
PAGECACHE_TAG_WRITEBACK,
- &fbatch))) {
+ &ceph_wbc.fbatch))) {
for (i = 0; i < nr; i++) {
- page = &fbatch.folios[i]->page;
- if (page_snap_context(page) != snapc)
+ page = &ceph_wbc.fbatch.folios[i]->page;
+ if (page_snap_context(page) != ceph_wbc.snapc)
continue;
wait_on_page_writeback(page);
}
- folio_batch_release(&fbatch);
+ folio_batch_release(&ceph_wbc.fbatch);
cond_resched();
}
}
- start_index = 0;
- index = 0;
+ ceph_wbc.start_index = 0;
+ ceph_wbc.index = 0;
goto retry;
}
- if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
- mapping->writeback_index = index;
+ if (wbc->range_cyclic || (ceph_wbc.range_whole && wbc->nr_to_write > 0))
+ mapping->writeback_index = ceph_wbc.index;
out:
ceph_osdc_put_request(req);
- ceph_put_snap_context(last_snapc);
+ ceph_put_snap_context(ceph_wbc.last_snapc);
doutc(cl, "%llx.%llx dend - startone, rc = %d\n", ceph_vinop(inode),
rc);
return rc;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 283/869] ceph: introduce ceph_process_folio_batch() method
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (281 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 282/869] ceph: extend ceph_writeback_ctl for ceph_writepages_start() refactoring Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 284/869] ceph: Remove uses of page from ceph_process_folio_batch() Greg Kroah-Hartman
` (586 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Viacheslav Dubeyko, David Howells,
Christian Brauner, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
[ Upstream commit ce80b76dd32764cc914975777e058d4fae4f0ea0 ]
First step of ceph_writepages_start() logic is
of finding the dirty memory folios and processing it.
This patch introduces ceph_process_folio_batch()
method that moves this logic into dedicated method.
The ceph_writepages_start() has this logic:
if (ceph_wbc.locked_pages == 0)
lock_page(page); /* first page */
else if (!trylock_page(page))
break;
<skipped>
if (folio_test_writeback(folio) ||
folio_test_private_2(folio) /* [DEPRECATED] */) {
if (wbc->sync_mode == WB_SYNC_NONE) {
doutc(cl, "%p under writeback\n", folio);
folio_unlock(folio);
continue;
}
doutc(cl, "waiting on writeback %p\n", folio);
folio_wait_writeback(folio);
folio_wait_private_2(folio); /* [DEPRECATED] */
}
The problem here that folio/page is locked here at first
and it is by set_page_writeback(page) later before
submitting the write request. The folio/page is unlocked
by writepages_finish() after finishing the write
request. It means that logic of checking folio_test_writeback()
and folio_wait_writeback() never works because page is locked
and it cannot be locked again until write request completion.
However, for majority of folios/pages the trylock_page()
is used. As a result, multiple threads can try to lock the same
folios/pages multiple times even if they are under writeback
already. It makes this logic more compute intensive than
it is necessary.
This patch changes this logic:
if (folio_test_writeback(folio) ||
folio_test_private_2(folio) /* [DEPRECATED] */) {
if (wbc->sync_mode == WB_SYNC_NONE) {
doutc(cl, "%p under writeback\n", folio);
folio_unlock(folio);
continue;
}
doutc(cl, "waiting on writeback %p\n", folio);
folio_wait_writeback(folio);
folio_wait_private_2(folio); /* [DEPRECATED] */
}
if (ceph_wbc.locked_pages == 0)
lock_page(page); /* first page */
else if (!trylock_page(page))
break;
This logic should exclude the ignoring of writeback
state of folios/pages.
Signed-off-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Link: https://lore.kernel.org/r/20250205000249.123054-3-slava@dubeyko.com
Tested-by: David Howells <dhowells@redhat.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: a0d9555bf9ea ("ceph: fix num_ops off-by-one when crypto allocation fails")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ceph/addr.c | 568 +++++++++++++++++++++++++++++++------------------
1 file changed, 365 insertions(+), 203 deletions(-)
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 9ca7fe3da6bce..36aa5cf8300af 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -966,6 +966,27 @@ static void writepages_finish(struct ceph_osd_request *req)
ceph_dec_osd_stopping_blocker(fsc->mdsc);
}
+static inline
+bool is_forced_umount(struct address_space *mapping)
+{
+ struct inode *inode = mapping->host;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
+ struct ceph_client *cl = fsc->client;
+
+ if (ceph_inode_is_shutdown(inode)) {
+ if (ci->i_wrbuffer_ref > 0) {
+ pr_warn_ratelimited_client(cl,
+ "%llx.%llx %lld forced umount\n",
+ ceph_vinop(inode), ceph_ino(inode));
+ }
+ mapping_set_error(mapping, -EIO);
+ return true;
+ }
+
+ return false;
+}
+
static inline
unsigned int ceph_define_write_size(struct address_space *mapping)
{
@@ -1034,6 +1055,334 @@ void ceph_init_writeback_ctl(struct address_space *mapping,
ceph_wbc->data_pages = NULL;
}
+static inline
+int ceph_define_writeback_range(struct address_space *mapping,
+ struct writeback_control *wbc,
+ struct ceph_writeback_ctl *ceph_wbc)
+{
+ struct inode *inode = mapping->host;
+ struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
+ struct ceph_client *cl = fsc->client;
+
+ /* find oldest snap context with dirty data */
+ ceph_wbc->snapc = get_oldest_context(inode, ceph_wbc, NULL);
+ if (!ceph_wbc->snapc) {
+ /* hmm, why does writepages get called when there
+ is no dirty data? */
+ doutc(cl, " no snap context with dirty data?\n");
+ return -ENODATA;
+ }
+
+ doutc(cl, " oldest snapc is %p seq %lld (%d snaps)\n",
+ ceph_wbc->snapc, ceph_wbc->snapc->seq,
+ ceph_wbc->snapc->num_snaps);
+
+ ceph_wbc->should_loop = false;
+
+ if (ceph_wbc->head_snapc && ceph_wbc->snapc != ceph_wbc->last_snapc) {
+ /* where to start/end? */
+ if (wbc->range_cyclic) {
+ ceph_wbc->index = ceph_wbc->start_index;
+ ceph_wbc->end = -1;
+ if (ceph_wbc->index > 0)
+ ceph_wbc->should_loop = true;
+ doutc(cl, " cyclic, start at %lu\n", ceph_wbc->index);
+ } else {
+ ceph_wbc->index = wbc->range_start >> PAGE_SHIFT;
+ ceph_wbc->end = wbc->range_end >> PAGE_SHIFT;
+ if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
+ ceph_wbc->range_whole = true;
+ doutc(cl, " not cyclic, %lu to %lu\n",
+ ceph_wbc->index, ceph_wbc->end);
+ }
+ } else if (!ceph_wbc->head_snapc) {
+ /* Do not respect wbc->range_{start,end}. Dirty pages
+ * in that range can be associated with newer snapc.
+ * They are not writeable until we write all dirty pages
+ * associated with 'snapc' get written */
+ if (ceph_wbc->index > 0)
+ ceph_wbc->should_loop = true;
+ doutc(cl, " non-head snapc, range whole\n");
+ }
+
+ ceph_put_snap_context(ceph_wbc->last_snapc);
+ ceph_wbc->last_snapc = ceph_wbc->snapc;
+
+ return 0;
+}
+
+static inline
+bool has_writeback_done(struct ceph_writeback_ctl *ceph_wbc)
+{
+ return ceph_wbc->done && ceph_wbc->index > ceph_wbc->end;
+}
+
+static inline
+bool can_next_page_be_processed(struct ceph_writeback_ctl *ceph_wbc,
+ unsigned index)
+{
+ return index < ceph_wbc->nr_folios &&
+ ceph_wbc->locked_pages < ceph_wbc->max_pages;
+}
+
+static
+int ceph_check_page_before_write(struct address_space *mapping,
+ struct writeback_control *wbc,
+ struct ceph_writeback_ctl *ceph_wbc,
+ struct folio *folio)
+{
+ struct inode *inode = mapping->host;
+ struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
+ struct ceph_client *cl = fsc->client;
+ struct ceph_snap_context *pgsnapc;
+ struct page *page = &folio->page;
+
+ /* only dirty pages, or our accounting breaks */
+ if (unlikely(!PageDirty(page)) || unlikely(page->mapping != mapping)) {
+ doutc(cl, "!dirty or !mapping %p\n", page);
+ return -ENODATA;
+ }
+
+ /* only if matching snap context */
+ pgsnapc = page_snap_context(page);
+ if (pgsnapc != ceph_wbc->snapc) {
+ doutc(cl, "page snapc %p %lld != oldest %p %lld\n",
+ pgsnapc, pgsnapc->seq,
+ ceph_wbc->snapc, ceph_wbc->snapc->seq);
+
+ if (!ceph_wbc->should_loop && !ceph_wbc->head_snapc &&
+ wbc->sync_mode != WB_SYNC_NONE)
+ ceph_wbc->should_loop = true;
+
+ return -ENODATA;
+ }
+
+ if (page_offset(page) >= ceph_wbc->i_size) {
+ doutc(cl, "folio at %lu beyond eof %llu\n",
+ folio->index, ceph_wbc->i_size);
+
+ if ((ceph_wbc->size_stable ||
+ folio_pos(folio) >= i_size_read(inode)) &&
+ folio_clear_dirty_for_io(folio))
+ folio_invalidate(folio, 0, folio_size(folio));
+
+ return -ENODATA;
+ }
+
+ if (ceph_wbc->strip_unit_end &&
+ (page->index > ceph_wbc->strip_unit_end)) {
+ doutc(cl, "end of strip unit %p\n", page);
+ return -E2BIG;
+ }
+
+ return 0;
+}
+
+static inline
+void __ceph_allocate_page_array(struct ceph_writeback_ctl *ceph_wbc,
+ unsigned int max_pages)
+{
+ ceph_wbc->pages = kmalloc_array(max_pages,
+ sizeof(*ceph_wbc->pages),
+ GFP_NOFS);
+ if (!ceph_wbc->pages) {
+ ceph_wbc->from_pool = true;
+ ceph_wbc->pages = mempool_alloc(ceph_wb_pagevec_pool, GFP_NOFS);
+ BUG_ON(!ceph_wbc->pages);
+ }
+}
+
+static inline
+void ceph_allocate_page_array(struct address_space *mapping,
+ struct ceph_writeback_ctl *ceph_wbc,
+ struct page *page)
+{
+ struct inode *inode = mapping->host;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ u64 objnum;
+ u64 objoff;
+ u32 xlen;
+
+ /* prepare async write request */
+ ceph_wbc->offset = (u64)page_offset(page);
+ ceph_calc_file_object_mapping(&ci->i_layout,
+ ceph_wbc->offset, ceph_wbc->wsize,
+ &objnum, &objoff, &xlen);
+
+ ceph_wbc->num_ops = 1;
+ ceph_wbc->strip_unit_end = page->index + ((xlen - 1) >> PAGE_SHIFT);
+
+ BUG_ON(ceph_wbc->pages);
+ ceph_wbc->max_pages = calc_pages_for(0, (u64)xlen);
+ __ceph_allocate_page_array(ceph_wbc, ceph_wbc->max_pages);
+
+ ceph_wbc->len = 0;
+}
+
+static inline
+bool is_page_index_contiguous(struct ceph_writeback_ctl *ceph_wbc,
+ struct page *page)
+{
+ return page->index == (ceph_wbc->offset + ceph_wbc->len) >> PAGE_SHIFT;
+}
+
+static inline
+bool is_num_ops_too_big(struct ceph_writeback_ctl *ceph_wbc)
+{
+ return ceph_wbc->num_ops >=
+ (ceph_wbc->from_pool ? CEPH_OSD_SLAB_OPS : CEPH_OSD_MAX_OPS);
+}
+
+static inline
+bool is_write_congestion_happened(struct ceph_fs_client *fsc)
+{
+ return atomic_long_inc_return(&fsc->writeback_count) >
+ CONGESTION_ON_THRESH(fsc->mount_options->congestion_kb);
+}
+
+static inline
+int ceph_move_dirty_page_in_page_array(struct address_space *mapping,
+ struct writeback_control *wbc,
+ struct ceph_writeback_ctl *ceph_wbc,
+ struct page *page)
+{
+ struct inode *inode = mapping->host;
+ struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
+ struct ceph_client *cl = fsc->client;
+ struct page **pages = ceph_wbc->pages;
+ unsigned int index = ceph_wbc->locked_pages;
+ gfp_t gfp_flags = ceph_wbc->locked_pages ? GFP_NOWAIT : GFP_NOFS;
+
+ if (IS_ENCRYPTED(inode)) {
+ pages[index] = fscrypt_encrypt_pagecache_blocks(page,
+ PAGE_SIZE,
+ 0,
+ gfp_flags);
+ if (IS_ERR(pages[index])) {
+ if (PTR_ERR(pages[index]) == -EINVAL) {
+ pr_err_client(cl, "inode->i_blkbits=%hhu\n",
+ inode->i_blkbits);
+ }
+
+ /* better not fail on first page! */
+ BUG_ON(ceph_wbc->locked_pages == 0);
+
+ pages[index] = NULL;
+ return PTR_ERR(pages[index]);
+ }
+ } else {
+ pages[index] = page;
+ }
+
+ ceph_wbc->locked_pages++;
+
+ return 0;
+}
+
+static
+int ceph_process_folio_batch(struct address_space *mapping,
+ struct writeback_control *wbc,
+ struct ceph_writeback_ctl *ceph_wbc)
+{
+ struct inode *inode = mapping->host;
+ struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
+ struct ceph_client *cl = fsc->client;
+ struct folio *folio = NULL;
+ struct page *page = NULL;
+ unsigned i;
+ int rc = 0;
+
+ for (i = 0; can_next_page_be_processed(ceph_wbc, i); i++) {
+ folio = ceph_wbc->fbatch.folios[i];
+
+ if (!folio)
+ continue;
+
+ page = &folio->page;
+
+ doutc(cl, "? %p idx %lu, folio_test_writeback %#x, "
+ "folio_test_dirty %#x, folio_test_locked %#x\n",
+ page, page->index, folio_test_writeback(folio),
+ folio_test_dirty(folio),
+ folio_test_locked(folio));
+
+ if (folio_test_writeback(folio) ||
+ folio_test_private_2(folio) /* [DEPRECATED] */) {
+ doutc(cl, "waiting on writeback %p\n", folio);
+ folio_wait_writeback(folio);
+ folio_wait_private_2(folio); /* [DEPRECATED] */
+ continue;
+ }
+
+ if (ceph_wbc->locked_pages == 0)
+ lock_page(page); /* first page */
+ else if (!trylock_page(page))
+ break;
+
+ rc = ceph_check_page_before_write(mapping, wbc,
+ ceph_wbc, folio);
+ if (rc == -ENODATA) {
+ rc = 0;
+ unlock_page(page);
+ ceph_wbc->fbatch.folios[i] = NULL;
+ continue;
+ } else if (rc == -E2BIG) {
+ rc = 0;
+ unlock_page(page);
+ ceph_wbc->fbatch.folios[i] = NULL;
+ break;
+ }
+
+ if (!clear_page_dirty_for_io(page)) {
+ doutc(cl, "%p !clear_page_dirty_for_io\n", page);
+ unlock_page(page);
+ ceph_wbc->fbatch.folios[i] = NULL;
+ continue;
+ }
+
+ /*
+ * We have something to write. If this is
+ * the first locked page this time through,
+ * calculate max possible write size and
+ * allocate a page array
+ */
+ if (ceph_wbc->locked_pages == 0) {
+ ceph_allocate_page_array(mapping, ceph_wbc, page);
+ } else if (!is_page_index_contiguous(ceph_wbc, page)) {
+ if (is_num_ops_too_big(ceph_wbc)) {
+ redirty_page_for_writepage(wbc, page);
+ unlock_page(page);
+ break;
+ }
+
+ ceph_wbc->num_ops++;
+ ceph_wbc->offset = (u64)page_offset(page);
+ ceph_wbc->len = 0;
+ }
+
+ /* note position of first page in fbatch */
+ doutc(cl, "%llx.%llx will write page %p idx %lu\n",
+ ceph_vinop(inode), page, page->index);
+
+ fsc->write_congested = is_write_congestion_happened(fsc);
+
+ rc = ceph_move_dirty_page_in_page_array(mapping, wbc,
+ ceph_wbc, page);
+ if (rc) {
+ redirty_page_for_writepage(wbc, page);
+ unlock_page(page);
+ break;
+ }
+
+ ceph_wbc->fbatch.folios[i] = NULL;
+ ceph_wbc->len += thp_size(page);
+ }
+
+ ceph_wbc->processed_in_fbatch = i;
+
+ return rc;
+}
+
/*
* initiate async writeback
*/
@@ -1045,7 +1394,6 @@ static int ceph_writepages_start(struct address_space *mapping,
struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
struct ceph_client *cl = fsc->client;
struct ceph_vino vino = ceph_vino(inode);
- struct ceph_snap_context *pgsnapc;
struct ceph_writeback_ctl ceph_wbc;
struct ceph_osd_request *req = NULL;
int rc = 0;
@@ -1059,235 +1407,49 @@ static int ceph_writepages_start(struct address_space *mapping,
wbc->sync_mode == WB_SYNC_NONE ? "NONE" :
(wbc->sync_mode == WB_SYNC_ALL ? "ALL" : "HOLD"));
- if (ceph_inode_is_shutdown(inode)) {
- if (ci->i_wrbuffer_ref > 0) {
- pr_warn_ratelimited_client(cl,
- "%llx.%llx %lld forced umount\n",
- ceph_vinop(inode), ceph_ino(inode));
- }
- mapping_set_error(mapping, -EIO);
- return -EIO; /* we're in a forced umount, don't write! */
+ if (is_forced_umount(mapping)) {
+ /* we're in a forced umount, don't write! */
+ return -EIO;
}
ceph_init_writeback_ctl(mapping, wbc, &ceph_wbc);
retry:
- /* find oldest snap context with dirty data */
- ceph_wbc.snapc = get_oldest_context(inode, &ceph_wbc, NULL);
- if (!ceph_wbc.snapc) {
+ rc = ceph_define_writeback_range(mapping, wbc, &ceph_wbc);
+ if (rc == -ENODATA) {
/* hmm, why does writepages get called when there
is no dirty data? */
- doutc(cl, " no snap context with dirty data?\n");
+ rc = 0;
goto out;
}
- doutc(cl, " oldest snapc is %p seq %lld (%d snaps)\n",
- ceph_wbc.snapc, ceph_wbc.snapc->seq,
- ceph_wbc.snapc->num_snaps);
-
- ceph_wbc.should_loop = false;
- if (ceph_wbc.head_snapc && ceph_wbc.snapc != ceph_wbc.last_snapc) {
- /* where to start/end? */
- if (wbc->range_cyclic) {
- ceph_wbc.index = ceph_wbc.start_index;
- ceph_wbc.end = -1;
- if (ceph_wbc.index > 0)
- ceph_wbc.should_loop = true;
- doutc(cl, " cyclic, start at %lu\n", ceph_wbc.index);
- } else {
- ceph_wbc.index = wbc->range_start >> PAGE_SHIFT;
- ceph_wbc.end = wbc->range_end >> PAGE_SHIFT;
- if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
- ceph_wbc.range_whole = true;
- doutc(cl, " not cyclic, %lu to %lu\n",
- ceph_wbc.index, ceph_wbc.end);
- }
- } else if (!ceph_wbc.head_snapc) {
- /* Do not respect wbc->range_{start,end}. Dirty pages
- * in that range can be associated with newer snapc.
- * They are not writeable until we write all dirty pages
- * associated with 'snapc' get written */
- if (ceph_wbc.index > 0)
- ceph_wbc.should_loop = true;
- doutc(cl, " non-head snapc, range whole\n");
- }
if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
tag_pages_for_writeback(mapping, ceph_wbc.index, ceph_wbc.end);
- ceph_put_snap_context(ceph_wbc.last_snapc);
- ceph_wbc.last_snapc = ceph_wbc.snapc;
-
- while (!ceph_wbc.done && ceph_wbc.index <= ceph_wbc.end) {
+ while (!has_writeback_done(&ceph_wbc)) {
unsigned i;
struct page *page;
+ ceph_wbc.locked_pages = 0;
ceph_wbc.max_pages = ceph_wbc.wsize >> PAGE_SHIFT;
get_more_pages:
+ ceph_folio_batch_reinit(&ceph_wbc);
+
ceph_wbc.nr_folios = filemap_get_folios_tag(mapping,
&ceph_wbc.index,
ceph_wbc.end,
ceph_wbc.tag,
&ceph_wbc.fbatch);
- doutc(cl, "pagevec_lookup_range_tag got %d\n",
- ceph_wbc.nr_folios);
+ doutc(cl, "pagevec_lookup_range_tag for tag %#x got %d\n",
+ ceph_wbc.tag, ceph_wbc.nr_folios);
+
if (!ceph_wbc.nr_folios && !ceph_wbc.locked_pages)
break;
- for (i = 0; i < ceph_wbc.nr_folios &&
- ceph_wbc.locked_pages < ceph_wbc.max_pages; i++) {
- struct folio *folio = ceph_wbc.fbatch.folios[i];
-
- page = &folio->page;
- doutc(cl, "? %p idx %lu\n", page, page->index);
- if (ceph_wbc.locked_pages == 0)
- lock_page(page); /* first page */
- else if (!trylock_page(page))
- break;
-
- /* only dirty pages, or our accounting breaks */
- if (unlikely(!PageDirty(page)) ||
- unlikely(page->mapping != mapping)) {
- doutc(cl, "!dirty or !mapping %p\n", page);
- unlock_page(page);
- continue;
- }
- /* only if matching snap context */
- pgsnapc = page_snap_context(page);
- if (pgsnapc != ceph_wbc.snapc) {
- doutc(cl, "page snapc %p %lld != oldest %p %lld\n",
- pgsnapc, pgsnapc->seq,
- ceph_wbc.snapc, ceph_wbc.snapc->seq);
- if (!ceph_wbc.should_loop &&
- !ceph_wbc.head_snapc &&
- wbc->sync_mode != WB_SYNC_NONE)
- ceph_wbc.should_loop = true;
- unlock_page(page);
- continue;
- }
- if (page_offset(page) >= ceph_wbc.i_size) {
- doutc(cl, "folio at %lu beyond eof %llu\n",
- folio->index, ceph_wbc.i_size);
- if ((ceph_wbc.size_stable ||
- folio_pos(folio) >= i_size_read(inode)) &&
- folio_clear_dirty_for_io(folio))
- folio_invalidate(folio, 0,
- folio_size(folio));
- folio_unlock(folio);
- continue;
- }
- if (ceph_wbc.strip_unit_end &&
- (page->index > ceph_wbc.strip_unit_end)) {
- doutc(cl, "end of strip unit %p\n", page);
- unlock_page(page);
- break;
- }
- if (folio_test_writeback(folio) ||
- folio_test_private_2(folio) /* [DEPRECATED] */) {
- if (wbc->sync_mode == WB_SYNC_NONE) {
- doutc(cl, "%p under writeback\n", folio);
- folio_unlock(folio);
- continue;
- }
- doutc(cl, "waiting on writeback %p\n", folio);
- folio_wait_writeback(folio);
- folio_wait_private_2(folio); /* [DEPRECATED] */
- }
-
- if (!clear_page_dirty_for_io(page)) {
- doutc(cl, "%p !clear_page_dirty_for_io\n", page);
- unlock_page(page);
- continue;
- }
-
- /*
- * We have something to write. If this is
- * the first locked page this time through,
- * calculate max possinle write size and
- * allocate a page array
- */
- if (ceph_wbc.locked_pages == 0) {
- u64 objnum;
- u64 objoff;
- u32 xlen;
-
- /* prepare async write request */
- ceph_wbc.offset = (u64)page_offset(page);
- ceph_calc_file_object_mapping(&ci->i_layout,
- ceph_wbc.offset,
- ceph_wbc.wsize,
- &objnum, &objoff,
- &xlen);
- ceph_wbc.len = xlen;
-
- ceph_wbc.num_ops = 1;
- ceph_wbc.strip_unit_end = page->index +
- ((ceph_wbc.len - 1) >> PAGE_SHIFT);
-
- BUG_ON(ceph_wbc.pages);
- ceph_wbc.max_pages =
- calc_pages_for(0, (u64)ceph_wbc.len);
- ceph_wbc.pages = kmalloc_array(ceph_wbc.max_pages,
- sizeof(*ceph_wbc.pages),
- GFP_NOFS);
- if (!ceph_wbc.pages) {
- ceph_wbc.from_pool = true;
- ceph_wbc.pages =
- mempool_alloc(ceph_wb_pagevec_pool,
- GFP_NOFS);
- BUG_ON(!ceph_wbc.pages);
- }
- ceph_wbc.len = 0;
- } else if (page->index !=
- (ceph_wbc.offset + ceph_wbc.len) >> PAGE_SHIFT) {
- if (ceph_wbc.num_ops >=
- (ceph_wbc.from_pool ? CEPH_OSD_SLAB_OPS :
- CEPH_OSD_MAX_OPS)) {
- redirty_page_for_writepage(wbc, page);
- unlock_page(page);
- break;
- }
-
- ceph_wbc.num_ops++;
- ceph_wbc.offset = (u64)page_offset(page);
- ceph_wbc.len = 0;
- }
-
- /* note position of first page in fbatch */
- doutc(cl, "%llx.%llx will write page %p idx %lu\n",
- ceph_vinop(inode), page, page->index);
-
- if (atomic_long_inc_return(&fsc->writeback_count) >
- CONGESTION_ON_THRESH(
- fsc->mount_options->congestion_kb))
- fsc->write_congested = true;
-
- if (IS_ENCRYPTED(inode)) {
- ceph_wbc.pages[ceph_wbc.locked_pages] =
- fscrypt_encrypt_pagecache_blocks(page,
- PAGE_SIZE, 0,
- ceph_wbc.locked_pages ?
- GFP_NOWAIT : GFP_NOFS);
- if (IS_ERR(ceph_wbc.pages[ceph_wbc.locked_pages])) {
- if (PTR_ERR(ceph_wbc.pages[ceph_wbc.locked_pages]) == -EINVAL)
- pr_err_client(cl,
- "inode->i_blkbits=%hhu\n",
- inode->i_blkbits);
- /* better not fail on first page! */
- BUG_ON(ceph_wbc.locked_pages == 0);
- ceph_wbc.pages[ceph_wbc.locked_pages] = NULL;
- redirty_page_for_writepage(wbc, page);
- unlock_page(page);
- break;
- }
- ++ceph_wbc.locked_pages;
- } else {
- ceph_wbc.pages[ceph_wbc.locked_pages++] = page;
- }
-
- ceph_wbc.fbatch.folios[i] = NULL;
- ceph_wbc.len += thp_size(page);
- }
+ rc = ceph_process_folio_batch(mapping, wbc, &ceph_wbc);
+ if (rc)
+ goto release_folios;
/* did we get anything? */
if (!ceph_wbc.locked_pages)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 284/869] ceph: Remove uses of page from ceph_process_folio_batch()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (282 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 283/869] ceph: introduce ceph_process_folio_batch() method Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 285/869] ceph: fix num_ops off-by-one when crypto allocation fails Greg Kroah-Hartman
` (585 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Matthew Wilcox (Oracle),
Viacheslav Dubeyko, Christian Brauner, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Wilcox (Oracle) <willy@infradead.org>
[ Upstream commit a55cf4fd8faea83dbb1ac7a3cb708193e33aa7a1 ]
Remove uses of page->index and deprecated page APIs. Saves a lot of
hidden calls to compound_head().
Also convert is_page_index_contiguous() to is_folio_index_contiguous()
and make its arguments const.
Signed-off-by: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Link: https://lore.kernel.org/r/20250217185119.430193-8-willy@infradead.org
Tested-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: a0d9555bf9ea ("ceph: fix num_ops off-by-one when crypto allocation fails")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ceph/addr.c | 47 ++++++++++++++++++++++-------------------------
1 file changed, 22 insertions(+), 25 deletions(-)
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 36aa5cf8300af..4ba991efb1ca3 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -1220,10 +1220,10 @@ void ceph_allocate_page_array(struct address_space *mapping,
}
static inline
-bool is_page_index_contiguous(struct ceph_writeback_ctl *ceph_wbc,
- struct page *page)
+bool is_folio_index_contiguous(const struct ceph_writeback_ctl *ceph_wbc,
+ const struct folio *folio)
{
- return page->index == (ceph_wbc->offset + ceph_wbc->len) >> PAGE_SHIFT;
+ return folio->index == (ceph_wbc->offset + ceph_wbc->len) >> PAGE_SHIFT;
}
static inline
@@ -1288,7 +1288,6 @@ int ceph_process_folio_batch(struct address_space *mapping,
struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
struct ceph_client *cl = fsc->client;
struct folio *folio = NULL;
- struct page *page = NULL;
unsigned i;
int rc = 0;
@@ -1298,11 +1297,9 @@ int ceph_process_folio_batch(struct address_space *mapping,
if (!folio)
continue;
- page = &folio->page;
-
doutc(cl, "? %p idx %lu, folio_test_writeback %#x, "
"folio_test_dirty %#x, folio_test_locked %#x\n",
- page, page->index, folio_test_writeback(folio),
+ folio, folio->index, folio_test_writeback(folio),
folio_test_dirty(folio),
folio_test_locked(folio));
@@ -1315,27 +1312,27 @@ int ceph_process_folio_batch(struct address_space *mapping,
}
if (ceph_wbc->locked_pages == 0)
- lock_page(page); /* first page */
- else if (!trylock_page(page))
+ folio_lock(folio);
+ else if (!folio_trylock(folio))
break;
rc = ceph_check_page_before_write(mapping, wbc,
ceph_wbc, folio);
if (rc == -ENODATA) {
rc = 0;
- unlock_page(page);
+ folio_unlock(folio);
ceph_wbc->fbatch.folios[i] = NULL;
continue;
} else if (rc == -E2BIG) {
rc = 0;
- unlock_page(page);
+ folio_unlock(folio);
ceph_wbc->fbatch.folios[i] = NULL;
break;
}
- if (!clear_page_dirty_for_io(page)) {
- doutc(cl, "%p !clear_page_dirty_for_io\n", page);
- unlock_page(page);
+ if (!folio_clear_dirty_for_io(folio)) {
+ doutc(cl, "%p !folio_clear_dirty_for_io\n", folio);
+ folio_unlock(folio);
ceph_wbc->fbatch.folios[i] = NULL;
continue;
}
@@ -1347,35 +1344,35 @@ int ceph_process_folio_batch(struct address_space *mapping,
* allocate a page array
*/
if (ceph_wbc->locked_pages == 0) {
- ceph_allocate_page_array(mapping, ceph_wbc, page);
- } else if (!is_page_index_contiguous(ceph_wbc, page)) {
+ ceph_allocate_page_array(mapping, ceph_wbc, &folio->page);
+ } else if (!is_folio_index_contiguous(ceph_wbc, folio)) {
if (is_num_ops_too_big(ceph_wbc)) {
- redirty_page_for_writepage(wbc, page);
- unlock_page(page);
+ folio_redirty_for_writepage(wbc, folio);
+ folio_unlock(folio);
break;
}
ceph_wbc->num_ops++;
- ceph_wbc->offset = (u64)page_offset(page);
+ ceph_wbc->offset = (u64)folio_pos(folio);
ceph_wbc->len = 0;
}
/* note position of first page in fbatch */
- doutc(cl, "%llx.%llx will write page %p idx %lu\n",
- ceph_vinop(inode), page, page->index);
+ doutc(cl, "%llx.%llx will write folio %p idx %lu\n",
+ ceph_vinop(inode), folio, folio->index);
fsc->write_congested = is_write_congestion_happened(fsc);
rc = ceph_move_dirty_page_in_page_array(mapping, wbc,
- ceph_wbc, page);
+ ceph_wbc, &folio->page);
if (rc) {
- redirty_page_for_writepage(wbc, page);
- unlock_page(page);
+ folio_redirty_for_writepage(wbc, folio);
+ folio_unlock(folio);
break;
}
ceph_wbc->fbatch.folios[i] = NULL;
- ceph_wbc->len += thp_size(page);
+ ceph_wbc->len += folio_size(folio);
}
ceph_wbc->processed_in_fbatch = i;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 285/869] ceph: fix num_ops off-by-one when crypto allocation fails
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (283 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 284/869] ceph: Remove uses of page from ceph_process_folio_batch() Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 286/869] KVM: nSVM: Avoid clearing VMCB_LBR in vmcb12 Greg Kroah-Hartman
` (584 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sam Edwards, Viacheslav Dubeyko,
Ilya Dryomov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sam Edwards <cfsworks@gmail.com>
[ Upstream commit a0d9555bf9eaeba34fe6b6bb86f442fe08ba3842 ]
move_dirty_folio_in_page_array() may fail if the file is encrypted, the
dirty folio is not the first in the batch, and it fails to allocate a
bounce buffer to hold the ciphertext. When that happens,
ceph_process_folio_batch() simply redirties the folio and flushes the
current batch -- it can retry that folio in a future batch.
However, if this failed folio is not contiguous with the last folio that
did make it into the batch, then ceph_process_folio_batch() has already
incremented `ceph_wbc->num_ops`; because it doesn't follow through and
add the discontiguous folio to the array, ceph_submit_write() -- which
expects that `ceph_wbc->num_ops` accurately reflects the number of
contiguous ranges (and therefore the required number of "write extent"
ops) in the writeback -- will panic the kernel:
BUG_ON(ceph_wbc->op_idx + 1 != req->r_num_ops);
This issue can be reproduced on affected kernels by writing to
fscrypt-enabled CephFS file(s) with a 4KiB-written/4KiB-skipped/repeat
pattern (total filesize should not matter) and gradually increasing the
system's memory pressure until a bounce buffer allocation fails.
Fix this crash by decrementing `ceph_wbc->num_ops` back to the correct
value when move_dirty_folio_in_page_array() fails, but the folio already
started counting a new (i.e. still-empty) extent.
The defect corrected by this patch has existed since 2022 (see first
`Fixes:`), but another bug blocked multi-folio encrypted writeback until
recently (see second `Fixes:`). The second commit made it into 6.18.16,
6.19.6, and 7.0-rc1, unmasking the panic in those versions. This patch
therefore fixes a regression (panic) introduced by cac190c7674f.
Cc: stable@vger.kernel.org
Fixes: d55207717ded ("ceph: add encryption support to writepage and writepages")
Fixes: cac190c7674f ("ceph: fix write storm on fscrypted files")
Signed-off-by: Sam Edwards <CFSworks@gmail.com>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ceph/addr.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 4ba991efb1ca3..355555e313102 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -1366,6 +1366,10 @@ int ceph_process_folio_batch(struct address_space *mapping,
rc = ceph_move_dirty_page_in_page_array(mapping, wbc,
ceph_wbc, &folio->page);
if (rc) {
+ /* Did we just begin a new contiguous op? Nevermind! */
+ if (ceph_wbc->len == 0)
+ ceph_wbc->num_ops--;
+
folio_redirty_for_writepage(wbc, folio);
folio_unlock(folio);
break;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 286/869] KVM: nSVM: Avoid clearing VMCB_LBR in vmcb12
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (284 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 285/869] ceph: fix num_ops off-by-one when crypto allocation fails Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 287/869] dm-verity-fec: fix reading parity bytes split across blocks (take 3) Greg Kroah-Hartman
` (583 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yosry Ahmed, Sean Christopherson,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yosry Ahmed <yosry@kernel.org>
[ Upstream commit b53ab5167a81537777ac780bbd93d32613aa3bda ]
svm_copy_lbrs() always marks VMCB_LBR dirty in the destination VMCB.
However, nested_svm_vmexit() uses it to copy LBRs to vmcb12, and
clearing clean bits in vmcb12 is not architecturally defined.
Move vmcb_mark_dirty() to callers and drop it for vmcb12.
This also facilitates incoming refactoring that does not pass the entire
VMCB to svm_copy_lbrs().
Fixes: d20c796ca370 ("KVM: x86: nSVM: implement nested LBR virtualization")
Cc: stable@vger.kernel.org
Signed-off-by: Yosry Ahmed <yosry@kernel.org>
Link: https://patch.msgid.link/20260303003421.2185681-2-yosry@kernel.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/svm/nested.c | 7 +++++--
arch/x86/kvm/svm/svm.c | 2 --
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index 2f98a90537d28..636f0354fa815 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -621,6 +621,7 @@ static void nested_vmcb02_prepare_save(struct vcpu_svm *svm, struct vmcb *vmcb12
} else {
svm_copy_lbrs(vmcb02, vmcb01);
}
+ vmcb_mark_dirty(vmcb02, VMCB_LBR);
svm_update_lbrv(&svm->vcpu);
}
@@ -1091,10 +1092,12 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
if (unlikely(guest_cpu_cap_has(vcpu, X86_FEATURE_LBRV) &&
- (svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK)))
+ (svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK))) {
svm_copy_lbrs(vmcb12, vmcb02);
- else
+ } else {
svm_copy_lbrs(vmcb01, vmcb02);
+ vmcb_mark_dirty(vmcb01, VMCB_LBR);
+ }
svm_update_lbrv(vcpu);
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 3e2af127a4e27..4c3891fb789a5 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -990,8 +990,6 @@ void svm_copy_lbrs(struct vmcb *to_vmcb, struct vmcb *from_vmcb)
to_vmcb->save.br_to = from_vmcb->save.br_to;
to_vmcb->save.last_excp_from = from_vmcb->save.last_excp_from;
to_vmcb->save.last_excp_to = from_vmcb->save.last_excp_to;
-
- vmcb_mark_dirty(to_vmcb, VMCB_LBR);
}
static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 287/869] dm-verity-fec: fix reading parity bytes split across blocks (take 3)
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (285 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 286/869] KVM: nSVM: Avoid clearing VMCB_LBR in vmcb12 Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 288/869] spi: microchip-core-qspi: Support per spi-mem operation frequency switches Greg Kroah-Hartman
` (582 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Biggers, Mikulas Patocka,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <ebiggers@kernel.org>
[ Upstream commit 430a05cb926f6bdf53e81460a2c3a553257f3f61 ]
fec_decode_bufs() assumes that the parity bytes of the first RS codeword
it decodes are never split across parity blocks.
This assumption is false. Consider v->fec->block_size == 4096 &&
v->fec->roots == 17 && fio->nbufs == 1, for example. In that case, each
call to fec_decode_bufs() consumes v->fec->roots * (fio->nbufs <<
DM_VERITY_FEC_BUF_RS_BITS) = 272 parity bytes.
Considering that the parity data for each message block starts on a
block boundary, the byte alignment in the parity data will iterate
through 272*i mod 4096 until the 3 parity blocks have been consumed. On
the 16th call (i=15), the alignment will be 4080 bytes into the first
block. Only 16 bytes remain in that block, but 17 parity bytes will be
needed. The code reads out-of-bounds from the parity block buffer.
Fortunately this doesn't normally happen, since it can occur only for
certain non-default values of fec_roots *and* when the maximum number of
buffers couldn't be allocated due to low memory. For example with
block_size=4096 only the following cases are affected:
fec_roots=17: nbufs in [1, 3, 5, 15]
fec_roots=19: nbufs in [1, 229]
fec_roots=21: nbufs in [1, 3, 5, 13, 15, 39, 65, 195]
fec_roots=23: nbufs in [1, 89]
Regardless, fix it by refactoring how the parity blocks are read.
Fixes: 6df90c02bae4 ("dm-verity FEC: Fix RS FEC repair for roots unaligned to block size (take 2)")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/dm-verity-fec.c | 98 +++++++++++++++++---------------------
1 file changed, 44 insertions(+), 54 deletions(-)
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
index 9e9ff481d5a0a..56813d02d5465 100644
--- a/drivers/md/dm-verity-fec.c
+++ b/drivers/md/dm-verity-fec.c
@@ -55,36 +55,6 @@ static int fec_decode_rs8(struct dm_verity *v, struct dm_verity_fec_io *fio,
fio->erasures, 0, NULL);
}
-/*
- * Read error-correcting codes for the requested RS block. Returns a pointer
- * to the data block. Caller is responsible for releasing buf.
- */
-static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index,
- unsigned int *offset, unsigned int par_buf_offset,
- struct dm_buffer **buf, unsigned short ioprio)
-{
- u64 position, block, rem;
- u8 *res;
-
- /* We have already part of parity bytes read, skip to the next block */
- if (par_buf_offset)
- index++;
-
- position = (index + rsb) * v->fec->roots;
- block = div64_u64_rem(position, v->fec->io_size, &rem);
- *offset = par_buf_offset ? 0 : (unsigned int)rem;
-
- res = dm_bufio_read_with_ioprio(v->fec->bufio, block, buf, ioprio);
- if (IS_ERR(res)) {
- DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
- v->data_dev->name, (unsigned long long)rsb,
- (unsigned long long)block, PTR_ERR(res));
- *buf = NULL;
- }
-
- return res;
-}
-
/* Loop over each preallocated buffer slot. */
#define fec_for_each_prealloc_buffer(__i) \
for (__i = 0; __i < DM_VERITY_FEC_BUF_PREALLOC; __i++)
@@ -132,14 +102,28 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io,
{
int r, corrected = 0, res;
struct dm_buffer *buf;
- unsigned int n, i, offset, par_buf_offset = 0;
+ unsigned int n, i, j, parity_pos, to_copy;
u8 *par, *block, par_buf[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN];
+ u64 parity_block;
struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
- par = fec_read_parity(v, rsb, block_offset, &offset,
- par_buf_offset, &buf, bio_prio(bio));
- if (IS_ERR(par))
+ /*
+ * Compute the index of the first parity block that will be needed and
+ * the starting position in that block. Then read that block.
+ *
+ * io_size is always a power of 2, but roots might not be. Note that
+ * when it's not, a codeword's parity bytes can span a block boundary.
+ */
+ parity_block = (rsb + block_offset) * v->fec->roots;
+ parity_pos = parity_block & (v->fec->io_size - 1);
+ parity_block >>= v->data_dev_block_bits;
+ par = dm_bufio_read_with_ioprio(v->fec->bufio, parity_block, &buf,
+ bio_prio(bio));
+ if (IS_ERR(par)) {
+ DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
+ v->data_dev->name, rsb, parity_block, PTR_ERR(par));
return PTR_ERR(par);
+ }
/*
* Decode the RS blocks we have in bufs. Each RS block results in
@@ -147,7 +131,32 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io,
*/
fec_for_each_buffer_rs_block(fio, n, i) {
block = fec_buffer_rs_block(v, fio, n, i);
- memcpy(&par_buf[par_buf_offset], &par[offset], v->fec->roots - par_buf_offset);
+
+ /*
+ * Copy the next 'roots' parity bytes to 'par_buf', reading
+ * another parity block if needed.
+ */
+ to_copy = min(v->fec->io_size - parity_pos, v->fec->roots);
+ for (j = 0; j < to_copy; j++)
+ par_buf[j] = par[parity_pos++];
+ if (to_copy < v->fec->roots) {
+ parity_block++;
+ parity_pos = 0;
+
+ dm_bufio_release(buf);
+ par = dm_bufio_read_with_ioprio(v->fec->bufio,
+ parity_block, &buf,
+ bio_prio(bio));
+ if (IS_ERR(par)) {
+ DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
+ v->data_dev->name, rsb, parity_block,
+ PTR_ERR(par));
+ return PTR_ERR(par);
+ }
+ for (; j < v->fec->roots; j++)
+ par_buf[j] = par[parity_pos++];
+ }
+
res = fec_decode_rs8(v, fio, block, par_buf, neras);
if (res < 0) {
r = res;
@@ -160,25 +169,6 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io,
block_offset++;
if (block_offset >= 1 << v->data_dev_block_bits)
goto done;
-
- /* Read the next block when we run out of parity bytes */
- offset += (v->fec->roots - par_buf_offset);
- /* Check if parity bytes are split between blocks */
- if (offset < v->fec->io_size && (offset + v->fec->roots) > v->fec->io_size) {
- par_buf_offset = v->fec->io_size - offset;
- memcpy(par_buf, &par[offset], par_buf_offset);
- offset += par_buf_offset;
- } else
- par_buf_offset = 0;
-
- if (offset >= v->fec->io_size) {
- dm_bufio_release(buf);
-
- par = fec_read_parity(v, rsb, block_offset, &offset,
- par_buf_offset, &buf, bio_prio(bio));
- if (IS_ERR(par))
- return PTR_ERR(par);
- }
}
done:
r = corrected;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 288/869] spi: microchip-core-qspi: Support per spi-mem operation frequency switches
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (286 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 287/869] dm-verity-fec: fix reading parity bytes split across blocks (take 3) Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 289/869] spi: microchip-core-qspi: set min_speed_hz during probe Greg Kroah-Hartman
` (581 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Conor Dooley, Daire McNamara,
Miquel Raynal, Mark Brown, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miquel Raynal <miquel.raynal@bootlin.com>
[ Upstream commit 13529647743d906ed3cf991f1d77727e7ff1fb6f ]
Every ->exec_op() call correctly configures the spi bus speed to the
maximum allowed frequency for the memory using the constant spi default
parameter. Since we can now have per-operation constraints, let's use
the value that comes from the spi-mem operation structure instead. In
case there is no specific limitation for this operation, the default spi
device value will be given anyway.
This controller however performed a frequency check, which is also
observed during the ->check_op() phase.
The per-operation frequency capability is thus advertised to the spi-mem
core.
Cc: Conor Dooley <conor.dooley@microchip.com>
Cc: Daire McNamara <daire.mcnamara@microchip.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://patch.msgid.link/20241224-winbond-6-11-rc1-quad-support-v2-9-ad218dbc406f@bootlin.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Stable-dep-of: 7672749e1496 ("spi: microchip-core-qspi: control built-in cs manually")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/spi/spi-microchip-core-qspi.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c
index 6aba933fcc0b3..bda9a43dbf2ef 100644
--- a/drivers/spi/spi-microchip-core-qspi.c
+++ b/drivers/spi/spi-microchip-core-qspi.c
@@ -265,7 +265,8 @@ static irqreturn_t mchp_coreqspi_isr(int irq, void *dev_id)
return ret;
}
-static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_device *spi)
+static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_device *spi,
+ const struct spi_mem_op *op)
{
unsigned long clk_hz;
u32 control, baud_rate_val = 0;
@@ -274,11 +275,11 @@ static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_devi
if (!clk_hz)
return -EINVAL;
- baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * spi->max_speed_hz);
+ baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * op->max_freq);
if (baud_rate_val > MAX_DIVIDER || baud_rate_val < MIN_DIVIDER) {
dev_err(&spi->dev,
"could not configure the clock for spi clock %d Hz & system clock %ld Hz\n",
- spi->max_speed_hz, clk_hz);
+ op->max_freq, clk_hz);
return -EINVAL;
}
@@ -399,7 +400,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
if (err)
goto error;
- err = mchp_coreqspi_setup_clock(qspi, mem->spi);
+ err = mchp_coreqspi_setup_clock(qspi, mem->spi, op);
if (err)
goto error;
@@ -457,6 +458,10 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
static bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
+ struct mchp_coreqspi *qspi = spi_controller_get_devdata(mem->spi->controller);
+ unsigned long clk_hz;
+ u32 baud_rate_val;
+
if (!spi_mem_default_supports_op(mem, op))
return false;
@@ -479,6 +484,14 @@ static bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_
return false;
}
+ clk_hz = clk_get_rate(qspi->clk);
+ if (!clk_hz)
+ return false;
+
+ baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * op->max_freq);
+ if (baud_rate_val > MAX_DIVIDER || baud_rate_val < MIN_DIVIDER)
+ return false;
+
return true;
}
@@ -498,6 +511,10 @@ static const struct spi_controller_mem_ops mchp_coreqspi_mem_ops = {
.exec_op = mchp_coreqspi_exec_op,
};
+static const struct spi_controller_mem_caps mchp_coreqspi_mem_caps = {
+ .per_op_freq = true,
+};
+
static int mchp_coreqspi_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
@@ -540,6 +557,7 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->mem_ops = &mchp_coreqspi_mem_ops;
+ ctlr->mem_caps = &mchp_coreqspi_mem_caps;
ctlr->setup = mchp_coreqspi_setup_op;
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD |
SPI_TX_DUAL | SPI_TX_QUAD;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 289/869] spi: microchip-core-qspi: set min_speed_hz during probe
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (287 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 288/869] spi: microchip-core-qspi: Support per spi-mem operation frequency switches Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 290/869] spi: microchip-core-qspi: remove unused param from mchp_coreqspi_write_op() Greg Kroah-Hartman
` (580 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Conor Dooley, Mark Brown,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Conor Dooley <conor.dooley@microchip.com>
[ Upstream commit 76f03ce1c6f22805ecf689b1f3ecfb56582eddd5 ]
The controller's minimum possible bus clock is 1/30 the rate of the
input clock. Naively set the minimum bus clock speed the controller
is capable of during probe, assuming that the rate will never reduce
further.
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Link: https://patch.msgid.link/20250620-drained-widen-ac311bd5f172@spud
Signed-off-by: Mark Brown <broonie@kernel.org>
Stable-dep-of: 7672749e1496 ("spi: microchip-core-qspi: control built-in cs manually")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/spi/spi-microchip-core-qspi.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c
index bda9a43dbf2ef..8bce9aeb259a4 100644
--- a/drivers/spi/spi-microchip-core-qspi.c
+++ b/drivers/spi/spi-microchip-core-qspi.c
@@ -562,6 +562,7 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD |
SPI_TX_DUAL | SPI_TX_QUAD;
ctlr->dev.of_node = np;
+ ctlr->min_speed_hz = clk_get_rate(qspi->clk) / 30;
ret = spi_register_controller(ctlr);
if (ret)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 290/869] spi: microchip-core-qspi: remove unused param from mchp_coreqspi_write_op()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (288 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 289/869] spi: microchip-core-qspi: set min_speed_hz during probe Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 291/869] spi: microchip-core-qspi: control built-in cs manually Greg Kroah-Hartman
` (579 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Conor Dooley, Mark Brown,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Conor Dooley <conor.dooley@microchip.com>
[ Upstream commit 75ca45c472dac206df2ebbc1c0f1f9c3bbdace50 ]
"word" is unused in mchp_coreqspi_write_op(), so delete it.
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Link: https://patch.msgid.link/20250620-starry-excusably-25e6be957d9d@spud
Signed-off-by: Mark Brown <broonie@kernel.org>
Stable-dep-of: 7672749e1496 ("spi: microchip-core-qspi: control built-in cs manually")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/spi/spi-microchip-core-qspi.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c
index 8bce9aeb259a4..1d24aee26dac5 100644
--- a/drivers/spi/spi-microchip-core-qspi.c
+++ b/drivers/spi/spi-microchip-core-qspi.c
@@ -194,7 +194,7 @@ static inline void mchp_coreqspi_read_op(struct mchp_coreqspi *qspi)
}
}
-static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word)
+static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi)
{
u32 control, data;
@@ -415,7 +415,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
qspi->rxbuf = NULL;
qspi->tx_len = op->cmd.nbytes;
qspi->rx_len = 0;
- mchp_coreqspi_write_op(qspi, false);
+ mchp_coreqspi_write_op(qspi);
}
qspi->txbuf = &opaddr[0];
@@ -426,7 +426,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
qspi->rxbuf = NULL;
qspi->tx_len = op->addr.nbytes;
qspi->rx_len = 0;
- mchp_coreqspi_write_op(qspi, false);
+ mchp_coreqspi_write_op(qspi);
}
if (op->data.nbytes) {
@@ -435,7 +435,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
qspi->rxbuf = NULL;
qspi->rx_len = 0;
qspi->tx_len = op->data.nbytes;
- mchp_coreqspi_write_op(qspi, true);
+ mchp_coreqspi_write_op(qspi);
} else {
qspi->txbuf = NULL;
qspi->rxbuf = (u8 *)op->data.buf.in;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 291/869] spi: microchip-core-qspi: control built-in cs manually
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (289 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 290/869] spi: microchip-core-qspi: remove unused param from mchp_coreqspi_write_op() Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 292/869] riscv: kvm: fix vector context allocation leak Greg Kroah-Hartman
` (578 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Conor Dooley, Mark Brown,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Conor Dooley <conor.dooley@microchip.com>
[ Upstream commit 7672749e1496215e8683ce57cf323119033954cf ]
The coreQSPI IP supports only a single chip select, which is
automagically operated by the hardware - set low when the transmit
buffer first gets written to and set high when the number of bytes
written to the TOTALBYTES field of the FRAMES register have been sent on
the bus. Additional devices must use GPIOs for their chip selects.
It was reported to me that if there are two devices attached to this
QSPI controller that the in-built chip select is set low while linux
tries to access the device attached to the GPIO.
This went undetected as the boards that connected multiple devices to
the SPI controller all exclusively used GPIOs for chip selects, not
relying on the built-in chip select at all. It turns out that this was
because the built-in chip select, when controlled automagically, is set
low when active and high when inactive, thereby ruling out its use for
active-high devices or devices that need to transmit with the chip
select disabled.
Modify the driver so that it controls chip select directly, retaining
the behaviour for mem_ops of setting the chip select active for the
entire duration of the transfer in the exec_op callback. For regular
transfers, implement the set_cs callback for the core to use.
As part of this, the existing setup callback, mchp_coreqspi_setup_op(),
is removed. Modifying the CLKIDLE field is not safe to do during
operation when there are multiple devices, so this code is removed
entirely. Setting the MASTER and ENABLE fields is something that can be
done once at probe, it doesn't need to be re-run for each device.
Instead the new setup callback sets the built-in chip select to its
inactive state for active-low devices, as the reset value of the chip
select in software controlled mode is low.
Fixes: 8f9cf02c88528 ("spi: microchip-core-qspi: Add regular transfers")
Fixes: 8596124c4c1bc ("spi: microchip-core-qspi: Add support for microchip fpga qspi controllers")
CC: stable@vger.kernel.org
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Link: https://patch.msgid.link/20260430-hamstring-busload-f941d0347b5e@spud
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/spi/spi-microchip-core-qspi.c | 77 ++++++++++++++++++++++-----
1 file changed, 63 insertions(+), 14 deletions(-)
diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c
index 1d24aee26dac5..bc5e4e4e558a0 100644
--- a/drivers/spi/spi-microchip-core-qspi.c
+++ b/drivers/spi/spi-microchip-core-qspi.c
@@ -74,6 +74,13 @@
#define STATUS_FLAGSX4 BIT(8)
#define STATUS_MASK GENMASK(8, 0)
+/*
+ * QSPI Direct Access register defines
+ */
+#define DIRECT_ACCESS_EN_SSEL BIT(0)
+#define DIRECT_ACCESS_OP_SSEL BIT(1)
+#define DIRECT_ACCESS_OP_SSEL_SHIFT 1
+
#define BYTESUPPER_MASK GENMASK(31, 16)
#define BYTESLOWER_MASK GENMASK(15, 0)
@@ -158,6 +165,38 @@ static int mchp_coreqspi_set_mode(struct mchp_coreqspi *qspi, const struct spi_m
return 0;
}
+static void mchp_coreqspi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct mchp_coreqspi *qspi = spi_controller_get_devdata(spi->controller);
+ u32 val;
+
+ val = readl(qspi->regs + REG_DIRECT_ACCESS);
+
+ val &= ~DIRECT_ACCESS_OP_SSEL;
+ val |= !enable << DIRECT_ACCESS_OP_SSEL_SHIFT;
+
+ writel(val, qspi->regs + REG_DIRECT_ACCESS);
+}
+
+static int mchp_coreqspi_setup(struct spi_device *spi)
+{
+ struct mchp_coreqspi *qspi = spi_controller_get_devdata(spi->controller);
+ u32 val;
+
+ /*
+ * Active low devices need to be specifically set to their inactive
+ * states during probe.
+ */
+ if (spi->mode & SPI_CS_HIGH)
+ return 0;
+
+ val = readl(qspi->regs + REG_DIRECT_ACCESS);
+ val |= DIRECT_ACCESS_OP_SSEL;
+ writel(val, qspi->regs + REG_DIRECT_ACCESS);
+
+ return 0;
+}
+
static inline void mchp_coreqspi_read_op(struct mchp_coreqspi *qspi)
{
u32 control, data;
@@ -299,19 +338,6 @@ static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_devi
return 0;
}
-static int mchp_coreqspi_setup_op(struct spi_device *spi_dev)
-{
- struct spi_controller *ctlr = spi_dev->controller;
- struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
- u32 control = readl_relaxed(qspi->regs + REG_CONTROL);
-
- control |= (CONTROL_MASTER | CONTROL_ENABLE);
- control &= ~CONTROL_CLKIDLE;
- writel_relaxed(control, qspi->regs + REG_CONTROL);
-
- return 0;
-}
-
static inline void mchp_coreqspi_config_op(struct mchp_coreqspi *qspi, const struct spi_mem_op *op)
{
u32 idle_cycles = 0;
@@ -410,6 +436,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
reinit_completion(&qspi->data_completion);
mchp_coreqspi_config_op(qspi, op);
+ mchp_coreqspi_set_cs(mem->spi, true);
if (op->cmd.opcode) {
qspi->txbuf = &opcode;
qspi->rxbuf = NULL;
@@ -450,6 +477,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
err = -ETIMEDOUT;
error:
+ mchp_coreqspi_set_cs(mem->spi, false);
mutex_unlock(&qspi->op_lock);
mchp_coreqspi_disable_ints(qspi);
@@ -522,6 +550,7 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
int ret;
+ u32 num_cs, val;
ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*qspi));
if (!ctlr)
@@ -555,14 +584,34 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)
return ret;
}
+ /*
+ * The IP core only has a single CS, any more have to be provided via
+ * gpios
+ */
+ if (of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs))
+ num_cs = 1;
+
+ ctlr->num_chipselect = num_cs;
+
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->mem_ops = &mchp_coreqspi_mem_ops;
ctlr->mem_caps = &mchp_coreqspi_mem_caps;
- ctlr->setup = mchp_coreqspi_setup_op;
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD |
SPI_TX_DUAL | SPI_TX_QUAD;
ctlr->dev.of_node = np;
ctlr->min_speed_hz = clk_get_rate(qspi->clk) / 30;
+ ctlr->setup = mchp_coreqspi_setup;
+
+ val = readl_relaxed(qspi->regs + REG_CONTROL);
+ val |= (CONTROL_MASTER | CONTROL_ENABLE);
+ writel_relaxed(val, qspi->regs + REG_CONTROL);
+
+ /*
+ * Put cs into software controlled mode
+ */
+ val = readl_relaxed(qspi->regs + REG_DIRECT_ACCESS);
+ val |= DIRECT_ACCESS_EN_SSEL;
+ writel(val, qspi->regs + REG_DIRECT_ACCESS);
ret = spi_register_controller(ctlr);
if (ret)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 292/869] riscv: kvm: fix vector context allocation leak
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (290 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 291/869] spi: microchip-core-qspi: control built-in cs manually Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 293/869] f2fs: fix fsck inconsistency caused by FGGC of node block Greg Kroah-Hartman
` (577 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Osama Abdelkader, Andy Chiu,
Anup Patel, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Osama Abdelkader <osama.abdelkader@gmail.com>
[ Upstream commit b7c958d7c1eb1cb9b2be7b5ee4129fcd66cec978 ]
When the second kzalloc (host_context.vector.datap) fails in
kvm_riscv_vcpu_alloc_vector_context, the first allocation
(guest_context.vector.datap) is leaked. Free it before returning.
Fixes: 0f4b82579716 ("riscv: KVM: Add vector lazy save/restore support")
Cc: stable@vger.kernel.org
Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com>
Reviewed-by: Andy Chiu <andybnac@gmail.com>
Link: https://lore.kernel.org/r/20260316151612.13305-1-osama.abdelkader@gmail.com
Signed-off-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/riscv/kvm/vcpu_vector.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
index 8454c1c3655a4..eaf88c20508a4 100644
--- a/arch/riscv/kvm/vcpu_vector.c
+++ b/arch/riscv/kvm/vcpu_vector.c
@@ -79,8 +79,11 @@ int kvm_riscv_vcpu_alloc_vector_context(struct kvm_vcpu *vcpu,
cntx->vector.vlenb = riscv_v_vsize / 32;
vcpu->arch.host_context.vector.datap = kzalloc(riscv_v_vsize, GFP_KERNEL);
- if (!vcpu->arch.host_context.vector.datap)
+ if (!vcpu->arch.host_context.vector.datap) {
+ kfree(vcpu->arch.guest_context.vector.datap);
+ vcpu->arch.guest_context.vector.datap = NULL;
return -ENOMEM;
+ }
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 293/869] f2fs: fix fsck inconsistency caused by FGGC of node block
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (291 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 292/869] riscv: kvm: fix vector context allocation leak Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 294/869] refcount: provide ops for cases when objects memory can be reused Greg Kroah-Hartman
` (576 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable, Yongpeng Yang, Chao Yu,
Jaegeuk Kim, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongpeng Yang <yangyongpeng@xiaomi.com>
[ Upstream commit c3e238bd1f56993f205ef83889d406dfeaf717a8 ]
During FGGC node block migration, fsck may incorrectly treat the
migrated node block as fsync-written data.
The reproduction scenario:
root@vm:/mnt/f2fs# seq 1 2048 | xargs -n 1 ./test_sync // write inline inode and sync
root@vm:/mnt/f2fs# rm -f 1
root@vm:/mnt/f2fs# sync
root@vm:/mnt/f2fs# f2fs_io gc_range // move data block in sync mode and not write CP
SPO, "fsck --dry-run" find inode has already checkpointed but still
with DENT_BIT_SHIFT set
The root cause is that GC does not clear the dentry mark and fsync mark
during node block migration, leading fsck to misinterpret them as
user-issued fsync writes.
In BGGC mode, node block migration is handled by f2fs_sync_node_pages(),
which guarantees the dentry and fsync marks are cleared before writing.
This patch move the set/clear of the fsync|dentry marks into
__write_node_folio to make the logic clearer, and ensures the
fsync|dentry mark is cleared in FGGC.
Cc: stable@kernel.org
Fixes: da011cc0da8c ("f2fs: move node pages only in victim section during GC")
Signed-off-by: Yongpeng Yang <yangyongpeng@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/node.c | 40 +++++++++++++++++++---------------------
1 file changed, 19 insertions(+), 21 deletions(-)
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 0898ce801f281..9709a212e6a03 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -1643,9 +1643,10 @@ static struct page *last_fsync_dnode(struct f2fs_sb_info *sbi, nid_t ino)
return last_page;
}
-static int __write_node_page(struct page *page, bool atomic, bool *submitted,
- struct writeback_control *wbc, bool do_balance,
- enum iostat_type io_type, unsigned int *seq_id)
+static int __write_node_page(struct page *page, bool atomic, bool do_fsync,
+ bool *submitted, struct writeback_control *wbc,
+ bool do_balance, enum iostat_type io_type,
+ unsigned int *seq_id)
{
struct f2fs_sb_info *sbi = F2FS_P_SB(page);
struct folio *folio = page_folio(page);
@@ -1715,13 +1716,14 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
goto redirty_out;
}
- if (atomic) {
- if (!test_opt(sbi, NOBARRIER))
- fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
- if (IS_INODE(page))
- set_dentry_mark(page,
+ if (atomic && !test_opt(sbi, NOBARRIER))
+ fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
+
+ set_dentry_mark(page, false);
+ set_fsync_mark(page, do_fsync);
+ if (IS_INODE(page) && (atomic || is_fsync_dnode(page)))
+ set_dentry_mark(page,
f2fs_need_dentry_mark(sbi, ino_of_node(page)));
- }
/* should add to global list before clearing PAGECACHE status */
if (f2fs_in_warm_node_list(sbi, page)) {
@@ -1781,7 +1783,7 @@ int f2fs_move_node_page(struct page *node_page, int gc_type)
goto out_page;
}
- if (__write_node_page(node_page, false, NULL,
+ if (__write_node_page(node_page, false, false, NULL,
&wbc, false, FS_GC_NODE_IO, NULL)) {
err = -EAGAIN;
unlock_page(node_page);
@@ -1802,7 +1804,7 @@ int f2fs_move_node_page(struct page *node_page, int gc_type)
static int f2fs_write_node_page(struct page *page,
struct writeback_control *wbc)
{
- return __write_node_page(page, false, NULL, wbc, false,
+ return __write_node_page(page, false, false, NULL, wbc, false,
FS_NODE_IO, NULL);
}
@@ -1836,6 +1838,7 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
for (i = 0; i < nr_folios; i++) {
struct page *page = &fbatch.folios[i]->page;
bool submitted = false;
+ bool do_fsync = false;
if (unlikely(f2fs_cp_error(sbi))) {
f2fs_put_page(last_page, 0);
@@ -1866,11 +1869,8 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
f2fs_wait_on_page_writeback(page, NODE, true, true);
- set_fsync_mark(page, 0);
- set_dentry_mark(page, 0);
-
if (!atomic || page == last_page) {
- set_fsync_mark(page, 1);
+ do_fsync = true;
percpu_counter_inc(&sbi->rf_node_block_count);
if (IS_INODE(page)) {
if (is_inode_flag_set(inode,
@@ -1890,8 +1890,9 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
ret = __write_node_page(page, atomic &&
page == last_page,
- &submitted, wbc, true,
- FS_NODE_IO, seq_id);
+ do_fsync, &submitted,
+ wbc, true, FS_NODE_IO,
+ seq_id);
if (ret) {
unlock_page(page);
f2fs_put_page(last_page, 0);
@@ -2098,10 +2099,7 @@ int f2fs_sync_node_pages(struct f2fs_sb_info *sbi,
if (!clear_page_dirty_for_io(page))
goto continue_unlock;
- set_fsync_mark(page, 0);
- set_dentry_mark(page, 0);
-
- ret = __write_node_page(page, false, &submitted,
+ ret = __write_node_page(page, false, false, &submitted,
wbc, do_balance, io_type, NULL);
if (ret)
unlock_page(page);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 294/869] refcount: provide ops for cases when objects memory can be reused
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (292 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 293/869] f2fs: fix fsck inconsistency caused by FGGC of node block Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 295/869] RDMA/mlx4: Fix mis-use of RCU in mlx4_srq_event() Greg Kroah-Hartman
` (575 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Suren Baghdasaryan, Shivank Garg,
Peter Zijlstra, Will Deacon, Paul E. McKenney, Christian Brauner,
David Hildenbrand, David Howells, Davidlohr Bueso, Hugh Dickins,
Jann Horn, Johannes Weiner, Jonathan Corbet, Klara Modin,
Liam R. Howlett, Lokesh Gidra, Lorenzo Stoakes, Mateusz Guzik,
Matthew Wilcox, Mel Gorman, Michal Hocko, Minchan Kim,
Oleg Nesterov, Pasha Tatashin, Peter Xu, Shakeel Butt,
Sourav Panda, Wei Yang, Heiko Carstens, Stephen Rothwell,
Andrew Morton, Sasha Levin, Vlastimil Babka
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Suren Baghdasaryan <surenb@google.com>
[ Upstream commit 7f8ceea0c58039dcea3d31b8d5da58aa5f6e12bf ]
For speculative lookups where a successful inc_not_zero() pins the object,
but where we still need to double check if the object acquired is indeed
the one we set out to acquire (identity check), needs this validation to
happen *after* the increment. Similarly, when a new object is initialized
and its memory might have been previously occupied by another object, all
stores to initialize the object should happen *before* refcount
initialization.
Notably SLAB_TYPESAFE_BY_RCU is one such an example when this ordering is
required for reference counting.
Add refcount_{add|inc}_not_zero_acquire() to guarantee the proper ordering
between acquiring a reference count on an object and performing the
identity check for that object.
Add refcount_set_release() to guarantee proper ordering between stores
initializing object attributes and the store initializing the refcount.
refcount_set_release() should be done after all other object attributes
are initialized. Once refcount_set_release() is called, the object should
be considered visible to other tasks even if it was not yet added into an
object collection normally used to discover it. This is because other
tasks might have discovered the object previously occupying the same
memory and after memory reuse they can succeed in taking refcount for the
new object and start using it.
Object reuse example to consider:
consumer:
obj = lookup(collection, key);
if (!refcount_inc_not_zero_acquire(&obj->ref))
return;
if (READ_ONCE(obj->key) != key) { /* identity check */
put_ref(obj);
return;
}
use(obj->value);
producer:
remove(collection, obj->key);
if (!refcount_dec_and_test(&obj->ref))
return;
obj->key = KEY_INVALID;
free(obj);
obj = malloc(); /* obj is reused */
obj->key = new_key;
obj->value = new_value;
refcount_set_release(obj->ref, 1);
add(collection, new_key, obj);
refcount_{add|inc}_not_zero_acquire() is required to prevent the following
reordering when refcount_inc_not_zero() is used instead:
consumer:
obj = lookup(collection, key);
if (READ_ONCE(obj->key) != key) { /* reordered identity check */
put_ref(obj);
return;
}
producer:
remove(collection, obj->key);
if (!refcount_dec_and_test(&obj->ref))
return;
obj->key = KEY_INVALID;
free(obj);
obj = malloc(); /* obj is reused */
obj->key = new_key;
obj->value = new_value;
refcount_set_release(obj->ref, 1);
add(collection, new_key, obj);
if (!refcount_inc_not_zero(&obj->ref))
return;
use(obj->value); /* USING WRONG OBJECT */
refcount_set_release() is required to prevent the following reordering
when refcount_set() is used instead:
consumer:
obj = lookup(collection, key);
producer:
remove(collection, obj->key);
if (!refcount_dec_and_test(&obj->ref))
return;
obj->key = KEY_INVALID;
free(obj);
obj = malloc(); /* obj is reused */
obj->key = new_key; /* new_key == old_key */
refcount_set(obj->ref, 1);
if (!refcount_inc_not_zero_acquire(&obj->ref))
return;
if (READ_ONCE(obj->key) != key) { /* pass since new_key == old_key */
put_ref(obj);
return;
}
use(obj->value); /* USING STALE obj->value */
obj->value = new_value; /* reordered store */
add(collection, key, obj);
[surenb@google.com: fix title underlines in refcount-vs-atomic.rst]
Link: https://lkml.kernel.org/r/20250217161645.3137927-1-surenb@google.com
Link: https://lkml.kernel.org/r/20250213224655.1680278-11-surenb@google.com
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz> [slab]
Tested-by: Shivank Garg <shivankg@amd.com>
Link: https://lkml.kernel.org/r/5e19ec93-8307-47c2-bb13-3ddf7150624e@amd.com
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will@kernel.org>
Cc: Paul E. McKenney <paulmck@kernel.org>
Cc: Christian Brauner <brauner@kernel.org>
Cc: David Hildenbrand <david@redhat.com>
Cc: David Howells <dhowells@redhat.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Klara Modin <klarasmodin@gmail.com>
Cc: Liam R. Howlett <Liam.Howlett@Oracle.com>
Cc: Lokesh Gidra <lokeshgidra@google.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Mateusz Guzik <mjguzik@gmail.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Minchan Kim <minchan@google.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Sourav Panda <souravpanda@google.com>
Cc: Wei Yang <richard.weiyang@gmail.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Stable-dep-of: c9341307ea16 ("RDMA/mlx4: Fix mis-use of RCU in mlx4_srq_event()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
Documentation/RCU/whatisRCU.rst | 10 ++
Documentation/core-api/refcount-vs-atomic.rst | 37 +++++-
include/linux/refcount.h | 106 ++++++++++++++++++
include/linux/slab.h | 9 ++
4 files changed, 156 insertions(+), 6 deletions(-)
diff --git a/Documentation/RCU/whatisRCU.rst b/Documentation/RCU/whatisRCU.rst
index 1ef5784c1b84e..53faeed7c1905 100644
--- a/Documentation/RCU/whatisRCU.rst
+++ b/Documentation/RCU/whatisRCU.rst
@@ -971,6 +971,16 @@ unfortunately any spinlock in a ``SLAB_TYPESAFE_BY_RCU`` object must be
initialized after each and every call to kmem_cache_alloc(), which renders
reference-free spinlock acquisition completely unsafe. Therefore, when
using ``SLAB_TYPESAFE_BY_RCU``, make proper use of a reference counter.
+If using refcount_t, the specialized refcount_{add|inc}_not_zero_acquire()
+and refcount_set_release() APIs should be used to ensure correct operation
+ordering when verifying object identity and when initializing newly
+allocated objects. Acquire fence in refcount_{add|inc}_not_zero_acquire()
+ensures that identity checks happen *after* reference count is taken.
+refcount_set_release() should be called after a newly allocated object is
+fully initialized and release fence ensures that new values are visible
+*before* refcount can be successfully taken by other users. Once
+refcount_set_release() is called, the object should be considered visible
+by other tasks.
(Those willing to initialize their locks in a kmem_cache constructor
may also use locking, including cache-friendly sequence locking.)
diff --git a/Documentation/core-api/refcount-vs-atomic.rst b/Documentation/core-api/refcount-vs-atomic.rst
index 79a009ce11df9..94e628c1eb497 100644
--- a/Documentation/core-api/refcount-vs-atomic.rst
+++ b/Documentation/core-api/refcount-vs-atomic.rst
@@ -86,7 +86,19 @@ Memory ordering guarantee changes:
* none (both fully unordered)
-case 2) - increment-based ops that return no value
+case 2) - non-"Read/Modify/Write" (RMW) ops with release ordering
+-----------------------------------------------------------------
+
+Function changes:
+
+ * atomic_set_release() --> refcount_set_release()
+
+Memory ordering guarantee changes:
+
+ * none (both provide RELEASE ordering)
+
+
+case 3) - increment-based ops that return no value
--------------------------------------------------
Function changes:
@@ -98,7 +110,7 @@ Memory ordering guarantee changes:
* none (both fully unordered)
-case 3) - decrement-based RMW ops that return no value
+case 4) - decrement-based RMW ops that return no value
------------------------------------------------------
Function changes:
@@ -110,7 +122,7 @@ Memory ordering guarantee changes:
* fully unordered --> RELEASE ordering
-case 4) - increment-based RMW ops that return a value
+case 5) - increment-based RMW ops that return a value
-----------------------------------------------------
Function changes:
@@ -126,7 +138,20 @@ Memory ordering guarantees changes:
result of obtaining pointer to the object!
-case 5) - generic dec/sub decrement-based RMW ops that return a value
+case 6) - increment-based RMW ops with acquire ordering that return a value
+---------------------------------------------------------------------------
+
+Function changes:
+
+ * atomic_inc_not_zero() --> refcount_inc_not_zero_acquire()
+ * no atomic counterpart --> refcount_add_not_zero_acquire()
+
+Memory ordering guarantees changes:
+
+ * fully ordered --> ACQUIRE ordering on success
+
+
+case 7) - generic dec/sub decrement-based RMW ops that return a value
---------------------------------------------------------------------
Function changes:
@@ -139,7 +164,7 @@ Memory ordering guarantees changes:
* fully ordered --> RELEASE ordering + ACQUIRE ordering on success
-case 6) other decrement-based RMW ops that return a value
+case 8) other decrement-based RMW ops that return a value
---------------------------------------------------------
Function changes:
@@ -154,7 +179,7 @@ Memory ordering guarantees changes:
.. note:: atomic_add_unless() only provides full order on success.
-case 7) - lock-based RMW
+case 9) - lock-based RMW
------------------------
Function changes:
diff --git a/include/linux/refcount.h b/include/linux/refcount.h
index 35f039ecb2725..4589d2e7bfea4 100644
--- a/include/linux/refcount.h
+++ b/include/linux/refcount.h
@@ -87,6 +87,15 @@
* The decrements dec_and_test() and sub_and_test() also provide acquire
* ordering on success.
*
+ * refcount_{add|inc}_not_zero_acquire() and refcount_set_release() provide
+ * acquire and release ordering for cases when the memory occupied by the
+ * object might be reused to store another object. This is important for the
+ * cases where secondary validation is required to detect such reuse, e.g.
+ * SLAB_TYPESAFE_BY_RCU. The secondary validation checks have to happen after
+ * the refcount is taken, hence acquire order is necessary. Similarly, when the
+ * object is initialized, all stores to its attributes should be visible before
+ * the refcount is set, otherwise a stale attribute value might be used by
+ * another task which succeeds in taking a refcount to the new object.
*/
#ifndef _LINUX_REFCOUNT_H
@@ -125,6 +134,31 @@ static inline void refcount_set(refcount_t *r, int n)
atomic_set(&r->refs, n);
}
+/**
+ * refcount_set_release - set a refcount's value with release ordering
+ * @r: the refcount
+ * @n: value to which the refcount will be set
+ *
+ * This function should be used when memory occupied by the object might be
+ * reused to store another object -- consider SLAB_TYPESAFE_BY_RCU.
+ *
+ * Provides release memory ordering which will order previous memory operations
+ * against this store. This ensures all updates to this object are visible
+ * once the refcount is set and stale values from the object previously
+ * occupying this memory are overwritten with new ones.
+ *
+ * This function should be called only after new object is fully initialized.
+ * After this call the object should be considered visible to other tasks even
+ * if it was not yet added into an object collection normally used to discover
+ * it. This is because other tasks might have discovered the object previously
+ * occupying the same memory and after memory reuse they can succeed in taking
+ * refcount to the new object and start using it.
+ */
+static inline void refcount_set_release(refcount_t *r, int n)
+{
+ atomic_set_release(&r->refs, n);
+}
+
/**
* refcount_read - get a refcount's value
* @r: the refcount
@@ -178,6 +212,52 @@ static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r)
return __refcount_add_not_zero(i, r, NULL);
}
+static inline __must_check __signed_wrap
+bool __refcount_add_not_zero_acquire(int i, refcount_t *r, int *oldp)
+{
+ int old = refcount_read(r);
+
+ do {
+ if (!old)
+ break;
+ } while (!atomic_try_cmpxchg_acquire(&r->refs, &old, old + i));
+
+ if (oldp)
+ *oldp = old;
+
+ if (unlikely(old < 0 || old + i < 0))
+ refcount_warn_saturate(r, REFCOUNT_ADD_NOT_ZERO_OVF);
+
+ return old;
+}
+
+/**
+ * refcount_add_not_zero_acquire - add a value to a refcount with acquire ordering unless it is 0
+ *
+ * @i: the value to add to the refcount
+ * @r: the refcount
+ *
+ * Will saturate at REFCOUNT_SATURATED and WARN.
+ *
+ * This function should be used when memory occupied by the object might be
+ * reused to store another object -- consider SLAB_TYPESAFE_BY_RCU.
+ *
+ * Provides acquire memory ordering on success, it is assumed the caller has
+ * guaranteed the object memory to be stable (RCU, etc.). It does provide a
+ * control dependency and thereby orders future stores. See the comment on top.
+ *
+ * Use of this function is not recommended for the normal reference counting
+ * use case in which references are taken and released one at a time. In these
+ * cases, refcount_inc_not_zero_acquire() should instead be used to increment a
+ * reference count.
+ *
+ * Return: false if the passed refcount is 0, true otherwise
+ */
+static inline __must_check bool refcount_add_not_zero_acquire(int i, refcount_t *r)
+{
+ return __refcount_add_not_zero_acquire(i, r, NULL);
+}
+
static inline __signed_wrap
void __refcount_add(int i, refcount_t *r, int *oldp)
{
@@ -236,6 +316,32 @@ static inline __must_check bool refcount_inc_not_zero(refcount_t *r)
return __refcount_inc_not_zero(r, NULL);
}
+static inline __must_check bool __refcount_inc_not_zero_acquire(refcount_t *r, int *oldp)
+{
+ return __refcount_add_not_zero_acquire(1, r, oldp);
+}
+
+/**
+ * refcount_inc_not_zero_acquire - increment a refcount with acquire ordering unless it is 0
+ * @r: the refcount to increment
+ *
+ * Similar to refcount_inc_not_zero(), but provides acquire memory ordering on
+ * success.
+ *
+ * This function should be used when memory occupied by the object might be
+ * reused to store another object -- consider SLAB_TYPESAFE_BY_RCU.
+ *
+ * Provides acquire memory ordering on success, it is assumed the caller has
+ * guaranteed the object memory to be stable (RCU, etc.). It does provide a
+ * control dependency and thereby orders future stores. See the comment on top.
+ *
+ * Return: true if the increment was successful, false otherwise
+ */
+static inline __must_check bool refcount_inc_not_zero_acquire(refcount_t *r)
+{
+ return __refcount_inc_not_zero_acquire(r, NULL);
+}
+
static inline void __refcount_inc(refcount_t *r, int *oldp)
{
__refcount_add(1, r, oldp);
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 28eba6cbb7670..7b58cc1844303 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -125,6 +125,15 @@ enum _slab_flag_bits {
* rcu_read_lock before reading the address, then rcu_read_unlock after
* taking the spinlock within the structure expected at that address.
*
+ * Note that object identity check has to be done *after* acquiring a
+ * reference, therefore user has to ensure proper ordering for loads.
+ * Similarly, when initializing objects allocated with SLAB_TYPESAFE_BY_RCU,
+ * the newly allocated object has to be fully initialized *before* its
+ * refcount gets initialized and proper ordering for stores is required.
+ * refcount_{add|inc}_not_zero_acquire() and refcount_set_release() are
+ * designed with the proper fences required for reference counting objects
+ * allocated with SLAB_TYPESAFE_BY_RCU.
+ *
* Note that it is not possible to acquire a lock within a structure
* allocated with SLAB_TYPESAFE_BY_RCU without first acquiring a reference
* as described above. The reason is that SLAB_TYPESAFE_BY_RCU pages
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 295/869] RDMA/mlx4: Fix mis-use of RCU in mlx4_srq_event()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (293 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 294/869] refcount: provide ops for cases when objects memory can be reused Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 296/869] spi: ch341: switch to use devm_spi_alloc_host() Greg Kroah-Hartman
` (574 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jason Gunthorpe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason Gunthorpe <jgg@nvidia.com>
[ Upstream commit c9341307ea16b9395c2e4c9c94d8499d91fe31d0 ]
Sashiko points out the radix_tree itself is RCU safe, but nothing ever
frees the mlx4_srq struct with RCU, and it isn't even accessed within the
RCU critical section. It also will crash if an event is delivered before
the srq object is finished initializing.
Use the spinlock since it isn't easy to make RCU work, use
refcount_inc_not_zero() to protect against partially initialized objects,
and order the refcount_set() to be after the srq is fully initialized.
Cc: stable@vger.kernel.org
Fixes: 30353bfc43a1 ("net/mlx4_core: Use RCU to perform radix tree lookup for SRQ")
Link: https://sashiko.dev/#/patchset/0-v2-1c49eeb88c48%2B91-rdma_udata_rep_jgg%40nvidia.com?part=5
Link: https://patch.msgid.link/r/12-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/mellanox/mlx4/srq.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/srq.c b/drivers/net/ethernet/mellanox/mlx4/srq.c
index dd890f5d7b725..8711689120f30 100644
--- a/drivers/net/ethernet/mellanox/mlx4/srq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/srq.c
@@ -44,13 +44,14 @@ void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type)
{
struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
struct mlx4_srq *srq;
+ unsigned long flags;
- rcu_read_lock();
+ spin_lock_irqsave(&srq_table->lock, flags);
srq = radix_tree_lookup(&srq_table->tree, srqn & (dev->caps.num_srqs - 1));
- rcu_read_unlock();
- if (srq)
- refcount_inc(&srq->refcount);
- else {
+ if (!srq || !refcount_inc_not_zero(&srq->refcount))
+ srq = NULL;
+ spin_unlock_irqrestore(&srq_table->lock, flags);
+ if (!srq) {
mlx4_warn(dev, "Async event for bogus SRQ %08x\n", srqn);
return;
}
@@ -203,8 +204,8 @@ int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd,
if (err)
goto err_radix;
- refcount_set(&srq->refcount, 1);
init_completion(&srq->free);
+ refcount_set_release(&srq->refcount, 1);
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 296/869] spi: ch341: switch to use devm_spi_alloc_host()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (294 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 295/869] RDMA/mlx4: Fix mis-use of RCU in mlx4_srq_event() Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 297/869] spi: ch341: fix devres lifetime Greg Kroah-Hartman
` (573 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Yang Yingliang, Mark Brown,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Yingliang <yangyingliang@huawei.com>
[ Upstream commit 0191e98ae6e22bebae4e9a487ba70f90d2f8714c ]
Switch to use modern name function devm_spi_alloc_host().
No functional changed.
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
Link: https://patch.msgid.link/20240902125947.1368-4-yangyingliang@huaweicloud.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Stable-dep-of: abe572f630bc ("spi: ch341: fix devres lifetime")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/spi/spi-ch341.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/spi/spi-ch341.c b/drivers/spi/spi-ch341.c
index 850b428b8f64f..ded0935662605 100644
--- a/drivers/spi/spi-ch341.c
+++ b/drivers/spi/spi-ch341.c
@@ -152,7 +152,7 @@ static int ch341_probe(struct usb_interface *intf,
if (ret)
return ret;
- ctrl = devm_spi_alloc_master(&udev->dev, sizeof(struct ch341_spi_dev));
+ ctrl = devm_spi_alloc_host(&udev->dev, sizeof(struct ch341_spi_dev));
if (!ctrl)
return -ENOMEM;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 297/869] spi: ch341: fix devres lifetime
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (295 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 296/869] spi: ch341: switch to use devm_spi_alloc_host() Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 298/869] drm/amd/display: Fix dc_link NULL handling in HPD init Greg Kroah-Hartman
` (572 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johannes Thumshirn, Johan Hovold,
Mark Brown, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <johan@kernel.org>
[ Upstream commit abe572f630bc1f0e77041012ab075869036ede4f ]
USB drivers bind to USB interfaces and any device managed resources
should have their lifetime tied to the interface rather than parent USB
device. This avoids issues like memory leaks when drivers are unbound
without their devices being physically disconnected (e.g. on probe
deferral or configuration changes).
Fix the controller and driver data lifetime so that they are released
on driver unbind.
Note that this also makes sure that the SPI controller is placed
correctly under the USB interface in the device tree.
Fixes: 8846739f52af ("spi: add ch341a usb2spi driver")
Cc: stable@vger.kernel.org # 6.11
Cc: Johannes Thumshirn <jth@kernel.org>
Signed-off-by: Johan Hovold <johan@kernel.org>
Link: https://patch.msgid.link/20260327104305.1309915-3-johan@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/spi/spi-ch341.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-ch341.c b/drivers/spi/spi-ch341.c
index ded0935662605..3eaa8f176f63a 100644
--- a/drivers/spi/spi-ch341.c
+++ b/drivers/spi/spi-ch341.c
@@ -152,7 +152,7 @@ static int ch341_probe(struct usb_interface *intf,
if (ret)
return ret;
- ctrl = devm_spi_alloc_host(&udev->dev, sizeof(struct ch341_spi_dev));
+ ctrl = devm_spi_alloc_host(&intf->dev, sizeof(struct ch341_spi_dev));
if (!ctrl)
return -ENOMEM;
@@ -163,7 +163,7 @@ static int ch341_probe(struct usb_interface *intf,
ch341->read_pipe = usb_rcvbulkpipe(udev, usb_endpoint_num(in));
ch341->rx_len = usb_endpoint_maxp(in);
- ch341->rx_buf = devm_kzalloc(&udev->dev, ch341->rx_len, GFP_KERNEL);
+ ch341->rx_buf = devm_kzalloc(&intf->dev, ch341->rx_len, GFP_KERNEL);
if (!ch341->rx_buf)
return -ENOMEM;
@@ -171,8 +171,7 @@ static int ch341_probe(struct usb_interface *intf,
if (!ch341->rx_urb)
return -ENOMEM;
- ch341->tx_buf =
- devm_kzalloc(&udev->dev, CH341_PACKET_LENGTH, GFP_KERNEL);
+ ch341->tx_buf = devm_kzalloc(&intf->dev, CH341_PACKET_LENGTH, GFP_KERNEL);
if (!ch341->tx_buf) {
ret = -ENOMEM;
goto err_free_urb;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 298/869] drm/amd/display: Fix dc_link NULL handling in HPD init
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (296 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 297/869] spi: ch341: fix devres lifetime Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 299/869] NFS/localio: prevent direct reclaim recursion into NFS via nfs_writepages Greg Kroah-Hartman
` (571 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Timur Kristóf, Harry Wentland,
Mario Limonciello, Alex Hung, Aurabindo Pillai, ChiaHsuan Chung,
Roman Li, Dan Carpenter, Srinivasan Shanmugam, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
[ Upstream commit 226a40c06a183abaeb7529a4f54d6c203bd14407 ]
amdgpu_dm_hpd_init() may see connectors without a valid dc_link.
The code already checks dc_link for the polling decision, but later
unconditionally dereferences it when setting up HPD interrupts.
Assign dc_link early and skip connectors where it is NULL.
Fixes the below:
drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm_irq.c:940 amdgpu_dm_hpd_init()
error: we previously assumed 'dc_link' could be null (see line 931)
drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm_irq.c
923 /*
924 * Analog connectors may be hot-plugged unlike other connector
925 * types that don't support HPD. Only poll analog connectors.
926 */
927 use_polling |=
928 amdgpu_dm_connector->dc_link &&
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The patch adds this NULL check but hopefully it can be removed
929 dc_connector_supports_analog(amdgpu_dm_connector->dc_link->link_id.id);
930
931 dc_link = amdgpu_dm_connector->dc_link;
dc_link assigned here.
932
933 /*
934 * Get a base driver irq reference for hpd ints for the lifetime
935 * of dm. Note that only hpd interrupt types are registered with
936 * base driver; hpd_rx types aren't. IOW, amdgpu_irq_get/put on
937 * hpd_rx isn't available. DM currently controls hpd_rx
938 * explicitly with dc_interrupt_set()
939 */
--> 940 if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) {
^^^^^^^^^^^^^^^^^^^^^^^ If it's NULL then we are trouble because we dereference it here.
941 irq_type = dc_link->irq_source_hpd - DC_IRQ_SOURCE_HPD1;
942 /*
943 * TODO: There's a mismatch between mode_info.num_hpd
944 * and what bios reports as the # of connectors with hpd
Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)")
Cc: Timur Kristóf <timur.kristof@gmail.com>
Cc: Harry Wentland <harry.wentland@amd.com>
Cc: Mario Limonciello <superm1@kernel.org>
Cc: Alex Hung <alex.hung@amd.com>
Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
Cc: ChiaHsuan Chung <chiahsuan.chung@amd.com>
Cc: Roman Li <roman.li@amd.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
Reviewed-by: Timur Kristóf <timur.kristof@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
index a215234151ac3..82bc3dcd3f652 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
@@ -913,8 +913,9 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
continue;
amdgpu_dm_connector = to_amdgpu_dm_connector(connector);
-
dc_link = amdgpu_dm_connector->dc_link;
+ if (!dc_link)
+ continue;
/*
* Get a base driver irq reference for hpd ints for the lifetime
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 299/869] NFS/localio: prevent direct reclaim recursion into NFS via nfs_writepages
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (297 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 298/869] drm/amd/display: Fix dc_link NULL handling in HPD init Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 300/869] coresight: tmc-etr: Fix race condition between sysfs and perf mode Greg Kroah-Hartman
` (570 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, John Cagle, Allen Lu,
Benjamin Coddington, Mike Snitzer, Anna Schumaker, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mike Snitzer <snitzer@hammerspace.com>
[ Upstream commit 67435d2d8a33a75f9647724952cb1b18279d2e95 ]
LOCALIO is an NFS loopback mount optimization that avoids using the
network for READ, WRITE and COMMIT if the NFS client and server are
determined to be on the same system. But because LOCALIO is still
fundamentally "just NFS loopback mount" it is susceptible to recursion
deadlock via direct reclaim, e.g.: NFS LOCALIO down to XFS and then
back into NFS via nfs_writepages.
Fix LOCALIO's potential for direct reclaim deadlock by ensuring that
all its page cache allocations are done from GFP_NOFS context.
Thanks to Ben Coddington for pointing out commit ad22c7a043c2 ("xfs:
prevent stack overflows from page cache allocation").
Reported-by: John Cagle <john.cagle@hammerspace.com>
Tested-by: Allen Lu <allen.lu@hammerspace.com>
Suggested-by: Benjamin Coddington <bcodding@hammerspace.com>
Fixes: 70ba381e1a43 ("nfs: add LOCALIO support")
Signed-off-by: Mike Snitzer <snitzer@hammerspace.com>
Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfs/localio.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c
index c59f205b51308..fe76b8a9f2e67 100644
--- a/fs/nfs/localio.c
+++ b/fs/nfs/localio.c
@@ -270,6 +270,18 @@ nfs_bvec_alloc_and_import_pagevec(struct page **pagevec,
return bvec;
}
+/*
+ * Ensure all page cache allocations are done from GFP_NOFS context to
+ * prevent direct reclaim recursion back into NFS via nfs_writepages.
+ */
+static void
+nfs_local_mapping_set_gfp_nofs_context(struct address_space *m)
+{
+ gfp_t gfp_mask = mapping_gfp_mask(m);
+
+ mapping_set_gfp_mask(m, (gfp_mask & ~(__GFP_FS)));
+}
+
static void
nfs_local_iocb_free(struct nfs_local_kiocb *iocb)
{
@@ -293,6 +305,7 @@ nfs_local_iocb_alloc(struct nfs_pgio_header *hdr,
return NULL;
}
+ nfs_local_mapping_set_gfp_nofs_context(file->f_mapping);
if (localio_O_DIRECT_semantics &&
test_bit(NFS_IOHDR_ODIRECT, &hdr->flags)) {
iocb->kiocb.ki_filp = file;
@@ -734,6 +747,8 @@ nfs_local_run_commit(struct file *filp, struct nfs_commit_data *data)
end = LLONG_MAX;
}
+ nfs_local_mapping_set_gfp_nofs_context(filp->f_mapping);
+
dprintk("%s: commit %llu - %llu\n", __func__, start, end);
return vfs_fsync_range(filp, start, end, 0);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 300/869] coresight: tmc-etr: Fix race condition between sysfs and perf mode
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (298 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 299/869] NFS/localio: prevent direct reclaim recursion into NFS via nfs_writepages Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 301/869] selinux: allow multiple opens of /sys/fs/selinux/policy Greg Kroah-Hartman
` (569 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yicong Yang, Junhao He,
Suzuki K Poulose, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yicong Yang <yangyicong@hisilicon.com>
[ Upstream commit e6e43e82c79c97917cbe356c07e8a6f3f982ab53 ]
When trying to run perf and sysfs mode simultaneously, the WARN_ON()
in tmc_etr_enable_hw() is triggered sometimes:
WARNING: CPU: 42 PID: 3911571 at drivers/hwtracing/coresight/coresight-tmc-etr.c:1060 tmc_etr_enable_hw+0xc0/0xd8 [coresight_tmc]
[..snip..]
Call trace:
tmc_etr_enable_hw+0xc0/0xd8 [coresight_tmc] (P)
tmc_enable_etr_sink+0x11c/0x250 [coresight_tmc] (L)
tmc_enable_etr_sink+0x11c/0x250 [coresight_tmc]
coresight_enable_path+0x1c8/0x218 [coresight]
coresight_enable_sysfs+0xa4/0x228 [coresight]
enable_source_store+0x58/0xa8 [coresight]
dev_attr_store+0x20/0x40
sysfs_kf_write+0x4c/0x68
kernfs_fop_write_iter+0x120/0x1b8
vfs_write+0x2c8/0x388
ksys_write+0x74/0x108
__arm64_sys_write+0x24/0x38
el0_svc_common.constprop.0+0x64/0x148
do_el0_svc+0x24/0x38
el0_svc+0x3c/0x130
el0t_64_sync_handler+0xc8/0xd0
el0t_64_sync+0x1ac/0x1b0
---[ end trace 0000000000000000 ]---
Since the enablement of sysfs mode is separeted into two critical regions,
one for sysfs buffer allocation and another for hardware enablement, it's
possible to race with the perf mode. Fix this by double check whether
the perf mode's been used before enabling the hardware in sysfs mode.
mode:
[sysfs mode] [perf mode]
tmc_etr_get_sysfs_buffer()
spin_lock(&drvdata->spinlock)
[sysfs buffer allocation]
spin_unlock(&drvdata->spinlock)
spin_lock(&drvdata->spinlock)
tmc_etr_enable_hw()
drvdata->etr_buf = etr_perf->etr_buf
spin_unlock(&drvdata->spinlock)
spin_lock(&drvdata->spinlock)
tmc_etr_enable_hw()
WARN_ON(drvdata->etr_buf) // WARN sicne etr_buf initialized at
the perf side
spin_unlock(&drvdata->spinlock)
With this fix, we retain the check for CS_MODE_PERF in get_etr_sysfs_buf.
This ensures we verify whether the perf mode's already running before we
actually allocate the buffer. Then we can save the time of
allocating/freeing the sysfs buffer if race with the perf mode.
Fixes: 296b01fd106e ("coresight: Refactor out buffer allocation function for ETR")
Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
Signed-off-by: Junhao He <hejunhao3@h-partners.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20260121101543.2017014-3-wangyushan12@huawei.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hwtracing/coresight/coresight-tmc-etr.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 25f0335e2db05..11ac1a8b9e7a2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1233,6 +1233,19 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+ /*
+ * Since the sysfs buffer allocation and the hardware enablement is not
+ * in the same critical region, it's possible to race with the perf.
+ */
+ if (coresight_get_mode(csdev) == CS_MODE_PERF) {
+ drvdata->sysfs_buf = NULL;
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+ /* Free allocated memory out side of the spinlock */
+ tmc_etr_free_sysfs_buf(sysfs_buf);
+ return -EBUSY;
+ }
+
/*
* In sysFS mode we can have multiple writers per sink. Since this
* sink is already enabled no memory is needed and the HW need not be
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 301/869] selinux: allow multiple opens of /sys/fs/selinux/policy
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (299 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 300/869] coresight: tmc-etr: Fix race condition between sysfs and perf mode Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 302/869] netfilter: nf_tables: use list_del_rcu for netlink hooks Greg Kroah-Hartman
` (568 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Stephen Smalley, Paul Moore,
Sasha Levin
6.12-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 ec3030614ab26..1ee472482c8ae 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] 872+ messages in thread
* [PATCH 6.12 302/869] netfilter: nf_tables: use list_del_rcu for netlink hooks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (300 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 301/869] selinux: allow multiple opens of /sys/fs/selinux/policy Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 303/869] RDMA/rxe: Move some code to rxe_loc.h in preparation for ODP Greg Kroah-Hartman
` (567 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Florian Westphal, Pablo Neira Ayuso,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <fw@strlen.de>
[ Upstream commit f3224ee463f8f6f6ced7dcdf6081add4f8128527 ]
nft_netdev_unregister_hooks and __nft_unregister_flowtable_net_hooks need
to use list_del_rcu(), this list can be walked by concurrent dumpers.
Add a new helper and use it consistently.
Fixes: f9a43007d3f7 ("netfilter: nf_tables: double hook unregistration in netns path")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/netfilter/nf_tables_api.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index f30c4d8029e0c..d6745e9b63370 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -350,7 +350,7 @@ static void nft_netdev_unregister_hooks(struct net *net,
list_for_each_entry_safe(hook, next, hook_list, list) {
nf_unregister_net_hook(net, &hook->ops);
if (release_netdev) {
- list_del(&hook->list);
+ list_del_rcu(&hook->list);
kfree_rcu(hook, rcu);
}
}
@@ -8498,7 +8498,7 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net,
flowtable->data.type->setup(&flowtable->data, hook->ops.dev,
FLOW_BLOCK_UNBIND);
if (release_netdev) {
- list_del(&hook->list);
+ list_del_rcu(&hook->list);
kfree_rcu(hook, rcu);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 303/869] RDMA/rxe: Move some code to rxe_loc.h in preparation for ODP
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (301 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 302/869] netfilter: nf_tables: use list_del_rcu for netlink hooks Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 304/869] RDMA/rxe: Fix iova-to-va conversion for MR page sizes != PAGE_SIZE Greg Kroah-Hartman
` (566 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Daisuke Matsuda, Jason Gunthorpe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daisuke Matsuda <matsuda-daisuke@fujitsu.com>
[ Upstream commit 7f880725078d2314f6761f24c2a244e4a68c69c2 ]
rxe_mr_init() and resp_states are going to be used in rxe_odp.c, which is
to be created in the subsequent patch.
Link: https://patch.msgid.link/r/20241220100936.2193541-2-matsuda-daisuke@fujitsu.com
Signed-off-by: Daisuke Matsuda <matsuda-daisuke@fujitsu.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Stable-dep-of: 12985e5915a0 ("RDMA/rxe: Fix iova-to-va conversion for MR page sizes != PAGE_SIZE")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/sw/rxe/rxe.h | 37 ---------------------------
drivers/infiniband/sw/rxe/rxe_loc.h | 1 +
drivers/infiniband/sw/rxe/rxe_mr.c | 2 +-
drivers/infiniband/sw/rxe/rxe_verbs.h | 37 +++++++++++++++++++++++++++
4 files changed, 39 insertions(+), 38 deletions(-)
diff --git a/drivers/infiniband/sw/rxe/rxe.h b/drivers/infiniband/sw/rxe/rxe.h
index fe7f970667325..120e114c2e1ee 100644
--- a/drivers/infiniband/sw/rxe/rxe.h
+++ b/drivers/infiniband/sw/rxe/rxe.h
@@ -100,43 +100,6 @@
#define rxe_info_mw(mw, fmt, ...) ibdev_info_ratelimited((mw)->ibmw.device, \
"mw#%d %s: " fmt, (mw)->elem.index, __func__, ##__VA_ARGS__)
-/* responder states */
-enum resp_states {
- RESPST_NONE,
- RESPST_GET_REQ,
- RESPST_CHK_PSN,
- RESPST_CHK_OP_SEQ,
- RESPST_CHK_OP_VALID,
- RESPST_CHK_RESOURCE,
- RESPST_CHK_LENGTH,
- RESPST_CHK_RKEY,
- RESPST_EXECUTE,
- RESPST_READ_REPLY,
- RESPST_ATOMIC_REPLY,
- RESPST_ATOMIC_WRITE_REPLY,
- RESPST_PROCESS_FLUSH,
- RESPST_COMPLETE,
- RESPST_ACKNOWLEDGE,
- RESPST_CLEANUP,
- RESPST_DUPLICATE_REQUEST,
- RESPST_ERR_MALFORMED_WQE,
- RESPST_ERR_UNSUPPORTED_OPCODE,
- RESPST_ERR_MISALIGNED_ATOMIC,
- RESPST_ERR_PSN_OUT_OF_SEQ,
- RESPST_ERR_MISSING_OPCODE_FIRST,
- RESPST_ERR_MISSING_OPCODE_LAST_C,
- RESPST_ERR_MISSING_OPCODE_LAST_D1E,
- RESPST_ERR_TOO_MANY_RDMA_ATM_REQ,
- RESPST_ERR_RNR,
- RESPST_ERR_RKEY_VIOLATION,
- RESPST_ERR_INVALIDATE_RKEY,
- RESPST_ERR_LENGTH,
- RESPST_ERR_CQ_OVERFLOW,
- RESPST_ERROR,
- RESPST_DONE,
- RESPST_EXIT,
-};
-
void rxe_set_mtu(struct rxe_dev *rxe, unsigned int dev_mtu);
int rxe_add(struct rxe_dev *rxe, unsigned int mtu, const char *ibdev_name,
diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h
index ded46119151bb..1c78b9d36da4c 100644
--- a/drivers/infiniband/sw/rxe/rxe_loc.h
+++ b/drivers/infiniband/sw/rxe/rxe_loc.h
@@ -58,6 +58,7 @@ int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
/* rxe_mr.c */
u8 rxe_get_next_key(u32 last_key);
+void rxe_mr_init(int access, struct rxe_mr *mr);
void rxe_mr_init_dma(int access, struct rxe_mr *mr);
int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length,
int access, struct rxe_mr *mr);
diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
index 83e325b76f67d..ab1635d53da3d 100644
--- a/drivers/infiniband/sw/rxe/rxe_mr.c
+++ b/drivers/infiniband/sw/rxe/rxe_mr.c
@@ -46,7 +46,7 @@ int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length)
}
}
-static void rxe_mr_init(int access, struct rxe_mr *mr)
+void rxe_mr_init(int access, struct rxe_mr *mr)
{
u32 key = mr->elem.index << 8 | rxe_get_next_key(-1);
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h
index 6573ceec0ef58..f7a226155e359 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.h
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.h
@@ -126,6 +126,43 @@ struct rxe_comp_info {
u32 rnr_retry;
};
+/* responder states */
+enum resp_states {
+ RESPST_NONE,
+ RESPST_GET_REQ,
+ RESPST_CHK_PSN,
+ RESPST_CHK_OP_SEQ,
+ RESPST_CHK_OP_VALID,
+ RESPST_CHK_RESOURCE,
+ RESPST_CHK_LENGTH,
+ RESPST_CHK_RKEY,
+ RESPST_EXECUTE,
+ RESPST_READ_REPLY,
+ RESPST_ATOMIC_REPLY,
+ RESPST_ATOMIC_WRITE_REPLY,
+ RESPST_PROCESS_FLUSH,
+ RESPST_COMPLETE,
+ RESPST_ACKNOWLEDGE,
+ RESPST_CLEANUP,
+ RESPST_DUPLICATE_REQUEST,
+ RESPST_ERR_MALFORMED_WQE,
+ RESPST_ERR_UNSUPPORTED_OPCODE,
+ RESPST_ERR_MISALIGNED_ATOMIC,
+ RESPST_ERR_PSN_OUT_OF_SEQ,
+ RESPST_ERR_MISSING_OPCODE_FIRST,
+ RESPST_ERR_MISSING_OPCODE_LAST_C,
+ RESPST_ERR_MISSING_OPCODE_LAST_D1E,
+ RESPST_ERR_TOO_MANY_RDMA_ATM_REQ,
+ RESPST_ERR_RNR,
+ RESPST_ERR_RKEY_VIOLATION,
+ RESPST_ERR_INVALIDATE_RKEY,
+ RESPST_ERR_LENGTH,
+ RESPST_ERR_CQ_OVERFLOW,
+ RESPST_ERROR,
+ RESPST_DONE,
+ RESPST_EXIT,
+};
+
enum rdatm_res_state {
rdatm_res_state_next,
rdatm_res_state_new,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 304/869] RDMA/rxe: Fix iova-to-va conversion for MR page sizes != PAGE_SIZE
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (302 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 303/869] RDMA/rxe: Move some code to rxe_loc.h in preparation for ODP Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 305/869] Revert "net/smc: Introduce TCP ULP support" Greg Kroah-Hartman
` (565 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Li Zhijian, Leon Romanovsky,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Zhijian <lizhijian@fujitsu.com>
[ Upstream commit 12985e5915a0b8354796efadaaeb201eed115377 ]
The current implementation incorrectly handles memory regions (MRs) with
page sizes different from the system PAGE_SIZE. The core issue is that
rxe_set_page() is called with mr->page_size step increments, but the
page_list stores individual struct page pointers, each representing
PAGE_SIZE of memory.
ib_sg_to_page() has ensured that when i>=1 either
a) SG[i-1].dma_end and SG[i].dma_addr are contiguous
or
b) SG[i-1].dma_end and SG[i].dma_addr are mr->page_size aligned.
This leads to incorrect iova-to-va conversion in scenarios:
1) page_size < PAGE_SIZE (e.g., MR: 4K, system: 64K):
ibmr->iova = 0x181800
sg[0]: dma_addr=0x181800, len=0x800
sg[1]: dma_addr=0x173000, len=0x1000
Access iova = 0x181800 + 0x810 = 0x182010
Expected VA: 0x173010 (second SG, offset 0x10)
Before fix:
- index = (0x182010 >> 12) - (0x181800 >> 12) = 1
- page_offset = 0x182010 & 0xFFF = 0x10
- xarray[1] stores system page base 0x170000
- Resulting VA: 0x170000 + 0x10 = 0x170010 (wrong)
2) page_size > PAGE_SIZE (e.g., MR: 64K, system: 4K):
ibmr->iova = 0x18f800
sg[0]: dma_addr=0x18f800, len=0x800
sg[1]: dma_addr=0x170000, len=0x1000
Access iova = 0x18f800 + 0x810 = 0x190010
Expected VA: 0x170010 (second SG, offset 0x10)
Before fix:
- index = (0x190010 >> 16) - (0x18f800 >> 16) = 1
- page_offset = 0x190010 & 0xFFFF = 0x10
- xarray[1] stores system page for dma_addr 0x170000
- Resulting VA: system page of 0x170000 + 0x10 = 0x170010 (wrong)
Yi Zhang reported a kernel panic[1] years ago related to this defect.
Solution:
1. Replace xarray with pre-allocated rxe_mr_page array for sequential
indexing (all MR page indices are contiguous)
2. Each rxe_mr_page stores both struct page* and offset within the
system page
3. Handle MR page_size != PAGE_SIZE relationships:
- page_size > PAGE_SIZE: Split MR pages into multiple system pages
- page_size <= PAGE_SIZE: Store offset within system page
4. Add boundary checks and compatibility validation
This ensures correct iova-to-va conversion regardless of MR page size
and system PAGE_SIZE relationship, while improving performance through
array-based sequential access.
Tests on 4K and 64K PAGE_SIZE hosts:
- rdma-core/pytests
$ ./build/bin/run_tests.py --dev eth0_rxe
- blktest:
$ TIMEOUT=30 QUICK_RUN=1 USE_RXE=1 NVMET_TRTYPES=rdma ./check nvme srp rnbd
[1] https://lore.kernel.org/all/CAHj4cs9XRqE25jyVw9rj9YugffLn5+f=1znaBEnu1usLOciD+g@mail.gmail.com/T/
Fixes: 592627ccbdff ("RDMA/rxe: Replace rxe_map and rxe_phys_buf by xarray")
Signed-off-by: Li Zhijian <lizhijian@fujitsu.com>
Link: https://patch.msgid.link/20260116032753.2574363-1-lizhijian@fujitsu.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/sw/rxe/rxe_mr.c | 281 +++++++++++++++++---------
drivers/infiniband/sw/rxe/rxe_verbs.h | 10 +-
2 files changed, 194 insertions(+), 97 deletions(-)
diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
index ab1635d53da3d..818f1693bdec7 100644
--- a/drivers/infiniband/sw/rxe/rxe_mr.c
+++ b/drivers/infiniband/sw/rxe/rxe_mr.c
@@ -73,14 +73,46 @@ void rxe_mr_init_dma(int access, struct rxe_mr *mr)
mr->ibmr.type = IB_MR_TYPE_DMA;
}
+/*
+ * Convert iova to page_info index. The page_info stores pages of size
+ * PAGE_SIZE, but MRs can have different page sizes. This function
+ * handles the conversion for all cases:
+ *
+ * 1. mr->page_size > PAGE_SIZE:
+ * The MR's iova may not be aligned to mr->page_size. We use the
+ * aligned base (iova & page_mask) as reference, then calculate
+ * which PAGE_SIZE sub-page the iova falls into.
+ *
+ * 2. mr->page_size <= PAGE_SIZE:
+ * Use simple shift arithmetic since each page_info entry corresponds
+ * to one or more MR pages.
+ */
static unsigned long rxe_mr_iova_to_index(struct rxe_mr *mr, u64 iova)
{
- return (iova >> mr->page_shift) - (mr->ibmr.iova >> mr->page_shift);
+ int idx;
+
+ if (mr_page_size(mr) > PAGE_SIZE)
+ idx = (iova - (mr->ibmr.iova & mr->page_mask)) >> PAGE_SHIFT;
+ else
+ idx = (iova >> mr->page_shift) -
+ (mr->ibmr.iova >> mr->page_shift);
+
+ WARN_ON(idx >= mr->nbuf);
+ return idx;
}
+/*
+ * Convert iova to offset within the page_info entry.
+ *
+ * For mr_page_size > PAGE_SIZE, the offset is within the system page.
+ * For mr_page_size <= PAGE_SIZE, the offset is within the MR page size.
+ */
static unsigned long rxe_mr_iova_to_page_offset(struct rxe_mr *mr, u64 iova)
{
- return iova & (mr_page_size(mr) - 1);
+ if (mr_page_size(mr) > PAGE_SIZE)
+ return iova & (PAGE_SIZE - 1);
+ else
+ return iova & (mr_page_size(mr) - 1);
}
static bool is_pmem_page(struct page *pg)
@@ -94,37 +126,69 @@ static bool is_pmem_page(struct page *pg)
static int rxe_mr_fill_pages_from_sgt(struct rxe_mr *mr, struct sg_table *sgt)
{
- XA_STATE(xas, &mr->page_list, 0);
struct sg_page_iter sg_iter;
struct page *page;
bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT);
+ WARN_ON(mr_page_size(mr) != PAGE_SIZE);
+
__sg_page_iter_start(&sg_iter, sgt->sgl, sgt->orig_nents, 0);
if (!__sg_page_iter_next(&sg_iter))
return 0;
- do {
- xas_lock(&xas);
- while (true) {
- page = sg_page_iter_page(&sg_iter);
-
- if (persistent && !is_pmem_page(page)) {
- rxe_dbg_mr(mr, "Page can't be persistent\n");
- xas_set_err(&xas, -EINVAL);
- break;
- }
+ while (true) {
+ page = sg_page_iter_page(&sg_iter);
- xas_store(&xas, page);
- if (xas_error(&xas))
- break;
- xas_next(&xas);
- if (!__sg_page_iter_next(&sg_iter))
- break;
+ if (persistent && !is_pmem_page(page)) {
+ rxe_dbg_mr(mr, "Page can't be persistent\n");
+ return -EINVAL;
}
- xas_unlock(&xas);
- } while (xas_nomem(&xas, GFP_KERNEL));
- return xas_error(&xas);
+ mr->page_info[mr->nbuf].page = page;
+ mr->page_info[mr->nbuf].offset = 0;
+ mr->nbuf++;
+
+ if (!__sg_page_iter_next(&sg_iter))
+ break;
+ }
+
+ return 0;
+}
+
+static int __alloc_mr_page_info(struct rxe_mr *mr, int num_pages)
+{
+ mr->page_info = kcalloc(num_pages, sizeof(struct rxe_mr_page),
+ GFP_KERNEL);
+ if (!mr->page_info)
+ return -ENOMEM;
+
+ mr->max_allowed_buf = num_pages;
+ mr->nbuf = 0;
+
+ return 0;
+}
+
+static int alloc_mr_page_info(struct rxe_mr *mr, int num_pages)
+{
+ int ret;
+
+ WARN_ON(mr->num_buf);
+ ret = __alloc_mr_page_info(mr, num_pages);
+ if (ret)
+ return ret;
+
+ mr->num_buf = num_pages;
+
+ return 0;
+}
+
+static void free_mr_page_info(struct rxe_mr *mr)
+{
+ if (!mr->page_info)
+ return;
+
+ kfree(mr->page_info);
+ mr->page_info = NULL;
}
int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length,
@@ -135,8 +199,6 @@ int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length,
rxe_mr_init(access, mr);
- xa_init(&mr->page_list);
-
umem = ib_umem_get(&rxe->ib_dev, start, length, access);
if (IS_ERR(umem)) {
rxe_dbg_mr(mr, "Unable to pin memory region err = %d\n",
@@ -144,46 +206,24 @@ int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length,
return PTR_ERR(umem);
}
+ err = alloc_mr_page_info(mr, ib_umem_num_pages(umem));
+ if (err)
+ goto err2;
+
err = rxe_mr_fill_pages_from_sgt(mr, &umem->sgt_append.sgt);
- if (err) {
- ib_umem_release(umem);
- return err;
- }
+ if (err)
+ goto err1;
mr->umem = umem;
mr->ibmr.type = IB_MR_TYPE_USER;
mr->state = RXE_MR_STATE_VALID;
return 0;
-}
-
-static int rxe_mr_alloc(struct rxe_mr *mr, int num_buf)
-{
- XA_STATE(xas, &mr->page_list, 0);
- int i = 0;
- int err;
-
- xa_init(&mr->page_list);
-
- do {
- xas_lock(&xas);
- while (i != num_buf) {
- xas_store(&xas, XA_ZERO_ENTRY);
- if (xas_error(&xas))
- break;
- xas_next(&xas);
- i++;
- }
- xas_unlock(&xas);
- } while (xas_nomem(&xas, GFP_KERNEL));
-
- err = xas_error(&xas);
- if (err)
- return err;
-
- mr->num_buf = num_buf;
-
- return 0;
+err1:
+ free_mr_page_info(mr);
+err2:
+ ib_umem_release(umem);
+ return err;
}
int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr)
@@ -193,7 +233,7 @@ int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr)
/* always allow remote access for FMRs */
rxe_mr_init(RXE_ACCESS_REMOTE, mr);
- err = rxe_mr_alloc(mr, max_pages);
+ err = alloc_mr_page_info(mr, max_pages);
if (err)
goto err1;
@@ -206,26 +246,43 @@ int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr)
return err;
}
+/*
+ * I) MRs with page_size >= PAGE_SIZE,
+ * Split a large MR page (mr->page_size) into multiple PAGE_SIZE
+ * sub-pages and store them in page_info, offset is always 0.
+ *
+ * Called when mr->page_size > PAGE_SIZE. Each call to rxe_set_page()
+ * represents one mr->page_size region, which we must split into
+ * (mr->page_size >> PAGE_SHIFT) individual pages.
+ *
+ * II) MRs with page_size < PAGE_SIZE,
+ * Save each PAGE_SIZE page and its offset within the system page in page_info.
+ */
static int rxe_set_page(struct ib_mr *ibmr, u64 dma_addr)
{
struct rxe_mr *mr = to_rmr(ibmr);
- struct page *page = ib_virt_dma_to_page(dma_addr);
bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT);
- int err;
+ u32 i, pages_per_mr = mr_page_size(mr) >> PAGE_SHIFT;
- if (persistent && !is_pmem_page(page)) {
- rxe_dbg_mr(mr, "Page cannot be persistent\n");
- return -EINVAL;
- }
+ pages_per_mr = MAX(1, pages_per_mr);
- if (unlikely(mr->nbuf == mr->num_buf))
- return -ENOMEM;
+ for (i = 0; i < pages_per_mr; i++) {
+ u64 addr = dma_addr + i * PAGE_SIZE;
+ struct page *sub_page = ib_virt_dma_to_page(addr);
- err = xa_err(xa_store(&mr->page_list, mr->nbuf, page, GFP_KERNEL));
- if (err)
- return err;
+ if (unlikely(mr->nbuf >= mr->max_allowed_buf))
+ return -ENOMEM;
+
+ if (persistent && !is_pmem_page(sub_page)) {
+ rxe_dbg_mr(mr, "Page cannot be persistent\n");
+ return -EINVAL;
+ }
+
+ mr->page_info[mr->nbuf].page = sub_page;
+ mr->page_info[mr->nbuf].offset = addr & (PAGE_SIZE - 1);
+ mr->nbuf++;
+ }
- mr->nbuf++;
return 0;
}
@@ -235,6 +292,31 @@ int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sgl,
struct rxe_mr *mr = to_rmr(ibmr);
unsigned int page_size = mr_page_size(mr);
+ /*
+ * Ensure page_size and PAGE_SIZE are compatible for mapping.
+ * We require one to be a multiple of the other for correct
+ * iova-to-page conversion.
+ */
+ if (!IS_ALIGNED(page_size, PAGE_SIZE) &&
+ !IS_ALIGNED(PAGE_SIZE, page_size)) {
+ rxe_dbg_mr(mr, "MR page size %u must be compatible with PAGE_SIZE %lu\n",
+ page_size, PAGE_SIZE);
+ return -EINVAL;
+ }
+
+ if (mr_page_size(mr) > PAGE_SIZE) {
+ /* resize page_info if needed */
+ u32 map_mr_pages = (page_size >> PAGE_SHIFT) * mr->num_buf;
+
+ if (map_mr_pages > mr->max_allowed_buf) {
+ rxe_dbg_mr(mr, "requested pages %u exceed max %u\n",
+ map_mr_pages, mr->max_allowed_buf);
+ free_mr_page_info(mr);
+ if (__alloc_mr_page_info(mr, map_mr_pages))
+ return -ENOMEM;
+ }
+ }
+
mr->nbuf = 0;
mr->page_shift = ilog2(page_size);
mr->page_mask = ~((u64)page_size - 1);
@@ -246,30 +328,30 @@ int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sgl,
static int rxe_mr_copy_xarray(struct rxe_mr *mr, u64 iova, void *addr,
unsigned int length, enum rxe_mr_copy_dir dir)
{
- unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova);
- unsigned long index = rxe_mr_iova_to_index(mr, iova);
unsigned int bytes;
- struct page *page;
- void *va;
+ u8 *va;
while (length) {
- page = xa_load(&mr->page_list, index);
- if (!page)
+ unsigned long index = rxe_mr_iova_to_index(mr, iova);
+ struct rxe_mr_page *info = &mr->page_info[index];
+ unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova);
+
+ if (!info->page)
return -EFAULT;
- bytes = min_t(unsigned int, length,
- mr_page_size(mr) - page_offset);
- va = kmap_local_page(page);
+ page_offset += info->offset;
+ bytes = min_t(unsigned int, length, PAGE_SIZE - page_offset);
+ va = kmap_local_page(info->page);
+
if (dir == RXE_FROM_MR_OBJ)
memcpy(addr, va + page_offset, bytes);
else
memcpy(va + page_offset, addr, bytes);
kunmap_local(va);
- page_offset = 0;
addr += bytes;
+ iova += bytes;
length -= bytes;
- index++;
}
return 0;
@@ -424,9 +506,6 @@ int copy_data(
int rxe_flush_pmem_iova(struct rxe_mr *mr, u64 iova, unsigned int length)
{
- unsigned int page_offset;
- unsigned long index;
- struct page *page;
unsigned int bytes;
int err;
u8 *va;
@@ -446,15 +525,17 @@ int rxe_flush_pmem_iova(struct rxe_mr *mr, u64 iova, unsigned int length)
return err;
while (length > 0) {
- index = rxe_mr_iova_to_index(mr, iova);
- page = xa_load(&mr->page_list, index);
- page_offset = rxe_mr_iova_to_page_offset(mr, iova);
- if (!page)
+ unsigned long index = rxe_mr_iova_to_index(mr, iova);
+ struct rxe_mr_page *info = &mr->page_info[index];
+ unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova);
+
+ if (!info->page)
return -EFAULT;
- bytes = min_t(unsigned int, length,
- mr_page_size(mr) - page_offset);
- va = kmap_local_page(page);
+ page_offset += info->offset;
+ bytes = min_t(unsigned int, length, PAGE_SIZE - page_offset);
+
+ va = kmap_local_page(info->page);
arch_wb_cache_pmem(va + page_offset, bytes);
kunmap_local(va);
@@ -488,6 +569,7 @@ int rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode,
} else {
unsigned long index;
int err;
+ struct rxe_mr_page *info;
err = mr_check_range(mr, iova, sizeof(value));
if (err) {
@@ -496,9 +578,12 @@ int rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode,
}
page_offset = rxe_mr_iova_to_page_offset(mr, iova);
index = rxe_mr_iova_to_index(mr, iova);
- page = xa_load(&mr->page_list, index);
- if (!page)
+ info = &mr->page_info[index];
+ if (!info->page)
return RESPST_ERR_RKEY_VIOLATION;
+
+ page_offset += info->offset;
+ page = info->page;
}
if (unlikely(page_offset & 0x7)) {
@@ -545,6 +630,7 @@ int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value)
} else {
unsigned long index;
int err;
+ struct rxe_mr_page *info;
/* See IBA oA19-28 */
err = mr_check_range(mr, iova, sizeof(value));
@@ -554,9 +640,12 @@ int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value)
}
page_offset = rxe_mr_iova_to_page_offset(mr, iova);
index = rxe_mr_iova_to_index(mr, iova);
- page = xa_load(&mr->page_list, index);
- if (!page)
+ info = &mr->page_info[index];
+ if (!info->page)
return RESPST_ERR_RKEY_VIOLATION;
+
+ page_offset += info->offset;
+ page = info->page;
}
/* See IBA A19.4.2 */
@@ -728,5 +817,5 @@ void rxe_mr_cleanup(struct rxe_pool_elem *elem)
ib_umem_release(mr->umem);
if (mr->ibmr.type != IB_MR_TYPE_DMA)
- xa_destroy(&mr->page_list);
+ free_mr_page_info(mr);
}
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h
index f7a226155e359..49bac90a8f272 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.h
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.h
@@ -335,6 +335,11 @@ static inline int rkey_is_mw(u32 rkey)
return (index >= RXE_MIN_MW_INDEX) && (index <= RXE_MAX_MW_INDEX);
}
+struct rxe_mr_page {
+ struct page *page;
+ unsigned int offset; /* offset in system page */
+};
+
struct rxe_mr {
struct rxe_pool_elem elem;
struct ib_mr ibmr;
@@ -351,10 +356,13 @@ struct rxe_mr {
unsigned int page_shift;
u64 page_mask;
+ /* size of page_info when mr allocated */
u32 num_buf;
+ /* real size of page_info */
+ u32 max_allowed_buf;
u32 nbuf;
- struct xarray page_list;
+ struct rxe_mr_page *page_info;
};
static inline unsigned int mr_page_size(struct rxe_mr *mr)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 305/869] Revert "net/smc: Introduce TCP ULP support"
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (303 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 304/869] RDMA/rxe: Fix iova-to-va conversion for MR page sizes != PAGE_SIZE Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 306/869] tap: fix stack info leak in tap_ioctl() SIOCGIFHWADDR Greg Kroah-Hartman
` (564 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Al Viro, D. Wythe, Tony Lu, Dust Li,
Simon Horman, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: D. Wythe <alibuda@linux.alibaba.com>
[ Upstream commit df31a6b0a3057e66994ad6ccf5d95b9b9514f033 ]
This reverts commit d7cd421da9da2cc7b4d25b8537f66db5c8331c40.
As reported by Al Viro, the TCP ULP support for SMC is fundamentally
broken. The implementation attempts to convert an active TCP socket
into an SMC socket by modifying the underlying `struct file`, dentry,
and inode in-place, which violates core VFS invariants that assume
these structures are immutable for an open file, creating a risk of
use after free errors and general system instability.
Given the severity of this design flaw and the fact that cleaner
alternatives (e.g., LD_PRELOAD, BPF) exist for legacy application
transparency, the correct course of action is to remove this feature
entirely.
Fixes: d7cd421da9da ("net/smc: Introduce TCP ULP support")
Link: https://lore.kernel.org/netdev/Yus1SycZxcd+wHwz@ZenIV/
Reported-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: D. Wythe <alibuda@linux.alibaba.com>
Reviewed-by: Tony Lu <tonylu@linux.alibaba.com>
Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260128055452.98251-1-alibuda@linux.alibaba.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/smc/af_smc.c | 90 +++---------------------------------------------
1 file changed, 4 insertions(+), 86 deletions(-)
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 17ce4d32f64f2..6f8c9b79e7bfb 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -3380,11 +3380,10 @@ int smc_create_clcsk(struct net *net, struct sock *sk, int family)
return 0;
}
-static int __smc_create(struct net *net, struct socket *sock, int protocol,
- int kern, struct socket *clcsock)
+static int smc_create(struct net *net, struct socket *sock, int protocol,
+ int kern)
{
int family = (protocol == SMCPROTO_SMC6) ? PF_INET6 : PF_INET;
- struct smc_sock *smc;
struct sock *sk;
int rc;
@@ -3403,15 +3402,7 @@ static int __smc_create(struct net *net, struct socket *sock, int protocol,
if (!sk)
goto out;
- /* create internal TCP socket for CLC handshake and fallback */
- smc = smc_sk(sk);
-
- rc = 0;
- if (clcsock)
- smc->clcsock = clcsock;
- else
- rc = smc_create_clcsk(net, sk, family);
-
+ rc = smc_create_clcsk(net, sk, family);
if (rc) {
sk_common_release(sk);
sock->sk = NULL;
@@ -3420,76 +3411,12 @@ static int __smc_create(struct net *net, struct socket *sock, int protocol,
return rc;
}
-static int smc_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- return __smc_create(net, sock, protocol, kern, NULL);
-}
-
static const struct net_proto_family smc_sock_family_ops = {
.family = PF_SMC,
.owner = THIS_MODULE,
.create = smc_create,
};
-static int smc_ulp_init(struct sock *sk)
-{
- struct socket *tcp = sk->sk_socket;
- struct net *net = sock_net(sk);
- struct socket *smcsock;
- int protocol, ret;
-
- /* only TCP can be replaced */
- if (tcp->type != SOCK_STREAM || sk->sk_protocol != IPPROTO_TCP ||
- (sk->sk_family != AF_INET && sk->sk_family != AF_INET6))
- return -ESOCKTNOSUPPORT;
- /* don't handle wq now */
- if (tcp->state != SS_UNCONNECTED || !tcp->file || tcp->wq.fasync_list)
- return -ENOTCONN;
-
- if (sk->sk_family == AF_INET)
- protocol = SMCPROTO_SMC;
- else
- protocol = SMCPROTO_SMC6;
-
- smcsock = sock_alloc();
- if (!smcsock)
- return -ENFILE;
-
- smcsock->type = SOCK_STREAM;
- __module_get(THIS_MODULE); /* tried in __tcp_ulp_find_autoload */
- ret = __smc_create(net, smcsock, protocol, 1, tcp);
- if (ret) {
- sock_release(smcsock); /* module_put() which ops won't be NULL */
- return ret;
- }
-
- /* replace tcp socket to smc */
- smcsock->file = tcp->file;
- smcsock->file->private_data = smcsock;
- smcsock->file->f_inode = SOCK_INODE(smcsock); /* replace inode when sock_close */
- smcsock->file->f_path.dentry->d_inode = SOCK_INODE(smcsock); /* dput() in __fput */
- tcp->file = NULL;
-
- return ret;
-}
-
-static void smc_ulp_clone(const struct request_sock *req, struct sock *newsk,
- const gfp_t priority)
-{
- struct inet_connection_sock *icsk = inet_csk(newsk);
-
- /* don't inherit ulp ops to child when listen */
- icsk->icsk_ulp_ops = NULL;
-}
-
-static struct tcp_ulp_ops smc_ulp_ops __read_mostly = {
- .name = "smc",
- .owner = THIS_MODULE,
- .init = smc_ulp_init,
- .clone = smc_ulp_clone,
-};
-
unsigned int smc_net_id;
static __net_init int smc_net_init(struct net *net)
@@ -3617,20 +3544,13 @@ static int __init smc_init(void)
goto out_ib;
}
- rc = tcp_register_ulp(&smc_ulp_ops);
- if (rc) {
- pr_err("%s: tcp_ulp_register fails with %d\n", __func__, rc);
- goto out_lo;
- }
rc = smc_inet_init();
if (rc) {
pr_err("%s: smc_inet_init fails with %d\n", __func__, rc);
- goto out_ulp;
+ goto out_lo;
}
static_branch_enable(&tcp_have_smc);
return 0;
-out_ulp:
- tcp_unregister_ulp(&smc_ulp_ops);
out_lo:
smc_loopback_exit();
out_ib:
@@ -3668,7 +3588,6 @@ static void __exit smc_exit(void)
{
static_branch_disable(&tcp_have_smc);
smc_inet_exit();
- tcp_unregister_ulp(&smc_ulp_ops);
sock_unregister(PF_SMC);
smc_core_exit();
smc_loopback_exit();
@@ -3694,7 +3613,6 @@ MODULE_AUTHOR("Ursula Braun <ubraun@linux.vnet.ibm.com>");
MODULE_DESCRIPTION("smc socket address family");
MODULE_LICENSE("GPL");
MODULE_ALIAS_NETPROTO(PF_SMC);
-MODULE_ALIAS_TCP_ULP("smc");
/* 256 for IPPROTO_SMC and 1 for SOCK_STREAM */
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 256, 1);
#if IS_ENABLED(CONFIG_IPV6)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 306/869] tap: fix stack info leak in tap_ioctl() SIOCGIFHWADDR
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (304 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 305/869] Revert "net/smc: Introduce TCP ULP support" Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 307/869] libceph: Fix potential out-of-bounds access in __ceph_x_decrypt() Greg Kroah-Hartman
` (563 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Xiang Mei, Weiming Shi,
Willem de Bruijn, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <bestswngs@gmail.com>
[ Upstream commit bddc09212c24934643bd44fc794748d2bbb3b6cd ]
In the SIOCGIFHWADDR path, tap_ioctl() copies 16 bytes of an
uninitialised on-stack struct sockaddr_storage to userspace via
ifr_hwaddr, but netif_get_mac_address() only writes sa_family and
dev->addr_len (6 for Ethernet) bytes, leaving sa_data[6..13] uninitialised.
Those 8 trailing bytes leak kernel stack contents; SIOCGIFHWADDR on a
macvtap chardev returns kernel .text and direct-map pointers, defeating
KASLR.
Initialise ss at declaration.
Fixes: 3b23a32a6321 ("net: fix dev_ifsioc_locked() race condition")
Reported-by: Xiang Mei <xmei5@asu.edu>
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Link: https://patch.msgid.link/20260520075736.3415676-3-bestswngs@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/tap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index b3cb7d5a95850..018bc2941a967 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -1015,7 +1015,7 @@ static long tap_ioctl(struct file *file, unsigned int cmd,
unsigned int __user *up = argp;
unsigned short u;
int __user *sp = argp;
- struct sockaddr sa;
+ struct sockaddr sa = {};
int s;
int ret;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 307/869] libceph: Fix potential out-of-bounds access in __ceph_x_decrypt()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (305 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 306/869] tap: fix stack info leak in tap_ioctl() SIOCGIFHWADDR Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 308/869] net: airoha: fix BQL imbalance in TX path Greg Kroah-Hartman
` (562 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Raphael Zimmer, Ilya Dryomov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <raphael.zimmer@tu-ilmenau.de>
[ Upstream commit 821365487aa58d06bda65c676ba215d506ba9768 ]
In __ceph_x_decrypt(), a part of the buffer p is interpreted as a
ceph_x_encrypt_header, and the magic field of this struct is accessed.
This happens without any guarantee that the buffer is large enough to
hold this struct. The function parameter ciphertext_len represents the
length of the ciphertext to decrypt and is guaranteed to be at most the
remaining size of the allocated buffer p. However, this value is not
necessarily greater than sizeof(ceph_x_encrypt_header). E.g., a message
frame of type FRAME_TAG_AUTH_REPLY_MORE, that is just as long to hold
the ciphertext at its end with a ciphertext_len of 8 or less, can
trigger an out-of-bounds memory access when accessing hdr->magic.
This patch fixes the issue by adding a check to ensure that the
decrypted plaintext in the buffer is large enough to represent at least
the ceph_x_encrypt_header.
Cc: stable@vger.kernel.org
Signed-off-by: Raphael Zimmer <raphael.zimmer@tu-ilmenau.de>
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ceph/auth_x.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
index c83559f015e46..f805a813308fd 100644
--- a/net/ceph/auth_x.c
+++ b/net/ceph/auth_x.c
@@ -86,6 +86,11 @@ static int __ceph_x_decrypt(struct ceph_crypto_key *secret, void *p,
if (ret)
return ret;
+ if (plaintext_len < sizeof(*hdr)) {
+ pr_err("%s plaintext too small %d\n", __func__, plaintext_len);
+ return -EINVAL;
+ }
+
if (le64_to_cpu(hdr->magic) != CEPHX_ENC_MAGIC) {
pr_err("%s bad magic\n", __func__);
return -EINVAL;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 308/869] net: airoha: fix BQL imbalance in TX path
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (306 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 307/869] libceph: Fix potential out-of-bounds access in __ceph_x_decrypt() Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 309/869] sched/psi: fix race between file release and pressure write Greg Kroah-Hartman
` (561 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lorenzo Bianconi, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <lorenzo@kernel.org>
[ Upstream commit 2d9f5a118205da2683ffcec78b9347f1f01a820e ]
Fix a possible BQL imbalance in airoha_dev_xmit(), where inflight
packets are accounted only for the AIROHA_NUM_TX_RING netdev TX
queues. The queue index is computed as:
qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx)
txq = netdev_get_tx_queue(dev, qid);
However, airoha_qdma_tx_napi_poll() accounts completions across all
netdev TX queues (num_tx_queues), leading to inconsistent BQL
accounting.
Also reset all netdev TX queues in the ndo_stop callback.
Fixes: 1d304174106c ("net: airoha: Implement BQL support")
Fixes: c9f947769b77 ("net: airoha: Reset BQL stopping the netdevice")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20260421-airoha-fix-bql-v1-1-f135afe4275b@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 9ebc9788ded70..41695f353cdc6 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1777,10 +1777,9 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
WRITE_ONCE(desc->msg1, 0);
if (skb) {
- u16 queue = skb_get_queue_mapping(skb);
struct netdev_queue *txq;
- txq = netdev_get_tx_queue(skb->dev, queue);
+ txq = skb_get_tx_queue(skb->dev, skb);
netdev_tx_completed_queue(txq, 1, skb->len);
if (netif_tx_queue_stopped(txq) &&
q->ndesc - q->queued >= q->free_thr)
@@ -2559,7 +2558,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
spin_lock_bh(&q->lock);
- txq = netdev_get_tx_queue(dev, qid);
+ txq = skb_get_tx_queue(dev, skb);
if (q->queued + nr_frags > q->ndesc) {
/* not enough space in the queue */
netif_tx_stop_queue(txq);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 309/869] sched/psi: fix race between file release and pressure write
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (307 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 308/869] net: airoha: fix BQL imbalance in TX path Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 310/869] netfilter: nat: use kfree_rcu to release ops Greg Kroah-Hartman
` (560 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+33e571025d88efd1312c,
Edward Adam Davis, Chen Ridong, Tejun Heo, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Edward Adam Davis <eadavis@qq.com>
[ Upstream commit a5b98009f16d8a5fb4a8ff9a193f5735515c38fa ]
A potential race condition exists between pressure write and cgroup file
release regarding the priv member of struct kernfs_open_file, which
triggers the uaf reported in [1].
Consider the following scenario involving execution on two separate CPUs:
CPU0 CPU1
==== ====
vfs_rmdir()
kernfs_iop_rmdir()
cgroup_rmdir()
cgroup_kn_lock_live()
cgroup_destroy_locked()
cgroup_addrm_files()
cgroup_rm_file()
kernfs_remove_by_name()
kernfs_remove_by_name_ns()
vfs_write() __kernfs_remove()
new_sync_write() kernfs_drain()
kernfs_fop_write_iter() kernfs_drain_open_files()
cgroup_file_write() kernfs_release_file()
pressure_write() cgroup_file_release()
ctx = of->priv;
kfree(ctx);
of->priv = NULL;
cgroup_kn_unlock()
cgroup_kn_lock_live()
cgroup_get(cgrp)
cgroup_kn_unlock()
if (ctx->psi.trigger) // here, trigger uaf for ctx, that is of->priv
The cgroup_rmdir() is protected by the cgroup_mutex, it also safeguards
the memory deallocation of of->priv performed within cgroup_file_release().
However, the operations involving of->priv executed within pressure_write()
are not entirely covered by the protection of cgroup_mutex. Consequently,
if the code in pressure_write(), specifically the section handling the
ctx variable executes after cgroup_file_release() has completed, a uaf
vulnerability involving of->priv is triggered.
Therefore, the issue can be resolved by extending the scope of the
cgroup_mutex lock within pressure_write() to encompass all code paths
involving of->priv, thereby properly synchronizing the race condition
occurring between cgroup_file_release() and pressure_write().
And, if an live kn lock can be successfully acquired while executing
the pressure write operation, it indicates that the cgroup deletion
process has not yet reached its final stage; consequently, the priv
pointer within open_file cannot be NULL. Therefore, the operation to
retrieve the ctx value must be moved to a point *after* the live kn
lock has been successfully acquired.
In another situation, specifically after entering cgroup_kn_lock_live()
but before acquiring cgroup_mutex, there exists a different class of
race condition:
CPU0: write memory.pressure CPU1: write cgroup.pressure=0
=========================== =============================
kernfs_fop_write_iter()
kernfs_get_active_of(of)
pressure_write()
cgroup_kn_lock_live(memory.pressure)
cgroup_tryget(cgrp)
kernfs_break_active_protection(kn)
... blocks on cgroup_mutex
cgroup_pressure_write()
cgroup_kn_lock_live(cgroup.pressure)
cgroup_file_show(memory.pressure, false)
kernfs_show(false)
kernfs_drain_open_files()
cgroup_file_release(of)
kfree(ctx)
of->priv = NULL
cgroup_kn_unlock()
... acquires cgroup_mutex
ctx = of->priv; // may now be NULL
if (ctx->psi.trigger) // NULL dereference
Consequently, there is a possibility that of->priv is NULL, the pressure
write needs to check for this.
Now that the scope of the cgroup_mutex has been expanded, the original
explicit cgroup_get/put operations are no longer necessary, this is
because acquiring/releasing the live kn lock inherently executes a
cgroup get/put operation.
[1]
BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011
Call Trace:
pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011
cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311
kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352
Allocated by task 9352:
cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256
kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724
do_dentry_open+0x83d/0x13e0 fs/open.c:949
Freed by task 9353:
cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283
kernfs_release_file fs/kernfs/file.c:764 [inline]
kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834
kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525
Fixes: 0e94682b73bf ("psi: introduce psi monitor")
Reported-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=33e571025d88efd1312c
Tested-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com
Signed-off-by: Edward Adam Davis <eadavis@qq.com>
Reviewed-by: Chen Ridong <chenridong@huaweicloud.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/cgroup/cgroup.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index ce012aca272a5..38fd322ccf2e9 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -3881,33 +3881,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)
static ssize_t pressure_write(struct kernfs_open_file *of, char *buf,
size_t nbytes, enum psi_res res)
{
- struct cgroup_file_ctx *ctx = of->priv;
+ struct cgroup_file_ctx *ctx;
struct psi_trigger *new;
struct cgroup *cgrp;
struct psi_group *psi;
+ ssize_t ret = 0;
cgrp = cgroup_kn_lock_live(of->kn, false);
if (!cgrp)
return -ENODEV;
- cgroup_get(cgrp);
- cgroup_kn_unlock(of->kn);
+ ctx = of->priv;
+ if (!ctx) {
+ ret = -ENODEV;
+ goto out_unlock;
+ }
/* Allow only one trigger per file descriptor */
if (ctx->psi.trigger) {
- cgroup_put(cgrp);
- return -EBUSY;
+ ret = -EBUSY;
+ goto out_unlock;
}
psi = cgroup_psi(cgrp);
new = psi_trigger_create(psi, buf, res, of->file, of);
if (IS_ERR(new)) {
- cgroup_put(cgrp);
- return PTR_ERR(new);
+ ret = PTR_ERR(new);
+ goto out_unlock;
}
smp_store_release(&ctx->psi.trigger, new);
- cgroup_put(cgrp);
+
+out_unlock:
+ cgroup_kn_unlock(of->kn);
+ if (ret)
+ return ret;
return nbytes;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 310/869] netfilter: nat: use kfree_rcu to release ops
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (308 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 309/869] sched/psi: fix race between file release and pressure write Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 311/869] ice: fix double-free of tx_buf skb Greg Kroah-Hartman
` (559 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Pablo Neira Ayuso, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <pablo@netfilter.org>
[ Upstream commit 6eda0d771f94267f73f57c94630aa47e90957915 ]
Florian Westphal says:
"Historically this is not an issue, even for normal base hooks: the data
path doesn't use the original nf_hook_ops that are used to register the
callbacks.
However, in v5.14 I added the ability to dump the active netfilter
hooks from userspace.
This code will peek back into the nf_hook_ops that are available
at the tail of the pointer-array blob used by the datapath.
The nat hooks are special, because they are called indirectly from
the central nat dispatcher hook. They are currently invisible to
the nfnl hook dump subsystem though.
But once that changes the nat ops structures have to be deferred too."
Update nf_nat_register_fn() to deal with partial exposition of the hooks
from error path which can be also an issue for nfnetlink_hook.
Fixes: e2cf17d3774c ("netfilter: add new hook nfnl subsystem")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/netfilter.h | 2 ++
net/ipv4/netfilter/iptable_nat.c | 4 ++--
net/ipv6/netfilter/ip6table_nat.c | 4 ++--
net/netfilter/nf_nat_core.c | 10 ++++++----
4 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 2b8aac2c70ada..9b3357d8d8c3e 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -95,6 +95,8 @@ enum nf_hook_ops_type {
};
struct nf_hook_ops {
+ struct rcu_head rcu;
+
/* User fills in from here down. */
nf_hookfn *hook;
struct net_device *dev;
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index a5db7c67d61be..625a1ca13b1ba 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -79,7 +79,7 @@ static int ipt_nat_register_lookups(struct net *net)
while (i)
nf_nat_ipv4_unregister_fn(net, &ops[--i]);
- kfree(ops);
+ kfree_rcu(ops, rcu);
return ret;
}
}
@@ -100,7 +100,7 @@ static void ipt_nat_unregister_lookups(struct net *net)
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++)
nf_nat_ipv4_unregister_fn(net, &ops[i]);
- kfree(ops);
+ kfree_rcu(ops, rcu);
}
static int iptable_nat_table_init(struct net *net)
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c
index e119d4f090cc8..5be723232df8f 100644
--- a/net/ipv6/netfilter/ip6table_nat.c
+++ b/net/ipv6/netfilter/ip6table_nat.c
@@ -81,7 +81,7 @@ static int ip6t_nat_register_lookups(struct net *net)
while (i)
nf_nat_ipv6_unregister_fn(net, &ops[--i]);
- kfree(ops);
+ kfree_rcu(ops, rcu);
return ret;
}
}
@@ -102,7 +102,7 @@ static void ip6t_nat_unregister_lookups(struct net *net)
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++)
nf_nat_ipv6_unregister_fn(net, &ops[i]);
- kfree(ops);
+ kfree_rcu(ops, rcu);
}
static int ip6table_nat_table_init(struct net *net)
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 34e1ff930e28d..109c12fdc57d7 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -1247,9 +1247,11 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
ret = nf_register_net_hooks(net, nat_ops, ops_count);
if (ret < 0) {
mutex_unlock(&nf_nat_proto_mutex);
- for (i = 0; i < ops_count; i++)
- kfree(nat_ops[i].priv);
- kfree(nat_ops);
+ for (i = 0; i < ops_count; i++) {
+ priv = nat_ops[i].priv;
+ kfree_rcu(priv, rcu_head);
+ }
+ kfree_rcu(nat_ops, rcu);
return ret;
}
@@ -1313,7 +1315,7 @@ void nf_nat_unregister_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
}
nat_proto_net->nat_hook_ops = NULL;
- kfree(nat_ops);
+ kfree_rcu(nat_ops, rcu);
}
unlock:
mutex_unlock(&nf_nat_proto_mutex);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 311/869] ice: fix double-free of tx_buf skb
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (309 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 310/869] netfilter: nat: use kfree_rcu to release ops Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 312/869] f2fs: fix data loss caused by incorrect use of nat_entry flag Greg Kroah-Hartman
` (558 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Michal Schmidt, Jacob Keller,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michal Schmidt <mschmidt@redhat.com>
[ Upstream commit 1a303baa715e6b78d6a406aaf335f87ff35acfcd ]
If ice_tso() or ice_tx_csum() fail, the error path in
ice_xmit_frame_ring() frees the skb, but the 'first' tx_buf still points
to it and is marked as valid (ICE_TX_BUF_SKB).
'next_to_use' remains unchanged, so the potential problem will
likely fix itself when the next packet is transmitted and the tx_buf
gets overwritten. But if there is no next packet and the interface is
brought down instead, ice_clean_tx_ring() -> ice_unmap_and_free_tx_buf()
will find the tx_buf and free the skb for the second time.
The fix is to reset the tx_buf type to ICE_TX_BUF_EMPTY in the error
path, so that ice_unmap_and_free_tx_buf().
Move the initialization of 'first' up, to ensure it's already valid in
case we hit the linearization error path.
The bug was spotted by AI while I had it looking for something else.
It also proposed an initial version of the patch.
I reproduced the bug and tested the fix by adding code to inject
failures, on a build with KASAN.
I looked for similar bugs in related Intel drivers and did not find any.
Fixes: d76a60ba7afb ("ice: Add support for VLANs and offloads")
Assisted-by: Claude:claude-4.6-opus-high Cursor
Signed-off-by: Michal Schmidt <mschmidt@redhat.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-4-686c33c9828d@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/ice/ice_txrx.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 0bb9f0dbf5350..16b540258576b 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -2344,6 +2344,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
ice_trace(xmit_frame_ring, tx_ring, skb);
+ /* record the location of the first descriptor for this packet */
+ first = &tx_ring->tx_buf[tx_ring->next_to_use];
+
if (unlikely(ipv6_hopopt_jumbo_remove(skb)))
goto out_drop;
@@ -2372,8 +2375,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
offload.tx_ring = tx_ring;
- /* record the location of the first descriptor for this packet */
- first = &tx_ring->tx_buf[tx_ring->next_to_use];
first->skb = skb;
first->type = ICE_TX_BUF_SKB;
first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN);
@@ -2437,6 +2438,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
out_drop:
ice_trace(xmit_frame_ring_drop, tx_ring, skb);
dev_kfree_skb_any(skb);
+ first->type = ICE_TX_BUF_EMPTY;
return NETDEV_TX_OK;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 312/869] f2fs: fix data loss caused by incorrect use of nat_entry flag
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (310 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 311/869] ice: fix double-free of tx_buf skb Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 313/869] f2fs: avoid reading already updated pages during GC Greg Kroah-Hartman
` (557 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yongpeng Yang, Chao Yu, Jaegeuk Kim,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongpeng Yang <yangyongpeng@xiaomi.com>
[ Upstream commit 238e14eb7226f883b72caccd2d37bf5707df066b ]
Data loss can occur when fsync is performed on a newly created file
(before any checkpoint has been written) concurrently with a checkpoint
operation. The scenario is as follows:
create & write & fsync 'file A' write checkpoint
- f2fs_do_sync_file // inline inode
- f2fs_write_inode // inode folio is dirty
- f2fs_write_checkpoint
- f2fs_flush_merged_writes
- f2fs_sync_node_pages
- f2fs_flush_nat_entries
- f2fs_fsync_node_pages // no dirty node
- f2fs_need_inode_block_update // return false
SPO and lost 'file A'
f2fs_flush_nat_entries() sets the IS_CHECKPOINTED and HAS_LAST_FSYNC
flags for the nat_entry, but this does not mean that the checkpoint has
actually completed successfully. However, f2fs_need_inode_block_update()
checks these flags and incorrectly assumes that the checkpoint has
finished.
The root cause is that the semantics of IS_CHECKPOINTED and
HAS_LAST_FSYNC are only guaranteed after the checkpoint write fully
completes.
This patch modifies f2fs_need_inode_block_update() to acquire the
sbi->node_write lock before reading the nat_entry flags, ensuring that
once IS_CHECKPOINTED and HAS_LAST_FSYNC are observed to be set, the
checkpoint operation has already completed.
Fixes: e05df3b115e7 ("f2fs: add node operations")
Signed-off-by: Yongpeng Yang <yangyongpeng@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/node.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 9709a212e6a03..56d5fb77569d7 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -419,6 +419,7 @@ bool f2fs_need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino)
struct nat_entry *e;
bool need_update = true;
+ f2fs_down_read(&sbi->node_write);
f2fs_down_read(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, ino);
if (e && get_nat_flag(e, HAS_LAST_FSYNC) &&
@@ -426,6 +427,7 @@ bool f2fs_need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino)
get_nat_flag(e, HAS_FSYNCED_INODE)))
need_update = false;
f2fs_up_read(&nm_i->nat_tree_lock);
+ f2fs_up_read(&sbi->node_write);
return need_update;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 313/869] f2fs: avoid reading already updated pages during GC
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (311 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 312/869] f2fs: fix data loss caused by incorrect use of nat_entry flag Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 314/869] greybus: raw: fix use-after-free on cdev close Greg Kroah-Hartman
` (556 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jianan Huang, Sheng Yong, Chao Yu,
Jaegeuk Kim, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jianan Huang <huangjianan@xiaomi.com>
[ Upstream commit 570e2ccc7cb35fe720106964e65060602d3d2ac4 ]
We found the following issue during fuzz testing:
page: refcount:3 mapcount:0 mapping:00000000b6e89c65 index:0x18b2dc pfn:0x161ba9
memcg:f8ffff800e269c00
aops:f2fs_meta_aops ino:2
flags: 0x52880000000080a9(locked|waiters|uptodate|lru|private|zone=1|kasantag=0x4a)
raw: 52880000000080a9 fffffffec6e17588 fffffffec0ccc088 a7ffff8067063618
raw: 000000000018b2dc 0000000000000009 00000003ffffffff f8ffff800e269c00
page dumped because: VM_BUG_ON_FOLIO(folio_test_uptodate(folio))
page_owner tracks the page as allocated
post_alloc_hook+0x58c/0x5ec
prep_new_page+0x34/0x284
get_page_from_freelist+0x2dcc/0x2e8c
__alloc_pages_noprof+0x280/0x76c
__folio_alloc_noprof+0x18/0xac
__filemap_get_folio+0x6bc/0xdc4
pagecache_get_page+0x3c/0x104
do_garbage_collect+0x5c78/0x77a4
f2fs_gc+0xd74/0x25f0
gc_thread_func+0xb28/0x2930
kthread+0x464/0x5d8
ret_from_fork+0x10/0x20
------------[ cut here ]------------
kernel BUG at mm/filemap.c:1563!
folio_end_read+0x140/0x168
f2fs_finish_read_bio+0x5c4/0xb80
f2fs_read_end_io+0x64c/0x708
bio_endio+0x85c/0x8c0
blk_update_request+0x690/0x127c
scsi_end_request+0x9c/0xb8c
scsi_io_completion+0xf0/0x250
scsi_finish_command+0x430/0x45c
scsi_complete+0x178/0x6d4
blk_mq_complete_request+0xcc/0x104
scsi_done_internal+0x214/0x454
scsi_done+0x24/0x34
which is similar to the problem reported by syzbot:
https://syzkaller.appspot.com/bug?extid=3686758660f980b402dc
This case is consistent with the description in commit 9bf1a3f
("f2fs: avoid GC causing encrypted file corrupted"):
Page 1 is moved from blkaddr A to blkaddr B by move_data_block, and after
being written it is marked as uptodate. Then, Page 1 is moved from blkaddr
B to blkaddr C, VM_BUG_ON_FOLIO was triggered in the endio initiated by
ra_data_block.
There is no need to read Page 1 again from blkaddr B, since it has already
been updated. Therefore, avoid initiating I/O in this case.
Fixes: 6aa58d8ad20a ("f2fs: readahead encrypted block during GC")
Signed-off-by: Jianan Huang <huangjianan@xiaomi.com>
Signed-off-by: Sheng Yong <shengyong1@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/gc.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 6c831276d81da..6924876f1c2f5 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -1222,7 +1222,7 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
.encrypted_page = NULL,
.in_list = 0,
};
- int err;
+ int err = 0;
f2fs_down_read(&F2FS_I(inode)->i_sem);
if (f2fs_is_cow_file(inode)) {
@@ -1287,6 +1287,9 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
goto put_page;
}
+ if (PageUptodate(fio.encrypted_page))
+ goto put_encrypted_page;
+
err = f2fs_submit_page_bio(&fio);
if (err)
goto put_encrypted_page;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 314/869] greybus: raw: fix use-after-free on cdev close
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (312 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 313/869] f2fs: avoid reading already updated pages during GC Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 315/869] net: pull headers in qdisc_pkt_len_segs_init() Greg Kroah-Hartman
` (555 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johan Hovold, Damien Riégel,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Damien Riégel <damien.riegel@silabs.com>
[ Upstream commit 983cc2c7efbce04ecbf6328448d895044dd6ab31 ]
This addresses a use-after-free bug when a raw bundle is disconnected
but its chardev is still opened by an application. When the application
releases the cdev, it causes the following panic when init on free is
enabled (CONFIG_INIT_ON_FREE_DEFAULT_ON=y):
refcount_t: underflow; use-after-free.
WARNING: CPU: 0 PID: 139 at lib/refcount.c:28 refcount_warn_saturate+0xd0/0x130
...
Call Trace:
<TASK>
cdev_put+0x18/0x30
__fput+0x255/0x2a0
__x64_sys_close+0x3d/0x80
do_syscall_64+0xa4/0x290
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The cdev is contained in the "gb_raw" structure, which is freed in the
disconnect operation. When the cdev is released at a later time,
cdev_put gets an address that points to freed memory.
To fix this use-after-free, convert the struct device from a pointer to
being embedded, that makes the lifetime of the cdev and of this device
the same. Then, use cdev_device_add, which guarantees that the device
won't be released until all references to the cdev have been released.
Finally, delegate the freeing of the structure to the device release
function, instead of freeing immediately in the disconnect callback.
Fixes: e806c7fb8e9b ("greybus: raw: add raw greybus kernel driver")
Reviewed-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Damien Riégel <damien.riegel@silabs.com>
Link: https://patch.msgid.link/20260324140039.40001-1-damien.riegel@silabs.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/staging/greybus/raw.c | 67 +++++++++++++++++------------------
1 file changed, 33 insertions(+), 34 deletions(-)
diff --git a/drivers/staging/greybus/raw.c b/drivers/staging/greybus/raw.c
index 71de6776739c2..e668438e1a2c4 100644
--- a/drivers/staging/greybus/raw.c
+++ b/drivers/staging/greybus/raw.c
@@ -21,9 +21,8 @@ struct gb_raw {
struct list_head list;
int list_data;
struct mutex list_lock;
- dev_t dev;
struct cdev cdev;
- struct device *device;
+ struct device dev;
};
struct raw_data {
@@ -148,6 +147,15 @@ static int gb_raw_send(struct gb_raw *raw, u32 len, const char __user *data)
return retval;
}
+static void raw_dev_release(struct device *dev)
+{
+ struct gb_raw *raw = container_of(dev, struct gb_raw, dev);
+
+ ida_free(&minors, MINOR(raw->dev.devt));
+
+ kfree(raw);
+}
+
static int gb_raw_probe(struct gb_bundle *bundle,
const struct greybus_bundle_id *id)
{
@@ -164,15 +172,30 @@ static int gb_raw_probe(struct gb_bundle *bundle,
if (cport_desc->protocol_id != GREYBUS_PROTOCOL_RAW)
return -ENODEV;
+ minor = ida_alloc(&minors, GFP_KERNEL);
+ if (minor < 0)
+ return minor;
+
raw = kzalloc(sizeof(*raw), GFP_KERNEL);
- if (!raw)
+ if (!raw) {
+ ida_free(&minors, minor);
return -ENOMEM;
+ }
+
+ device_initialize(&raw->dev);
+ raw->dev.devt = MKDEV(raw_major, minor);
+ raw->dev.class = &raw_class;
+ raw->dev.parent = &bundle->dev;
+ raw->dev.release = raw_dev_release;
+ retval = dev_set_name(&raw->dev, "gb!raw%d", minor);
+ if (retval)
+ goto error_put_device;
connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
gb_raw_request_handler);
if (IS_ERR(connection)) {
retval = PTR_ERR(connection);
- goto error_free;
+ goto error_put_device;
}
INIT_LIST_HEAD(&raw->list);
@@ -181,46 +204,26 @@ static int gb_raw_probe(struct gb_bundle *bundle,
raw->connection = connection;
greybus_set_drvdata(bundle, raw);
- minor = ida_alloc(&minors, GFP_KERNEL);
- if (minor < 0) {
- retval = minor;
- goto error_connection_destroy;
- }
-
- raw->dev = MKDEV(raw_major, minor);
cdev_init(&raw->cdev, &raw_fops);
retval = gb_connection_enable(connection);
if (retval)
- goto error_remove_ida;
+ goto error_connection_destroy;
- retval = cdev_add(&raw->cdev, raw->dev, 1);
+ retval = cdev_device_add(&raw->cdev, &raw->dev);
if (retval)
goto error_connection_disable;
- raw->device = device_create(&raw_class, &connection->bundle->dev,
- raw->dev, raw, "gb!raw%d", minor);
- if (IS_ERR(raw->device)) {
- retval = PTR_ERR(raw->device);
- goto error_del_cdev;
- }
-
return 0;
-error_del_cdev:
- cdev_del(&raw->cdev);
-
error_connection_disable:
gb_connection_disable(connection);
-error_remove_ida:
- ida_free(&minors, minor);
-
error_connection_destroy:
gb_connection_destroy(connection);
-error_free:
- kfree(raw);
+error_put_device:
+ put_device(&raw->dev);
return retval;
}
@@ -231,11 +234,8 @@ static void gb_raw_disconnect(struct gb_bundle *bundle)
struct raw_data *raw_data;
struct raw_data *temp;
- // FIXME - handle removing a connection when the char device node is open.
- device_destroy(&raw_class, raw->dev);
- cdev_del(&raw->cdev);
+ cdev_device_del(&raw->cdev, &raw->dev);
gb_connection_disable(connection);
- ida_free(&minors, MINOR(raw->dev));
gb_connection_destroy(connection);
mutex_lock(&raw->list_lock);
@@ -244,8 +244,7 @@ static void gb_raw_disconnect(struct gb_bundle *bundle)
kfree(raw_data);
}
mutex_unlock(&raw->list_lock);
-
- kfree(raw);
+ put_device(&raw->dev);
}
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 315/869] net: pull headers in qdisc_pkt_len_segs_init()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (313 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 314/869] greybus: raw: fix use-after-free on cdev close Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 316/869] wifi: mt76: mt7925: fix potential deadlock in mt7925_roc_abort_sync Greg Kroah-Hartman
` (554 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Dumazet, Joe Damato,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 7fb4c19670110f052c04e1ec1d2b953b9f4f57e4 ]
Most ndo_start_xmit() methods expects headers of gso packets
to be already in skb->head.
net/core/tso.c users are particularly at risk, because tso_build_hdr()
does a memcpy(hdr, skb->data, hdr_len);
qdisc_pkt_len_segs_init() already does a dissection of gso packets.
Use pskb_may_pull() instead of skb_header_pointer() to make
sure drivers do not have to reimplement this.
Some malicious packets could be fed, detect them so that we can
drop them sooner with a new SKB_DROP_REASON_SKB_BAD_GSO drop_reason.
Fixes: e876f208af18 ("net: Add a software TSO helper API")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Joe Damato <joe@dama.to>
Link: https://patch.msgid.link/20260403221540.3297753-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/dropreason-core.h | 3 ++
net/core/dev.c | 81 +++++++++++++++++++++--------------
2 files changed, 53 insertions(+), 31 deletions(-)
diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h
index 07826c85d31ca..f8f4d2b77e6ac 100644
--- a/include/net/dropreason-core.h
+++ b/include/net/dropreason-core.h
@@ -66,6 +66,7 @@
FN(UNHANDLED_PROTO) \
FN(SKB_CSUM) \
FN(SKB_GSO_SEG) \
+ FN(SKB_BAD_GSO) \
FN(SKB_UCOPY_FAULT) \
FN(DEV_HDR) \
FN(DEV_READY) \
@@ -331,6 +332,8 @@ enum skb_drop_reason {
SKB_DROP_REASON_SKB_CSUM,
/** @SKB_DROP_REASON_SKB_GSO_SEG: gso segmentation error */
SKB_DROP_REASON_SKB_GSO_SEG,
+ /** @SKB_DROP_REASON_SKB_BAD_GSO: malicious gso packet. */
+ SKB_DROP_REASON_SKB_BAD_GSO,
/**
* @SKB_DROP_REASON_SKB_UCOPY_FAULT: failed to copy data from user space,
* e.g., via zerocopy_sg_from_iter() or skb_orphan_frags_rx()
diff --git a/net/core/dev.c b/net/core/dev.c
index 48f099f9e804c..388770b88b449 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3862,49 +3862,62 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d
}
EXPORT_SYMBOL_GPL(validate_xmit_skb_list);
-static void qdisc_pkt_len_init(struct sk_buff *skb)
+static enum skb_drop_reason qdisc_pkt_len_init(struct sk_buff *skb)
{
- const struct skb_shared_info *shinfo = skb_shinfo(skb);
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ unsigned int hdr_len, tlen;
+ u16 gso_segs;
qdisc_skb_cb(skb)->pkt_len = skb->len;
+ if (!shinfo->gso_size)
+ return SKB_NOT_DROPPED_YET;
+
+ gso_segs = shinfo->gso_segs;
/* To get more precise estimation of bytes sent on wire,
* we add to pkt_len the headers size of all segments
*/
- if (shinfo->gso_size && skb_transport_header_was_set(skb)) {
- u16 gso_segs = shinfo->gso_segs;
- unsigned int hdr_len;
- /* mac layer + network layer */
+ /* mac layer + network layer */
+ if (!skb->encapsulation) {
+ if (unlikely(!skb_transport_header_was_set(skb)))
+ return SKB_NOT_DROPPED_YET;
hdr_len = skb_transport_offset(skb);
+ } else {
+ hdr_len = skb_inner_transport_offset(skb);
+ }
+ /* + transport layer */
+ if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
+ const struct tcphdr *th;
- /* + transport layer */
- if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
- const struct tcphdr *th;
- struct tcphdr _tcphdr;
-
- th = skb_header_pointer(skb, hdr_len,
- sizeof(_tcphdr), &_tcphdr);
- if (likely(th))
- hdr_len += __tcp_hdrlen(th);
- } else if (shinfo->gso_type & SKB_GSO_UDP_L4) {
- struct udphdr _udphdr;
-
- if (skb_header_pointer(skb, hdr_len,
- sizeof(_udphdr), &_udphdr))
- hdr_len += sizeof(struct udphdr);
- }
+ if (!pskb_may_pull(skb, hdr_len + sizeof(struct tcphdr)))
+ return SKB_DROP_REASON_SKB_BAD_GSO;
- if (unlikely(shinfo->gso_type & SKB_GSO_DODGY)) {
- int payload = skb->len - hdr_len;
+ th = (const struct tcphdr *)(skb->data + hdr_len);
+ tlen = __tcp_hdrlen(th);
+ if (tlen < sizeof(*th))
+ return SKB_DROP_REASON_SKB_BAD_GSO;
+ hdr_len += tlen;
+ if (!pskb_may_pull(skb, hdr_len))
+ return SKB_DROP_REASON_SKB_BAD_GSO;
+ } else if (shinfo->gso_type & SKB_GSO_UDP_L4) {
+ if (!pskb_may_pull(skb, hdr_len + sizeof(struct udphdr)))
+ return SKB_DROP_REASON_SKB_BAD_GSO;
+ hdr_len += sizeof(struct udphdr);
+ }
- /* Malicious packet. */
- if (payload <= 0)
- return;
- gso_segs = DIV_ROUND_UP(payload, shinfo->gso_size);
- }
- qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len;
+ /* prior pskb_may_pull() might have changed skb->head. */
+ shinfo = skb_shinfo(skb);
+ if (unlikely(shinfo->gso_type & SKB_GSO_DODGY)) {
+ int payload = skb->len - hdr_len;
+
+ /* Malicious packet. */
+ if (payload <= 0)
+ return SKB_DROP_REASON_SKB_BAD_GSO;
+ gso_segs = DIV_ROUND_UP(payload, shinfo->gso_size);
}
+ qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len;
+ return SKB_NOT_DROPPED_YET;
}
static int dev_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *q,
@@ -4485,6 +4498,7 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
struct Qdisc *q;
int rc = -ENOMEM;
bool again = false;
+ enum skb_drop_reason reason;
skb_reset_mac_header(skb);
skb_assert_len(skb);
@@ -4492,6 +4506,12 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_SCHED_TSTAMP))
__skb_tstamp_tx(skb, NULL, NULL, skb->sk, SCM_TSTAMP_SCHED);
+ reason = qdisc_pkt_len_init(skb);
+ if (unlikely(reason)) {
+ dev_core_stats_tx_dropped_inc(dev);
+ kfree_skb_reason(skb, reason);
+ return -EINVAL;
+ }
/* Disable soft irqs for various locks below. Also
* stops preemption for RCU.
*/
@@ -4499,7 +4519,6 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
skb_update_prio(skb);
- qdisc_pkt_len_init(skb);
tcx_set_ingress(skb, false);
#ifdef CONFIG_NET_EGRESS
if (static_branch_unlikely(&egress_needed_key)) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 316/869] wifi: mt76: mt7925: fix potential deadlock in mt7925_roc_abort_sync
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (314 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 315/869] net: pull headers in qdisc_pkt_len_segs_init() Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 317/869] wifi: mt76: Fix memory leak destroying device Greg Kroah-Hartman
` (553 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Quan Zhou, Sean Wang, Felix Fietkau,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Wang <sean.wang@mediatek.com>
[ Upstream commit dd08ca3f092f4185ece69ce2a835c23198b1628a ]
roc_abort_sync() can deadlock with roc_work(). roc_work() holds
dev->mt76.mutex, while cancel_work_sync() waits for roc_work()
to finish. If the caller already owns the same mutex, both
sides block and no progress is possible.
This deadlock can occur during station removal when
mt76_sta_state() -> mt76_sta_remove() ->
mt7925_mac_sta_remove_link() -> mt7925_mac_link_sta_remove() ->
mt7925_roc_abort_sync() invokes cancel_work_sync() while
roc_work() is still running and holding dev->mt76.mutex.
This avoids the mutex deadlock and preserves exactly-once
work ownership.
Fixes: 45064d19fd3a ("wifi: mt76: mt7925: fix a potential association failure upon resuming")
Co-developed-by: Quan Zhou <quan.zhou@mediatek.com>
Signed-off-by: Quan Zhou <quan.zhou@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Link: https://patch.msgid.link/20251216013849.17976-1-sean.wang@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index deb226cf5413b..9a52607dc5a8f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -473,12 +473,16 @@ void mt7925_roc_abort_sync(struct mt792x_dev *dev)
{
struct mt792x_phy *phy = &dev->phy;
+ if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
+ return;
+
del_timer_sync(&phy->roc_timer);
- cancel_work_sync(&phy->roc_work);
- if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
- ieee80211_iterate_interfaces(mt76_hw(dev),
- IEEE80211_IFACE_ITER_RESUME_ALL,
- mt7925_roc_iter, (void *)phy);
+
+ cancel_work(&phy->roc_work);
+
+ ieee80211_iterate_interfaces(mt76_hw(dev),
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7925_roc_iter, (void *)phy);
}
EXPORT_SYMBOL_GPL(mt7925_roc_abort_sync);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 317/869] wifi: mt76: Fix memory leak destroying device
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (315 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 316/869] wifi: mt76: mt7925: fix potential deadlock in mt7925_roc_abort_sync Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 318/869] powerpc/64s: Fix unmap race with PMD migration entries Greg Kroah-Hartman
` (552 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lorenzo Bianconi, Felix Fietkau,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <lorenzo@kernel.org>
[ Upstream commit 6b470f36616e3448d44b0ef4b1de2a3e3a31b5be ]
All MT76 rx queues have an associated page_pool even if the queue is not
associated to a NAPI (e.g. WED RRO queues with WED enabled). Destroy the
page_pool running mt76_dma_cleanup routine during module unload.
Moreover returns pages to the page pool if WED is not enabled for WED RRO
queues.
Fixes: 950d0abb5cd94 ("wifi: mt76: mt7996: add wed rx support")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20251208-mt76-fix-memory-leak-v1-1-cba813fc62b8@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/mediatek/mt76/dma.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index e02741c5892e6..872d39d46a332 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -769,7 +769,11 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
if (!buf)
break;
- if (!mt76_queue_is_wed_rro(q))
+ if (mtk_wed_device_active(&dev->mmio.wed) &&
+ mt76_queue_is_wed_rro(q))
+ continue;
+
+ if (!mt76_queue_is_wed_rro_ind(q))
mt76_put_page_pool_buf(buf, false);
} while (1);
@@ -1033,10 +1037,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
mt76_for_each_q_rx(dev, i) {
struct mt76_queue *q = &dev->q_rx[i];
- if (mtk_wed_device_active(&dev->mmio.wed) &&
- mt76_queue_is_wed_rro(q))
- continue;
-
netif_napi_del(&dev->napi[i]);
mt76_dma_rx_cleanup(dev, q);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 318/869] powerpc/64s: Fix unmap race with PMD migration entries
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (316 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 317/869] wifi: mt76: Fix memory leak destroying device Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 319/869] powerpc/pgtable-frag: Fix bad page state in pte_frag_destroy Greg Kroah-Hartman
` (551 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pavithra Prakash,
Ritesh Harjani (IBM), Venkat Rao Bagalkote, Madhavan Srinivasan,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
[ Upstream commit bbcbf045d6c778e82b47a35fc8728387708e9a3d ]
The following race is possible with migration swap entries or
device-private THP entries. e.g. when move_pages is called on a PMD THP
page, then there maybe an intermediate state, where PMD entry acts as
a migration swap entry (pmd_present() is true). Then if an munmap
happens at the same time, then this VM_BUG_ON() can happen in
pmdp_huge_get_and_clear_full().
This patch fixes that.
Thread A: move_pages() syscall
add_folio_for_migration()
mmap_read_lock(mm)
folio_isolate_lru(folio)
mmap_read_unlock(mm)
do_move_pages_to_node()
migrate_pages()
try_to_migrate_one()
spin_lock(ptl)
set_pmd_migration_entry()
pmdp_invalidate() # PMD: _PAGE_INVALID | _PAGE_PTE | pfn
set_pmd_at() # PMD: migration swap entry (pmd_present=0)
spin_unlock(ptl)
[page copy phase] # <--- RACE WINDOW -->
Thread B: munmap()
mmap_write_downgrade(mm)
unmap_vmas() -> zap_pmd_range()
zap_huge_pmd()
__pmd_trans_huge_lock()
pmd_is_huge(): # !pmd_present && !pmd_none -> TRUE (swap entry)
pmd_lock() -> # spin_lock(ptl), waits for Thread A to release ptl
pmdp_huge_get_and_clear_full()
VM_BUG_ON(!pmd_present(*pmdp)) # HITS!
[ 287.738700][ T1867] ------------[ cut here ]------------
[ 287.743843][ T1867] kernel BUG at arch/powerpc/mm/book3s64/pgtable.c:187!
cpu 0x0: Vector: 700 (Program Check) at [c00000044037f4f0]
pc: c000000000094ca4: pmdp_huge_get_and_clear_full+0x6c/0x23c
lr: c000000000645dec: zap_huge_pmd+0xb0/0x868
sp: c00000044037f790
msr: 800000000282b033
current = 0xc0000004032c1a00
paca = 0xc000000004fe0000 irqmask: 0x03 irq_happened: 0x09
pid = 1867, comm = a.out
kernel BUG at :187!
Linux version 6.19.0-12136-g14360d4f917c-dirty (powerpc64le-linux-gnu-gcc (Debian 12.2.0-14) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40) #27 SMP PREEMPT Sun Feb 22 10:38:56 IST 2026
enter ? for help
[link register ] c000000000645dec zap_huge_pmd+0xb0/0x868
[c00000044037f790] c00000044037f7d0 (unreliable)
[c00000044037f7d0] c000000000645dcc zap_huge_pmd+0x90/0x868
[c00000044037f840] c0000000005724cc unmap_page_range+0x176c/0x1f40
[c00000044037fa00] c000000000572ea0 unmap_vmas+0xb0/0x1d8
[c00000044037fa90] c0000000005af254 unmap_region+0xb4/0x128
[c00000044037fb50] c0000000005af400 vms_complete_munmap_vmas+0x138/0x310
[c00000044037fbe0] c0000000005b0f1c do_vmi_align_munmap+0x1ec/0x238
[c00000044037fd30] c0000000005b3688 __vm_munmap+0x170/0x1f8
[c00000044037fdf0] c000000000587f74 sys_munmap+0x2c/0x40
[c00000044037fe10] c000000000032668 system_call_exception+0x128/0x350
[c00000044037fe50] c00000000000d05c system_call_vectored_common+0x15c/0x2ec
---- Exception: 3000 (System Call Vectored) at 0000000010064a2c
SP (7fff9b1ee9c0) is in userspace
0:mon> zh
commit a30b48bf1b24 ("mm/migrate_device: implement THP migration of zone device pages"),
enabled migration for device-private PMD entries. Hence this is one
other path where this warning could get trigger from.
------------[ cut here ]------------
WARNING: arch/powerpc/mm/book3s64/hash_pgtable.c:199 at hash__pmd_hugepage_update+0x48/0x284, CPU#3: hmm-tests/1905
Modules linked in: test_hmm
CPU: 3 UID: 0 PID: 1905 Comm: hmm-tests Tainted: G B W L N 7.0.0-rc1-01438-g7e2f0ee7581c #21 PREEMPT
Tainted: [B]=BAD_PAGE, [W]=WARN, [L]=SOFTLOCKUP, [N]=TEST
Hardware name: IBM pSeries (emulated by qemu) POWER10 (architected) 0x801200 0xf000006 of:SLOF,git-ee03ae pSeries
NIP [c000000000096b70] hash__pmd_hugepage_update+0x48/0x284
LR [c000000000096e7c] hash__pmdp_huge_get_and_clear+0xd0/0xd4
Call Trace:
[c000000604707670] [c000000004e102b8] 0xc000000004e102b8 (unreliable)
[c000000604707700] [c00000000064ec3c] set_pmd_migration_entry+0x414/0x498
[c000000604707760] [c00000000063e5a4] migrate_vma_collect_pmd+0x12e8/0x16c4
[c000000604707890] [c00000000059282c] walk_pgd_range+0x7fc/0xd2c
[c000000604707990] [c000000000592e40] __walk_page_range+0xe4/0x2ac
[c000000604707a10] [c000000000593534] walk_page_range_mm_unsafe+0x204/0x2a4
[c000000604707ab0] [c00000000063af10] migrate_vma_setup+0x1dc/0x2e8
[c000000604707b10] [c008000006a21838] dmirror_migrate_to_system.constprop.0+0x210/0x4b0 [test_hmm]
[c000000604707c30] [c008000006a245b0] dmirror_fops_unlocked_ioctl+0x454/0xa5c [test_hmm]
[c000000604707d20] [c0000000006aab84] sys_ioctl+0x4ec/0x1178
[c000000604707e10] [c0000000000326a8] system_call_exception+0x128/0x350
[c000000604707e50] [c00000000000d05c] system_call_vectored_common+0x15c/0x2ec
---- interrupt: 3000 at 0x7fffbe44f50c
Fixes: 75358ea359e7c ("powerpc/mm/book3s64: Fix MADV_DONTNEED and parallel page fault race")
Fixes: a30b48bf1b24 ("mm/migrate_device: implement THP migration of zone device pages")
Reported-by: Pavithra Prakash <pavrampu@linux.vnet.ibm.com>
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/9437e5ef28d1e2f5cbdd7f8286350ce93c1d43c5.1773078178.git.ritesh.list@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/powerpc/include/asm/book3s/64/pgtable.h | 15 +++++++++++++++
arch/powerpc/mm/book3s64/pgtable.c | 13 +++++++++----
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 6d98e6f08d4de..a709969277f9c 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -1304,6 +1304,21 @@ extern int pudp_test_and_clear_young(struct vm_area_struct *vma,
static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
unsigned long addr, pmd_t *pmdp)
{
+ /*
+ * Non-present PMDs can be migration entries or device-private THP
+ * entries. This can happen at 2 places:
+ * - When the address space is being unmapped zap_huge_pmd(), and we
+ * encounter non-present pmds.
+ * - migrate_vma_collect_huge_pmd() could calls this during migration
+ * of device-private pmd entries.
+ */
+ if (!pmd_present(*pmdp)) {
+ pmd_t old_pmd = READ_ONCE(*pmdp);
+
+ pmd_clear(pmdp);
+ return old_pmd;
+ }
+
if (radix_enabled())
return radix__pmdp_huge_get_and_clear(mm, addr, pmdp);
return hash__pmdp_huge_get_and_clear(mm, addr, pmdp);
diff --git a/arch/powerpc/mm/book3s64/pgtable.c b/arch/powerpc/mm/book3s64/pgtable.c
index 5a4a753690431..af3fe81c7e67a 100644
--- a/arch/powerpc/mm/book3s64/pgtable.c
+++ b/arch/powerpc/mm/book3s64/pgtable.c
@@ -191,16 +191,21 @@ pmd_t pmdp_huge_get_and_clear_full(struct vm_area_struct *vma,
unsigned long addr, pmd_t *pmdp, int full)
{
pmd_t pmd;
+ bool was_present = pmd_present(*pmdp);
+
VM_BUG_ON(addr & ~HPAGE_PMD_MASK);
- VM_BUG_ON((pmd_present(*pmdp) && !pmd_trans_huge(*pmdp) &&
- !pmd_devmap(*pmdp)) || !pmd_present(*pmdp));
+ VM_BUG_ON(was_present && !pmd_trans_huge(*pmdp) && !pmd_devmap(*pmdp));
+ /*
+ * Check pmdp_huge_get_and_clear() for non-present pmd case.
+ */
pmd = pmdp_huge_get_and_clear(vma->vm_mm, addr, pmdp);
/*
* if it not a fullmm flush, then we can possibly end up converting
* this PMD pte entry to a regular level 0 PTE by a parallel page fault.
- * Make sure we flush the tlb in this case.
+ * Make sure we flush the tlb in this case. TLB flush not needed for
+ * non-present case.
*/
- if (!full)
+ if (was_present && !full)
flush_pmd_tlb_range(vma, addr, addr + HPAGE_PMD_SIZE);
return pmd;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 319/869] powerpc/pgtable-frag: Fix bad page state in pte_frag_destroy
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (317 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 318/869] powerpc/64s: Fix unmap race with PMD migration entries Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 320/869] vdpa: use generic driver_override infrastructure Greg Kroah-Hartman
` (550 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christophe Leroy (CS GROUP),
Ritesh Harjani (IBM), Venkat Rao Bagalkote, Madhavan Srinivasan,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
[ Upstream commit fda4d71651f71c44b35829d13f3c8bf920032f77 ]
powerpc uses pt_frag_refcount as a reference counter for tracking it's
pte and pmd page table fragments. For PTE table, in case of Hash with
64K pagesize, we have 16 fragments of 4K size in one 64K page.
Patch series [1] "mm: free retracted page table by RCU"
added pte_free_defer() to defer the freeing of PTE tables when
retract_page_tables() is called for madvise MADV_COLLAPSE on shmem
range.
[1]: https://lore.kernel.org/all/7cd843a9-aa80-14f-5eb2-33427363c20@google.com/
pte_free_defer() sets the active flag on the corresponding fragment's
folio & calls pte_fragment_free(), which reduces the pt_frag_refcount.
When pt_frag_refcount reaches 0 (no active fragment using the folio), it
checks if the folio active flag is set, if set, it calls call_rcu to
free the folio, it the active flag is unset then it calls pte_free_now().
Now, this can lead to following problem in a corner case...
[ 265.351553][ T183] BUG: Bad page state in process a.out pfn:20d62
[ 265.353555][ T183] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x20d62
[ 265.355457][ T183] flags: 0x3ffff800000100(active|node=0|zone=0|lastcpupid=0x7ffff)
[ 265.358719][ T183] raw: 003ffff800000100 0000000000000000 5deadbeef0000122 0000000000000000
[ 265.360177][ T183] raw: 0000000000000000 c0000000119caf58 00000000ffffffff 0000000000000000
[ 265.361438][ T183] page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set
[ 265.362572][ T183] Modules linked in:
[ 265.364622][ T183] CPU: 0 UID: 0 PID: 183 Comm: a.out Not tainted 6.18.0-rc3-00141-g1ddeaaace7ff-dirty #53 VOLUNTARY
[ 265.364785][ T183] Hardware name: IBM pSeries (emulated by qemu) POWER10 (architected) 0x801200 0xf000006 of:SLOF,git-ee03ae pSeries
[ 265.364908][ T183] Call Trace:
[ 265.364955][ T183] [c000000011e6f7c0] [c000000001cfaa18] dump_stack_lvl+0x130/0x148 (unreliable)
[ 265.365202][ T183] [c000000011e6f7f0] [c000000000794758] bad_page+0xb4/0x1c8
[ 265.365384][ T183] [c000000011e6f890] [c00000000079c020] __free_frozen_pages+0x838/0xd08
[ 265.365554][ T183] [c000000011e6f980] [c0000000000a70ac] pte_frag_destroy+0x298/0x310
[ 265.365729][ T183] [c000000011e6fa30] [c0000000000aa764] arch_exit_mmap+0x34/0x218
[ 265.365912][ T183] [c000000011e6fa80] [c000000000751698] exit_mmap+0xb8/0x820
[ 265.366080][ T183] [c000000011e6fc30] [c0000000001b1258] __mmput+0x98/0x300
[ 265.366244][ T183] [c000000011e6fc80] [c0000000001c81f8] do_exit+0x470/0x1508
[ 265.366421][ T183] [c000000011e6fd70] [c0000000001c95e4] do_group_exit+0x88/0x148
[ 265.366602][ T183] [c000000011e6fdc0] [c0000000001c96ec] pid_child_should_wake+0x0/0x178
[ 265.366780][ T183] [c000000011e6fdf0] [c00000000003a270] system_call_exception+0x1b0/0x4e0
[ 265.366958][ T183] [c000000011e6fe50] [c00000000000d05c] system_call_vectored_common+0x15c/0x2ec
The bad page state error occurs when such a folio gets freed (with
active flag set), from do_exit() path in parallel.
... this can happen when the pte fragment was allocated from this folio,
but when all the fragments get freed, the pte_frag_refcount still had some
unused fragments. Now, if this process exits, with such folio as it's cached
pte_frag in mm->context, then during pte_frag_destroy(), we simply call
pagetable_dtor() and pagetable_free(), meaning it doesn't clear the
active flag. This, can lead to the above bug. Since we are anyway in
do_exit() path, then if the refcount is 0, then I guess it should be
ok to simply clear the folio active flag before calling pagetable_dtor()
& pagetable_free().
Fixes: 32cc0b7c9d50 ("powerpc: add pte_free_defer() for pgtables sharing page")
Reviewed-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/ee13e7f99b8f258019da2b37655b998e73e5ef8b.1773078178.git.ritesh.list@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/powerpc/mm/pgtable-frag.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/powerpc/mm/pgtable-frag.c b/arch/powerpc/mm/pgtable-frag.c
index e89f64a0f24ae..2d817d95db80f 100644
--- a/arch/powerpc/mm/pgtable-frag.c
+++ b/arch/powerpc/mm/pgtable-frag.c
@@ -25,6 +25,7 @@ void pte_frag_destroy(void *pte_frag)
count = ((unsigned long)pte_frag & ~PAGE_MASK) >> PTE_FRAG_SIZE_SHIFT;
/* We allow PTE_FRAG_NR fragments from a PTE page */
if (atomic_sub_and_test(PTE_FRAG_NR - count, &ptdesc->pt_frag_refcount)) {
+ folio_clear_active(ptdesc_folio(ptdesc));
pagetable_pte_dtor(ptdesc);
pagetable_free(ptdesc);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 320/869] vdpa: use generic driver_override infrastructure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (318 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 319/869] powerpc/pgtable-frag: Fix bad page state in pte_frag_destroy Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 321/869] staging: rtl8723bs: rtw_mlme: add bounds checks before ie_length subtraction Greg Kroah-Hartman
` (549 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Gui-Dong Han, Eugenio Pérez,
Michael S. Tsirkin, Danilo Krummrich, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Danilo Krummrich <dakr@kernel.org>
[ Upstream commit 85bb534ff12aab6916058897b39c748940a7a4c6 ]
When a driver is probed through __driver_attach(), the bus' match()
callback is called without the device lock held, thus accessing the
driver_override field without a lock, which can cause a UAF.
Fix this by using the driver-core driver_override infrastructure taking
care of proper locking internally.
Note that calling match() from __driver_attach() without the device lock
held is intentional. [1]
Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1]
Reported-by: Gui-Dong Han <hanguidong02@gmail.com>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789
Fixes: 539fec78edb4 ("vdpa: add driver_override support")
Acked-by: Eugenio Pérez <eperezma@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Link: https://patch.msgid.link/20260324005919.2408620-9-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/vdpa/vdpa.c | 48 +++++---------------------------------------
include/linux/vdpa.h | 4 ----
2 files changed, 5 insertions(+), 47 deletions(-)
diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c
index 8a372b51c21ad..0fb00c8bde5e3 100644
--- a/drivers/vdpa/vdpa.c
+++ b/drivers/vdpa/vdpa.c
@@ -67,57 +67,20 @@ static void vdpa_dev_remove(struct device *d)
static int vdpa_dev_match(struct device *dev, const struct device_driver *drv)
{
- struct vdpa_device *vdev = dev_to_vdpa(dev);
+ int ret;
/* Check override first, and if set, only use the named driver */
- if (vdev->driver_override)
- return strcmp(vdev->driver_override, drv->name) == 0;
+ ret = device_match_driver_override(dev, drv);
+ if (ret >= 0)
+ return ret;
/* Currently devices must be supported by all vDPA bus drivers */
return 1;
}
-static ssize_t driver_override_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct vdpa_device *vdev = dev_to_vdpa(dev);
- int ret;
-
- ret = driver_set_override(dev, &vdev->driver_override, buf, count);
- if (ret)
- return ret;
-
- return count;
-}
-
-static ssize_t driver_override_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct vdpa_device *vdev = dev_to_vdpa(dev);
- ssize_t len;
-
- device_lock(dev);
- len = sysfs_emit(buf, "%s\n", vdev->driver_override);
- device_unlock(dev);
-
- return len;
-}
-static DEVICE_ATTR_RW(driver_override);
-
-static struct attribute *vdpa_dev_attrs[] = {
- &dev_attr_driver_override.attr,
- NULL,
-};
-
-static const struct attribute_group vdpa_dev_group = {
- .attrs = vdpa_dev_attrs,
-};
-__ATTRIBUTE_GROUPS(vdpa_dev);
-
static const struct bus_type vdpa_bus = {
.name = "vdpa",
- .dev_groups = vdpa_dev_groups,
+ .driver_override = true,
.match = vdpa_dev_match,
.probe = vdpa_dev_probe,
.remove = vdpa_dev_remove,
@@ -132,7 +95,6 @@ static void vdpa_release_dev(struct device *d)
ops->free(vdev);
ida_free(&vdpa_index_ida, vdev->index);
- kfree(vdev->driver_override);
kfree(vdev);
}
diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h
index 2e7a30fe6b925..c1da2f6ee5d3f 100644
--- a/include/linux/vdpa.h
+++ b/include/linux/vdpa.h
@@ -71,9 +71,6 @@ struct vdpa_mgmt_dev;
* struct vdpa_device - representation of a vDPA device
* @dev: underlying device
* @dma_dev: the actual device that is performing DMA
- * @driver_override: driver name to force a match; do not set directly,
- * because core frees it; use driver_set_override() to
- * set or clear it.
* @config: the configuration ops for this device.
* @cf_lock: Protects get and set access to configuration layout.
* @index: device index
@@ -88,7 +85,6 @@ struct vdpa_mgmt_dev;
struct vdpa_device {
struct device dev;
struct device *dma_dev;
- const char *driver_override;
const struct vdpa_config_ops *config;
struct rw_semaphore cf_lock; /* Protects get/set config */
unsigned int index;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 321/869] staging: rtl8723bs: rtw_mlme: add bounds checks before ie_length subtraction
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (319 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 320/869] vdpa: use generic driver_override infrastructure Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 322/869] sctp: validate embedded INIT chunk and address list lengths in cookie Greg Kroah-Hartman
` (548 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable, Salman Alghamdi, Luka Gejak,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Salman Alghamdi <me@cipherat.com>
[ Upstream commit 88e994c57a79f62d5338231d8d37ee8dd98baffe ]
Add guards to ensure ie_length is large enough before subtracting
fixed IE offsets to prevent unsigned integer underflow.
Fixes: 2038fe84b8bd ("staging: rtl8723bs: fix spacing around operators")
Fixes: d3fcee1b78a5 ("staging: rtl8723bs: fix camel case in struct wlan_bssid_ex")
Closes: https://lore.kernel.org/linux-staging/DI2H39EAAFBZ.3KI5NWN02AQ2S@linux.dev/
Cc: stable <stable@kernel.org>
Signed-off-by: Salman Alghamdi <me@cipherat.com>
Reviewed-by: Luka Gejak <luka.gejak@linux.dev>
Link: https://patch.msgid.link/20260513203455.31792-1-me@cipherat.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/staging/rtl8723bs/core/rtw_mlme.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c
index 506ba55f15b78..e2d5a40085f68 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c
@@ -590,6 +590,8 @@ int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwor
privacy = pnetwork->network.privacy;
if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
+ if (pnetwork->network.ie_length < _FIXED_IE_LENGTH_)
+ return false;
if (rtw_get_wps_ie(pnetwork->network.ies+_FIXED_IE_LENGTH_, pnetwork->network.ie_length-_FIXED_IE_LENGTH_, NULL, &wps_ielen))
return true;
else
@@ -604,11 +606,15 @@ int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwor
bselected = false;
if (psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) {
- p = rtw_get_ie(pnetwork->network.ies + _BEACON_IE_OFFSET_, WLAN_EID_RSN, &ie_len, (pnetwork->network.ie_length - _BEACON_IE_OFFSET_));
- if (p && ie_len > 0)
- bselected = true;
- else
+ if (pnetwork->network.ie_length < _BEACON_IE_OFFSET_) {
bselected = false;
+ } else {
+ p = rtw_get_ie(pnetwork->network.ies + _BEACON_IE_OFFSET_, WLAN_EID_RSN, &ie_len, (pnetwork->network.ie_length - _BEACON_IE_OFFSET_));
+ if (p && ie_len > 0)
+ bselected = true;
+ else
+ bselected = false;
+ }
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 322/869] sctp: validate embedded INIT chunk and address list lengths in cookie
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (320 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 321/869] staging: rtl8723bs: rtw_mlme: add bounds checks before ie_length subtraction Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 323/869] wifi: fix leak if split 6 GHz scanning fails Greg Kroah-Hartman
` (547 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Xin Long, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <lucien.xin@gmail.com>
[ Upstream commit 6f4c80a2a7e6d06753b89a578b710a2499a5e62b ]
sctp_unpack_cookie() only checked that the embedded INIT chunk length
did not exceed the remaining cookie payload, but did not ensure that the
INIT chunk is large enough to contain a complete INIT header.
A malformed COOKIE_ECHO can therefore carry a truncated INIT chunk whose
length field is smaller than sizeof(struct sctp_init_chunk). Later,
sctp_process_init() accesses INIT parameters unconditionally, which may
lead to out-of-bounds reads.
In addition, raw_addr_list_len is not fully validated against the
remaining cookie payload. When cookie authentication is disabled, an
attacker can supply an oversized raw_addr_list_len and cause
sctp_raw_to_bind_addrs() to read beyond the end of the cookie. The
address parser also lacks sufficient bounds checks for parameter headers
and lengths, allowing malformed address parameters to trigger
out-of-bounds reads.
Fix this by:
- requiring the embedded INIT chunk length to be at least sizeof(struct
sctp_init_chunk);
- validating that the INIT chunk and raw address list together fit
within the cookie payload;
- verifying sufficient data exists for each address parameter header and
payload before parsing it.
Note that sctp_verify_init() must be called after sctp_unpack_cookie()
and before sctp_process_init() when cookie authentication is disabled.
This will be addressed in a separate patch.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/75af23a89adf881a0895d511775e4770da367cbf.1780873427.git.lucien.xin@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sctp/bind_addr.c | 11 ++++++++++-
net/sctp/sm_make_chunk.c | 12 +++++++++++-
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index 6b95d3ba8fe1c..0947b276d1e08 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -275,6 +275,16 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
param = (struct sctp_paramhdr *)raw_addr_list;
rawaddr = (union sctp_addr_param *)raw_addr_list;
+ if (addrs_len < sizeof(*param)) {
+ retval = -EINVAL;
+ goto out_err;
+ }
+ len = ntohs(param->length);
+ if (addrs_len < len) {
+ retval = -EINVAL;
+ goto out_err;
+ }
+
af = sctp_get_af_specific(param_type2af(param->type));
if (unlikely(!af) ||
!af->from_addr_param(&addr, rawaddr, htons(port), 0)) {
@@ -291,7 +301,6 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
goto out_err;
next:
- len = ntohs(param->length);
addrs_len -= len;
raw_addr_list += len;
}
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 2366dd0298ebd..bec5bd6cf1d1f 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1750,8 +1750,9 @@ struct sctp_association *sctp_unpack_cookie(
struct sk_buff *skb = chunk->skb;
struct sctp_cookie *bear_cookie;
__u8 *digest = ep->digest;
+ struct sctp_chunkhdr *ch;
+ unsigned int len, chlen;
enum sctp_scope scope;
- unsigned int len;
ktime_t kt;
/* Header size is static data prior to the actual cookie, including
@@ -1779,6 +1780,15 @@ struct sctp_association *sctp_unpack_cookie(
cookie = chunk->subh.cookie_hdr;
bear_cookie = &cookie->c;
+ ch = (struct sctp_chunkhdr *)(bear_cookie + 1);
+ chlen = ntohs(ch->length);
+ if (chlen < sizeof(struct sctp_init_chunk))
+ goto malformed;
+ if (chlen > len - fixed_size)
+ goto malformed;
+ if (bear_cookie->raw_addr_list_len > len - fixed_size - chlen)
+ goto malformed;
+
if (!sctp_sk(ep->base.sk)->hmac)
goto no_hmac;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 323/869] wifi: fix leak if split 6 GHz scanning fails
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (321 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 322/869] sctp: validate embedded INIT chunk and address list lengths in cookie Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 324/869] KVM: arm64: Take the SRCU lock for page table walks in fault injection and AT emulation Greg Kroah-Hartman
` (546 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Fedor Pchelkin, Johannes Berg,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fedor Pchelkin <pchelkin@ispras.ru>
[ Upstream commit e8694f7cc29287e843648d1075177b9a2000d957 ]
rdev->int_scan_req is leaked if cfg80211_scan() fails. Note that it's
supposed to be released at ___cfg80211_scan_done() but this doesn't happen
as rdev->scan_req is NULL at that point, too, leading to the early return
from the freeing function.
unreferenced object 0xffff8881161d0800 (size 512):
comm "wpa_supplicant", pid 379, jiffies 4294749765
hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 f0 81 13 16 81 88 ff ff ................
backtrace (crc c867fdb6):
kmemleak_alloc+0x89/0x90
__kmalloc_noprof+0x2fd/0x410
cfg80211_scan+0x133/0x730
nl80211_trigger_scan+0xc69/0x1cc0
genl_family_rcv_msg_doit+0x204/0x2f0
genl_rcv_msg+0x431/0x6b0
netlink_rcv_skb+0x143/0x3f0
genl_rcv+0x27/0x40
netlink_unicast+0x4f6/0x820
netlink_sendmsg+0x797/0xce0
__sock_sendmsg+0xc4/0x160
____sys_sendmsg+0x5e4/0x890
___sys_sendmsg+0xf8/0x180
__sys_sendmsg+0x136/0x1e0
__x64_sys_sendmsg+0x76/0xc0
x64_sys_call+0x13f0/0x17d0
Found by Linux Verification Center (linuxtesting.org).
Fixes: c8cb5b854b40 ("nl80211/cfg80211: support 6 GHz scanning")
Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
Link: https://patch.msgid.link/20260601094157.92703-1-pchelkin@ispras.ru
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/wireless/scan.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 6fab9abb47b2b..520dcc16920a8 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1030,6 +1030,7 @@ int cfg80211_scan(struct cfg80211_registered_device *rdev)
struct cfg80211_scan_request *request;
struct cfg80211_scan_request *rdev_req = rdev->scan_req;
u32 n_channels = 0, idx, i;
+ int err;
if (!(rdev->wiphy.flags & WIPHY_FLAG_SPLIT_SCAN_6GHZ))
return rdev_scan(rdev, rdev_req);
@@ -1056,8 +1057,14 @@ int cfg80211_scan(struct cfg80211_registered_device *rdev)
}
rdev_req->scan_6ghz = false;
+ err = rdev_scan(rdev, request);
+ if (err) {
+ kfree(request);
+ return err;
+ }
+
rdev->int_scan_req = request;
- return rdev_scan(rdev, request);
+ return 0;
}
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 324/869] KVM: arm64: Take the SRCU lock for page table walks in fault injection and AT emulation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (322 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 323/869] wifi: fix leak if split 6 GHz scanning fails Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 325/869] iommu/vt-d: Avoid NULL pointer dereference or refcount corruption Greg Kroah-Hartman
` (545 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Oliver Upton, Hyunwoo Kim,
Marc Zyngier, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hyunwoo Kim <imv4bel@gmail.com>
[ Upstream commit f2ca45b50d4216c9cc7ffabf50d9ad1932209251 ]
walk_s1() and kvm_walk_nested_s2() expect to be called while holding
kvm->srcu to guard against memslot changes. While this is generally
the case, __kvm_at_s12() and __kvm_find_s1_desc_level() call into the
respective walkers without taking kvm->srcu.
Fix by acquiring kvm->srcu prior to the table walk in both instances.
Cc: stable@vger.kernel.org
Fixes: 50f77dc87f13 ("KVM: arm64: Populate level on S1PTW SEA injection")
Fixes: be04cebf3e78 ("KVM: arm64: nv: Add emulation of AT S12E{0,1}{R,W}")
Suggested-by: Oliver Upton <oupton@kernel.org>
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
Reviewed-by: Oliver Upton <oupton@kernel.org>
Link: https://patch.msgid.link/aiAZfdeyanIvP8SD@v4bel
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm64/kvm/at.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c
index 39f0e87a340e8..8192bc0bbc87b 100644
--- a/arch/arm64/kvm/at.c
+++ b/arch/arm64/kvm/at.c
@@ -1087,7 +1087,8 @@ void __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
/* Do the stage-2 translation */
ipa = (par & GENMASK_ULL(47, 12)) | (vaddr & GENMASK_ULL(11, 0));
out.esr = 0;
- ret = kvm_walk_nested_s2(vcpu, ipa, &out);
+ scoped_guard(srcu, &vcpu->kvm->srcu)
+ ret = kvm_walk_nested_s2(vcpu, ipa, &out);
if (ret < 0)
return;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 325/869] iommu/vt-d: Avoid NULL pointer dereference or refcount corruption
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (323 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 324/869] KVM: arm64: Take the SRCU lock for page table walks in fault injection and AT emulation Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 326/869] btrfs: only release the dirty pages io tree after successful writes Greg Kroah-Hartman
` (544 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kevin Tian, Zhenzhong Duan, Lu Baolu,
Joerg Roedel, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhenzhong Duan <zhenzhong.duan@intel.com>
[ Upstream commit 79ea2feb917b05366b49d85573c9c5331f043b2c ]
Commit 60f030f7418d ("iommu/vt-d: Avoid use of NULL after WARN_ON_ONCE")
fixed a NULL pointer dereference in an unlikely situation partly.
If dev_pasid is not found in the dev_pasids list, it remains NULL.
However, the teardown operations are executed unconditionally, this lead
to a NULL pointer dereference or refcount corruption.
If the domain was never attached to this IOMMU, info will be NULL, which
would cause an immediate dereference when checking --info->refcnt.
Even if info is not NULL, decrementing the refcount without having removed
a valid PASID might unbalance the count. This could lead to premature
dropping of the refcount to 0, potentially causing a use-after-free for the
remaining active devices sharing the domain.
Fix it by returning early if dev_pasid is NULL, before executing the
teardown operations.
Issue found by AI review and suggested by Kevin Tian.
https://sashiko.dev/#/patchset/20260421031347.1408890-1-zhenzhong.duan%40intel.com
Fixes: 60f030f7418d ("iommu/vt-d: Avoid use of NULL after WARN_ON_ONCE")
Cc: stable@vger.kernel.org
Suggested-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/20260422033538.95000-1-zhenzhong.duan@intel.com
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/iommu/intel/iommu.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 39742525e1a89..9da974068b828 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4339,9 +4339,9 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
}
spin_unlock_irqrestore(&dmar_domain->lock, flags);
- cache_tag_unassign_domain(dmar_domain, dev, pasid);
- domain_detach_iommu(dmar_domain, iommu);
if (!WARN_ON_ONCE(!dev_pasid)) {
+ cache_tag_unassign_domain(dmar_domain, dev, pasid);
+ domain_detach_iommu(dmar_domain, iommu);
intel_iommu_debugfs_remove_dev_pasid(dev_pasid);
kfree(dev_pasid);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 326/869] btrfs: only release the dirty pages io tree after successful writes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (324 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 325/869] iommu/vt-d: Avoid NULL pointer dereference or refcount corruption Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 327/869] drm/amd/display: Wrap DCN32 phantom-plane allocation in DC_RUN_WITH_PREEMPTION_ENABLED Greg Kroah-Hartman
` (543 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Filipe Manana, Qu Wenruo,
David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <wqu@suse.com>
[ Upstream commit 4066c55e109475a06d18a1f127c939d551211956 ]
[WARNING]
With extra warning on dirty extent buffers at umount (aka, the next
patch in the series), test case generic/388 can trigger the following
warning about dirty extent buffers at unmount time:
BTRFS critical (device dm-2 state E): emergency shutdown
BTRFS error (device dm-2 state E): error while writing out transaction: -30
BTRFS warning (device dm-2 state E): Skipping commit of aborted transaction.
BTRFS error (device dm-2 state EA): Transaction 9 aborted (error -30)
BTRFS: error (device dm-2 state EA) in cleanup_transaction:2068: errno=-30 Readonly filesystem
BTRFS info (device dm-2 state EA): forced readonly
BTRFS info (device dm-2 state EA): last unmount of filesystem 4fbf2e15-f941-49a0-bc7c-716315d2777c
------------[ cut here ]------------
WARNING: disk-io.c:3311 at invalidate_and_check_btree_folios+0xfd/0x1ca [btrfs], CPU#8: umount/914368
CPU: 8 UID: 0 PID: 914368 Comm: umount Tainted: G OE 7.1.0-rc1-custom+ #372 PREEMPT(full) 2de38db8d1deae71fde295430a0ff3ab98ccf596
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS unknown 02/02/2022
RIP: 0010:invalidate_and_check_btree_folios+0xfd/0x1ca [btrfs]
Call Trace:
<TASK>
close_ctree+0x52e/0x574 [btrfs d2f0b1cd330d1287e7a9919d112eadfc0e914efd]
generic_shutdown_super+0x89/0x1a0
kill_anon_super+0x16/0x40
btrfs_kill_super+0x16/0x20 [btrfs d2f0b1cd330d1287e7a9919d112eadfc0e914efd]
deactivate_locked_super+0x2d/0xb0
cleanup_mnt+0xdc/0x140
task_work_run+0x5a/0xa0
exit_to_user_mode_loop+0x123/0x4b0
do_syscall_64+0x243/0x7c0
entry_SYSCALL_64_after_hwframe+0x4b/0x53
</TASK>
---[ end trace 0000000000000000 ]---
BTRFS warning (device dm-2 state EA): unable to release extent buffer 30539776 owner 9 gen 9 refs 2 flags 0x7
BTRFS warning (device dm-2 state EA): unable to release extent buffer 30621696 owner 257 gen 9 refs 2 flags 0x7
BTRFS warning (device dm-2 state EA): unable to release extent buffer 30638080 owner 258 gen 9 refs 2 flags 0x7
BTRFS warning (device dm-2 state EA): unable to release extent buffer 30654464 owner 7 gen 9 refs 2 flags 0x7
BTRFS warning (device dm-2 state EA): unable to release extent buffer 30703616 owner 2 gen 9 refs 2 flags 0x7
BTRFS warning (device dm-2 state EA): unable to release extent buffer 30720000 owner 10 gen 9 refs 2 flags 0x7
BTRFS warning (device dm-2 state EA): unable to release extent buffer 30736384 owner 4 gen 9 refs 2 flags 0x7
BTRFS warning (device dm-2 state EA): unable to release extent buffer 30752768 owner 11 gen 9 refs 2 flags 0x7
I'm using a stripped down version, which seems to trigger the warning
more reliably:
_fsstress_pid=""
workload()
{
dmesg -C
mkfs.btrfs -f -K $dev > /dev/null
echo 1 > /sys/kernel/debug/clear_warn_once
mount $dev $mnt
$fsstress -w -n 1024 -p 4 -d $mnt &
_fsstress_pid=$!
sleep 0
$godown $mnt
pkill --echo -PIPE fsstress > /dev/null
wait $_fsstress_pid
unset _fsstress_pid
umount $mnt
if dmesg | grep -q "WARNING"; then
fail
fi
}
for (( i = 0; i < $runtime; i++ )); do
echo "=== $i/$runtime ==="
workload
done
[CAUSE]
Inside btrfs_write_and_wait_transaction(), we first try to write all
dirty ebs, then wait for them to finish.
After that we call btrfs_extent_io_tree_release() to free all
extent states from dirty_pages io tree.
However if we hit an error from btrfs_write_marked_extent(), then we
still call btrfs_extent_io_tree_release() to clear that dirty_pages io
tree, which may contain dirty records that we haven't yet submitted.
Furthermore, the later transaction cleanup path will utilize that
dirty_pages io tree to properly cleanup those dirty ebs, but since it's
already empty, no dirty ebs are properly cleaned up, thus will later
trigger the warnings inside invalidate_btree_folios().
[FIX]
Normally such dirty ebs won't cause problems, as when the iput() is
called on the btree inode, the dirty ebs will be forcibly written back,
and since the fs is already in an error status, such writeback will not
reach disk and finish immediately.
But it's still better to get rid of such dirty ebs, if we ended up with
dirty ebs but the fs is not in an error status, then such writeback at
iput() time will be too late, as all workers are already stopped but
writeback will utilize workers, which will lead to NULL pointer
dereferences.
Instead of unconditionally calling btrfs_extent_io_tree_release(), only
call it if btrfs_write_and_wait_transaction() finished successfully, so
that @dirty_pages extent io tree is kept untouched for transaction
cleanup.
CC: stable@vger.kernel.org # 6.1+
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/disk-io.c | 1 +
fs/btrfs/transaction.c | 9 ++++-----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index b0035d13286a4..2c98dd8c126e8 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -4693,6 +4693,7 @@ static void btrfs_destroy_marked_extents(struct btrfs_fs_info *fs_info,
free_extent_buffer_stale(eb);
}
}
+ extent_io_tree_release(dirty_pages);
}
static void btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info,
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 76842ed54335d..4cf852f531847 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -1281,14 +1281,13 @@ static int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans)
blk_finish_plug(&plug);
ret2 = btrfs_wait_extents(fs_info, dirty_pages);
- extent_io_tree_release(&trans->transaction->dirty_pages);
-
if (ret)
return ret;
- else if (ret2)
+ if (ret2)
return ret2;
- else
- return 0;
+
+ extent_io_tree_release(&trans->transaction->dirty_pages);
+ return 0;
}
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 327/869] drm/amd/display: Wrap DCN32 phantom-plane allocation in DC_RUN_WITH_PREEMPTION_ENABLED
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (325 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 326/869] btrfs: only release the dirty pages io tree after successful writes Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 328/869] net: phonet: do not BUG_ON() in pn_socket_autobind() on failed bind Greg Kroah-Hartman
` (542 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Aurabindo Pillai, Mikhail Gavrilov,
James Lin, Daniel Wheeler, Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
[ Upstream commit 183182235f6d53bac62c6c39014738a54a68dfa6 ]
[Why]
dcn32_validate_bandwidth() wraps dcn32_internal_validate_bw() with
DC_FP_START()/DC_FP_END(). In x86 non-RT, DC_FP_START takes fpregs_lock(),
which disables local softirqs.
The DML1 path through dcn32_enable_phantom_plane() calls kvzalloc() to
allocate ~335 KiB for dc_plane_state. This triggers the vmalloc path,
which calls BUG_ON(in_interrupt()) because it's invoked within the
FPU-enabled (softirq disabled) region, leading to a kernel crash.
[How]
Wrap the dc_state_create_phantom_plane() call with the
DC_RUN_WITH_PREEMPTION_ENABLED() macro to allow preemption during
this memory allocation.
Fixes: 235c67634230 ("drm/amd/display: add DCN32/321 specific files for Display Core")
Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/4470
Reviewed-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Signed-off-by: James Lin <pinglei.lin@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 885ccbef7b94a8b38f69c4211c679021aa27ad11)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../drm/amd/display/dc/resource/dcn32/dcn32_resource.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
index ccfdca7c83f66..1fa4d32ce0be7 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
@@ -90,9 +90,14 @@
#include "dml/dcn32/dcn32_fpu.h"
#include "dc_state_priv.h"
+#include "dc_fpu.h"
#include "dml2/dml2_wrapper.h"
+#if !defined(DC_RUN_WITH_PREEMPTION_ENABLED)
+#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code
+#endif
+
#define DC_LOGGER_INIT(logger)
enum dcn32_clk_src_array_id {
@@ -1649,7 +1654,8 @@ static void dcn32_enable_phantom_plane(struct dc *dc,
if (curr_pipe->top_pipe && curr_pipe->top_pipe->plane_state == curr_pipe->plane_state)
phantom_plane = prev_phantom_plane;
else
- phantom_plane = dc_state_create_phantom_plane(dc, context, curr_pipe->plane_state);
+ DC_RUN_WITH_PREEMPTION_ENABLED(phantom_plane =
+ dc_state_create_phantom_plane(dc, context, curr_pipe->plane_state));
if (!phantom_plane)
continue;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 328/869] net: phonet: do not BUG_ON() in pn_socket_autobind() on failed bind
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (326 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 327/869] drm/amd/display: Wrap DCN32 phantom-plane allocation in DC_RUN_WITH_PREEMPTION_ENABLED Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 329/869] net: mana: Guard mana_remove against double invocation Greg Kroah-Hartman
` (541 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+706f5eb79044e686c794,
Remi Denis-Courmont, Morduan Zang, zhanjun,
Rémi Denis-Courmont, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Morduan Zang <zhangdandan@uniontech.com>
[ Upstream commit 5b0c911bcdbd982f7748d11c0b39ec5808eae2de ]
syzbot reported a kernel BUG triggered from pn_socket_sendmsg() via
pn_socket_autobind():
kernel BUG at net/phonet/socket.c:213!
RIP: 0010:pn_socket_autobind net/phonet/socket.c:213 [inline]
RIP: 0010:pn_socket_sendmsg+0x240/0x250 net/phonet/socket.c:421
Call Trace:
sock_sendmsg_nosec+0x112/0x150 net/socket.c:797
__sock_sendmsg net/socket.c:812 [inline]
__sys_sendto+0x402/0x590 net/socket.c:2280
...
pn_socket_autobind() calls pn_socket_bind() with port 0 and, on
-EINVAL, assumes the socket was already bound and asserts that the
port is non-zero:
err = pn_socket_bind(sock, ..., sizeof(struct sockaddr_pn));
if (err != -EINVAL)
return err;
BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
return 0; /* socket was already bound */
However pn_socket_bind() also returns -EINVAL when sk->sk_state is not
TCP_CLOSE, even when the socket has never been bound and pn_port() is
still 0. In that case the BUG_ON() fires and panics the kernel from a
user-triggerable path.
Treat the "bind returned -EINVAL but pn_port() is still 0" case as a
regular error and propagate -EINVAL to the caller instead of crashing.
Existing callers already translate a non-zero return from
pn_socket_autobind() into -ENOBUFS/-EAGAIN, so returning -EINVAL here
only changes behaviour from panic to a normal errno.
Fixes: ba113a94b750 ("Phonet: common socket glue")
Reported-by: syzbot+706f5eb79044e686c794@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=706f5eb79044e686c794
Suggested-by: Remi Denis-Courmont <courmisch@gmail.com>
Signed-off-by: Morduan Zang <zhangdandan@uniontech.com>
Signed-off-by: zhanjun <zhanjun@uniontech.com>
Acked-by: Rémi Denis-Courmont <remi@remlab.net>
Link: https://patch.msgid.link/87A8960A2045AF3C+20260423010557.138124-1-zhangdandan@uniontech.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/phonet/socket.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 5ce0b3ee5def8..11250d2d1dda8 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -208,9 +208,15 @@ static int pn_socket_autobind(struct socket *sock)
sa.spn_family = AF_PHONET;
err = pn_socket_bind(sock, (struct sockaddr *)&sa,
sizeof(struct sockaddr_pn));
- if (err != -EINVAL)
+ /*
+ * pn_socket_bind() also returns -EINVAL when sk_state != TCP_CLOSE
+ * without a prior bind, so -EINVAL alone is not sufficient to infer
+ * that the socket was already bound. Only treat it as "already
+ * bound" when the port is non-zero; otherwise propagate the error
+ * instead of crashing the kernel.
+ */
+ if (err != -EINVAL || unlikely(!pn_port(pn_sk(sock->sk)->sobject)))
return err;
- BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
return 0; /* socket was already bound */
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 329/869] net: mana: Guard mana_remove against double invocation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (327 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 328/869] net: phonet: do not BUG_ON() in pn_socket_autobind() on failed bind Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 330/869] io_uring/napi: protect concurrent io_napi_entry timeout accesses Greg Kroah-Hartman
` (540 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Erni Sri Satya Vennela, Simon Horman,
Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Erni Sri Satya Vennela <ernis@linux.microsoft.com>
[ Upstream commit 50271d7ec95144d26808025b508f463780517d3c ]
If PM resume fails (e.g., mana_attach() returns an error), mana_probe()
calls mana_remove(), which tears down the device and sets
gd->gdma_context = NULL and gd->driver_data = NULL.
However, a failed resume callback does not automatically unbind the
driver. When the device is eventually unbound, mana_remove() is invoked
a second time. Without a NULL check, it dereferences gc->dev with
gc == NULL, causing a kernel panic.
Add an early return if gdma_context or driver_data is NULL so the second
invocation is harmless. Move the dev = gc->dev assignment after the
guard so it cannot dereference NULL.
Fixes: 635096a86edb ("net: mana: Support hibernation and kexec")
Signed-off-by: Erni Sri Satya Vennela <ernis@linux.microsoft.com>
Link: https://patch.msgid.link/20260420124741.1056179-4-ernis@linux.microsoft.com
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/microsoft/mana/mana_en.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index bd1ae41df552d..ef89f3e06a265 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -3006,11 +3006,16 @@ void mana_remove(struct gdma_dev *gd, bool suspending)
struct gdma_context *gc = gd->gdma_context;
struct mana_context *ac = gd->driver_data;
struct mana_port_context *apc;
- struct device *dev = gc->dev;
+ struct device *dev;
struct net_device *ndev;
int err;
int i;
+ if (!gc || !ac)
+ return;
+
+ dev = gc->dev;
+
/* adev currently doesn't support suspending, always remove it */
if (gd->adev)
remove_adev(gd);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 330/869] io_uring/napi: protect concurrent io_napi_entry timeout accesses
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (328 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 329/869] net: mana: Guard mana_remove against double invocation Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 331/869] io_uring/napi: improve __io_napi_add Greg Kroah-Hartman
` (539 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Olivier Langlois, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Olivier Langlois <olivier@trillion01.com>
[ Upstream commit 2f3cc8e441c9f657ff036c56baaab7dddbd0b350 ]
io_napi_entry timeout value can be updated while accessed from the poll
functions.
Its concurrent accesses are wrapped with READ_ONCE()/WRITE_ONCE() macros
to avoid incorrect compiler optimizations.
Signed-off-by: Olivier Langlois <olivier@trillion01.com>
Link: https://lore.kernel.org/r/3de3087563cf98f75266fd9f85fdba063a8720db.1728828877.git.olivier@trillion01.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Stable-dep-of: df8599ee18c0 ("io_uring/napi: cap busy_poll_to 10 msec")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/napi.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/io_uring/napi.c b/io_uring/napi.c
index fa959fd320429..921de9de8d753 100644
--- a/io_uring/napi.c
+++ b/io_uring/napi.c
@@ -60,7 +60,7 @@ void __io_napi_add(struct io_ring_ctx *ctx, struct socket *sock)
rcu_read_lock();
e = io_napi_hash_find(hash_list, napi_id);
if (e) {
- e->timeout = jiffies + NAPI_TIMEOUT;
+ WRITE_ONCE(e->timeout, jiffies + NAPI_TIMEOUT);
rcu_read_unlock();
return;
}
@@ -155,7 +155,7 @@ static bool __io_napi_do_busy_loop(struct io_ring_ctx *ctx,
napi_busy_loop_rcu(e->napi_id, loop_end, loop_end_arg,
ctx->napi_prefer_busy_poll, BUSY_POLL_BUDGET);
- if (time_after(jiffies, e->timeout))
+ if (time_after(jiffies, READ_ONCE(e->timeout)))
is_stale = true;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 331/869] io_uring/napi: improve __io_napi_add
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (329 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 330/869] io_uring/napi: protect concurrent io_napi_entry timeout accesses Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 332/869] io_uring/napi: Use lock guards Greg Kroah-Hartman
` (538 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Olivier Langlois, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Olivier Langlois <olivier@trillion01.com>
[ Upstream commit a5e26f49fef9485bc4ae24666d984a6de11e058c ]
1. move the sock->sk pointer validity test outside the function to
avoid the function call overhead and to make the function more
more reusable
2. change its name to __io_napi_add_id to be more precise about it is
doing
3. return an error code to report errors
Signed-off-by: Olivier Langlois <olivier@trillion01.com>
Link: https://lore.kernel.org/r/d637fa3b437d753c0f4e44ff6a7b5bf2c2611270.1728828877.git.olivier@trillion01.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Stable-dep-of: df8599ee18c0 ("io_uring/napi: cap busy_poll_to 10 msec")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/napi.c | 19 ++++++-------------
io_uring/napi.h | 6 +++---
2 files changed, 9 insertions(+), 16 deletions(-)
diff --git a/io_uring/napi.c b/io_uring/napi.c
index 921de9de8d753..5e2299e7ff8ee 100644
--- a/io_uring/napi.c
+++ b/io_uring/napi.c
@@ -38,22 +38,14 @@ static inline ktime_t net_to_ktime(unsigned long t)
return ns_to_ktime(t << 10);
}
-void __io_napi_add(struct io_ring_ctx *ctx, struct socket *sock)
+int __io_napi_add_id(struct io_ring_ctx *ctx, unsigned int napi_id)
{
struct hlist_head *hash_list;
- unsigned int napi_id;
- struct sock *sk;
struct io_napi_entry *e;
- sk = sock->sk;
- if (!sk)
- return;
-
- napi_id = READ_ONCE(sk->sk_napi_id);
-
/* Non-NAPI IDs can be rejected. */
if (napi_id < MIN_NAPI_ID)
- return;
+ return -EINVAL;
hash_list = &ctx->napi_ht[hash_min(napi_id, HASH_BITS(ctx->napi_ht))];
@@ -62,13 +54,13 @@ void __io_napi_add(struct io_ring_ctx *ctx, struct socket *sock)
if (e) {
WRITE_ONCE(e->timeout, jiffies + NAPI_TIMEOUT);
rcu_read_unlock();
- return;
+ return -EEXIST;
}
rcu_read_unlock();
e = kmalloc(sizeof(*e), GFP_NOWAIT);
if (!e)
- return;
+ return -ENOMEM;
e->napi_id = napi_id;
e->timeout = jiffies + NAPI_TIMEOUT;
@@ -77,12 +69,13 @@ void __io_napi_add(struct io_ring_ctx *ctx, struct socket *sock)
if (unlikely(io_napi_hash_find(hash_list, napi_id))) {
spin_unlock(&ctx->napi_lock);
kfree(e);
- return;
+ return -EEXIST;
}
hlist_add_tail_rcu(&e->node, hash_list);
list_add_tail_rcu(&e->list, &ctx->napi_list);
spin_unlock(&ctx->napi_lock);
+ return 0;
}
static void __io_napi_remove_stale(struct io_ring_ctx *ctx)
diff --git a/io_uring/napi.h b/io_uring/napi.h
index fd275ef0456d1..4ae622f37b302 100644
--- a/io_uring/napi.h
+++ b/io_uring/napi.h
@@ -15,7 +15,7 @@ void io_napi_free(struct io_ring_ctx *ctx);
int io_register_napi(struct io_ring_ctx *ctx, void __user *arg);
int io_unregister_napi(struct io_ring_ctx *ctx, void __user *arg);
-void __io_napi_add(struct io_ring_ctx *ctx, struct socket *sock);
+int __io_napi_add_id(struct io_ring_ctx *ctx, unsigned int napi_id);
void __io_napi_busy_loop(struct io_ring_ctx *ctx, struct io_wait_queue *iowq);
int io_napi_sqpoll_busy_poll(struct io_ring_ctx *ctx);
@@ -48,8 +48,8 @@ static inline void io_napi_add(struct io_kiocb *req)
return;
sock = sock_from_file(req->file);
- if (sock)
- __io_napi_add(ctx, sock);
+ if (sock && sock->sk)
+ __io_napi_add_id(ctx, READ_ONCE(sock->sk->sk_napi_id));
}
#else
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 332/869] io_uring/napi: Use lock guards
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (330 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 331/869] io_uring/napi: improve __io_napi_add Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 333/869] io_uring/napi: clean up __io_napi_do_busy_loop Greg Kroah-Hartman
` (537 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Olivier Langlois, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Olivier Langlois <olivier@trillion01.com>
[ Upstream commit db1e1adf6f993b1c2cef605d86eff709a8db5052 ]
Convert napi locks to use the shiny new Scope-Based Resource Management
machinery.
Signed-off-by: Olivier Langlois <olivier@trillion01.com>
Link: https://lore.kernel.org/r/2680ca47ee183cfdb89d1a40c84d349edeb620ab.1728828877.git.olivier@trillion01.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Stable-dep-of: df8599ee18c0 ("io_uring/napi: cap busy_poll_to 10 msec")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/napi.c | 40 +++++++++++++++++++++-------------------
1 file changed, 21 insertions(+), 19 deletions(-)
diff --git a/io_uring/napi.c b/io_uring/napi.c
index 5e2299e7ff8ee..6d5fdd397f2f4 100644
--- a/io_uring/napi.c
+++ b/io_uring/napi.c
@@ -49,14 +49,13 @@ int __io_napi_add_id(struct io_ring_ctx *ctx, unsigned int napi_id)
hash_list = &ctx->napi_ht[hash_min(napi_id, HASH_BITS(ctx->napi_ht))];
- rcu_read_lock();
- e = io_napi_hash_find(hash_list, napi_id);
- if (e) {
- WRITE_ONCE(e->timeout, jiffies + NAPI_TIMEOUT);
- rcu_read_unlock();
- return -EEXIST;
+ scoped_guard(rcu) {
+ e = io_napi_hash_find(hash_list, napi_id);
+ if (e) {
+ WRITE_ONCE(e->timeout, jiffies + NAPI_TIMEOUT);
+ return -EEXIST;
+ }
}
- rcu_read_unlock();
e = kmalloc(sizeof(*e), GFP_NOWAIT);
if (!e)
@@ -65,6 +64,10 @@ int __io_napi_add_id(struct io_ring_ctx *ctx, unsigned int napi_id)
e->napi_id = napi_id;
e->timeout = jiffies + NAPI_TIMEOUT;
+ /*
+ * guard(spinlock) is not used to manually unlock it before calling
+ * kfree()
+ */
spin_lock(&ctx->napi_lock);
if (unlikely(io_napi_hash_find(hash_list, napi_id))) {
spin_unlock(&ctx->napi_lock);
@@ -82,7 +85,7 @@ static void __io_napi_remove_stale(struct io_ring_ctx *ctx)
{
struct io_napi_entry *e;
- spin_lock(&ctx->napi_lock);
+ guard(spinlock)(&ctx->napi_lock);
/*
* list_for_each_entry_safe() is not required as long as:
* 1. list_del_rcu() does not reset the deleted node next pointer
@@ -96,7 +99,6 @@ static void __io_napi_remove_stale(struct io_ring_ctx *ctx)
kfree_rcu(e, rcu);
}
}
- spin_unlock(&ctx->napi_lock);
}
static inline void io_napi_remove_stale(struct io_ring_ctx *ctx, bool is_stale)
@@ -168,11 +170,12 @@ static void io_napi_blocking_busy_loop(struct io_ring_ctx *ctx,
if (list_is_singular(&ctx->napi_list))
loop_end_arg = iowq;
- rcu_read_lock();
- do {
- is_stale = __io_napi_do_busy_loop(ctx, loop_end_arg);
- } while (!io_napi_busy_loop_should_end(iowq, start_time) && !loop_end_arg);
- rcu_read_unlock();
+ scoped_guard(rcu) {
+ do {
+ is_stale = __io_napi_do_busy_loop(ctx, loop_end_arg);
+ } while (!io_napi_busy_loop_should_end(iowq, start_time) &&
+ !loop_end_arg);
+ }
io_napi_remove_stale(ctx, is_stale);
}
@@ -203,13 +206,12 @@ void io_napi_free(struct io_ring_ctx *ctx)
{
struct io_napi_entry *e;
- spin_lock(&ctx->napi_lock);
+ guard(spinlock)(&ctx->napi_lock);
list_for_each_entry(e, &ctx->napi_list, list) {
hash_del_rcu(&e->node);
kfree_rcu(e, rcu);
}
INIT_LIST_HEAD_RCU(&ctx->napi_list);
- spin_unlock(&ctx->napi_lock);
}
/*
@@ -305,9 +307,9 @@ int io_napi_sqpoll_busy_poll(struct io_ring_ctx *ctx)
if (list_empty_careful(&ctx->napi_list))
return 0;
- rcu_read_lock();
- is_stale = __io_napi_do_busy_loop(ctx, NULL);
- rcu_read_unlock();
+ scoped_guard(rcu) {
+ is_stale = __io_napi_do_busy_loop(ctx, NULL);
+ }
io_napi_remove_stale(ctx, is_stale);
return 1;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 333/869] io_uring/napi: clean up __io_napi_do_busy_loop
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (331 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 332/869] io_uring/napi: Use lock guards Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 334/869] io_uring/napi: cap busy_poll_to 10 msec Greg Kroah-Hartman
` (536 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Olivier Langlois, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Olivier Langlois <olivier@trillion01.com>
[ Upstream commit 71afd926f292bb8f3ca86e6c3c40123037f109c6 ]
__io_napi_do_busy_loop now requires to have loop_end in its parameters.
This makes the code cleaner and also has the benefit of removing a
branch since the only caller not passing NULL for loop_end_arg is also
setting the value conditionally.
Signed-off-by: Olivier Langlois <olivier@trillion01.com>
Link: https://lore.kernel.org/r/d5b9bb91b1a08fff50525e1c18d7b4709b9ca100.1728828877.git.olivier@trillion01.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Stable-dep-of: df8599ee18c0 ("io_uring/napi: cap busy_poll_to 10 msec")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/napi.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/io_uring/napi.c b/io_uring/napi.c
index 6d5fdd397f2f4..1de1543d80344 100644
--- a/io_uring/napi.c
+++ b/io_uring/napi.c
@@ -137,15 +137,12 @@ static bool io_napi_busy_loop_should_end(void *data,
}
static bool __io_napi_do_busy_loop(struct io_ring_ctx *ctx,
+ bool (*loop_end)(void *, unsigned long),
void *loop_end_arg)
{
struct io_napi_entry *e;
- bool (*loop_end)(void *, unsigned long) = NULL;
bool is_stale = false;
- if (loop_end_arg)
- loop_end = io_napi_busy_loop_should_end;
-
list_for_each_entry_rcu(e, &ctx->napi_list, list) {
napi_busy_loop_rcu(e->napi_id, loop_end, loop_end_arg,
ctx->napi_prefer_busy_poll, BUSY_POLL_BUDGET);
@@ -161,18 +158,22 @@ static void io_napi_blocking_busy_loop(struct io_ring_ctx *ctx,
struct io_wait_queue *iowq)
{
unsigned long start_time = busy_loop_current_time();
+ bool (*loop_end)(void *, unsigned long) = NULL;
void *loop_end_arg = NULL;
bool is_stale = false;
/* Singular lists use a different napi loop end check function and are
* only executed once.
*/
- if (list_is_singular(&ctx->napi_list))
+ if (list_is_singular(&ctx->napi_list)) {
+ loop_end = io_napi_busy_loop_should_end;
loop_end_arg = iowq;
+ }
scoped_guard(rcu) {
do {
- is_stale = __io_napi_do_busy_loop(ctx, loop_end_arg);
+ is_stale = __io_napi_do_busy_loop(ctx, loop_end,
+ loop_end_arg);
} while (!io_napi_busy_loop_should_end(iowq, start_time) &&
!loop_end_arg);
}
@@ -308,7 +309,7 @@ int io_napi_sqpoll_busy_poll(struct io_ring_ctx *ctx)
return 0;
scoped_guard(rcu) {
- is_stale = __io_napi_do_busy_loop(ctx, NULL);
+ is_stale = __io_napi_do_busy_loop(ctx, NULL, NULL);
}
io_napi_remove_stale(ctx, is_stale);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 334/869] io_uring/napi: cap busy_poll_to 10 msec
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (332 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 333/869] io_uring/napi: clean up __io_napi_do_busy_loop Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 335/869] drm/amd/display: Fix out-of-bounds read in dp_get_eq_aux_rd_interval() Greg Kroah-Hartman
` (535 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jens Axboe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <axboe@kernel.dk>
[ Upstream commit df8599ee18c0e5fe343ffe0b4c379636b8bb839a ]
Currently there's no cap on the maximum amount of time that napi is
allowed to poll if no events are found, which can lead to kernel
complaints on a task being stuck as there's no conditional rescheduling
done within that loop.
Just cap it to 10 msec in total, that's already way above any kind of
sane value that will reap any benefits, yet low enough that it's
nowhere near being able to trigger preemption complaints.
Fixes: 8d0c12a80cde ("io-uring: add napi busy poll support")
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
io_uring/napi.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/io_uring/napi.c b/io_uring/napi.c
index 1de1543d80344..5542d78a4bd8c 100644
--- a/io_uring/napi.c
+++ b/io_uring/napi.c
@@ -240,6 +240,8 @@ int io_register_napi(struct io_ring_ctx *ctx, void __user *arg)
if (copy_to_user(arg, &curr, sizeof(curr)))
return -EFAULT;
+ /* cap NAPI at 10 msec of spin time */
+ napi.busy_poll_to = min(10000, napi.busy_poll_to);
WRITE_ONCE(ctx->napi_busy_poll_dt, napi.busy_poll_to * NSEC_PER_USEC);
WRITE_ONCE(ctx->napi_prefer_busy_poll, !!napi.prefer_busy_poll);
WRITE_ONCE(ctx->napi_enabled, true);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 335/869] drm/amd/display: Fix out-of-bounds read in dp_get_eq_aux_rd_interval()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (333 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 334/869] io_uring/napi: cap busy_poll_to 10 msec Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 336/869] f2fs: fix fsck inconsistency caused by incorrect nat_entry flag usage Greg Kroah-Hartman
` (534 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Harry Wentland, Ray Wu,
Daniel Wheeler, Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <harry.wentland@amd.com>
[ Upstream commit e8b4d37eba05141ee01794fc6b7f2da808cee83b ]
[Why & How]
The aux_rd_interval array in struct dc_lttpr_caps is declared with
MAX_REPEATER_CNT - 1 (7) elements, indexed 0..6. However, the offset
parameter passed to dp_get_eq_aux_rd_interval() can be as large as
MAX_REPEATER_CNT (8) when a sink reports 8 LTTPR repeaters via DPCD.
This leads to an out-of-bounds read of aux_rd_interval[7] when offset
is 8.
Fix this by growing aux_rd_interval to MAX_REPEATER_CNT elements to
accommodate the full range of valid repeater counts defined by the DP
spec.
Assisted-by: GitHub Copilot:Claude claude-4-opus
Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit a55a458a8df37a65ffda5cf721d554a8f74f6b04)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
index 223c3d55544b2..b128f1da98c91 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
@@ -1112,7 +1112,7 @@ struct dc_lttpr_caps {
union dp_main_link_channel_coding_lttpr_cap main_link_channel_coding;
union dp_128b_132b_supported_lttpr_link_rates supported_128b_132b_rates;
union dp_alpm_lttpr_cap alpm;
- uint8_t aux_rd_interval[MAX_REPEATER_CNT - 1];
+ uint8_t aux_rd_interval[MAX_REPEATER_CNT];
};
struct dc_dongle_dfp_cap_ext {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 336/869] f2fs: fix fsck inconsistency caused by incorrect nat_entry flag usage
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (334 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 335/869] drm/amd/display: Fix out-of-bounds read in dp_get_eq_aux_rd_interval() Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 337/869] drm/msm: always recover the gpu Greg Kroah-Hartman
` (533 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable, Yongpeng Yang, Chao Yu,
Jaegeuk Kim, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongpeng Yang <yangyongpeng@xiaomi.com>
[ Upstream commit 019f9dda7f66e55eb94cd32e1d3fff5835f73fbc ]
f2fs_need_dentry_mark() reads nat_entry flags without mutual exclusion
with the checkpoint path, which can result in an incorrect inode block
marking state. The scenario is as follows:
create & write & fsync 'file A' write checkpoint
- f2fs_do_sync_file // inline inode
- f2fs_write_inode // inode folio is dirty
- f2fs_write_checkpoint
- f2fs_flush_merged_writes
- f2fs_sync_node_pages
- f2fs_fsync_node_pages // no dirty node
- f2fs_need_inode_block_update // return true
- f2fs_fsync_node_pages // inode dirtied
- f2fs_need_dentry_mark //return true
- f2fs_flush_nat_entries
- f2fs_write_checkpoint end
- __write_node_folio // inode with DENT_BIT_SHIFT set
SPO, "fsck --dry-run" find inode has already checkpointed but still
with DENT_BIT_SHIFT set
The state observed by f2fs_need_dentry_mark() can differ from the state
observed in __write_node_folio() after acquiring sbi->node_write. The
root cause is that the semantics of IS_CHECKPOINTED and
HAS_FSYNCED_INODE are only guaranteed after the checkpoint write has
fully completed.
This patch moves set_dentry_mark() into __write_node_folio() and
protects it with the sbi->node_write lock.
Cc: stable@kernel.org
Fixes: 88bd02c9472a ("f2fs: fix conditions to remain recovery information in f2fs_sync_file")
Signed-off-by: Yongpeng Yang <yangyongpeng@xiaomi.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/node.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 56d5fb77569d7..111eba597a4a4 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -1878,9 +1878,6 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
if (is_inode_flag_set(inode,
FI_DIRTY_INODE))
f2fs_update_inode(inode, page);
- if (!atomic)
- set_dentry_mark(page,
- f2fs_need_dentry_mark(sbi, ino));
}
/* may be written by other thread */
if (!PageDirty(page))
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 337/869] drm/msm: always recover the gpu
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (335 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 336/869] f2fs: fix fsck inconsistency caused by incorrect nat_entry flag usage Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 338/869] fbdev: omap2: fix inconsistent lock returns in omapfb_mmap Greg Kroah-Hartman
` (532 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Anna Maniscalco, Rob Clark,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anna Maniscalco <anna.maniscalco2000@gmail.com>
[ Upstream commit 01a0d6cd7032e9993feea19fadb03ef9d5b488f2 ]
Previously, in case there was no more work to do, recover worker
wouldn't trigger recovery and would instead rely on the gpu going to
sleep and then resuming when more work is submitted.
Recover_worker will first increment the fence of the hung ring so, if
there's only one job submitted to a ring and that causes an hang, it
will early out.
There's no guarantee that the gpu will suspend and resume before more
work is submitted and if the gpu is in a hung state it will stay in that
state and probably trigger a timeout again.
Just stop checking and always recover the gpu.
Signed-off-by: Anna Maniscalco <anna.maniscalco2000@gmail.com>
Cc: stable@vger.kernel.org
Patchwork: https://patchwork.freedesktop.org/patch/704066/
Message-ID: <20260210-recovery_suspend_fix-v1-1-00ed9013da04@gmail.com>
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/msm/msm_gpu.c | 30 ++++++++++++++----------------
1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index ffb91e45aefde..76b44bb8de0d3 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -421,25 +421,23 @@ static void recover_worker(struct kthread_work *work)
msm_update_fence(ring->fctx, fence);
}
- if (msm_gpu_active(gpu)) {
- gpu->funcs->recover(gpu);
+ gpu->funcs->recover(gpu);
- /* retire completed submits, plus the one that hung: */
- retire_submits(gpu);
+ /* retire completed submits, plus the one that hung: */
+ retire_submits(gpu);
- /*
- * Replay all remaining submits starting with highest priority
- * ring
- */
- for (i = 0; i < gpu->nr_rings; i++) {
- struct msm_ringbuffer *ring = gpu->rb[i];
- unsigned long flags;
+ /*
+ * Replay all remaining submits starting with highest priority
+ * ring
+ */
+ for (i = 0; i < gpu->nr_rings; i++) {
+ struct msm_ringbuffer *ring = gpu->rb[i];
+ unsigned long flags;
- spin_lock_irqsave(&ring->submit_lock, flags);
- list_for_each_entry(submit, &ring->submits, node)
- gpu->funcs->submit(gpu, submit);
- spin_unlock_irqrestore(&ring->submit_lock, flags);
- }
+ spin_lock_irqsave(&ring->submit_lock, flags);
+ list_for_each_entry(submit, &ring->submits, node)
+ gpu->funcs->submit(gpu, submit);
+ spin_unlock_irqrestore(&ring->submit_lock, flags);
}
pm_runtime_put(&gpu->pdev->dev);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 338/869] fbdev: omap2: fix inconsistent lock returns in omapfb_mmap
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (336 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 337/869] drm/msm: always recover the gpu Greg Kroah-Hartman
@ 2026-10-17 15:52 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 339/869] fbdev: omap2: fix use-after-free " Greg Kroah-Hartman
` (531 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:52 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, kernel test robot, Hongling Zeng,
Helge Deller, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongling Zeng <zenghongling@kylinos.cn>
[ Upstream commit 98cf7df6e0844f7076df1db690c1ede9d69b61ff ]
Fix the warning about inconsistent returns for '&rg->lock' in
omapfb_mmap() function. The warning arises because the error path
uses 'ofbi->region' while the normal path uses 'rg'.
smatch warnings:
drivers/video/fbdev/omap2/omapfb/omapfb-main.c:1126 omapfb_mmap()
warn: inconsistent returns '&rg->lock'.
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
Signed-off-by: Helge Deller <deller@gmx.de>
Stable-dep-of: 7958e67375aa ("fbdev: omap2: fix use-after-free in omapfb_mmap")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
index 211f23648686c..79688c2cc6d68 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
@@ -1121,7 +1121,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
return 0;
error:
- omapfb_put_mem_region(ofbi->region);
+ omapfb_put_mem_region(rg);
return r;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 339/869] fbdev: omap2: fix use-after-free in omapfb_mmap
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (337 preceding siblings ...)
2026-10-17 15:52 ` [PATCH 6.12 338/869] fbdev: omap2: fix inconsistent lock returns in omapfb_mmap Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 340/869] f2fs: read COW data with the original inode during atomic write Greg Kroah-Hartman
` (530 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Hongling Zeng, Helge Deller,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongling Zeng <zenghongling@kylinos.cn>
[ Upstream commit 7958e67375aa111522086286bba13cfc0816ce8d ]
omapfb_mmap() has a race condition with OMAPFB_SETUP_PLANE ioctl that
can lead to use-after-free:
The fb_mmap() entry point holds mm_lock but not lock (fb_info->lock),
while ioctl handlers like OMAPFB_SETUP_PLANE hold lock but not mm_lock.
This allows concurrent execution.
In omapfb_mmap():
1. rg = omapfb_get_mem_region(ofbi->region); // Get old region ref
2. start = omapfb_get_region_paddr(ofbi); // Read from NEW region
3. len = fix->smem_len; // Read from NEW region
4. vm_iomap_memory(vma, start, len); // Map NEW region memory
5. atomic_inc(&rg->map_count); // Increment OLD region!
Concurrently, OMAPFB_SETUP_PLANE can:
- Reassign ofbi->region = new_rg
- Update fix->smem_len
- OMAPFB_SETUP_MEM then checks NEW region's map_count (0!) and frees it
This leaves userspace with a mapping to freed physical memory.
The fix is to read all required values (start, len) from the same
region reference (rg) that will have its map_count incremented,
preventing the region from being freed while still mapped.
Cc: stable@vger.kernel.org
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
index 79688c2cc6d68..2b99a58ad6758 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
@@ -1099,7 +1099,11 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
rg = omapfb_get_mem_region(ofbi->region);
- start = omapfb_get_region_paddr(ofbi);
+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
+ start = rg->vrfb.paddr[0];
+ else
+ start = rg->paddr;
+
len = fix->smem_len;
DBG("user mmap region start %lx, len %d, off %lx\n", start, len,
@@ -1109,6 +1113,8 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
vma->vm_ops = &mmap_user_ops;
vma->vm_private_data = rg;
+ atomic_inc(&rg->map_count);
+
r = vm_iomap_memory(vma, start, len);
if (r)
goto error;
@@ -1121,6 +1127,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
return 0;
error:
+ atomic_dec(&rg->map_count);
omapfb_put_mem_region(rg);
return r;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 340/869] f2fs: read COW data with the original inode during atomic write
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (338 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 339/869] fbdev: omap2: fix use-after-free " Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 341/869] gcov: use atomic counter updates to fix concurrent access crashes Greg Kroah-Hartman
` (529 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Mikhail Lobanov, Chao Yu,
Jaegeuk Kim, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikhail Lobanov <m.lobanov@rosa.ru>
[ Upstream commit a41075acde0124d2f8a5f563068a5d63e8ffd57b ]
When updating an atomic-write file, f2fs_write_begin() may read the
previously written data back from the COW inode:
prepare_atomic_write_begin() locates the block in the COW inode and sets
use_cow, and the read bio is then built with the COW inode:
f2fs_submit_page_read(use_cow ? F2FS_I(inode)->cow_inode : inode,
...);
and f2fs_grab_read_bio() decides whether to schedule fs-layer decryption
(STEP_DECRYPT) for the bio based on that inode via
fscrypt_inode_uses_fs_layer_crypto().
However, the folio being filled belongs to the original inode
(folio->mapping->host == inode), and the data stored in the COW block was
encrypted (or left as plaintext) using the original inode's context, not
the COW inode's -- see f2fs_encrypt_one_page(), which keys off
fio->page->mapping->host. fscrypt_decrypt_pagecache_blocks() likewise
operates on folio->mapping->host.
The COW inode is created as a tmpfile in the parent directory and inherits
its encryption policy from there. With test_dummy_encryption the newly
created COW inode gets the dummy policy and becomes encrypted, while a
pre-existing regular file -- created before the policy applied, e.g.
already present in the on-disk image -- stays unencrypted. The read
path then sets STEP_DECRYPT based on the encrypted COW inode and calls
fscrypt_decrypt_pagecache_blocks() on a folio whose host (the unencrypted
original inode) has a NULL ->i_crypt_info, dereferencing it:
Oops: general protection fault, probably for non-canonical address ...
KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
RIP: 0010:fscrypt_decrypt_pagecache_blocks+0xa0/0x310
Workqueue: f2fs_post_read_wq f2fs_post_read_work
Call Trace:
fscrypt_decrypt_bio+0x1eb/0x340
f2fs_post_read_work+0xba/0x140
process_one_work+0x91c/0x1a40
worker_thread+0x677/0xe90
kthread+0x2bc/0x3a0
The COW inode is only needed to locate the on-disk block, and that block
address is already resolved into @blkaddr by prepare_atomic_write_begin()
via __find_data_block(cow_inode, ...); f2fs_submit_page_read() then reads
from that physical @blkaddr directly, so the inode argument only selects
the post-read crypto context, not which block is fetched. Reading with
@inode therefore returns the same (latest, not-yet-committed) COW data,
while making both the fs-layer decryption decision and the inline crypto
path use the correct (original inode's) key.
With the COW inode no longer used at the read site, the use_cow flag has no
remaining consumer; drop it from f2fs_write_begin() and
prepare_atomic_write_begin().
Fixes: 591fc34e1f98 ("f2fs: use cow inode data when updating atomic write")
Cc: stable@vger.kernel.org
Signed-off-by: Mikhail Lobanov <m.lobanov@rosa.ru>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/data.c | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index f8154a431fc96..4bbaae47b184e 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -3593,7 +3593,7 @@ static int __reserve_data_block(struct inode *inode, pgoff_t index,
static int prepare_atomic_write_begin(struct f2fs_sb_info *sbi,
struct folio *folio, loff_t pos, unsigned int len,
- block_t *blk_addr, bool *node_changed, bool *use_cow)
+ block_t *blk_addr, bool *node_changed)
{
struct inode *inode = folio->mapping->host;
struct inode *cow_inode = F2FS_I(inode)->cow_inode;
@@ -3608,14 +3608,14 @@ static int prepare_atomic_write_begin(struct f2fs_sb_info *sbi,
/* Look for the block in COW inode first */
err = __find_data_block(cow_inode, index, blk_addr);
- if (err) {
+ if (err)
return err;
- } else if (__is_valid_data_blkaddr(*blk_addr)) {
- *use_cow = true;
+
+ if (__is_valid_data_blkaddr(*blk_addr))
return 0;
- } else if (*blk_addr == NEW_ADDR) {
+
+ if (*blk_addr == NEW_ADDR)
cow_has_reserved_block = true;
- }
if (is_inode_flag_set(inode, FI_ATOMIC_REPLACE))
goto reserve_block;
@@ -3648,7 +3648,6 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
struct folio *folio;
pgoff_t index = pos >> PAGE_SHIFT;
bool need_balance = false;
- bool use_cow = false;
block_t blkaddr = NULL_ADDR;
int err = 0;
@@ -3710,7 +3709,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
if (f2fs_is_atomic_file(inode))
err = prepare_atomic_write_begin(sbi, folio, pos, len,
- &blkaddr, &need_balance, &use_cow);
+ &blkaddr, &need_balance);
else
err = prepare_write_begin(sbi, folio, pos, len,
&blkaddr, &need_balance);
@@ -3750,9 +3749,15 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
err = -EFSCORRUPTED;
goto put_folio;
}
- err = f2fs_submit_page_read(use_cow ?
- F2FS_I(inode)->cow_inode : inode,
- folio, blkaddr, 0, true);
+ /*
+ * Although the block may be stored in the COW inode, the folio
+ * belongs to @inode and its data was encrypted (or not) using
+ * @inode's context (see f2fs_encrypt_one_page()). Read with
+ * @inode so the post-read decryption decision matches the
+ * folio's owner; otherwise an unencrypted @inode whose COW inode
+ * is encrypted hits a NULL ->i_crypt_info on decryption.
+ */
+ err = f2fs_submit_page_read(inode, folio, blkaddr, 0, true);
if (err)
goto put_folio;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 341/869] gcov: use atomic counter updates to fix concurrent access crashes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (339 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 340/869] f2fs: read COW data with the original inode during atomic write Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 342/869] wifi: mt76: add wcid publish check in mt76_sta_add Greg Kroah-Hartman
` (528 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Konstantin Khorenko, Arnd Bergmann,
Peter Oberparleiter, Masahiro Yamada, Miguel Ojeda,
Mikhail Zaslonko, Nathan Chancellor, Pavel Tikhomirov,
Thomas Weißschuh, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Khorenko <khorenko@virtuozzo.com>
[ Upstream commit 56cb9b7d96b28a1173a510ab25354b6599ad3a33 ]
GCC's GCOV instrumentation can merge global branch counters with loop
induction variables as an optimization. In inflate_fast(), the inner copy
loops get transformed so that the GCOV counter value is loaded multiple
times to compute the loop base address, start index, and end bound. Since
GCOV counters are global (not per-CPU), concurrent execution on different
CPUs causes the counter to change between loads, producing inconsistent
values and out-of-bounds memory writes.
The crash manifests during IPComp (IP Payload Compression) processing when
inflate_fast() runs concurrently on multiple CPUs:
BUG: unable to handle page fault for address: ffffd0a3c0902ffa
RIP: inflate_fast+1431
Call Trace:
zlib_inflate
__deflate_decompress
crypto_comp_decompress
ipcomp_decompress [xfrm_ipcomp]
ipcomp_input [xfrm_ipcomp]
xfrm_input
At the crash point, the compiler generated three loads from the same
global GCOV counter (__gcov0.inflate_fast+216) to compute base, start, and
end for an indexed loop. Another CPU modified the counter between loads,
making the values inconsistent - the write went 3.4 MB past a 65 KB
buffer.
Add -fprofile-update=prefer-atomic to CFLAGS_GCOV at the global level in
the top-level Makefile, guarded by a try-run compile test. The test
compiles a minimal program with and without -fprofile-update=prefer-atomic
using the full KBUILD_CFLAGS, then compares undefined symbols in the
resulting object files. If prefer-atomic introduces new undefined
references (such as __atomic_fetch_add_8 on i386 or __aarch64_ldadd8_relax
on arm64 with outline-atomics), the flag is not added -- the kernel does
not link against libatomic.
On architectures where GCC inlines 64-bit atomic counter updates (x86_64,
s390, ...) the test passes and the flag is enabled, preventing the
compiler from merging counters with loop induction variables and fixing
the observed concurrent-access crash.
On architectures where the flag would introduce libatomic dependencies, it
is silently omitted and behaviour is no worse than before this patch.
Move the CFLAGS_GCOV block from its original position (before the arch
Makefile include) to after the core KBUILD_CFLAGS assignments but before
the scripts/Makefile.gcc-plugins include. This placement ensures the
try-run test sees arch-specific flags (-m32, -march=,
-mno-outline-atomics) while avoiding GCC plugin flags (-fplugin=) that
would break the test on clean builds when plugin shared objects do not yet
exist.
Link: https://lore.kernel.org/20260511105052.417187-2-khorenko@virtuozzo.com
Signed-off-by: Konstantin Khorenko <khorenko@virtuozzo.com>
Tested-by: Arnd Bergmann <arnd@arndb.de>
Tested-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Miguel Ojeda <ojeda@kernel.org>
Cc: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Cc: Thomas Weißschuh <linux@weissschuh.net>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
Makefile | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)
diff --git a/Makefile b/Makefile
index 440ddc25dc9a6..9b4b99f66a012 100644
--- a/Makefile
+++ b/Makefile
@@ -753,12 +753,6 @@ endif # KBUILD_EXTMOD
# Defaults to vmlinux, but the arch makefile usually adds further targets
all: vmlinux
-CFLAGS_GCOV := -fprofile-arcs -ftest-coverage
-ifdef CONFIG_CC_IS_GCC
-CFLAGS_GCOV += -fno-tree-loop-im
-endif
-export CFLAGS_GCOV
-
# The arch Makefiles can override CC_FLAGS_FTRACE. We may also append it later.
ifdef CONFIG_FUNCTION_TRACER
CC_FLAGS_FTRACE := -pg
@@ -1027,6 +1021,27 @@ KBUILD_CFLAGS += -fno-builtin-wcslen
# Ensure compilers do not transform certain loops into calls to wcslen()
KBUILD_CFLAGS += -fno-builtin-wcslen
+CFLAGS_GCOV := -fprofile-arcs -ftest-coverage
+ifdef CONFIG_CC_IS_GCC
+CFLAGS_GCOV += -fno-tree-loop-im
+# Use atomic counter updates to avoid concurrent-access crashes in GCOV.
+# Only enable if -fprofile-update=prefer-atomic does not introduce new
+# undefined symbols (e.g. libatomic calls that the kernel cannot link).
+CFLAGS_GCOV += $(call try-run,\
+ echo 'long long x; void f(void){x++;}' | \
+ $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -w -fprofile-arcs \
+ -ftest-coverage -x c - -c -o "$$TMP.base" && \
+ echo 'long long x; void f(void){x++;}' | \
+ $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -w -fprofile-arcs \
+ -ftest-coverage -fprofile-update=prefer-atomic \
+ -x c - -c -o "$$TMP" && \
+ $(NM) "$$TMP.base" | grep ' U ' > "$$TMP.ubase" || true ; \
+ $(NM) "$$TMP" | grep ' U ' > "$$TMP.utest" || true ; \
+ cmp -s "$$TMP.ubase" "$$TMP.utest",\
+ -fprofile-update=prefer-atomic)
+endif
+export CFLAGS_GCOV
+
# change __FILE__ to the relative path from the srctree
KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 342/869] wifi: mt76: add wcid publish check in mt76_sta_add
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (340 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 341/869] gcov: use atomic counter updates to fix concurrent access crashes Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 343/869] drm/amdgpu/vcn: set no_user_fence for VCN v4.0 enc ring Greg Kroah-Hartman
` (527 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jiajia Liu, Felix Fietkau,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiajia Liu <liujiajia@kylinos.cn>
[ Upstream commit 20b126920a259df4d7dcae19fcfe2c57a74d6b2e ]
Since mt7925_mac_sta_add publishes wcid, add publish check in mt76_sta_add
to avoid reinitializing the wcid->poll_list.
Found dev->sta_poll_list corruption when using mt7925 and 7.1-rc4.
According to the corruption information, prev->next was changed to itself.
wlan0: disconnect from AP 90:fb:5d:94:8b:e3 for new auth to 90:fb:5d:94:8b:e2
wlan0: authenticate with 90:fb:5d:94:8b:e2 (local address=84:9e:56:9c:7e:6b)
wlan0: send auth to 90:fb:5d:94:8b:e2 (try 1/3)
slab kmalloc-8k start ffff8c80958a6000 pointer offset 4160 size 8192
list_add corruption. prev->next should be next (ffff8c808a7488f8), but was ffff8c80958a7040. (prev=ffff8c80958a7040).
mt76_wcid_add_poll+0x95/0xd0 [mt76]
mt7925_mac_add_txs.part.0+0xa5/0xe0 [mt7925_common]
mt7925_rx_check+0xa7/0xc0 [mt7925_common]
mt76_dma_rx_poll+0x50d/0x790 [mt76]
mt792x_poll_rx+0x52/0xe0 [mt792x_lib]
Signed-off-by: Jiajia Liu <liujiajia@kylinos.cn>
Link: https://patch.msgid.link/20260528033814.46418-1-liujiajia@kylinos.cn
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mac80211.c | 22 ++++++++++++++-----
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index ca1f7b2991c51..cd02dff7ab347 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -1486,6 +1486,7 @@ mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
{
struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
struct mt76_dev *dev = phy->dev;
+ struct mt76_wcid *published;
int ret;
int i;
@@ -1505,13 +1506,22 @@ mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
mtxq->wcid = wcid->idx;
}
- ewma_signal_init(&wcid->rssi);
- if (phy->band_idx == MT_BAND1)
- mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
- wcid->phy_idx = phy->band_idx;
- rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
+ published = rcu_dereference_protected(dev->wcid[wcid->idx],
+ lockdep_is_held(&dev->mutex));
+ if (published != wcid) {
+ WARN_ON_ONCE(published);
+ ewma_signal_init(&wcid->rssi);
+ if (phy->band_idx == MT_BAND1)
+ mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
+ wcid->phy_idx = phy->band_idx;
+ rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
+ mt76_wcid_init(wcid);
+ } else {
+ if (phy->band_idx == MT_BAND1)
+ mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
+ wcid->phy_idx = phy->band_idx;
+ }
- mt76_wcid_init(wcid);
out:
mutex_unlock(&dev->mutex);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 343/869] drm/amdgpu/vcn: set no_user_fence for VCN v4.0 enc ring
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (341 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 342/869] wifi: mt76: add wcid publish check in mt76_sta_add Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 344/869] net: airoha: Do not read uninitialized fragment address in airoha_dev_xmit() Greg Kroah-Hartman
` (526 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian König, Alex Deucher,
Yinjie Yao, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <yinjie.yao@amd.com>
[ Upstream commit 51f694221047c84fa185be98210eb2c354ffb8c6 ]
VCN encoder and decoder rings do not support 64-bit user fence writes,
reject CS submissions with user fences.
Fixes: 8da1170a16e4 ("drm/amdgpu: add VCN4 ip block support")
Reviewed-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Yinjie Yao <yinjie.yao@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit fd852c048b46f9825e904a4f3f4538fe9d8827d9)
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index d86de234765d6..e9d43924bcd73 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -1926,6 +1926,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = {
.type = AMDGPU_RING_TYPE_VCN_ENC,
.align_mask = 0x3f,
.nop = VCN_ENC_CMD_NO_OP,
+ .no_user_fence = true,
.extra_dw = sizeof(struct amdgpu_vcn_rb_metadata),
.get_rptr = vcn_v4_0_unified_ring_get_rptr,
.get_wptr = vcn_v4_0_unified_ring_get_wptr,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 344/869] net: airoha: Do not read uninitialized fragment address in airoha_dev_xmit()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (342 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 343/869] drm/amdgpu/vcn: set no_user_fence for VCN v4.0 enc ring Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 345/869] net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue() Greg Kroah-Hartman
` (525 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lorenzo Bianconi, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <lorenzo@kernel.org>
[ Upstream commit bde34e84edc8b5571fbde7e941e175a4293ee1eb ]
The transmit loop in airoha_dev_xmit() reads fragment address and length
during its final iteration, when the loop index equals
skb_shinfo(skb)->nr_frags, at which point the fragment data is
uninitialized. While these values are never consumed, the read itself is
unsafe and may trigger a page fault. Fix this by avoiding the fragment
read on the last iteration.
Additionally, move the skb pointer from the first to the last used packet
descriptor, so that airoha_qdma_tx_napi_poll() defers freeing the skb
until the final descriptor is processed.
Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20260424-airoha-xmit-fix-read-frag-v1-1-fdc0a83c79e8@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 41695f353cdc6..1488eb17514eb 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2592,10 +2592,13 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
WRITE_ONCE(desc->msg1, cpu_to_le32(msg1));
WRITE_ONCE(desc->msg2, cpu_to_le32(0xffff));
- e->skb = i ? NULL : skb;
+ e->skb = i == nr_frags - 1 ? skb : NULL;
e->dma_addr = addr;
e->dma_len = len;
+ if (i == nr_frags - 1)
+ continue;
+
data = skb_frag_address(frag);
len = skb_frag_size(frag);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 345/869] net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (343 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 344/869] net: airoha: Do not read uninitialized fragment address in airoha_dev_xmit() Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 346/869] drm/amdgpu: fix amdgpu_hmm_range_get_pages Greg Kroah-Hartman
` (524 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lorenzo Bianconi, Simon Horman,
Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <lorenzo@kernel.org>
[ Upstream commit 3309965fe44c00fd65af7cef5016e9e782c021a7 ]
Similar to airoha_qdma_cleanup_rx_queue(), reset DMA TX descriptors in
airoha_qdma_cleanup_tx_queue routine. Moreover, reset TX_DMA_IDX to
TX_CPU_IDX to notify the NIC the QDMA TX ring is empty.
Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20260417-airoha_qdma_cleanup_tx_queue-fix-net-v4-2-e04bcc2c9642@kernel.org
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 1488eb17514eb..4589396ab01fc 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1901,20 +1901,40 @@ static int airoha_qdma_init_tx(struct airoha_qdma *qdma)
static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q)
{
- struct airoha_eth *eth = q->qdma->eth;
+ struct airoha_qdma *qdma = q->qdma;
+ struct airoha_eth *eth = qdma->eth;
+ int qid = q - &qdma->q_tx[0];
spin_lock_bh(&q->lock);
while (q->queued) {
struct airoha_queue_entry *e = &q->entry[q->tail];
+ struct airoha_qdma_desc *desc = &q->desc[q->tail];
dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
DMA_TO_DEVICE);
dev_kfree_skb_any(e->skb);
e->skb = NULL;
+ /* Reset DMA descriptor */
+ WRITE_ONCE(desc->ctrl, 0);
+ WRITE_ONCE(desc->addr, 0);
+ WRITE_ONCE(desc->data, 0);
+ WRITE_ONCE(desc->msg0, 0);
+ WRITE_ONCE(desc->msg1, 0);
+ WRITE_ONCE(desc->msg2, 0);
+
q->tail = (q->tail + 1) % q->ndesc;
q->queued--;
}
+
+ /* Set TX_DMA_IDX to TX_CPU_IDX to notify the hw the QDMA TX ring is
+ * empty.
+ */
+ airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK,
+ FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head));
+ airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK,
+ FIELD_PREP(TX_RING_DMA_IDX_MASK, q->head));
+
spin_unlock_bh(&q->lock);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 346/869] drm/amdgpu: fix amdgpu_hmm_range_get_pages
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (344 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 345/869] net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue() Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 347/869] net/handshake: hand off the pinned file reference to accept_doit Greg Kroah-Hartman
` (523 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian König, Vitaly Prosyak,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian König <christian.koenig@amd.com>
[ Upstream commit 962d684b5dc0741dcd93485d41b450de402d5592 ]
The notifier sequence must only be read once or otherwise we could work
with invalid pages.
While at it also fix the coding style, e.g. drop the pre-initialized
return value and use the common define for 2G range.
Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
Tested-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit c08972f555945cda57b0adb72272a37910153390)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
index e36fede7f74c3..52882d88c290a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
@@ -51,8 +51,6 @@
#include "amdgpu_amdkfd.h"
#include "amdgpu_hmm.h"
-#define MAX_WALK_BYTE (2UL << 30)
-
/**
* amdgpu_hmm_invalidate_gfx - callback to notify about mm change
*
@@ -170,12 +168,14 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
void *owner, struct page **pages,
struct hmm_range **phmm_range)
{
+ const u64 max_bytes = SZ_2G;
+
struct hmm_range *hmm_range;
- unsigned long end;
unsigned long timeout;
- unsigned long i;
unsigned long *pfns;
- int r = 0;
+ unsigned long end;
+ unsigned long i;
+ int r;
hmm_range = kzalloc(sizeof(*hmm_range), GFP_KERNEL);
if (unlikely(!hmm_range))
@@ -196,8 +196,9 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
end = start + npages * PAGE_SIZE;
hmm_range->dev_private_owner = owner;
+ hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
do {
- hmm_range->end = min(hmm_range->start + MAX_WALK_BYTE, end);
+ hmm_range->end = min(hmm_range->start + max_bytes, end);
pr_debug("hmm range: start = 0x%lx, end = 0x%lx",
hmm_range->start, hmm_range->end);
@@ -205,7 +206,6 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
timeout = jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
retry:
- hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
r = hmm_range_fault(hmm_range);
if (unlikely(r)) {
if (r == -EBUSY && !time_after(jiffies, timeout))
@@ -215,7 +215,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
if (hmm_range->end == end)
break;
- hmm_range->hmm_pfns += MAX_WALK_BYTE >> PAGE_SHIFT;
+ hmm_range->hmm_pfns += max_bytes >> PAGE_SHIFT;
hmm_range->start = hmm_range->end;
} while (hmm_range->end < end);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 347/869] net/handshake: hand off the pinned file reference to accept_doit
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (345 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 346/869] drm/amdgpu: fix amdgpu_hmm_range_get_pages Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 348/869] ethtool: module: call ethnl_ops_complete() on module flash errors Greg Kroah-Hartman
` (522 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Chris Mason, Chuck Lever,
Hannes Reinecke, Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <chuck.lever@oracle.com>
[ Upstream commit f4251190e58b209999c1ba9e6d2976136a1be055 ]
handshake_req_next() removes the request from the per-net
pending list and drops hn_lock before handshake_nl_accept_doit()
reads req->hr_sk->sk_socket and dereferences sock->file (once in
FD_PREPARE() and again in get_file()). In that window a
consumer running tls_handshake_cancel() followed by sockfd_put()
(svc_sock_free) or __fput_sync() (xs_reset_transport) releases
sock->file. sock_release() then runs sock_orphan(), zeroing
sk_socket, and frees the struct socket. The accept-side code
either reads NULL through sk_socket or chases freed memory.
The submit-side sock_hold() does not prevent this. sk_refcnt
protects struct sock, but struct socket and sock->file are
independently refcounted via the file descriptor the consumer
owns. Pinning sk leaves sock and sock->file unprotected.
Retarget the accept-side dereferences at req->hr_file, which was
pinned at submit time, instead of req->hr_sk->sk_socket->file.
Pinning on its own is not sufficient: a consumer that cancels
between handshake_req_next() returning and accept_doit reaching
FD_PREPARE() takes the !remove_pending() branch in
handshake_req_cancel() and drops hr_file before the accept side
takes its own reference. Hand off an additional file reference
inside handshake_req_next(), under hn_lock, so the accept side
operates on a reference that no concurrent handshake_req_cancel()
can revoke. FD_PREPARE() consumes that handed-off reference,
either by transferring it to the new fd in fd_publish() or by
dropping it in the cleanup destructor on error; the explicit
get_file() that previously balanced FD_PREPARE() is therefore
redundant and goes away.
Update handshake_req_cancel_test2 and _test3 to simulate the
FD_PREPARE() consumption with an fput() so the kunit file-count
assertions stay balanced.
Reported-by: Chris Mason <clm@meta.com>
Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Link: https://patch.msgid.link/20260525-handshake-file-pin-v3-5-66c616906ead@oracle.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/handshake/handshake-test.c | 8 ++++++++
net/handshake/netlink.c | 6 +++---
net/handshake/request.c | 18 ++++++++++++++++++
3 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/net/handshake/handshake-test.c b/net/handshake/handshake-test.c
index a331b308aaa24..d66b133f59d12 100644
--- a/net/handshake/handshake-test.c
+++ b/net/handshake/handshake-test.c
@@ -375,6 +375,10 @@ static void handshake_req_cancel_test2(struct kunit *test)
/* Pretend to accept this request */
next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD);
KUNIT_ASSERT_PTR_EQ(test, req, next);
+ /* Simulate FD_PREPARE() consuming the file reference handed
+ * off by handshake_req_next(); see handshake_nl_accept_doit().
+ */
+ fput(filp);
/* Act */
result = handshake_req_cancel(sock->sk);
@@ -417,6 +421,10 @@ static void handshake_req_cancel_test3(struct kunit *test)
/* Pretend to accept this request */
next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD);
KUNIT_ASSERT_PTR_EQ(test, req, next);
+ /* Simulate FD_PREPARE() consuming the file reference handed
+ * off by handshake_req_next(); see handshake_nl_accept_doit().
+ */
+ fput(filp);
/* Pretend to complete this request */
handshake_complete(next, -ETIMEDOUT, NULL);
diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c
index e49041cc0f9d7..d36f069549f93 100644
--- a/net/handshake/netlink.c
+++ b/net/handshake/netlink.c
@@ -92,7 +92,6 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info)
struct net *net = sock_net(skb->sk);
struct handshake_net *hn = handshake_pernet(net);
struct handshake_req *req = NULL;
- struct socket *sock;
int class, fd, err;
err = -EOPNOTSUPP;
@@ -109,9 +108,9 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info)
if (!req)
goto out_status;
- sock = req->hr_sk->sk_socket;
fd = get_unused_fd_flags(O_CLOEXEC);
if (fd < 0) {
+ fput(req->hr_file); /* drop ref from handshake_req_next() */
err = fd;
goto out_complete;
}
@@ -119,10 +118,11 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info)
err = req->hr_proto->hp_accept(req, info, fd);
if (err) {
put_unused_fd(fd);
+ fput(req->hr_file); /* drop ref from handshake_req_next() */
goto out_complete;
}
- fd_install(fd, get_file(sock->file));
+ fd_install(fd, req->hr_file);
trace_handshake_cmd_accept(net, req, req->hr_sk, fd);
return 0;
diff --git a/net/handshake/request.c b/net/handshake/request.c
index 96f80e0df67b5..670e0f9793825 100644
--- a/net/handshake/request.c
+++ b/net/handshake/request.c
@@ -181,6 +181,17 @@ static bool remove_pending(struct handshake_net *hn, struct handshake_req *req)
return ret;
}
+/**
+ * handshake_req_next - Return the next queued handshake request
+ * @hn: per-net handshake state
+ * @class: handler class to match
+ *
+ * On a non-NULL return, the caller owns an extra reference
+ * on @req->hr_file. FD_PREPARE() consumes it on success; on
+ * the FD_PREPARE() failure path the caller must fput() it.
+ *
+ * Return: pointer to a removed handshake_req, or NULL.
+ */
struct handshake_req *handshake_req_next(struct handshake_net *hn, int class)
{
struct handshake_req *req, *pos;
@@ -191,6 +202,13 @@ struct handshake_req *handshake_req_next(struct handshake_net *hn, int class)
if (pos->hr_proto->hp_handler_class != class)
continue;
__remove_pending_locked(hn, pos);
+ /* Hand off a file reference to the accept side under
+ * hn_lock. A concurrent handshake_req_cancel() can drop
+ * hr_file before accept reaches FD_PREPARE(); this extra
+ * reference keeps the file alive until FD_PREPARE() takes
+ * ownership.
+ */
+ get_file(pos->hr_file);
req = pos;
break;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 348/869] ethtool: module: call ethnl_ops_complete() on module flash errors
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (346 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 347/869] net/handshake: hand off the pinned file reference to accept_doit Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 349/869] ethtool: rss: fix indir_table and hkey leak on get_rxfh failure Greg Kroah-Hartman
` (521 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Maxime Chevallier, Danielle Ratson,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <kuba@kernel.org>
[ Upstream commit 84371fb58423f997939aacdcbc02d128d76a54e5 ]
When validate() fails we are skipping over ethnl_ops_complete()
even tho we already called ethnl_ops_begin().
Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware")
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Danielle Ratson <danieller@nvidia.com>
Link: https://patch.msgid.link/20260522231312.1710836-2-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ethtool/module.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/ethtool/module.c b/net/ethtool/module.c
index 5a08c320b4660..e01275103bcd0 100644
--- a/net/ethtool/module.c
+++ b/net/ethtool/module.c
@@ -425,10 +425,11 @@ int ethnl_act_module_fw_flash(struct sk_buff *skb, struct genl_info *info)
ret = ethnl_module_fw_flash_validate(dev, info->extack);
if (ret < 0)
- goto out_rtnl;
+ goto out_complete;
ret = module_flash_fw(dev, tb, skb, info);
+out_complete:
ethnl_ops_complete(dev);
out_rtnl:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 349/869] ethtool: rss: fix indir_table and hkey leak on get_rxfh failure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (347 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 348/869] ethtool: module: call ethnl_ops_complete() on module flash errors Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 350/869] netfilter: nf_tables: fix dst corruption in same register operation Greg Kroah-Hartman
` (520 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <kuba@kernel.org>
[ Upstream commit 266297692f97008ca48bc311775c087c59bd7fe3 ]
rss_prepare_get() allocates the indirection table and hash key buffer
via rss_get_data_alloc(), then calls ops->get_rxfh() to populate them.
If get_rxfh() fails, the function returns an error without freeing
the allocation.
Fixes: 4f038a6a02d2 ("net: ethtool: Don't call .cleanup_data when prepare_data fails")
Link: https://patch.msgid.link/20260522230647.1705600-5-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
| 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--git a/net/ethtool/rss.c b/net/ethtool/rss.c
index 3570d58c5cca6..b543827ef373e 100644
--- a/net/ethtool/rss.c
+++ b/net/ethtool/rss.c
@@ -88,8 +88,10 @@ rss_prepare_get(const struct rss_req_info *request, struct net_device *dev,
rxfh.key = data->hkey;
ret = ops->get_rxfh(dev, &rxfh);
- if (ret)
+ if (ret) {
+ kfree(rss_config);
goto out_ops;
+ }
data->hfunc = rxfh.hfunc;
data->input_xfrm = rxfh.input_xfrm;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 350/869] netfilter: nf_tables: fix dst corruption in same register operation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (348 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 349/869] ethtool: rss: fix indir_table and hkey leak on get_rxfh failure Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 351/869] tcp: Remove sk->sk_prot->orphan_count Greg Kroah-Hartman
` (519 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jeremy Sowden,
Fernando Fernandez Mancera, Florian Westphal, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <fmancera@suse.de>
[ Upstream commit 18014147d3ee7831dce53fe65d7fc8d428b02552 ]
For lshift and rshift, the shift operations are performed in a loop over
32-bit words. The loop calculates the shifted value and write it to dst,
and then immediately reads from src to calculate the carry for the next
iteration. Because src and dst could point to the same memory location,
the carry is incorrectly calculated using the newly modified dst value
instead of the original src value.
Adding a temporary local variable to cache the original value before
writing to dst and using it for the carry calculation solves the
problem. In addition, partial overlap is rejected from control plane for
all kind of operations including byteorder. This was tested with the
following bytecode:
table test_table ip flags 0 use 1 handle 1
ip test_table test_chain use 3 type filter hook input prio 0 policy accept packets 0 bytes 0 flags 1
ip test_table test_chain 2
[ immediate reg 1 0x44332211 0x88776655 ]
[ bitwise reg 1 = ( reg 1 << 0x08000000 ) ]
[ cmp eq reg 1 0x66443322 0x00887766 ]
[ counter pkts 0 bytes 0 ]
ip test_table test_chain 4 3
[ immediate reg 1 0x44332211 0x88776655 ]
[ bitwise reg 1 = ( reg 1 << 0x08000000 ) ]
[ cmp eq reg 1 0x55443322 0x00887766 ]
[ counter pkts 21794 bytes 1917798 ]
Fixes: 567d746b55bc ("netfilter: bitwise: add support for shifts.")
Acked-by: Jeremy Sowden <jeremy@azazel.net>
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/netfilter/nf_tables.h | 7 +++++++
net/netfilter/nft_bitwise.c | 15 +++++++++++----
net/netfilter/nft_byteorder.c | 13 ++++++++++---
3 files changed, 28 insertions(+), 7 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index d14acbc44b44b..99cc25c233b8e 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -177,6 +177,13 @@ static inline u64 nft_reg_load64(const u32 *sreg)
return get_unaligned((u64 *)sreg);
}
+static inline bool nft_reg_overlap(u8 src, u8 dst, u32 len)
+{
+ unsigned int n = DIV_ROUND_UP(len, sizeof(u32));
+
+ return src != dst && src < dst + n && dst < src + n;
+}
+
static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
unsigned int len)
{
diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
index 0fc21b729eba3..b6e6143989a98 100644
--- a/net/netfilter/nft_bitwise.c
+++ b/net/netfilter/nft_bitwise.c
@@ -42,8 +42,10 @@ static void nft_bitwise_eval_lshift(u32 *dst, const u32 *src,
u32 carry = 0;
for (i = DIV_ROUND_UP(priv->len, sizeof(u32)); i > 0; i--) {
- dst[i - 1] = (src[i - 1] << shift) | carry;
- carry = src[i - 1] >> (BITS_PER_TYPE(u32) - shift);
+ u32 tmp_src = src[i - 1];
+
+ dst[i - 1] = (tmp_src << shift) | carry;
+ carry = tmp_src >> (BITS_PER_TYPE(u32) - shift);
}
}
@@ -55,8 +57,10 @@ static void nft_bitwise_eval_rshift(u32 *dst, const u32 *src,
u32 carry = 0;
for (i = 0; i < DIV_ROUND_UP(priv->len, sizeof(u32)); i++) {
- dst[i] = carry | (src[i] >> shift);
- carry = src[i] << (BITS_PER_TYPE(u32) - shift);
+ u32 tmp_src = src[i];
+
+ dst[i] = carry | (tmp_src >> shift);
+ carry = tmp_src << (BITS_PER_TYPE(u32) - shift);
}
}
@@ -183,6 +187,9 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
if (err < 0)
return err;
+ if (nft_reg_overlap(priv->sreg, priv->dreg, priv->len))
+ return -EINVAL;
+
if (tb[NFTA_BITWISE_OP]) {
priv->op = ntohl(nla_get_be32(tb[NFTA_BITWISE_OP]));
switch (priv->op) {
diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c
index 744878773dac0..74548b4c114b9 100644
--- a/net/netfilter/nft_byteorder.c
+++ b/net/netfilter/nft_byteorder.c
@@ -144,9 +144,16 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
if (err < 0)
return err;
- return nft_parse_register_store(ctx, tb[NFTA_BYTEORDER_DREG],
- &priv->dreg, NULL, NFT_DATA_VALUE,
- priv->len);
+ err = nft_parse_register_store(ctx, tb[NFTA_BYTEORDER_DREG],
+ &priv->dreg, NULL, NFT_DATA_VALUE,
+ priv->len);
+ if (err < 0)
+ return err;
+
+ if (nft_reg_overlap(priv->sreg, priv->dreg, priv->len))
+ return -EINVAL;
+
+ return 0;
}
static int nft_byteorder_dump(struct sk_buff *skb,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 351/869] tcp: Remove sk->sk_prot->orphan_count.
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (349 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 350/869] netfilter: nf_tables: fix dst corruption in same register operation Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 352/869] tcp: fix stale per-CPU tcp_tw_isn leak enabling ISN prediction Greg Kroah-Hartman
` (518 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kuniyuki Iwashima, Jason Xing,
Eric Dumazet, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit 7051b54fb5aa2d0b77657aef7c272471b36c0327 ]
TCP tracks the number of orphaned (SOCK_DEAD but not yet destructed)
sockets in tcp_orphan_count.
In some code that was shared with DCCP, tcp_orphan_count is referenced
via sk->sk_prot->orphan_count.
Let's reference tcp_orphan_count directly.
inet_csk_prepare_for_destroy_sock() is moved to inet_connection_sock.c
due to header dependency.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250829215641.711664-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Only the TCP-only users are converted: the code paths shared with DCCP
keep using sk->sk_prot->orphan_count, so DCCP orphan accounting is not
affected, and the struct proto member stays.
Stable-dep-of: 1bbf0ced1d9d ("tcp: fix stale per-CPU tcp_tw_isn leak enabling ISN prediction")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../ethernet/chelsio/inline_crypto/chtls/chtls_cm.c | 4 ++--
.../ethernet/chelsio/inline_crypto/chtls/chtls_cm.h | 1 -
include/net/tcp.h | 10 ++++++++++
net/ipv4/tcp.c | 2 +-
4 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
index 6d69c19ea7c30..5f9eb030aec9a 100644
--- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
+++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
@@ -505,7 +505,7 @@ static void reset_listen_child(struct sock *child)
chtls_send_reset(child, CPL_ABORT_SEND_RST, skb);
sock_orphan(child);
- INC_ORPHAN_COUNT(child);
+ tcp_orphan_count_inc();
if (child->sk_state == TCP_CLOSE)
inet_csk_destroy_sock(child);
}
@@ -870,7 +870,7 @@ static void do_abort_syn_rcv(struct sock *child, struct sock *parent)
* created only after 3 way handshake is done.
*/
sock_orphan(child);
- INC_ORPHAN_COUNT(child);
+ tcp_orphan_count_inc();
chtls_release_resources(child);
chtls_conn_done(child);
} else {
diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h
index f61ca657601ca..e949e4e580661 100644
--- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h
+++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h
@@ -95,7 +95,6 @@ struct deferred_skb_cb {
#define WSCALE_OK(tp) ((tp)->rx_opt.wscale_ok)
#define TSTAMP_OK(tp) ((tp)->rx_opt.tstamp_ok)
#define SACK_OK(tp) ((tp)->rx_opt.sack_ok)
-#define INC_ORPHAN_COUNT(sk) this_cpu_inc(*(sk)->sk_prot->orphan_count)
/* TLS SKB */
#define skb_ulp_tls_inline(skb) (ULP_SKB_CB(skb)->ulp.tls.ofld)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index ad9af706085ab..115f878540768 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -54,6 +54,16 @@ extern struct inet_hashinfo tcp_hashinfo;
DECLARE_PER_CPU(unsigned int, tcp_orphan_count);
int tcp_orphan_count_sum(void);
+static inline void tcp_orphan_count_inc(void)
+{
+ this_cpu_inc(tcp_orphan_count);
+}
+
+static inline void tcp_orphan_count_dec(void)
+{
+ this_cpu_dec(tcp_orphan_count);
+}
+
DECLARE_PER_CPU(u32, tcp_tw_isn);
void tcp_time_wait(struct sock *sk, int state, int timeo);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 21c64ca9bb9b4..2ab07164eba19 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3163,7 +3163,7 @@ void __tcp_close(struct sock *sk, long timeout)
/* remove backlog if any, without releasing ownership. */
__release_sock(sk);
- this_cpu_inc(tcp_orphan_count);
+ tcp_orphan_count_inc();
/* Have we already been destroyed by a softirq or backlog? */
if (state != TCP_CLOSE && sk->sk_state == TCP_CLOSE)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 352/869] tcp: fix stale per-CPU tcp_tw_isn leak enabling ISN prediction
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (350 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 351/869] tcp: Remove sk->sk_prot->orphan_count Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 353/869] cgroup/rstat: validate cpu before css_rstat_cpu() access Greg Kroah-Hartman
` (517 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Chris Mason, Eric Dumazet,
Kuniyuki Iwashima, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 1bbf0ced1d9db73ac7893c2187f3459288603e0d ]
Blamed commit moved the TIME_WAIT-derived ISN from the skb control
block to a per-CPU variable, assuming the value would always be consumed
by tcp_conn_request() for the same packet that wrote it. That assumption
is violated by multiple drop paths between the producer
(__this_cpu_write(tcp_tw_isn, isn) in tcp_v{4,6}_rcv()) and the consumer
(tcp_conn_request()):
- min_ttl / min_hopcount check
- xfrm policy check
- tcp_inbound_hash() MD5/AO mismatch
- tcp_filter() eBPF/SO_ATTACH_FILTER drop
- th->syn && th->fin discard in tcp_rcv_state_process() TCP_LISTEN
- psp_sk_rx_policy_check() in tcp_v{4,6}_do_rcv()
- tcp_checksum_complete() in tcp_v{4,6}_do_rcv()
- tcp_v{4,6}_cookie_check() returning NULL
When a packet is dropped on any of these paths, tcp_tw_isn is left set.
The next SYN processed on the same CPU then consumes the non zero value in
tcp_conn_request(), receiving a potentially predictable ISN.
This patch moves back tcp_tw_isn to skb->cb[], getting rid of the per-cpu
variable.
Note that tcp_v{4,6}_fill_cb() do not set it.
Very litle impact on overall code size/complexity:
$ scripts/bloat-o-meter -t vmlinux.old vmlinux.new
add/remove: 0/0 grow/shrink: 2/1 up/down: 8/-15 (-7)
Function old new delta
tcp_v6_rcv 3038 3042 +4
tcp_v4_rcv 3035 3039 +4
tcp_conn_request 2938 2923 -15
Total: Before=24436060, After=24436053, chg -0.00%
Fixes: 41eecbd712b7 ("tcp: replace TCP_SKB_CB(skb)->tcp_tw_isn with a per-cpu field")
Reported-by: Chris Mason <clm@meta.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260519084611.2485277-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/tcp.h | 7 ++++---
net/ipv4/tcp.c | 3 ---
net/ipv4/tcp_input.c | 15 ++++++---------
net/ipv4/tcp_ipv4.c | 3 ++-
net/ipv6/tcp_ipv6.c | 3 ++-
5 files changed, 14 insertions(+), 17 deletions(-)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 115f878540768..77f6c40ead438 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -64,8 +64,6 @@ static inline void tcp_orphan_count_dec(void)
this_cpu_dec(tcp_orphan_count);
}
-DECLARE_PER_CPU(u32, tcp_tw_isn);
-
void tcp_time_wait(struct sock *sk, int state, int timeo);
#define MAX_TCP_HEADER L1_CACHE_ALIGN(128 + MAX_HEADER)
@@ -947,10 +945,13 @@ struct tcp_skb_cb {
__u32 seq; /* Starting sequence number */
__u32 end_seq; /* SEQ + FIN + SYN + datalen */
union {
- /* Note :
+ /* Notes :
+ * tcp_tw_isn is used in input path only
+ * (isn chosen by tcp_timewait_state_process())
* tcp_gso_segs/size are used in write queue only,
* cf tcp_skb_pcount()/tcp_skb_mss()
*/
+ u32 tcp_tw_isn;
struct {
u16 tcp_gso_segs;
u16 tcp_gso_size;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 2ab07164eba19..7df7ce86b6904 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -297,9 +297,6 @@ enum {
DEFINE_PER_CPU(unsigned int, tcp_orphan_count);
EXPORT_PER_CPU_SYMBOL_GPL(tcp_orphan_count);
-DEFINE_PER_CPU(u32, tcp_tw_isn);
-EXPORT_PER_CPU_SYMBOL_GPL(tcp_tw_isn);
-
long sysctl_tcp_mem[3] __read_mostly;
EXPORT_IPV6_MOD(sysctl_tcp_mem);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 5c581d4821c1d..96eb6d2421413 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -7242,6 +7242,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
struct sock *sk, struct sk_buff *skb)
{
struct tcp_fastopen_cookie foc = { .len = -1 };
+ u32 isn = TCP_SKB_CB(skb)->tcp_tw_isn;
struct tcp_options_received tmp_opt;
struct tcp_sock *tp = tcp_sk(sk);
struct net *net = sock_net(sk);
@@ -7252,20 +7253,16 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
struct dst_entry *dst;
struct flowi fl;
u8 syncookies;
- u32 isn;
#ifdef CONFIG_TCP_AO
const struct tcp_ao_hdr *aoh;
#endif
- isn = __this_cpu_read(tcp_tw_isn);
- if (isn) {
- /* TW buckets are converted to open requests without
- * limitations, they conserve resources and peer is
- * evidently real one.
- */
- __this_cpu_write(tcp_tw_isn, 0);
- } else {
+ /* If isn is non-zero, this SYN originally matched a TIME_WAIT socket.
+ * TW sockets are converted to open requests without limitations,
+ * we skip the queue limits and syncookie checks in the block below.
+ */
+ if (!isn) {
syncookies = READ_ONCE(net->ipv4.sysctl_tcp_syncookies);
if (syncookies == 2 || inet_csk_reqsk_queue_is_full(sk)) {
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 48af4b0d77f26..c32ec598930b1 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2311,6 +2311,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
}
}
+ isn = 0;
process:
if (static_branch_unlikely(&ip4_min_ttl)) {
/* min_ttl can be changed concurrently from do_ip_setsockopt() */
@@ -2340,6 +2341,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
th = (const struct tcphdr *)skb->data;
iph = ip_hdr(skb);
tcp_v4_fill_cb(skb, iph, th);
+ TCP_SKB_CB(skb)->tcp_tw_isn = isn;
skb->dev = NULL;
@@ -2424,7 +2426,6 @@ int tcp_v4_rcv(struct sk_buff *skb)
sk = sk2;
tcp_v4_restore_cb(skb);
refcounted = false;
- __this_cpu_write(tcp_tw_isn, isn);
goto process;
}
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 69e37c3d4b1c8..ae2a91e3f15c9 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1853,6 +1853,7 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb)
}
}
+ isn = 0;
process:
if (static_branch_unlikely(&ip6_min_hopcount)) {
/* min_hopcount can be changed concurrently from do_ipv6_setsockopt() */
@@ -1882,6 +1883,7 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb)
th = (const struct tcphdr *)skb->data;
hdr = ipv6_hdr(skb);
tcp_v6_fill_cb(skb, hdr, th);
+ TCP_SKB_CB(skb)->tcp_tw_isn = isn;
skb->dev = NULL;
@@ -1968,7 +1970,6 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb)
sk = sk2;
tcp_v6_restore_cb(skb);
refcounted = false;
- __this_cpu_write(tcp_tw_isn, isn);
goto process;
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 353/869] cgroup/rstat: validate cpu before css_rstat_cpu() access
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (351 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 352/869] tcp: fix stale per-CPU tcp_tw_isn leak enabling ISN prediction Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 354/869] hwmon: (lm90) Stop work before releasing hwmon device Greg Kroah-Hartman
` (516 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Qing Ming, Tejun Heo, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qing Ming <a0yami@mailbox.org>
[ Upstream commit 8817005efbdfdf5d4e4814cb5dc52b53d12917d7 ]
css_rstat_updated() is exposed as a BPF kfunc and accepts a
caller-provided cpu argument. The function uses cpu for per-cpu rstat
lookups without checking whether it refers to a valid possible CPU.
A BPF iter/cgroup program with CAP_BPF and CAP_PERFMON can pass an
invalid cpu value. On an unfixed UBSCAN_BOUNDS test kernel, cpu ==
0x7fffffff triggers:
UBSAN: array-index-out-of-bounds in kernel/cgroup/rstat.c:31:9
index 2147483647 is out of range for type 'long unsigned int [64]'
Call Trace:
css_rstat_updated
bpf_iter_run_prog
cgroup_iter_seq_show
bpf_seq_read
Add cpu validation to the BPF-facing css_rstat_updated() kfunc and
move the common implementation to __css_rstat_updated() for in-kernel
callers.
Fixes: a319185be9f5 ("cgroup: bpf: enable bpf programs to integrate with rstat")
Signed-off-by: Qing Ming <a0yami@mailbox.org>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
block/blk-cgroup.c | 2 +-
include/linux/cgroup.h | 1 +
kernel/cgroup/rstat.c | 19 ++++++++++++++++---
mm/memcontrol.c | 2 +-
4 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index d89da7e067f42..cc882dc2db7f6 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -2189,7 +2189,7 @@ void blk_cgroup_bio_start(struct bio *bio)
}
u64_stats_update_end_irqrestore(&bis->sync, flags);
- cgroup_rstat_updated(blkcg->css.cgroup, cpu);
+ __cgroup_rstat_updated(blkcg->css.cgroup, cpu);
put_cpu();
}
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 2a510dbbfe623..66a283527fa98 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -688,6 +688,7 @@ static inline void cgroup_path_from_kernfs_id(u64 id, char *buf, size_t buflen)
/*
* cgroup scalable recursive statistics.
*/
+void __cgroup_rstat_updated(struct cgroup *cgrp, int cpu);
void cgroup_rstat_updated(struct cgroup *cgrp, int cpu);
void cgroup_rstat_flush(struct cgroup *cgrp);
void cgroup_rstat_flush_hold(struct cgroup *cgrp);
diff --git a/kernel/cgroup/rstat.c b/kernel/cgroup/rstat.c
index c4ce2f5a9745f..d8bdebdeac023 100644
--- a/kernel/cgroup/rstat.c
+++ b/kernel/cgroup/rstat.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
#include "cgroup-internal.h"
+#include <linux/cpumask.h>
#include <linux/sched/cputime.h>
#include <linux/bpf.h>
@@ -74,7 +75,7 @@ void _cgroup_rstat_cpu_unlock(raw_spinlock_t *cpu_lock, int cpu,
}
/**
- * cgroup_rstat_updated - keep track of updated rstat_cpu
+ * __cgroup_rstat_updated - keep track of updated rstat_cpu
* @cgrp: target cgroup
* @cpu: cpu on which rstat_cpu was updated
*
@@ -82,7 +83,7 @@ void _cgroup_rstat_cpu_unlock(raw_spinlock_t *cpu_lock, int cpu,
* rstat_cpu->updated_children list. See the comment on top of
* cgroup_rstat_cpu definition for details.
*/
-__bpf_kfunc void cgroup_rstat_updated(struct cgroup *cgrp, int cpu)
+void __cgroup_rstat_updated(struct cgroup *cgrp, int cpu)
{
raw_spinlock_t *cpu_lock = per_cpu_ptr(&cgroup_rstat_cpu_lock, cpu);
unsigned long flags;
@@ -129,6 +130,18 @@ __bpf_kfunc void cgroup_rstat_updated(struct cgroup *cgrp, int cpu)
_cgroup_rstat_cpu_unlock(cpu_lock, cpu, cgrp, flags, true);
}
+/*
+ * BPF-facing wrapper for __cgroup_rstat_updated(). Validate the
+ * caller-provided CPU before passing it to the internal rstat updater.
+ */
+__bpf_kfunc void cgroup_rstat_updated(struct cgroup *cgrp, int cpu)
+{
+ if (unlikely(cpu < 0 || cpu >= nr_cpu_ids || !cpu_possible(cpu)))
+ return;
+
+ __cgroup_rstat_updated(cgrp, cpu);
+}
+
/**
* cgroup_rstat_push_children - push children cgroups into the given list
* @head: current head of the list (= subtree root)
@@ -511,7 +524,7 @@ static void cgroup_base_stat_cputime_account_end(struct cgroup *cgrp,
unsigned long flags)
{
u64_stats_update_end_irqrestore(&rstatc->bsync, flags);
- cgroup_rstat_updated(cgrp, smp_processor_id());
+ __cgroup_rstat_updated(cgrp, smp_processor_id());
put_cpu_ptr(rstatc);
}
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 50a1fd9087fae..8b0635ed1d208 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -569,7 +569,7 @@ static inline void memcg_rstat_updated(struct mem_cgroup *memcg, int val)
if (!val)
return;
- cgroup_rstat_updated(memcg->css.cgroup, cpu);
+ __cgroup_rstat_updated(memcg->css.cgroup, cpu);
statc = this_cpu_ptr(memcg->vmstats_percpu);
for (; statc; statc = statc->parent) {
stats_updates = READ_ONCE(statc->stats_updates) + abs(val);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 354/869] hwmon: (lm90) Stop work before releasing hwmon device
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (352 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 353/869] cgroup/rstat: validate cpu before css_rstat_cpu() access Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 355/869] netfs: Fix leak of request in netfs_write_begin() error handling Greg Kroah-Hartman
` (515 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Sashiko, Guenter Roeck, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <linux@roeck-us.net>
[ Upstream commit b09a45601094c7f4ec4db8090b825fa61e169d93 ]
Sashiko reports:
In lm90_probe(), the devm action to cancel the alert_work and report_work
(lm90_restore_conf) is registered in lm90_init_client() before
devm_hwmon_device_register_with_info() is called.
Because devm executes cleanup actions in reverse order during module
unbind or probe failure, the hwmon device is unregistered and freed first.
If lm90_alert_work() or lm90_report_alarms() runs in the window between
the hwmon device being freed and the delayed works being cancelled,
lm90_update_alarms() will dereference the freed data->hwmon_dev here.
Fix the problem by canceling the workers separately after registering
the hwmon device and before registering the interrupt handler. This ensures
that the workers are canceled after interrupts are disabled and before
the hwmon device is released. Add "shutdown" flag to indicate that device
shutdown is in progress to prevent workers from being re-armed.
Fixes: f6d0775119fb9 ("hwmon: (lm90) Rework alarm/status handling")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hwmon/lm90.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 45d5a2427dcb1..d79f6d091e3ef 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -695,6 +695,7 @@ struct lm90_data {
struct mutex update_lock;
struct delayed_work alert_work;
struct work_struct report_work;
+ bool shutdown; /* true if shutting down */
bool valid; /* true if register values are valid */
bool alarms_valid; /* true if status register values are valid */
unsigned long last_updated; /* in jiffies */
@@ -1113,6 +1114,9 @@ static void lm90_report_alarms(struct work_struct *work)
static int lm90_update_alarms_locked(struct lm90_data *data, bool force)
{
+ if (data->shutdown)
+ return 0;
+
if (force || !data->alarms_valid ||
time_after(jiffies, data->alarms_updated + msecs_to_jiffies(data->update_interval))) {
struct i2c_client *client = data->client;
@@ -2522,15 +2526,23 @@ static void lm90_restore_conf(void *_data)
struct lm90_data *data = _data;
struct i2c_client *client = data->client;
- cancel_delayed_work_sync(&data->alert_work);
- cancel_work_sync(&data->report_work);
-
/* Restore initial configuration */
if (data->flags & LM90_HAVE_CONVRATE)
lm90_write_convrate(data, data->convrate_orig);
lm90_write_reg(client, LM90_REG_CONFIG1, data->config_orig);
}
+static void lm90_stop_work(void *_data)
+{
+ struct lm90_data *data = _data;
+
+ mutex_lock(&data->update_lock);
+ data->shutdown = true;
+ mutex_unlock(&data->update_lock);
+ cancel_delayed_work_sync(&data->alert_work);
+ cancel_work_sync(&data->report_work);
+}
+
static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
{
struct device_node *np = client->dev.of_node;
@@ -2841,6 +2853,10 @@ static int lm90_probe(struct i2c_client *client)
data->hwmon_dev = hwmon_dev;
+ err = devm_add_action_or_reset(&client->dev, lm90_stop_work, data);
+ if (err)
+ return err;
+
if (client->irq) {
dev_dbg(dev, "IRQ: %d\n", client->irq);
err = devm_request_threaded_irq(dev, client->irq,
@@ -2869,7 +2885,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,
*/
struct lm90_data *data = i2c_get_clientdata(client);
- if ((data->flags & LM90_HAVE_BROKEN_ALERT) &&
+ if (!data->shutdown && (data->flags & LM90_HAVE_BROKEN_ALERT) &&
(data->current_alarms & data->alert_alarms)) {
if (!(data->config & 0x80)) {
dev_dbg(&client->dev, "Disabling ALERT#\n");
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 355/869] netfs: Fix leak of request in netfs_write_begin() error handling
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (353 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 354/869] hwmon: (lm90) Stop work before releasing hwmon device Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 356/869] netfs: Fix missing locking around retry adding new subreqs Greg Kroah-Hartman
` (514 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Paulo Alcantara,
Matthew Wilcox, netfs, linux-fsdevel, Christian Brauner,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit 5046a34f0643441f05b0253ea64e1a3af87efe14 ]
Fix netfs_write_begin() to not leak our ref on the request in the event
that we get an error from netfs_wait_for_read().
Fixes: 4090b31422a6 ("netfs: Add a function to consolidate beginning a read")
Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260512123404.719402-19-dhowells@redhat.com
cc: Paulo Alcantara <pc@manguebit.org>
cc: Matthew Wilcox <willy@infradead.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/netfs/buffered_read.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c
index 562c59f421334..ec78ad094cf4a 100644
--- a/fs/netfs/buffered_read.c
+++ b/fs/netfs/buffered_read.c
@@ -753,9 +753,9 @@ int netfs_write_begin(struct netfs_inode *ctx,
netfs_read_to_pagecache(rreq);
ret = netfs_wait_for_read(rreq);
+ netfs_put_request(rreq, false, netfs_rreq_trace_put_return);
if (ret < 0)
goto error;
- netfs_put_request(rreq, false, netfs_rreq_trace_put_return);
have_folio:
ret = folio_wait_private_2_killable(folio);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 356/869] netfs: Fix missing locking around retry adding new subreqs
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (354 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 355/869] netfs: Fix leak of request in netfs_write_begin() error handling Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 357/869] netfilter: bridge: eb_tables: close module init race Greg Kroah-Hartman
` (513 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Paulo Alcantara,
netfs, linux-fsdevel, Christian Brauner, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit cce18c263e9623872327ba3c956012f73c1179cc ]
Fix netfs_retry_read_subrequests() and netfs_retry_write_stream() to take
the appropriate lock when adding extra subrequests into
stream->subrequests.
Fixes: e2d46f2ec332 ("netfs: Change the read result collector to only use one work item")
Fixes: 288ace2f57c9 ("netfs: New writeback implementation")
Closes: https://sashiko.dev/#/patchset/20260425125426.3855807-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260512123404.719402-3-dhowells@redhat.com
cc: Paulo Alcantara <pc@manguebit.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/netfs/write_collect.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/fs/netfs/write_collect.c b/fs/netfs/write_collect.c
index c349867d74c34..ad2edf794f0ff 100644
--- a/fs/netfs/write_collect.c
+++ b/fs/netfs/write_collect.c
@@ -263,7 +263,9 @@ static void netfs_retry_write_stream(struct netfs_io_request *wreq,
list_for_each_entry_safe_from(subreq, tmp,
&stream->subrequests, rreq_link) {
trace_netfs_sreq(subreq, netfs_sreq_trace_discard);
+ spin_lock_bh(&wreq->lock);
list_del(&subreq->rreq_link);
+ spin_unlock_bh(&wreq->lock);
netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_done);
if (subreq == to)
break;
@@ -287,8 +289,10 @@ static void netfs_retry_write_stream(struct netfs_io_request *wreq,
netfs_sreq_trace_new);
trace_netfs_sreq(subreq, netfs_sreq_trace_split);
+ spin_lock_bh(&wreq->lock);
list_add(&subreq->rreq_link, &to->rreq_link);
- to = list_next_entry(to, rreq_link);
+ spin_unlock_bh(&wreq->lock);
+ to = subreq;
trace_netfs_sreq(subreq, netfs_sreq_trace_retry);
stream->sreq_max_len = len;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 357/869] netfilter: bridge: eb_tables: close module init race
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (355 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 356/869] netfs: Fix missing locking around retry adding new subreqs Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 358/869] netfilter: ebtables: move to two-stage removal scheme Greg Kroah-Hartman
` (512 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Florian Westphal, Pablo Neira Ayuso,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <fw@strlen.de>
[ Upstream commit 27414ff1b287ea9a2a11675149ec28e05539f3cc ]
sashiko reports for unrelated patch:
Does the core ebtables initialization in ebtables.c suffer from a similar race?
Once nf_register_sockopt() completes, the sockopts are exposed globally.
sockopt has to be registered last, just like in ip/ip6/arptables.
Fixes: 5b53951cfc85 ("netfilter: ebtables: use net_generic infra")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bridge/netfilter/ebtables.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index ab5eca1c9981e..4990a1d0ffb35 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -2607,19 +2607,20 @@ static int __init ebtables_init(void)
{
int ret;
- ret = xt_register_target(&ebt_standard_target);
+ ret = register_pernet_subsys(&ebt_net_ops);
if (ret < 0)
return ret;
- ret = nf_register_sockopt(&ebt_sockopts);
+
+ ret = xt_register_target(&ebt_standard_target);
if (ret < 0) {
- xt_unregister_target(&ebt_standard_target);
+ unregister_pernet_subsys(&ebt_net_ops);
return ret;
}
- ret = register_pernet_subsys(&ebt_net_ops);
+ ret = nf_register_sockopt(&ebt_sockopts);
if (ret < 0) {
- nf_unregister_sockopt(&ebt_sockopts);
xt_unregister_target(&ebt_standard_target);
+ unregister_pernet_subsys(&ebt_net_ops);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 358/869] netfilter: ebtables: move to two-stage removal scheme
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (356 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 357/869] netfilter: bridge: eb_tables: close module init race Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 359/869] netfilter: x_tables: allow initial table replace without emitting audit log message Greg Kroah-Hartman
` (511 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Tristan Madani, Florian Westphal,
Pablo Neira Ayuso, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <fw@strlen.de>
[ Upstream commit b7f0544d86d439cb946515d2ef6a0a75e8626710 ]
Like previous patches for x_tables, follow same pattern in ebtables.
We can't reuse xt helpers: ebt_table struct layout is incompatible.
table->ops assignment is now done while still holding the ebt mutex
to make sure we never expose partially-filled table struct.
Fixes: 87663c39f898 ("netfilter: ebtables: do not hook tables by default")
Reviewed-by: Tristan Madani <tristan@talencesecurity.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bridge/netfilter/ebtable_broute.c | 2 +-
net/bridge/netfilter/ebtable_filter.c | 2 +-
net/bridge/netfilter/ebtable_nat.c | 2 +-
net/bridge/netfilter/ebtables.c | 60 +++++++++++++++++----------
4 files changed, 40 insertions(+), 26 deletions(-)
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
index 7413602195525..e6f9e343b41f1 100644
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -128,8 +128,8 @@ static int __init ebtable_broute_init(void)
static void __exit ebtable_broute_fini(void)
{
- unregister_pernet_subsys(&broute_net_ops);
ebt_unregister_template(&broute_table);
+ unregister_pernet_subsys(&broute_net_ops);
}
module_init(ebtable_broute_init);
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
index dacd81b12e626..02b6501c15a5e 100644
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -109,8 +109,8 @@ static int __init ebtable_filter_init(void)
static void __exit ebtable_filter_fini(void)
{
- unregister_pernet_subsys(&frame_filter_net_ops);
ebt_unregister_template(&frame_filter);
+ unregister_pernet_subsys(&frame_filter_net_ops);
}
module_init(ebtable_filter_init);
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
index 0f2a8c6118d42..9985a82555c41 100644
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -109,8 +109,8 @@ static int __init ebtable_nat_init(void)
static void __exit ebtable_nat_fini(void)
{
- unregister_pernet_subsys(&frame_nat_net_ops);
ebt_unregister_template(&frame_nat);
+ unregister_pernet_subsys(&frame_nat_net_ops);
}
module_init(ebtable_nat_init);
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 4990a1d0ffb35..96176aa881117 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -42,6 +42,7 @@
struct ebt_pernet {
struct list_head tables;
+ struct list_head dead_tables;
};
struct ebt_template {
@@ -1164,11 +1165,6 @@ static int do_replace(struct net *net, sockptr_t arg, unsigned int len)
static void __ebt_unregister_table(struct net *net, struct ebt_table *table)
{
- mutex_lock(&ebt_mutex);
- list_del(&table->list);
- mutex_unlock(&ebt_mutex);
- audit_log_nfcfg(table->name, AF_BRIDGE, table->private->nentries,
- AUDIT_XT_OP_UNREGISTER, GFP_KERNEL);
EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
ebt_cleanup_entry, net, NULL);
if (table->private->nentries)
@@ -1269,13 +1265,15 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table,
for (i = 0; i < num_ops; i++)
ops[i].priv = table;
- list_add(&table->list, &ebt_net->tables);
- mutex_unlock(&ebt_mutex);
-
table->ops = ops;
ret = nf_register_net_hooks(net, ops, num_ops);
- if (ret)
+ if (ret) {
+ synchronize_rcu();
__ebt_unregister_table(net, table);
+ } else {
+ list_add(&table->list, &ebt_net->tables);
+ }
+ mutex_unlock(&ebt_mutex);
audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries,
AUDIT_XT_OP_REGISTER, GFP_KERNEL);
@@ -1341,7 +1339,7 @@ void ebt_unregister_template(const struct ebt_table *t)
}
EXPORT_SYMBOL(ebt_unregister_template);
-static struct ebt_table *__ebt_find_table(struct net *net, const char *name)
+void ebt_unregister_table_pre_exit(struct net *net, const char *name)
{
struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id);
struct ebt_table *t;
@@ -1350,30 +1348,36 @@ static struct ebt_table *__ebt_find_table(struct net *net, const char *name)
list_for_each_entry(t, &ebt_net->tables, list) {
if (strcmp(t->name, name) == 0) {
+ list_move(&t->list, &ebt_net->dead_tables);
mutex_unlock(&ebt_mutex);
- return t;
+ nf_unregister_net_hooks(net, t->ops, hweight32(t->valid_hooks));
+ return;
}
}
mutex_unlock(&ebt_mutex);
- return NULL;
-}
-
-void ebt_unregister_table_pre_exit(struct net *net, const char *name)
-{
- struct ebt_table *table = __ebt_find_table(net, name);
-
- if (table)
- nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
}
EXPORT_SYMBOL(ebt_unregister_table_pre_exit);
void ebt_unregister_table(struct net *net, const char *name)
{
- struct ebt_table *table = __ebt_find_table(net, name);
+ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id);
+ struct ebt_table *t;
- if (table)
- __ebt_unregister_table(net, table);
+ mutex_lock(&ebt_mutex);
+
+ list_for_each_entry(t, &ebt_net->dead_tables, list) {
+ if (strcmp(t->name, name) == 0) {
+ list_del(&t->list);
+ audit_log_nfcfg(t->name, AF_BRIDGE, t->private->nentries,
+ AUDIT_XT_OP_UNREGISTER, GFP_KERNEL);
+ __ebt_unregister_table(net, t);
+ mutex_unlock(&ebt_mutex);
+ return;
+ }
+ }
+
+ mutex_unlock(&ebt_mutex);
}
/* userspace just supplied us with counters */
@@ -2594,11 +2598,21 @@ static int __net_init ebt_pernet_init(struct net *net)
struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id);
INIT_LIST_HEAD(&ebt_net->tables);
+ INIT_LIST_HEAD(&ebt_net->dead_tables);
return 0;
}
+static void __net_exit ebt_pernet_exit(struct net *net)
+{
+ struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id);
+
+ WARN_ON_ONCE(!list_empty(&ebt_net->tables));
+ WARN_ON_ONCE(!list_empty(&ebt_net->dead_tables));
+}
+
static struct pernet_operations ebt_net_ops = {
.init = ebt_pernet_init,
+ .exit = ebt_pernet_exit,
.id = &ebt_pernet_id,
.size = sizeof(struct ebt_pernet),
};
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 359/869] netfilter: x_tables: allow initial table replace without emitting audit log message
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (357 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 358/869] netfilter: ebtables: move to two-stage removal scheme Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 360/869] netfilter: x_tables: allocate hook ops while under mutex Greg Kroah-Hartman
` (510 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Florian Westphal, Pablo Neira Ayuso,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <fw@strlen.de>
[ Upstream commit 8e72510db9fa2d41f2b06d5c01fe9020e076fee4 ]
At the moment we emit the audit log a bit too early, which makes it
necessary to also emit an unregister log in case we have to unwind
errors after possible hook register failure.
Followup patch will be slightly simpler if we can delay the
register message until after the hooks have been wired up.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Stable-dep-of: b62eb8dcf2c4 ("netfilter: x_tables: allocate hook ops while under mutex")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/netfilter/x_tables.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index efe7b7d71e7f7..5c7dcb64cf0f9 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1404,11 +1404,9 @@ struct xt_counters *xt_counters_alloc(unsigned int counters)
}
EXPORT_SYMBOL(xt_counters_alloc);
-struct xt_table_info *
-xt_replace_table(struct xt_table *table,
- unsigned int num_counters,
- struct xt_table_info *newinfo,
- int *error)
+static struct xt_table_info *
+do_replace_table(struct xt_table *table, unsigned int num_counters,
+ struct xt_table_info *newinfo, int *error)
{
struct xt_table_info *private;
unsigned int cpu;
@@ -1463,10 +1461,23 @@ xt_replace_table(struct xt_table *table,
}
}
- audit_log_nfcfg(table->name, table->af, private->number,
- !private->number ? AUDIT_XT_OP_REGISTER :
- AUDIT_XT_OP_REPLACE,
- GFP_KERNEL);
+ return private;
+}
+
+struct xt_table_info *
+xt_replace_table(struct xt_table *table, unsigned int num_counters,
+ struct xt_table_info *newinfo,
+ int *error)
+{
+ struct xt_table_info *private;
+
+ private = do_replace_table(table, num_counters, newinfo, error);
+ if (private)
+ audit_log_nfcfg(table->name, table->af, private->number,
+ !private->number ? AUDIT_XT_OP_REGISTER :
+ AUDIT_XT_OP_REPLACE,
+ GFP_KERNEL);
+
return private;
}
EXPORT_SYMBOL_GPL(xt_replace_table);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 360/869] netfilter: x_tables: allocate hook ops while under mutex
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (358 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 359/869] netfilter: x_tables: allow initial table replace without emitting audit log message Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 361/869] wifi: mac80211: fix missing RX bitrate update for mesh forwarding path Greg Kroah-Hartman
` (509 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Tristan Madani, Florian Westphal,
Pablo Neira Ayuso, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <fw@strlen.de>
[ Upstream commit b62eb8dcf2c47d4d676a434efbd57c4f776f7829 ]
arp/ip(6)t_register_table() add the table to the per-netns list via
xt_register_table() before allocating the per-netns hook ops copy
via kmemdup_array(). This leaves a window where the table is
visible in the list with ops=NULL.
If the pernet exit happens runs concurrently the pre_exit callback finds
the table via xt_find_table() and passes the NULL ops pointer to
nf_unregister_net_hooks(), causing a NULL dereference:
general protection fault in nf_unregister_net_hooks+0xbc/0x150
RIP: nf_unregister_net_hooks (net/netfilter/core.c:613)
Call Trace:
ipt_unregister_table_pre_exit
iptable_mangle_net_pre_exit
ops_pre_exit_list
cleanup_net
Fix by moving the ops allocation into the xtables core so the table is
never in the list without valid ops. Also ensure the table is no longer
processing packets before its torn down on error unwind.
nf_register_net_hooks might have published at least one hook; call
synchronize_rcu() if there was an error.
audit log register message gets deferred until all operations have
passed, this avoids need to emit another ureg message in case of
error unwinding.
Based on earlier patch by Tristan Madani.
Fixes: f9006acc8dfe5 ("netfilter: arp_tables: pass table pointer via nf_hook_ops")
Fixes: ee177a54413a ("netfilter: ip6_tables: pass table pointer via nf_hook_ops")
Fixes: ae689334225f ("netfilter: ip_tables: pass table pointer via nf_hook_ops")
Link: https://lore.kernel.org/netfilter-devel/20260429175613.1459342-1-tristmd@gmail.com/
Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/netfilter/x_tables.h | 1 +
net/ipv4/netfilter/arp_tables.c | 35 +++------------------
net/ipv4/netfilter/ip_tables.c | 41 +++---------------------
net/ipv6/netfilter/ip6_tables.c | 38 +++--------------------
net/netfilter/x_tables.c | 50 +++++++++++++++++++++++++-----
5 files changed, 55 insertions(+), 110 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 5897f3dbaf7c3..3716b42a4ad60 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -307,6 +307,7 @@ struct xt_counters *xt_counters_alloc(unsigned int counters);
struct xt_table *xt_register_table(struct net *net,
const struct xt_table *table,
+ const struct nf_hook_ops *template_ops,
struct xt_table_info *bootstrap,
struct xt_table_info *newinfo);
void *xt_unregister_table(struct xt_table *table);
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index b752c9eac998e..c68ffde6d615d 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -1519,13 +1519,11 @@ int arpt_register_table(struct net *net,
const struct arpt_replace *repl,
const struct nf_hook_ops *template_ops)
{
- struct nf_hook_ops *ops;
- unsigned int num_ops;
- int ret, i;
- struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0};
- void *loc_cpu_entry;
+ struct xt_table_info *newinfo;
struct xt_table *new_table;
+ void *loc_cpu_entry;
+ int ret;
newinfo = xt_alloc_table_info(repl->size);
if (!newinfo)
@@ -1540,7 +1538,7 @@ int arpt_register_table(struct net *net,
return ret;
}
- new_table = xt_register_table(net, table, &bootstrap, newinfo);
+ new_table = xt_register_table(net, table, template_ops, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
struct arpt_entry *iter;
@@ -1550,31 +1548,6 @@ int arpt_register_table(struct net *net,
return PTR_ERR(new_table);
}
- num_ops = hweight32(table->valid_hooks);
- if (num_ops == 0) {
- ret = -EINVAL;
- goto out_free;
- }
-
- ops = kmemdup_array(template_ops, num_ops, sizeof(*ops), GFP_KERNEL);
- if (!ops) {
- ret = -ENOMEM;
- goto out_free;
- }
-
- for (i = 0; i < num_ops; i++)
- ops[i].priv = new_table;
-
- new_table->ops = ops;
-
- ret = nf_register_net_hooks(net, ops, num_ops);
- if (ret != 0)
- goto out_free;
-
- return ret;
-
-out_free:
- __arpt_unregister_table(net, new_table);
return ret;
}
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 0ba456c4c6341..2411ef91d2962 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1721,13 +1721,11 @@ int ipt_register_table(struct net *net, const struct xt_table *table,
const struct ipt_replace *repl,
const struct nf_hook_ops *template_ops)
{
- struct nf_hook_ops *ops;
- unsigned int num_ops;
- int ret, i;
- struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0};
- void *loc_cpu_entry;
+ struct xt_table_info *newinfo;
struct xt_table *new_table;
+ void *loc_cpu_entry;
+ int ret;
newinfo = xt_alloc_table_info(repl->size);
if (!newinfo)
@@ -1742,7 +1740,7 @@ int ipt_register_table(struct net *net, const struct xt_table *table,
return ret;
}
- new_table = xt_register_table(net, table, &bootstrap, newinfo);
+ new_table = xt_register_table(net, table, template_ops, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
struct ipt_entry *iter;
@@ -1752,37 +1750,6 @@ int ipt_register_table(struct net *net, const struct xt_table *table,
return PTR_ERR(new_table);
}
- /* No template? No need to do anything. This is used by 'nat' table, it registers
- * with the nat core instead of the netfilter core.
- */
- if (!template_ops)
- return 0;
-
- num_ops = hweight32(table->valid_hooks);
- if (num_ops == 0) {
- ret = -EINVAL;
- goto out_free;
- }
-
- ops = kmemdup_array(template_ops, num_ops, sizeof(*ops), GFP_KERNEL);
- if (!ops) {
- ret = -ENOMEM;
- goto out_free;
- }
-
- for (i = 0; i < num_ops; i++)
- ops[i].priv = new_table;
-
- new_table->ops = ops;
-
- ret = nf_register_net_hooks(net, ops, num_ops);
- if (ret != 0)
- goto out_free;
-
- return ret;
-
-out_free:
- __ipt_unregister_table(net, new_table);
return ret;
}
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index f4e01f451d576..551d3ca1036d7 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1735,13 +1735,11 @@ int ip6t_register_table(struct net *net, const struct xt_table *table,
const struct ip6t_replace *repl,
const struct nf_hook_ops *template_ops)
{
- struct nf_hook_ops *ops;
- unsigned int num_ops;
- int ret, i;
- struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0};
- void *loc_cpu_entry;
+ struct xt_table_info *newinfo;
struct xt_table *new_table;
+ void *loc_cpu_entry;
+ int ret;
newinfo = xt_alloc_table_info(repl->size);
if (!newinfo)
@@ -1756,7 +1754,7 @@ int ip6t_register_table(struct net *net, const struct xt_table *table,
return ret;
}
- new_table = xt_register_table(net, table, &bootstrap, newinfo);
+ new_table = xt_register_table(net, table, template_ops, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
struct ip6t_entry *iter;
@@ -1766,34 +1764,6 @@ int ip6t_register_table(struct net *net, const struct xt_table *table,
return PTR_ERR(new_table);
}
- if (!template_ops)
- return 0;
-
- num_ops = hweight32(table->valid_hooks);
- if (num_ops == 0) {
- ret = -EINVAL;
- goto out_free;
- }
-
- ops = kmemdup_array(template_ops, num_ops, sizeof(*ops), GFP_KERNEL);
- if (!ops) {
- ret = -ENOMEM;
- goto out_free;
- }
-
- for (i = 0; i < num_ops; i++)
- ops[i].priv = new_table;
-
- new_table->ops = ops;
-
- ret = nf_register_net_hooks(net, ops, num_ops);
- if (ret != 0)
- goto out_free;
-
- return ret;
-
-out_free:
- __ip6t_unregister_table(net, new_table);
return ret;
}
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 5c7dcb64cf0f9..fb777d2c73753 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1474,7 +1474,6 @@ xt_replace_table(struct xt_table *table, unsigned int num_counters,
private = do_replace_table(table, num_counters, newinfo, error);
if (private)
audit_log_nfcfg(table->name, table->af, private->number,
- !private->number ? AUDIT_XT_OP_REGISTER :
AUDIT_XT_OP_REPLACE,
GFP_KERNEL);
@@ -1484,20 +1483,32 @@ EXPORT_SYMBOL_GPL(xt_replace_table);
struct xt_table *xt_register_table(struct net *net,
const struct xt_table *input_table,
+ const struct nf_hook_ops *template_ops,
struct xt_table_info *bootstrap,
struct xt_table_info *newinfo)
{
struct xt_pernet *xt_net = net_generic(net, xt_pernet_id);
+ struct xt_table *t, *table = NULL;
+ struct nf_hook_ops *ops = NULL;
struct xt_table_info *private;
- struct xt_table *t, *table;
- int ret;
+ unsigned int num_ops;
+ int ret = -EINVAL;
+
+ num_ops = hweight32(input_table->valid_hooks);
+ if (num_ops == 0)
+ goto out;
+
+ ret = -ENOMEM;
+ if (template_ops) {
+ ops = kmemdup_array(template_ops, num_ops, sizeof(*ops), GFP_KERNEL);
+ if (!ops)
+ goto out;
+ }
/* Don't add one object to multiple lists. */
table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL);
- if (!table) {
- ret = -ENOMEM;
+ if (!table)
goto out;
- }
mutex_lock(&xt[table->af].mutex);
/* Don't autoload: we'd eat our tail... */
@@ -1511,7 +1522,7 @@ struct xt_table *xt_register_table(struct net *net,
/* Simplifies replace_table code. */
table->private = bootstrap;
- if (!xt_replace_table(table, 0, newinfo, &ret))
+ if (!do_replace_table(table, 0, newinfo, &ret))
goto unlock;
private = table->private;
@@ -1520,14 +1531,37 @@ struct xt_table *xt_register_table(struct net *net,
/* save number of initial entries */
private->initial_entries = private->number;
+ if (ops) {
+ int i;
+
+ for (i = 0; i < num_ops; i++)
+ ops[i].priv = table;
+
+ ret = nf_register_net_hooks(net, ops, num_ops);
+ if (ret != 0) {
+ mutex_unlock(&xt[table->af].mutex);
+ /* nf_register_net_hooks() might have published a
+ * base chain before internal error unwind.
+ */
+ synchronize_rcu();
+ goto out;
+ }
+
+ table->ops = ops;
+ }
+
+ audit_log_nfcfg(table->name, table->af, private->number,
+ AUDIT_XT_OP_REGISTER, GFP_KERNEL);
+
list_add(&table->list, &xt_net->tables[table->af]);
mutex_unlock(&xt[table->af].mutex);
return table;
unlock:
mutex_unlock(&xt[table->af].mutex);
- kfree(table);
out:
+ kfree(table);
+ kfree(ops);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(xt_register_table);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 361/869] wifi: mac80211: fix missing RX bitrate update for mesh forwarding path
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (359 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 360/869] netfilter: x_tables: allocate hook ops while under mutex Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 362/869] wifi: mac80211: capture fast-RX rate before mesh reuses skb->cb Greg Kroah-Hartman
` (508 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sarika Sharma, Johannes Berg,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sarika Sharma <sarika.sharma@oss.qualcomm.com>
[ Upstream commit cc18fffa3a51792637169872886df3407bd5bb84 ]
Currently, RX bitrate statistics are not updated for packets received
on the mesh forwarding path during fast RX processing. This results in
incomplete RX rate tracking in station dump outputs for mesh scenarios.
Update ieee80211_invoke_fast_rx() to record the RX rate using
sta_stats_encode_rate() and store it in the last_rate field of
ieee80211_sta_rx_stats when RX_QUEUED is returned from
ieee80211_rx_mesh_data(). This ensures that RX bitrate is properly
accounted for in both RSS and non-RSS paths.
Signed-off-by: Sarika Sharma <sarika.sharma@oss.qualcomm.com>
Link: https://patch.msgid.link/20251024043627.1640447-1-sarika.sharma@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Stable-dep-of: d71c841be5d9 ("wifi: mac80211: capture fast-RX rate before mesh reuses skb->cb")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mac80211/rx.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 7e3bcd709c579..7b4528e858bb8 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4968,6 +4968,11 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
/* after this point, don't punt to the slowpath! */
+ if (fast_rx->uses_rss)
+ stats = this_cpu_ptr(rx->link_sta->pcpu_rx_stats);
+ else
+ stats = &rx->link_sta->rx_stats;
+
if (rx->key && !(status->flag & RX_FLAG_MIC_STRIPPED) &&
pskb_trim(skb, skb->len - fast_rx->icv_len))
goto drop;
@@ -5002,6 +5007,8 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
switch (res) {
case RX_QUEUED:
+ stats->last_rx = jiffies;
+ stats->last_rate = sta_stats_encode_rate(status);
return true;
case RX_CONTINUE:
break;
@@ -5015,11 +5022,6 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
drop:
dev_kfree_skb(skb);
- if (fast_rx->uses_rss)
- stats = this_cpu_ptr(rx->link_sta->pcpu_rx_stats);
- else
- stats = &rx->link_sta->rx_stats;
-
stats->dropped++;
return true;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 362/869] wifi: mac80211: capture fast-RX rate before mesh reuses skb->cb
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (360 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 361/869] wifi: mac80211: fix missing RX bitrate update for mesh forwarding path Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 363/869] erofs: fix metabuf leak in inode xattr initialization Greg Kroah-Hartman
` (507 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Zhao Li, Johannes Berg, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <enderaoelyther@gmail.com>
[ Upstream commit d71c841be5d9e586ee7f36c0dc8ed4db0d9a1349 ]
ieee80211_invoke_fast_rx() reads RX status through
IEEE80211_SKB_RXCB(skb), which aliases the same skb->cb storage
that ieee80211_rx_mesh_data() reuses as IEEE80211_TX_INFO. In the
unicast forward path, mesh_data does:
info = IEEE80211_SKB_CB(fwd_skb);
memset(info, 0, sizeof(*info));
on the same skb the caller still names via rx->skb, then either
queues the skb for TX (success) or kfree_skb()'s it (no-route)
before returning RX_QUEUED. The caller's RX_QUEUED arm then
calls sta_stats_encode_rate(status) on memory that is either
zeroed (success path) or freed (no-route path). The latter is
KASAN slab-use-after-free in ieee80211_prepare_and_rx_handle.
Fix by encoding the rate from status before invoking
ieee80211_rx_mesh_data(), so the RX_QUEUED arm consumes a value
captured while status was still backed by valid memory.
Fixes: 3468e1e0c639 ("wifi: mac80211: add mesh fast-rx support")
Cc: stable@vger.kernel.org
Signed-off-by: Zhao Li <enderaoelyther@gmail.com>
Link: https://patch.msgid.link/20260509043427.60322-2-enderaoelyther@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mac80211/rx.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 7b4528e858bb8..e7f940a890dd4 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4897,6 +4897,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
u8 sa[ETH_ALEN];
} addrs __aligned(2);
struct ieee80211_sta_rx_stats *stats;
+ u32 encoded_rate;
/* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
* to a common data structure; drivers can implement that per queue
@@ -5004,11 +5005,14 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
/* push the addresses in front */
memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs));
+ /* capture before mesh forward may memset or free skb->cb */
+ encoded_rate = sta_stats_encode_rate(status);
+
res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
switch (res) {
case RX_QUEUED:
stats->last_rx = jiffies;
- stats->last_rate = sta_stats_encode_rate(status);
+ stats->last_rate = encoded_rate;
return true;
case RX_CONTINUE:
break;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 363/869] erofs: fix metabuf leak in inode xattr initialization
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (361 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 362/869] wifi: mac80211: capture fast-RX rate before mesh reuses skb->cb Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 364/869] drm/msm/adreno: Fix a reference leak in a6xx_gpu_init() Greg Kroah-Hartman
` (506 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jia Zhu, Gao Xiang, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jia Zhu <zhujia.zj@bytedance.com>
[ Upstream commit 79b09c54c6563df9846ca3094bcfd72082c3e1d7 ]
commit bb88e8da0025 ("erofs: use meta buffers for xattr operations")
converted xattr operations to use on-stack erofs_buf instances.
erofs_init_inode_xattrs() uses such a metabuf while reading the inline
xattr header and shared xattr id array.
Some error paths after erofs_read_metabuf() leave through out_unlock
without dropping the metabuf, so the folio reference can leak.
Consolidate the cleanup at out_unlock. erofs_put_metabuf() is a
no-op if no folio has been acquired, and this keeps all paths after
taking EROFS_I_BL_XATTR_BIT covered by a single cleanup site.
Fixes: bb88e8da0025 ("erofs: use meta buffers for xattr operations")
Signed-off-by: Jia Zhu <zhujia.zj@bytedance.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Fixes: bb88e8da0025 ("erofs: use meta buffers for xattr operations")
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/erofs/xattr.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/erofs/xattr.c b/fs/erofs/xattr.c
index 60d2cf26e837e..9753df4e95a24 100644
--- a/fs/erofs/xattr.c
+++ b/fs/erofs/xattr.c
@@ -47,6 +47,8 @@ static int erofs_init_inode_xattrs(struct inode *inode)
if (wait_on_bit_lock(&vi->flags, EROFS_I_BL_XATTR_BIT, TASK_KILLABLE))
return -ERESTARTSYS;
+ it.buf = __EROFS_BUF_INITIALIZER;
+
/* someone has initialized xattrs for us? */
if (test_bit(EROFS_I_EA_INITED_BIT, &vi->flags))
goto out_unlock;
@@ -76,7 +78,6 @@ static int erofs_init_inode_xattrs(struct inode *inode)
goto out_unlock;
}
- it.buf = __EROFS_BUF_INITIALIZER;
erofs_init_metabuf(&it.buf, sb);
it.pos = erofs_iloc(inode) + vi->inode_isize;
@@ -93,7 +94,6 @@ static int erofs_init_inode_xattrs(struct inode *inode)
vi->xattr_shared_xattrs = kmalloc_array(vi->xattr_shared_count,
sizeof(uint), GFP_KERNEL);
if (!vi->xattr_shared_xattrs) {
- erofs_put_metabuf(&it.buf);
ret = -ENOMEM;
goto out_unlock;
}
@@ -112,13 +112,13 @@ static int erofs_init_inode_xattrs(struct inode *inode)
vi->xattr_shared_xattrs[i] = le32_to_cpu(*(__le32 *)it.kaddr);
it.pos += sizeof(__le32);
}
- erofs_put_metabuf(&it.buf);
/* paired with smp_mb() at the beginning of the function. */
smp_mb();
set_bit(EROFS_I_EA_INITED_BIT, &vi->flags);
out_unlock:
+ erofs_put_metabuf(&it.buf);
clear_and_wake_up_bit(EROFS_I_BL_XATTR_BIT, &vi->flags);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 364/869] drm/msm/adreno: Fix a reference leak in a6xx_gpu_init()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (362 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 363/869] erofs: fix metabuf leak in inode xattr initialization Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 365/869] netfs: Fix zeropoint update where i_size > remote_i_size Greg Kroah-Hartman
` (505 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Felix Gu, Rob Clark, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <ustc.gu@gmail.com>
[ Upstream commit e64bca63647db1d5518198d6c5ca2dbcc66b182b ]
In a6xx_gpu_init(), node is obtained via of_parse_phandle().
While there was a manual of_node_put() at the end of the
common path, several early error returns would bypass this call,
resulting in a reference leak.
Fix this by using the __free(device_node) cleanup handler to
release the reference when the variable goes out of scope.
Fixes: 5a903a44a984 ("drm/msm/a6xx: Introduce GMU wrapper support")
Signed-off-by: Felix Gu <ustc.gu@gmail.com>
Patchwork: https://patchwork.freedesktop.org/patch/700661/
Message-ID: <20260124-a6xx_gpu-v1-1-fa0c8b2dcfb1@gmail.com>
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 2407140508d8a..4bae3813d90b5 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -2277,7 +2277,6 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
struct msm_drm_private *priv = dev->dev_private;
struct platform_device *pdev = priv->gpu_pdev;
struct adreno_platform_config *config = pdev->dev.platform_data;
- struct device_node *node;
struct a6xx_gpu *a6xx_gpu;
struct adreno_gpu *adreno_gpu;
struct msm_gpu *gpu;
@@ -2296,7 +2295,8 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
adreno_gpu->registers = NULL;
/* Check if there is a GMU phandle and set it up */
- node = of_parse_phandle(pdev->dev.of_node, "qcom,gmu", 0);
+ struct device_node *node __free(device_node) =
+ of_parse_phandle(pdev->dev.of_node, "qcom,gmu", 0);
/* FIXME: How do we gracefully handle this? */
BUG_ON(!node);
@@ -2341,7 +2341,6 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
ret = a6xx_gmu_wrapper_init(a6xx_gpu, node);
else
ret = a6xx_gmu_init(a6xx_gpu, node);
- of_node_put(node);
if (ret) {
a6xx_destroy(&(a6xx_gpu->base.base));
return ERR_PTR(ret);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 365/869] netfs: Fix zeropoint update where i_size > remote_i_size
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (363 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 364/869] drm/msm/adreno: Fix a reference leak in a6xx_gpu_init() Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 366/869] hwmon: (lm90) Add lock protection to lm90_alert Greg Kroah-Hartman
` (504 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Paulo Alcantara,
Matthew Wilcox, netfs, linux-fsdevel, Christian Brauner,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit 4543a4d737944134a1394afe797622546fbcc98a ]
Fix the update of the zero point[*] by netfs_release_folio() when there is
uncommitted data in the pagecache beyond the folio being released but the
on-server EOF is in this folio (ie. i_size > remote_i_size). The update
needs to limit zero_point to remote_i_size, not i_size as i_size is a local
phenomenon reflecting updates made locally to the pagecache, not stuff
written to the server. remote_i_size tracks the server's i_size.
[*] The zero point is the file position from which we can assume that the
server will just return zeros, so we can avoid generating reads.
Note that netfs_invalidate_folio() probably doesn't need fixing as
zero_point should be updated by setattr after truncation or fallocate.
Found with:
fsx -q -N 1000000 -p 10000 -o 128000 -l 600000 \
/xfstest.test/junk --replay-ops=junk.fsxops
using the following as junk.fsxops:
truncate 0x0 0x1bbae 0x82864
write 0x3ef2e 0xf9c8 0x1bbae
write 0x67e05 0xcb5a 0x4e8f6
mapread 0x57781 0x85b6 0x7495f
copy_range 0x5d3d 0x10329 0x54fac 0x7495f
write 0x64710 0x1c2b 0x7495f
mapread 0x64000 0x1000 0x7495f
on cifs with the default cache option.
It shows read-gaps on folio 0x64 failing with a short read (ie. it hits
EOF) if the FMODE_READ check is commented out in netfs_perform_write():
if (//(file->f_mode & FMODE_READ) ||
netfs_is_cache_enabled(ctx)) {
and no fscache. This was initially found with the generic/522 xfstest.
Fixes: cce6bfa6ca0e ("netfs: Fix trimming of streaming-write folios in netfs_inval_folio()")
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260512123404.719402-7-dhowells@redhat.com
cc: Paulo Alcantara <pc@manguebit.org>
cc: Matthew Wilcox <willy@infradead.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/netfs/misc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c
index f5f7c0de3a7ca..8bdacbf15226c 100644
--- a/fs/netfs/misc.c
+++ b/fs/netfs/misc.c
@@ -315,7 +315,7 @@ bool netfs_release_folio(struct folio *folio, gfp_t gfp)
if (folio_test_dirty(folio))
return false;
- end = umin(folio_pos(folio) + folio_size(folio), i_size_read(&ctx->inode));
+ end = umin(folio_pos(folio) + folio_size(folio), ctx->remote_i_size);
if (end > ctx->zero_point)
ctx->zero_point = end;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 366/869] hwmon: (lm90) Add lock protection to lm90_alert
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (364 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 365/869] netfs: Fix zeropoint update where i_size > remote_i_size Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 367/869] KVM: guest_memfd: Treat memslot binding offset+size as unsigned values Greg Kroah-Hartman
` (503 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Sashiko, Guenter Roeck, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <linux@roeck-us.net>
[ Upstream commit 873e919e3101063a7a75989510ccfc125a4391cf ]
Sashiko reports:
lm90_alert() executes in the smbus alert context and calls
lm90_update_confreg() to disable the hardware alert line, without
acquiring hwmon_lock.
Concurrently, sysfs write operations (such as lm90_write_convrate) hold
the hwmon_lock, temporarily modify data->config, and then restore it.
If an alert interrupt occurs concurrently with a sysfs write, the sysfs
path will overwrite the alert handler's modifications to data->config
and the hardware register.
This unintentionally re-enables the hardware alert line while the alarm is
still active, causing an interrupt storm.
Add the missing lock to lm90_alert() to solve the problem.
Fixes: 7a1d220ccb0cc ("hwmon: (lm90) Introduce function to update configuration register")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hwmon/lm90.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index d79f6d091e3ef..581a1d10a1b58 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -2885,6 +2885,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,
*/
struct lm90_data *data = i2c_get_clientdata(client);
+ mutex_lock(&data->update_lock);
if (!data->shutdown && (data->flags & LM90_HAVE_BROKEN_ALERT) &&
(data->current_alarms & data->alert_alarms)) {
if (!(data->config & 0x80)) {
@@ -2894,6 +2895,7 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,
schedule_delayed_work(&data->alert_work,
max_t(int, HZ, msecs_to_jiffies(data->update_interval)));
}
+ mutex_unlock(&data->update_lock);
} else {
dev_dbg(&client->dev, "Everything OK\n");
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 367/869] KVM: guest_memfd: Treat memslot binding offset+size as unsigned values
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (365 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 366/869] hwmon: (lm90) Add lock protection to lm90_alert Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 368/869] smb/client: fix chown/chgrp with SMB3 POSIX Extensions Greg Kroah-Hartman
` (502 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ackerley Tng, Michael Roth,
Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <seanjc@google.com>
[ Upstream commit eba85fee7fc6cf28fec38a5bf3c378bef9a79ca6 ]
When binding a memslot to a guest_memfd file, treat the offset and size as
unsigned values to fix a bug where the sum of the two can result in a false
negative when checking for overflow against the size of the file. Passing
unsigned values also avoids relying on somewhat obscure checks in other
flows for safety, and tracks the offset and size as they are intended to be
tracked, as unsigned values.
On 64-bit kernels, the number of pages a memslot contains and thus the size
(and offset) of its guest_memfd binding are unsigned 64-bit values. Taking
the offset+size as an loff_t instead of a uoff_t inadvertently converts
the unsigned value to a signed value if the offset and/or size is massive.
Locally storing the offset and size as signed values is benign in and of
itself (though even that is *extremely* difficult to discern), but
operating on their sum is not.
For the offset, KVM explicitly checks against a negative value, which might
seem like a bug as KVM could incorrectly reject a legitimate binding, but
that's not actually the case as KVM_CREATE_GUEST_MEMFD takes a signed value
for its size, i.e. a would-be-negative offset is also greater than the
maximum possible size of any guest_memfd file.
Regarding the size, while KVM lacks an explicit check for a negative value,
i.e. seemingly has a flawed overflow check, KVM restricts the number of
pages in a single memslot to the largest positive signed 32-bit value:
if (id < KVM_USER_MEM_SLOTS &&
(mem->memory_size >> PAGE_SHIFT) > KVM_MEM_MAX_NR_PAGES)
return -EINVAL;
and so that maximum "size" will ever be is 0x7fffffff000.
The sum of the two is, however, problematic. While the size is restricted
by KVM's memslot logic, the offset is not, i.e. the offset is completely
unchecked until the "offset + size > i_size_read(inode)" check. If the
offset is the (nearly) largest possible _positive_ value, then adding size
to the offset can result in a signed, negative 64-bit value. When compared
against the size of the file (guaranteed to be positive), the negative sum
is always smaller, and KVM incorrectly allows the absurd offset.
Opportunistically add missing includes in kvm_mm.h (instead of relying on
its parents).
Fixes: a7800aa80ea4 ("KVM: Add KVM_CREATE_GUEST_MEMFD ioctl() for guest-specific backing memory")
Cc: stable@vger.kernel.org
Cc: Ackerley Tng <ackerleytng@google.com>
Reviewed-by: Michael Roth <michael.roth@amd.com>
Reviewed-by: Ackerley Tng <ackerleytng@google.com>
Link: https://patch.msgid.link/20260602170921.1304394-2-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
virt/kvm/guest_memfd.c | 8 ++++----
virt/kvm/kvm_mm.h | 7 +++++--
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index e2c7e3d918406..71afb0ca0cc94 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -473,15 +473,16 @@ int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args)
}
int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
- unsigned int fd, loff_t offset)
+ unsigned int fd, u64 offset)
{
- loff_t size = slot->npages << PAGE_SHIFT;
+ u64 size = slot->npages << PAGE_SHIFT;
unsigned long start, end;
struct kvm_gmem *gmem;
struct inode *inode;
struct file *file;
int r = -EINVAL;
+ BUILD_BUG_ON(sizeof(gpa_t) != sizeof(offset));
BUILD_BUG_ON(sizeof(gfn_t) != sizeof(slot->gmem.pgoff));
file = fget(fd);
@@ -497,8 +498,7 @@ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
inode = file_inode(file);
- if (offset < 0 || !PAGE_ALIGNED(offset) ||
- offset + size > i_size_read(inode))
+ if (!PAGE_ALIGNED(offset) || offset + size > i_size_read(inode))
goto err;
filemap_invalidate_lock(inode->i_mapping);
diff --git a/virt/kvm/kvm_mm.h b/virt/kvm/kvm_mm.h
index 715f19669d01f..15b2c728f7dd5 100644
--- a/virt/kvm/kvm_mm.h
+++ b/virt/kvm/kvm_mm.h
@@ -3,6 +3,9 @@
#ifndef __KVM_MM_H__
#define __KVM_MM_H__ 1
+#include <linux/kvm.h>
+#include <linux/kvm_types.h>
+
/*
* Architectures can choose whether to use an rwlock or spinlock
* for the mmu_lock. These macros, for use in common code
@@ -39,7 +42,7 @@ static inline void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm,
void kvm_gmem_init(struct module *module);
int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args);
int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
- unsigned int fd, loff_t offset);
+ unsigned int fd, u64 offset);
void kvm_gmem_unbind(struct kvm_memory_slot *slot);
#else
static inline void kvm_gmem_init(struct module *module)
@@ -49,7 +52,7 @@ static inline void kvm_gmem_init(struct module *module)
static inline int kvm_gmem_bind(struct kvm *kvm,
struct kvm_memory_slot *slot,
- unsigned int fd, loff_t offset)
+ unsigned int fd, u64 offset)
{
WARN_ON_ONCE(1);
return -EIO;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 368/869] smb/client: fix chown/chgrp with SMB3 POSIX Extensions
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (366 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 367/869] KVM: guest_memfd: Treat memslot binding offset+size as unsigned values Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 369/869] ksmbd: validate NTLMv2 response before updating session key Greg Kroah-Hartman
` (501 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Ralph Boehme, Steve French,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ralph Boehme <slow@samba.org>
[ Upstream commit 760ef2c579c2609cf17fb1cd5392f64d42d43d33 ]
Ownership (chown) and group (chgrp) modifications were being ignored when
mounting with SMB3 POSIX Extensions unless CIFS_MOUNT_CIFS_ACL or
CIFS_MOUNT_MODE_FROM_SID were also explicitly set.
Fix this by checking for posix_extensions in cifs_setattr_nounix() when
updating UID and GID, ensuring that id_mode_to_cifs_acl() is called to map
and set the ownership/group information on the server.
Cc: stable@vger.kernel.org
Signed-off-by: Ralph Boehme <slow@samba.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/inode.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 7c4828580076c..acb3220e5b703 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -3296,7 +3296,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
gid = attrs->ia_gid;
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
+ (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) ||
+ cifs_sb_master_tcon(cifs_sb)->posix_extensions) {
if (uid_valid(uid) || gid_valid(gid)) {
mode = NO_CHANGE_64;
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 369/869] ksmbd: validate NTLMv2 response before updating session key
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (367 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 368/869] smb/client: fix chown/chgrp with SMB3 POSIX Extensions Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 370/869] ksmbd: prevent path traversal bypass by restricting caseless retry Greg Kroah-Hartman
` (500 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Haofeng Li, ChenXiaoSong,
Namjae Jeon, Steve French, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haofeng Li <lihaofeng@kylinos.cn>
[ Upstream commit 954d196bebb2b50151cb96454c72dc113b2af1ac ]
ksmbd_auth_ntlmv2() derives the NTLMv2 session key into
sess->sess_key before it verifies the NTLMv2 response.
ksmbd_decode_ntlmssp_auth_blob() then continues into KEY_XCH even
when ksmbd_auth_ntlmv2() failed.
With SMB3 multichannel binding, the failed authentication operates on
an existing session and the session setup error path does not expire
binding sessions. A client can send a binding session setup with a
bad NT proof and KEY_XCH and still modify sess->sess_key before
STATUS_LOGON_FAILURE is returned.
Relevant path:
smb2_sess_setup()
-> conn->binding = true
-> ntlm_authenticate()
-> session_user()
-> ksmbd_decode_ntlmssp_auth_blob()
-> ksmbd_auth_ntlmv2()
-> calc_ntlmv2_hash()
-> hmac_md5_usingrawkey(..., sess->sess_key)
-> crypto_memneq() returns mismatch
-> KEY_XCH arc4_crypt(..., sess->sess_key, ...)
-> out_err without expiring the binding session
Derive the base session key into a local buffer and copy it to
sess->sess_key only after the proof matches. Return immediately on
authentication failure so KEY_XCH is only processed after successful
authentication.
Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Fixes: f9929ef6a2a5 ("ksmbd: add support for key exchange")
Cc: stable@vger.kernel.org
Signed-off-by: Haofeng Li <lihaofeng@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/auth.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index d0f9403676238..97ffce1ff4176 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -278,15 +278,15 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
ksmbd_release_crypto_ctx(ctx);
ctx = NULL;
- rc = ksmbd_gen_sess_key(sess, ntlmv2_hash, ntlmv2_rsp);
- if (rc) {
- ksmbd_debug(AUTH, "Could not generate sess key\n");
+ if (crypto_memneq(ntlmv2->ntlmv2_hash, ntlmv2_rsp,
+ CIFS_HMAC_MD5_HASH_SIZE)) {
+ rc = -EINVAL;
goto out;
}
- if (crypto_memneq(ntlmv2->ntlmv2_hash, ntlmv2_rsp,
- CIFS_HMAC_MD5_HASH_SIZE))
- rc = -EINVAL;
+ rc = ksmbd_gen_sess_key(sess, ntlmv2_hash, ntlmv2_rsp);
+ if (rc)
+ ksmbd_debug(AUTH, "Could not generate sess key\n");
out:
if (ctx)
ksmbd_release_crypto_ctx(ctx);
@@ -348,6 +348,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
nt_len - CIFS_ENCPWD_SIZE,
domain_name, conn->ntlmssp.cryptkey);
kfree(domain_name);
+ if (ret)
+ return ret;
/* The recovered secondary session key */
if (conn->ntlmssp.client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 370/869] ksmbd: prevent path traversal bypass by restricting caseless retry
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (368 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 369/869] ksmbd: validate NTLMv2 response before updating session key Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 371/869] KVM: x86: Drop superfluous kvm_lapic_set_base() call when setting APIC state Greg Kroah-Hartman
` (499 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Y s65, Namjae Jeon, Steve French,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 54bab9ba5a9f156ffa9324fcbe5a356fd0242f95 ]
ksmbd_vfs_path_lookup() enforces LOOKUP_BENEATH to restrict path
resolution within the share root. When a crafted path attempts to
escape the share boundary using parent-directory components ('..'),
vfs_path_parent_lookup() detects this and immediately fails,
returning -EXDEV.
However, a bug exists in __ksmbd_vfs_kern_path() under caseless mode.
The function fails to intercept the -EXDEV error and erroneously
falls through to the caseless retry logic, which is intended only
for genuinely missing files. During this retry process, the path
is reconstructed, leading to an unintended LOOKUP_BENEATH bypass
that allows write-capable users to create zero-length files or
directories outside the exported share.
Fix this by ensuring that the execution only proceeds to the caseless
lookup retry when the error is specifically -ENOENT. Any other errors,
such as -EXDEV from a path traversal attempt, must be returned immediately.
Cc: stable@vger.kernel.org
Reported-by: Y s65 <yu4ys@outlook.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/vfs.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index 7785bc10aff11..967f669974861 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -1245,6 +1245,8 @@ int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,
path);
if (!err)
return 0;
+ if (err != -ENOENT)
+ return err;
if (caseless) {
char *filepath;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 371/869] KVM: x86: Drop superfluous kvm_lapic_set_base() call when setting APIC state
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (369 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 370/869] ksmbd: prevent path traversal bypass by restricting caseless retry Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 372/869] KVM: x86: Move kvm_set_apic_base() implementation to lapic.c (from x86.c) Greg Kroah-Hartman
` (498 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kai Huang, Paolo Bonzini,
Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <seanjc@google.com>
[ Upstream commit 8166d25579120590ad0ec4ece02afd00a3c54f6a ]
Now that kvm_lapic_set_base() does nothing if the "new" APIC base MSR is
the same as the current value, drop the kvm_lapic_set_base() call in the
KVM_SET_LAPIC flow that passes in the current value, as it too does
nothing.
Note, the purpose of invoking kvm_lapic_set_base() was purely to set
apic->base_address (see commit 5dbc8f3fed0b ("KVM: use kvm_lapic_set_base()
to change apic_base")). And there is no evidence that explicitly setting
apic->base_address in KVM_SET_LAPIC ever had any functional impact; even
in the original commit 96ad2cc61324 ("KVM: in-kernel LAPIC save and restore
support"), all flows that set apic_base also set apic->base_address to the
same address. E.g. svm_create_vcpu() did open code a write to apic_base,
svm->vcpu.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
but it also called kvm_create_lapic() when irqchip_in_kernel() is true.
Reviewed-by: Kai Huang <kai.huang@intel.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/r/20241009181742.1128779-3-seanjc@google.com
Link: https://lore.kernel.org/r/20241101183555.1794700-3-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Stable-dep-of: bb365a506b1e ("KVM: x86: Unconditionally recompute CR8 intercept on PPR update")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/lapic.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index a7d38b8cbd756..910db04a1addc 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -3107,7 +3107,6 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
kvm_x86_call(apicv_pre_state_restore)(vcpu);
- kvm_lapic_set_base(vcpu, vcpu->arch.apic_base);
/* set SPIV separately to get count of SW disabled APICs right */
apic_set_spiv(apic, *((u32 *)(s->regs + APIC_SPIV)));
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 372/869] KVM: x86: Move kvm_set_apic_base() implementation to lapic.c (from x86.c)
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (370 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 371/869] KVM: x86: Drop superfluous kvm_lapic_set_base() call when setting APIC state Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 373/869] KVM: x86: Rename APIC base setters to better capture their relationship Greg Kroah-Hartman
` (497 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kai Huang, Paolo Bonzini,
Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <seanjc@google.com>
[ Upstream commit c9c9acfcd5738fb292e670a582e4333a1187004c ]
Move kvm_set_apic_base() to lapic.c so that the bulk of KVM's local APIC
code resides in lapic.c, regardless of whether or not KVM is emulating the
local APIC in-kernel. This will also allow making various helpers visible
only to lapic.c.
No functional change intended.
Reviewed-by: Kai Huang <kai.huang@intel.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/r/20241009181742.1128779-6-seanjc@google.com
Link: https://lore.kernel.org/r/20241101183555.1794700-6-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Stable-dep-of: bb365a506b1e ("KVM: x86: Unconditionally recompute CR8 intercept on PPR update")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/lapic.c | 21 +++++++++++++++++++++
arch/x86/kvm/x86.c | 21 ---------------------
2 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 910db04a1addc..ea1c1728c1bf2 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -2656,6 +2656,27 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
}
}
+int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
+{
+ enum lapic_mode old_mode = kvm_get_apic_mode(vcpu);
+ enum lapic_mode new_mode = kvm_apic_mode(msr_info->data);
+ u64 reserved_bits = kvm_vcpu_reserved_gpa_bits_raw(vcpu) | 0x2ff |
+ (guest_cpuid_has(vcpu, X86_FEATURE_X2APIC) ? 0 : X2APIC_ENABLE);
+
+ if ((msr_info->data & reserved_bits) != 0 || new_mode == LAPIC_MODE_INVALID)
+ return 1;
+ if (!msr_info->host_initiated) {
+ if (old_mode == LAPIC_MODE_X2APIC && new_mode == LAPIC_MODE_XAPIC)
+ return 1;
+ if (old_mode == LAPIC_MODE_DISABLED && new_mode == LAPIC_MODE_X2APIC)
+ return 1;
+ }
+
+ kvm_lapic_set_base(vcpu, msr_info->data);
+ kvm_recalculate_apic_map(vcpu->kvm);
+ return 0;
+}
+
void kvm_apic_update_apicv(struct kvm_vcpu *vcpu)
{
struct kvm_lapic *apic = vcpu->arch.apic;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0a28c6346a96a..af99fb9666132 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -658,27 +658,6 @@ static void drop_user_return_notifiers(void)
kvm_on_user_return(&msrs->urn);
}
-int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
-{
- enum lapic_mode old_mode = kvm_get_apic_mode(vcpu);
- enum lapic_mode new_mode = kvm_apic_mode(msr_info->data);
- u64 reserved_bits = kvm_vcpu_reserved_gpa_bits_raw(vcpu) | 0x2ff |
- (guest_cpuid_has(vcpu, X86_FEATURE_X2APIC) ? 0 : X2APIC_ENABLE);
-
- if ((msr_info->data & reserved_bits) != 0 || new_mode == LAPIC_MODE_INVALID)
- return 1;
- if (!msr_info->host_initiated) {
- if (old_mode == LAPIC_MODE_X2APIC && new_mode == LAPIC_MODE_XAPIC)
- return 1;
- if (old_mode == LAPIC_MODE_DISABLED && new_mode == LAPIC_MODE_X2APIC)
- return 1;
- }
-
- kvm_lapic_set_base(vcpu, msr_info->data);
- kvm_recalculate_apic_map(vcpu->kvm);
- return 0;
-}
-
/*
* Handle a fault on a hardware virtualization (VMX or SVM) instruction.
*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 373/869] KVM: x86: Rename APIC base setters to better capture their relationship
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (371 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 372/869] KVM: x86: Move kvm_set_apic_base() implementation to lapic.c (from x86.c) Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 374/869] KVM: x86: Move update_cr8_intercept() to lapic.c Greg Kroah-Hartman
` (496 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kai Huang, Paolo Bonzini,
Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <seanjc@google.com>
[ Upstream commit 7d1cb7cee94ffd913cb3b70aa1c3538f195c1f23 ]
Rename kvm_set_apic_base() and kvm_lapic_set_base() to kvm_apic_set_base()
and __kvm_apic_set_base() respectively to capture that the underscores
version is a "special" variant (it exists purely to avoid recalculating
the optimized map multiple times when stuffing the RESET value).
Opportunistically add a comment explaining why kvm_lapic_reset() uses the
inner helper. Note, KVM deliberately invokes kvm_arch_vcpu_create() while
kvm->lock is NOT held so that vCPU setup isn't serialized if userspace is
creating multiple/all vCPUs in parallel. I.e. triggering an extra
recalculation is not limited to theoretical/rare edge cases, and so is
worth avoiding.
No functional change intended.
Reviewed-by: Kai Huang <kai.huang@intel.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/r/20241009181742.1128779-7-seanjc@google.com
Link: https://lore.kernel.org/r/20241101183555.1794700-7-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Stable-dep-of: bb365a506b1e ("KVM: x86: Unconditionally recompute CR8 intercept on PPR update")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/lapic.c | 15 +++++++++++----
arch/x86/kvm/lapic.h | 3 +--
arch/x86/kvm/regs.c | 2 +-
arch/x86/kvm/x86.c | 2 +-
4 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index ea1c1728c1bf2..58af5b4b7bdbd 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -2608,7 +2608,7 @@ u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
return (tpr & 0xf0) >> 4;
}
-void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
+static void __kvm_apic_set_base(struct kvm_vcpu *vcpu, u64 value)
{
u64 old_value = vcpu->arch.apic_base;
struct kvm_lapic *apic = vcpu->arch.apic;
@@ -2656,7 +2656,7 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
}
}
-int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
+int kvm_apic_set_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
enum lapic_mode old_mode = kvm_get_apic_mode(vcpu);
enum lapic_mode new_mode = kvm_apic_mode(msr_info->data);
@@ -2672,7 +2672,7 @@ int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
return 1;
}
- kvm_lapic_set_base(vcpu, msr_info->data);
+ __kvm_apic_set_base(vcpu, msr_info->data);
kvm_recalculate_apic_map(vcpu->kvm);
return 0;
}
@@ -2787,7 +2787,14 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
msr_val = APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE;
if (kvm_vcpu_is_reset_bsp(vcpu))
msr_val |= MSR_IA32_APICBASE_BSP;
- kvm_lapic_set_base(vcpu, msr_val);
+
+ /*
+ * Use the inner helper to avoid an extra recalcuation of the
+ * optimized APIC map if some other task has dirtied the map.
+ * The recalculation needed for this vCPU will be done after
+ * all APIC state has been initialized (see below).
+ */
+ __kvm_apic_set_base(vcpu, msr_val);
}
if (!apic)
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 3aa599db77968..99c07ee76e02d 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -95,7 +95,6 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event);
u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu);
-void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
void kvm_recalculate_apic_map(struct kvm *kvm);
void kvm_apic_set_version(struct kvm_vcpu *vcpu);
void kvm_apic_after_set_mcg_cap(struct kvm_vcpu *vcpu);
@@ -117,7 +116,7 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
struct kvm_lapic_irq *irq, int *r, struct dest_map *dest_map);
void kvm_apic_send_ipi(struct kvm_lapic *apic, u32 icr_low, u32 icr_high);
-int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
+int kvm_apic_set_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
int kvm_apic_get_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s);
int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s);
void kvm_apic_update_hwapic_isr(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/regs.c b/arch/x86/kvm/regs.c
index 26ee933ef5490..5001fe33c7f28 100644
--- a/arch/x86/kvm/regs.c
+++ b/arch/x86/kvm/regs.c
@@ -572,7 +572,7 @@ static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs,
apic_base_msr.data = sregs->apic_base;
apic_base_msr.host_initiated = true;
- if (kvm_set_apic_base(vcpu, &apic_base_msr))
+ if (kvm_apic_set_base(vcpu, &apic_base_msr))
return -EINVAL;
if (vcpu->arch.guest_state_protected)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index af99fb9666132..65f5a18824266 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3454,7 +3454,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case MSR_MTRRdefType:
return kvm_mtrr_set_msr(vcpu, msr, data);
case MSR_IA32_APICBASE:
- return kvm_set_apic_base(vcpu, msr_info);
+ return kvm_apic_set_base(vcpu, msr_info);
case APIC_BASE_MSR ... APIC_BASE_MSR + 0xff:
return kvm_x2apic_msr_write(vcpu, msr, data);
case MSR_IA32_TSC_DEADLINE:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 374/869] KVM: x86: Move update_cr8_intercept() to lapic.c
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (372 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 373/869] KVM: x86: Rename APIC base setters to better capture their relationship Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 375/869] KVM: x86: Unconditionally recompute CR8 intercept on PPR update Greg Kroah-Hartman
` (495 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kai Huang, Yosry Ahmed,
Sean Christopherson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <seanjc@google.com>
[ Upstream commit c7722e5e1daeeabbd9f969554d52bb7158120b27 ]
Move update_cr8_intercept() to lapic.c so that it's globally visible
in anticipation of extracting most of the register-specific code out of
x86.c and into a new compilation unit. Opportunistically prefix the
helper kvm_lapic_ to make its role/scope more obvious.
No functional change intended.
Reviewed-by: Kai Huang <kai.huang@intel.com>
Reviewed-by: Yosry Ahmed <yosry@kernel.org>
Link: https://patch.msgid.link/20260529222223.870923-14-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Stable-dep-of: bb365a506b1e ("KVM: x86: Unconditionally recompute CR8 intercept on PPR update")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/lapic.c | 26 ++++++++++++++++++++++++++
arch/x86/kvm/lapic.h | 1 +
arch/x86/kvm/regs.c | 2 +-
arch/x86/kvm/x86.c | 31 ++-----------------------------
arch/x86/kvm/x86.h | 1 -
5 files changed, 30 insertions(+), 31 deletions(-)
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 58af5b4b7bdbd..574111144a903 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -2608,6 +2608,32 @@ u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
return (tpr & 0xf0) >> 4;
}
+void kvm_lapic_update_cr8_intercept(struct kvm_vcpu *vcpu)
+{
+ int max_irr, tpr;
+
+ if (!kvm_x86_ops.update_cr8_intercept)
+ return;
+
+ if (!lapic_in_kernel(vcpu))
+ return;
+
+ if (vcpu->arch.apic->apicv_active)
+ return;
+
+ if (!vcpu->arch.apic->vapic_addr)
+ max_irr = kvm_lapic_find_highest_irr(vcpu);
+ else
+ max_irr = -1;
+
+ if (max_irr != -1)
+ max_irr >>= 4;
+
+ tpr = kvm_lapic_get_cr8(vcpu);
+
+ kvm_x86_call(update_cr8_intercept)(vcpu, tpr, max_irr);
+}
+
static void __kvm_apic_set_base(struct kvm_vcpu *vcpu, u64 value)
{
u64 old_value = vcpu->arch.apic_base;
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 99c07ee76e02d..a0668b0b1d36b 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -94,6 +94,7 @@ int kvm_apic_accept_events(struct kvm_vcpu *vcpu);
void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event);
u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
+void kvm_lapic_update_cr8_intercept(struct kvm_vcpu *vcpu);
void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu);
void kvm_recalculate_apic_map(struct kvm *kvm);
void kvm_apic_set_version(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/regs.c b/arch/x86/kvm/regs.c
index 5001fe33c7f28..6d71bdb9f72c8 100644
--- a/arch/x86/kvm/regs.c
+++ b/arch/x86/kvm/regs.c
@@ -621,7 +621,7 @@ static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs,
kvm_set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
- update_cr8_intercept(vcpu);
+ kvm_lapic_update_cr8_intercept(vcpu);
/* Older userspace won't unhalt the vcpu on reset. */
if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 &&
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 65f5a18824266..796bca8b9a865 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4697,7 +4697,7 @@ static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
r = kvm_apic_set_state(vcpu, s);
if (r)
return r;
- update_cr8_intercept(vcpu);
+ kvm_lapic_update_cr8_intercept(vcpu);
return 0;
}
@@ -9765,33 +9765,6 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
kvm_run->flags |= KVM_RUN_X86_GUEST_MODE;
}
-void update_cr8_intercept(struct kvm_vcpu *vcpu)
-{
- int max_irr, tpr;
-
- if (!kvm_x86_ops.update_cr8_intercept)
- return;
-
- if (!lapic_in_kernel(vcpu))
- return;
-
- if (vcpu->arch.apic->apicv_active)
- return;
-
- if (!vcpu->arch.apic->vapic_addr)
- max_irr = kvm_lapic_find_highest_irr(vcpu);
- else
- max_irr = -1;
-
- if (max_irr != -1)
- max_irr >>= 4;
-
- tpr = kvm_lapic_get_cr8(vcpu);
-
- kvm_x86_call(update_cr8_intercept)(vcpu, tpr, max_irr);
-}
-
-
int kvm_check_nested_events(struct kvm_vcpu *vcpu)
{
if (kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
@@ -10494,7 +10467,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
kvm_x86_call(enable_irq_window)(vcpu);
if (kvm_lapic_enabled(vcpu)) {
- update_cr8_intercept(vcpu);
+ kvm_lapic_update_cr8_intercept(vcpu);
kvm_lapic_sync_to_vapic(vcpu);
}
}
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index abab4bd96d0ac..75dc2219c51c5 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -641,6 +641,5 @@ int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
struct kvm_debugregs *dbgregs);
void kvm_invalidate_pcid(struct kvm_vcpu *vcpu, unsigned long pcid);
void kvm_handle_exception_payload_quirk(struct kvm_vcpu *vcpu);
-void update_cr8_intercept(struct kvm_vcpu *vcpu);
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 375/869] KVM: x86: Unconditionally recompute CR8 intercept on PPR update
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (373 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 374/869] KVM: x86: Move update_cr8_intercept() to lapic.c Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 376/869] KVM: nVMX: Put vmcs12 pages if nested VM-Enter fails due to invalid guest state Greg Kroah-Hartman
` (494 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Stefano Garzarella,
Carlos López, Sean Christopherson, Paolo Bonzini,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlos López <clopez@suse.de>
[ Upstream commit bb365a506b1e6fb050c0fceaad354fe395385ef0 ]
The TPR_THRESHOLD field in the VMCS is used by VMX to induce VM exits
when the guest's virtual TPR falls under the specified threshold,
allowing KVM to inject previously masked interrupts.
KVM handles these VM exits in handle_tpr_below_threshold().
Commit eb90f3417a0c ("KVM: vmx: speed up TPR below threshold vmexits")
optimized this function by calling apic_update_ppr() instead of raising
KVM_REQ_EVENT. apic_update_ppr() then raises KVM_REQ_EVENT if there is
a pending, deliverable interrupt.
However, if there are no new interrupts pending, apic_update_ppr() does
not issue the request. Thus, kvm_lapic_update_cr8_intercept() and
vmx_update_cr8_intercept() are not called before VM entry, which results
in a high, stale TPR_THRESHOLD. This is problematic due to the following
sentence in 28.2.1.1 "VM-Execution Control Fields" in the SDM:
The following check is performed if the “use TPR shadow” VM-execution
control is 1 and the “virtualize APIC accesses” and “virtual-interrupt
delivery” VM-execution controls are both 0: the value of bits 3:0 of
the TPR threshold VM-execution control field should not be greater
than the value of bits 7:4 of VTPR.
This error condition is typically not observed when KVM runs on a bare
metal system because modern processors support APICv, which enables
virtual-interrupt delivery, and which KVM uses when possible. This
causes the processor to no longer generate TPR-below-threshold exits
and to no longer check TPR_THRESHOLD on entry. However, when running
on older platforms, or under nested virtualization on a hypervisor that
does not support virtual-interrupt delivery and enforces this check
(like Hyper-V) this can cause a VM entry failure with hardware error
0x7, as seen in [1].
Call kvm_lapic_update_cr8_intercept() if apic_update_ppr() does not
find a deliverable interrupt (and thus does not raise KVM_REQ_EVENT).
Remove calls to kvm_lapic_update_cr8_intercept() on paths that end up in
apic_update_ppr(), as they now become redundant. This ensures that any
path that updates the guest's PPR also figures out if KVM needs to wait
for a TPR change (using TPR_THRESHOLD on VMX or CR8 intercepts on SVM).
Link: https://github.com/coconut-svsm/svsm/issues/1081 [1]
Tested-by: Stefano Garzarella <sgarzare@redhat.com>
Cc: stable@vger.kernel.org
Fixes: eb90f3417a0c ("KVM: vmx: speed up TPR below threshold vmexits")
Signed-off-by: Carlos López <clopez@suse.de>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20260618174347.1981064-3-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/lapic.c | 2 ++
arch/x86/kvm/regs.c | 4 +---
arch/x86/kvm/x86.c | 1 -
3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 574111144a903..6e6d00b3c042b 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -994,6 +994,8 @@ static void apic_update_ppr(struct kvm_lapic *apic)
if (__apic_update_ppr(apic, &ppr) &&
apic_has_interrupt_for_ppr(apic, ppr) != -1)
kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
+ else
+ kvm_lapic_update_cr8_intercept(apic->vcpu);
}
void kvm_apic_update_ppr(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/regs.c b/arch/x86/kvm/regs.c
index 6d71bdb9f72c8..49afacc9b0990 100644
--- a/arch/x86/kvm/regs.c
+++ b/arch/x86/kvm/regs.c
@@ -591,8 +591,6 @@ static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs,
kvm_register_mark_dirty(vcpu, VCPU_EXREG_CR3);
kvm_x86_call(post_set_cr3)(vcpu, sregs->cr3);
- kvm_set_cr8(vcpu, sregs->cr8);
-
*mmu_reset_needed |= vcpu->arch.efer != sregs->efer;
kvm_x86_call(set_efer)(vcpu, sregs->efer);
@@ -621,7 +619,7 @@ static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs,
kvm_set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
- kvm_lapic_update_cr8_intercept(vcpu);
+ kvm_set_cr8(vcpu, sregs->cr8);
/* Older userspace won't unhalt the vcpu on reset. */
if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 &&
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 796bca8b9a865..23696631599ac 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4697,7 +4697,6 @@ static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
r = kvm_apic_set_state(vcpu, s);
if (r)
return r;
- kvm_lapic_update_cr8_intercept(vcpu);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 376/869] KVM: nVMX: Put vmcs12 pages if nested VM-Enter fails due to invalid guest state
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (374 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 375/869] KVM: x86: Unconditionally recompute CR8 intercept on PPR update Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 377/869] drm/amdgpu: Fix kernel panic during driver load failure Greg Kroah-Hartman
` (493 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Minh Nguyen, Sean Christopherson,
Paolo Bonzini, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <seanjc@google.com>
[ Upstream commit 2f2312c422fd2695da772cecb30c69994b795964 ]
Put all vmcs12 pages if KVM synthesizes a nested VM-Exit due to invalid
guest while emulating VMLAUNCH or VMRESUME. The invalid guest state path
doesn't use nested_vmx_vmexit() as that API is intended to be used if and
only if L2 is active, and the open coded equivalent neglects to put the
vmcs12 pages. Failure to put the vmcs12 pages leaks any pinned pages
(and/or mappings) if L1 retries VMLAUNCH/VMRESUME.
Note, the !from_vmenter scenario doesn't suffer the same problem, as
vmx_get_nested_state_pages() only gets/pins/maps the vmcs12 pages if L2 is
active, i.e. if a "full" VM-Exit is guaranteed before KVM will retry
getting vmcs12 pages.
Fixes: 96c66e87deee ("KVM/nVMX: Use kvm_vcpu_map when mapping the virtual APIC page")
Fixes: 3278e0492554 ("KVM/nVMX: Use kvm_vcpu_map when mapping the posted interrupt descriptor table")
Fixes: fe1911aa443e ("KVM: nVMX: Use kvm_vcpu_map() to get/pin vmcs12's APIC-access page")
Reported-by: Minh Nguyen <minhnguyen.080505@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/vmx/nested.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index b2a0e36de0d32..bd9f41a78ec17 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -3692,6 +3692,11 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
if (!from_vmentry)
return NVMX_VMENTRY_VMEXIT;
+ kvm_vcpu_unmap(vcpu, &vmx->nested.apic_access_page_map, false);
+ kvm_vcpu_unmap(vcpu, &vmx->nested.virtual_apic_map, true);
+ kvm_vcpu_unmap(vcpu, &vmx->nested.pi_desc_map, true);
+ vmx->nested.pi_desc = NULL;
+
load_vmcs12_host_state(vcpu, vmcs12);
vmcs12->vm_exit_reason = exit_reason.full;
if (enable_shadow_vmcs || nested_vmx_is_evmptr12_valid(vmx))
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 377/869] drm/amdgpu: Fix kernel panic during driver load failure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (375 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 376/869] KVM: nVMX: Put vmcs12 pages if nested VM-Enter fails due to invalid guest state Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 378/869] media: stm32: dcmipp: use v4l2_subdev_is_streaming Greg Kroah-Hartman
` (492 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Harish Kasiviswanathan, Kent Russell,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com>
[ Upstream commit a279bd143b3c184358b658e43a057e31ee8c4de5 ]
Avoid kernel panic if MES init fails during driver load. The KIQ ring is
falsely marked as ready as ASICs that use MES, KIQ is owned by MES.
BUG: kernel NULL pointer dereference, address: 0000000000000000
RIP: 0010:gfx_v12_1_wait_reg_mem+0x5a/0x1f0 [amdgpu]
Call Trace:
gfx_v12_1_ring_emit_reg_write_reg_wait+0x1f/0x30 [amdgpu]
amdgpu_gmc_fw_reg_write_reg_wait+0xb2/0x190 [amdgpu]
amdgpu_gmc_flush_gpu_tlb+0x1cc/0x230 [amdgpu]
amdgpu_gart_invalidate_tlb+0x81/0xa0 [amdgpu]
amdgpu_gart_unbind+0x72/0x90 [amdgpu]
amdgpu_ttm_backend_unbind+0xa4/0xb0 [amdgpu]
amdgpu_ttm_tt_unpopulate+0x13/0xd0 [amdgpu]
amdttm_tt_unpopulate+0x29/0x70 [amdttm]
ttm_bo_put+0x1eb/0x360 [amdttm]
amdgpu_bo_free_kernel+0xf9/0x1f0 [amdgpu]
amdgpu_ih_ring_fini+0x5a/0x90 [amdgpu]
amdgpu_irq_fini_hw+0x58/0x80 [amdgpu]
amdgpu_device_fini_hw+0x4e0/0x5b0 [amdgpu]
amdgpu_driver_load_kms+0x60/0xa0 [amdgpu]
amdgpu_pci_probe+0x28e/0x6d0 [amdgpu]
pci_device_probe+0x19f/0x220
really_probe+0x1ed/0x340
driver_probe_device+0x1e/0x80
__driver_attach+0xd3/0x1a0
bus_for_each_dev+0x68/0xa0
bus_add_driver+0x19f/0x270
driver_register+0x5d/0xf0
do_one_initcall+0xac/0x200
do_init_module+0x1ec/0x280
__se_sys_finit_module+0x2de/0x310
do_syscall_64+0x6a/0x250
entry_SYSCALL_64_after_hwframe+0x4b/0x53
Signed-off-by: Harish Kasiviswanathan <Harish.Kasiviswanathan@amd.com>
Reviewed-by: Kent Russell <kent.russell@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 4623b958dd6da0f4c3026afdf330626a09ecb0f0)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
index 4d115538a9563..a076a314dc677 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
@@ -3398,10 +3398,19 @@ static int gfx_v12_0_cp_resume(struct amdgpu_device *adev)
gfx_v12_0_cp_gfx_enable(adev, true);
}
- if (adev->enable_mes_kiq && adev->mes.kiq_hw_init)
+ if (adev->enable_mes_kiq && adev->mes.kiq_hw_init) {
r = amdgpu_mes_kiq_hw_init(adev);
- else
+ /*
+ * With MES, GFX KIQ ring is owned by the MES and is never
+ * initialized/used directly by the driver, so it must
+ * not be left flagged as ready. mes_v12_0_hw_init() clears
+ * but clear here if MES init fails
+ */
+ if (r)
+ adev->gfx.kiq[0].ring.sched.ready = false;
+ } else {
r = gfx_v12_0_kiq_resume(adev);
+ }
if (r)
return r;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 378/869] media: stm32: dcmipp: use v4l2_subdev_is_streaming
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (376 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 377/869] drm/amdgpu: Fix kernel panic during driver load failure Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 379/869] media: stm32: dcmipp: replace s_stream with enable/disable_streams Greg Kroah-Hartman
` (491 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Alain Volmat, Hans Verkuil,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alain Volmat <alain.volmat@foss.st.com>
[ Upstream commit 255e0cc62b9b1afad9b9ba7738d5c53cd0d157fb ]
Rely on v4l2_subdev_is_streaming in order to know if the subdev
is streaming or not instead of relying on a local variable.
Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Stable-dep-of: ffc8eec06378 ("media: stm32-dcmipp: Return queued buffers on start_streaming() failure")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c | 6 +-----
.../media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c | 5 +----
2 files changed, 2 insertions(+), 9 deletions(-)
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
index 5a361ad6b0234..50500112eab9a 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
@@ -78,7 +78,6 @@ struct dcmipp_byteproc_device {
struct v4l2_subdev sd;
struct device *dev;
void __iomem *regs;
- bool streaming;
};
static const struct v4l2_mbus_framefmt fmt_default = {
@@ -239,11 +238,10 @@ static int dcmipp_byteproc_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf;
struct v4l2_rect *crop, *compose;
- if (byteproc->streaming)
+ if (v4l2_subdev_is_streaming(sd))
return -EBUSY;
mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
@@ -495,8 +493,6 @@ static int dcmipp_byteproc_s_stream(struct v4l2_subdev *sd, int enable)
}
}
- byteproc->streaming = enable;
-
return 0;
}
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c
index 62c5c3331cfec..05e8897ae37a4 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c
@@ -129,7 +129,6 @@ struct dcmipp_par_device {
struct v4l2_subdev sd;
struct device *dev;
void __iomem *regs;
- bool streaming;
};
static const struct v4l2_mbus_framefmt fmt_default = {
@@ -230,7 +229,7 @@ static int dcmipp_par_set_fmt(struct v4l2_subdev *sd,
struct dcmipp_par_device *par = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf;
- if (par->streaming)
+ if (v4l2_subdev_is_streaming(sd))
return -EBUSY;
mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
@@ -370,8 +369,6 @@ static int dcmipp_par_s_stream(struct v4l2_subdev *sd, int enable)
reg_clear(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE);
}
- par->streaming = enable;
-
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 379/869] media: stm32: dcmipp: replace s_stream with enable/disable_streams
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (377 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 378/869] media: stm32: dcmipp: use v4l2_subdev_is_streaming Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 380/869] media: stm32-dcmipp: Return queued buffers on start_streaming() failure Greg Kroah-Hartman
` (490 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Alain Volmat, Hans Verkuil,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alain Volmat <alain.volmat@foss.st.com>
[ Upstream commit b0f3cc70893289d0d74a1523e26d60346f747ebe ]
Replace s_stream ops with enable_streams and disable_streams.
At the same time, use v4l2_subdev_enable_streams and
v4l2_subdev_disable_streams functions instead of
direct s_stream calls.
Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Stable-dep-of: ffc8eec06378 ("media: stm32-dcmipp: Return queued buffers on start_streaming() failure")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../st/stm32/stm32-dcmipp/dcmipp-bytecap.c | 49 ++++----
.../st/stm32/stm32-dcmipp/dcmipp-byteproc.c | 98 +++++++++-------
.../st/stm32/stm32-dcmipp/dcmipp-parallel.c | 107 ++++++++++--------
3 files changed, 139 insertions(+), 115 deletions(-)
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
index b461d86bed540..2b323dd6cf6bf 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
@@ -112,6 +112,7 @@ struct dcmipp_bytecap_device {
u32 sequence;
struct media_pipeline pipe;
struct v4l2_subdev *s_subdev;
+ u32 s_subdev_pad_nb;
enum dcmipp_state state;
@@ -337,33 +338,6 @@ static const struct v4l2_ioctl_ops dcmipp_bytecap_ioctl_ops = {
.vidioc_streamoff = vb2_ioctl_streamoff,
};
-static int dcmipp_pipeline_s_stream(struct dcmipp_bytecap_device *vcap,
- int state)
-{
- struct media_pad *pad;
- int ret;
-
- /*
- * Get source subdev - since link is IMMUTABLE, pointer is cached
- * within the dcmipp_bytecap_device structure
- */
- if (!vcap->s_subdev) {
- pad = media_pad_remote_pad_first(&vcap->vdev.entity.pads[0]);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
- return -EINVAL;
- vcap->s_subdev = media_entity_to_v4l2_subdev(pad->entity);
- }
-
- ret = v4l2_subdev_call(vcap->s_subdev, video, s_stream, state);
- if (ret < 0) {
- dev_err(vcap->dev, "failed to %s streaming (%d)\n",
- state ? "start" : "stop", ret);
- return ret;
- }
-
- return 0;
-}
-
static void dcmipp_start_capture(struct dcmipp_bytecap_device *vcap,
struct dcmipp_buf *buf)
{
@@ -395,11 +369,24 @@ static int dcmipp_bytecap_start_streaming(struct vb2_queue *vq,
struct dcmipp_bytecap_device *vcap = vb2_get_drv_priv(vq);
struct media_entity *entity = &vcap->vdev.entity;
struct dcmipp_buf *buf;
+ struct media_pad *pad;
int ret;
vcap->sequence = 0;
memset(&vcap->count, 0, sizeof(vcap->count));
+ /*
+ * Get source subdev - since link is IMMUTABLE, pointer is cached
+ * within the dcmipp_bytecap_device structure
+ */
+ if (!vcap->s_subdev) {
+ pad = media_pad_remote_pad_first(&vcap->vdev.entity.pads[0]);
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ return -EINVAL;
+ vcap->s_subdev = media_entity_to_v4l2_subdev(pad->entity);
+ vcap->s_subdev_pad_nb = pad->index;
+ }
+
ret = pm_runtime_resume_and_get(vcap->dev);
if (ret < 0) {
dev_err(vcap->dev, "%s: Failed to start streaming, cannot get sync (%d)\n",
@@ -414,7 +401,8 @@ static int dcmipp_bytecap_start_streaming(struct vb2_queue *vq,
goto err_pm_put;
}
- ret = dcmipp_pipeline_s_stream(vcap, 1);
+ ret = v4l2_subdev_enable_streams(vcap->s_subdev,
+ vcap->s_subdev_pad_nb, BIT_ULL(0));
if (ret)
goto err_media_pipeline_stop;
@@ -482,7 +470,10 @@ static void dcmipp_bytecap_stop_streaming(struct vb2_queue *vq)
int ret;
u32 status;
- dcmipp_pipeline_s_stream(vcap, 0);
+ ret = v4l2_subdev_disable_streams(vcap->s_subdev,
+ vcap->s_subdev_pad_nb, BIT_ULL(0));
+ if (ret)
+ dev_warn(vcap->dev, "Failed to disable stream\n");
/* Stop the media pipeline */
media_pipeline_stop(vcap->vdev.entity.pads);
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
index 50500112eab9a..a19c8235af565 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
@@ -380,30 +380,19 @@ static int dcmipp_byteproc_set_selection(struct v4l2_subdev *sd,
return 0;
}
-static const struct v4l2_subdev_pad_ops dcmipp_byteproc_pad_ops = {
- .enum_mbus_code = dcmipp_byteproc_enum_mbus_code,
- .enum_frame_size = dcmipp_byteproc_enum_frame_size,
- .get_fmt = v4l2_subdev_get_fmt,
- .set_fmt = dcmipp_byteproc_set_fmt,
- .get_selection = dcmipp_byteproc_get_selection,
- .set_selection = dcmipp_byteproc_set_selection,
-};
-
static int dcmipp_byteproc_configure_scale_crop
- (struct dcmipp_byteproc_device *byteproc)
+ (struct dcmipp_byteproc_device *byteproc,
+ struct v4l2_subdev_state *state)
{
const struct dcmipp_byteproc_pix_map *vpix;
- struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *sink_fmt;
u32 hprediv, vprediv;
struct v4l2_rect *compose, *crop;
u32 val = 0;
- state = v4l2_subdev_lock_and_get_active_state(&byteproc->sd);
sink_fmt = v4l2_subdev_state_get_format(state, 0);
compose = v4l2_subdev_state_get_compose(state, 0);
crop = v4l2_subdev_state_get_crop(state, 1);
- v4l2_subdev_unlock_state(state);
/* find output format bpp */
vpix = dcmipp_byteproc_pix_map_by_code(sink_fmt->code);
@@ -458,46 +447,73 @@ static int dcmipp_byteproc_configure_scale_crop
return 0;
}
-static int dcmipp_byteproc_s_stream(struct v4l2_subdev *sd, int enable)
+static int dcmipp_byteproc_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
{
struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
struct v4l2_subdev *s_subdev;
- struct media_pad *pad;
- int ret = 0;
+ struct media_pad *s_pad;
+ int ret;
/* Get source subdev */
- pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
+ if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
return -EINVAL;
- s_subdev = media_entity_to_v4l2_subdev(pad->entity);
-
- if (enable) {
- ret = dcmipp_byteproc_configure_scale_crop(byteproc);
- if (ret)
- return ret;
-
- ret = v4l2_subdev_call(s_subdev, video, s_stream, enable);
- if (ret < 0) {
- dev_err(byteproc->dev,
- "failed to start source subdev streaming (%d)\n",
- ret);
- return ret;
- }
- } else {
- ret = v4l2_subdev_call(s_subdev, video, s_stream, enable);
- if (ret < 0) {
- dev_err(byteproc->dev,
- "failed to stop source subdev streaming (%d)\n",
- ret);
- return ret;
- }
+ s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
+
+ ret = dcmipp_byteproc_configure_scale_crop(byteproc, state);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_enable_streams(s_subdev, s_pad->index, BIT_ULL(0));
+ if (ret < 0) {
+ dev_err(byteproc->dev,
+ "failed to start source subdev streaming (%d)\n", ret);
+ return ret;
}
return 0;
}
+static int dcmipp_byteproc_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
+{
+ struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
+ struct v4l2_subdev *s_subdev;
+ struct media_pad *s_pad;
+ int ret;
+
+ /* Get source subdev */
+ s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
+ if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
+ return -EINVAL;
+ s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
+
+ ret = v4l2_subdev_disable_streams(s_subdev, s_pad->index, BIT_ULL(0));
+ if (ret < 0) {
+ dev_err(byteproc->dev,
+ "failed to start source subdev streaming (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops dcmipp_byteproc_pad_ops = {
+ .enum_mbus_code = dcmipp_byteproc_enum_mbus_code,
+ .enum_frame_size = dcmipp_byteproc_enum_frame_size,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = dcmipp_byteproc_set_fmt,
+ .get_selection = dcmipp_byteproc_get_selection,
+ .set_selection = dcmipp_byteproc_set_selection,
+ .enable_streams = dcmipp_byteproc_enable_streams,
+ .disable_streams = dcmipp_byteproc_disable_streams,
+};
+
static const struct v4l2_subdev_video_ops dcmipp_byteproc_video_ops = {
- .s_stream = dcmipp_byteproc_s_stream,
+ .s_stream = v4l2_subdev_s_stream_helper,
};
static const struct v4l2_subdev_ops dcmipp_byteproc_ops = {
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c
index 05e8897ae37a4..823c9da336a7f 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c
@@ -260,18 +260,11 @@ static int dcmipp_par_set_fmt(struct v4l2_subdev *sd,
return 0;
}
-static const struct v4l2_subdev_pad_ops dcmipp_par_pad_ops = {
- .enum_mbus_code = dcmipp_par_enum_mbus_code,
- .enum_frame_size = dcmipp_par_enum_frame_size,
- .get_fmt = v4l2_subdev_get_fmt,
- .set_fmt = dcmipp_par_set_fmt,
-};
-
-static int dcmipp_par_configure(struct dcmipp_par_device *par)
+static int dcmipp_par_configure(struct dcmipp_par_device *par,
+ struct v4l2_subdev_state *state)
{
u32 val = 0;
const struct dcmipp_par_pix_map *vpix;
- struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *sink_fmt;
struct v4l2_mbus_framefmt *src_fmt;
@@ -305,10 +298,8 @@ static int dcmipp_par_configure(struct dcmipp_par_device *par)
}
/* Set format */
- state = v4l2_subdev_lock_and_get_active_state(&par->sd);
sink_fmt = v4l2_subdev_state_get_format(state, 0);
src_fmt = v4l2_subdev_state_get_format(state, 1);
- v4l2_subdev_unlock_state(state);
vpix = dcmipp_par_pix_map_by_code(sink_fmt->code, src_fmt->code);
if (!vpix) {
@@ -327,53 +318,79 @@ static int dcmipp_par_configure(struct dcmipp_par_device *par)
return 0;
}
-static int dcmipp_par_s_stream(struct v4l2_subdev *sd, int enable)
+static int dcmipp_par_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
{
struct dcmipp_par_device *par =
container_of(sd, struct dcmipp_par_device, sd);
struct v4l2_subdev *s_subdev;
- struct media_pad *pad;
- int ret = 0;
+ struct media_pad *s_pad;
+ int ret;
/* Get source subdev */
- pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
+ if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
return -EINVAL;
- s_subdev = media_entity_to_v4l2_subdev(pad->entity);
-
- if (enable) {
- ret = dcmipp_par_configure(par);
- if (ret)
- return ret;
-
- /* Enable parallel interface */
- reg_set(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE);
-
- ret = v4l2_subdev_call(s_subdev, video, s_stream, enable);
- if (ret < 0) {
- dev_err(par->dev,
- "failed to start source subdev streaming (%d)\n",
- ret);
- return ret;
- }
- } else {
- ret = v4l2_subdev_call(s_subdev, video, s_stream, enable);
- if (ret < 0) {
- dev_err(par->dev,
- "failed to stop source subdev streaming (%d)\n",
- ret);
- return ret;
- }
+ s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
+
+ ret = dcmipp_par_configure(par, state);
+ if (ret)
+ return ret;
+
+ /* Enable parallel interface */
+ reg_set(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE);
- /* Disable parallel interface */
- reg_clear(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE);
+ ret = v4l2_subdev_enable_streams(s_subdev, s_pad->index, BIT_ULL(0));
+ if (ret < 0) {
+ dev_err(par->dev,
+ "failed to start source subdev streaming (%d)\n", ret);
+ return ret;
}
- return ret;
+ return 0;
}
+static int dcmipp_par_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
+{
+ struct dcmipp_par_device *par =
+ container_of(sd, struct dcmipp_par_device, sd);
+ struct v4l2_subdev *s_subdev;
+ struct media_pad *s_pad;
+ int ret;
+
+ /* Get source subdev */
+ s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
+ if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
+ return -EINVAL;
+ s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
+
+ ret = v4l2_subdev_disable_streams(s_subdev, s_pad->index, BIT_ULL(0));
+ if (ret < 0) {
+ dev_err(par->dev,
+ "failed to stop source subdev streaming (%d)\n", ret);
+ return ret;
+ }
+
+ /* Disable parallel interface */
+ reg_clear(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops dcmipp_par_pad_ops = {
+ .enum_mbus_code = dcmipp_par_enum_mbus_code,
+ .enum_frame_size = dcmipp_par_enum_frame_size,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = dcmipp_par_set_fmt,
+ .enable_streams = dcmipp_par_enable_streams,
+ .disable_streams = dcmipp_par_disable_streams,
+};
+
static const struct v4l2_subdev_video_ops dcmipp_par_video_ops = {
- .s_stream = dcmipp_par_s_stream,
+ .s_stream = v4l2_subdev_s_stream_helper,
};
static const struct v4l2_subdev_ops dcmipp_par_ops = {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 380/869] media: stm32-dcmipp: Return queued buffers on start_streaming() failure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (378 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 379/869] media: stm32: dcmipp: replace s_stream with enable/disable_streams Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 381/869] drm/vc4: Shut down BO cache timer before teardown Greg Kroah-Hartman
` (489 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Valery Borovsky, Hans Verkuil,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Valery Borovsky <vebohr@gmail.com>
[ Upstream commit ffc8eec06378a340d708c889184ab3e14b57d540 ]
The vb2 framework hands buffers to the driver via buf_queue() before
calling start_streaming(). If start_streaming() returns an error
without first returning those buffers via vb2_buffer_done(),
vb2_start_streaming() fires WARN_ON(owned_by_drv_count) and the queued
buffers leak.
dcmipp_bytecap_start_streaming() returned -EINVAL when the source
subdevice could not be resolved from the media graph, before
pm_runtime_resume_and_get() and media_pipeline_start() had been called.
The remaining error paths already converge on the err_buffer_done
label, which calls dcmipp_bytecap_all_buffers_done(...,
VB2_BUF_STATE_QUEUED). Jump to that label directly: the intermediate
err_pm_put / err_media_pipeline_stop labels are skipped, which is
correct because nothing they would undo has happened yet.
This mirrors the uvcvideo fix in commit 4cf3b6fd54eb ("media: uvcvideo:
Return queued buffers on start_streaming() failure").
Fixes: 28e0f3772296 ("media: stm32-dcmipp: STM32 DCMIPP camera interface driver")
Cc: stable@vger.kernel.org
Signed-off-by: Valery Borovsky <vebohr@gmail.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
index 2b323dd6cf6bf..b1e35df41a9c0 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
@@ -381,8 +381,10 @@ static int dcmipp_bytecap_start_streaming(struct vb2_queue *vq,
*/
if (!vcap->s_subdev) {
pad = media_pad_remote_pad_first(&vcap->vdev.entity.pads[0]);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
- return -EINVAL;
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) {
+ ret = -EINVAL;
+ goto err_buffer_done;
+ }
vcap->s_subdev = media_entity_to_v4l2_subdev(pad->entity);
vcap->s_subdev_pad_nb = pad->index;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 381/869] drm/vc4: Shut down BO cache timer before teardown
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (379 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 380/869] media: stm32-dcmipp: Return queued buffers on start_streaming() failure Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 382/869] drm/amdgpu: Use dbg level for VBIOS check messages Greg Kroah-Hartman
` (488 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Linmao Li, Maíra Canal,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <lilinmao@kylinos.cn>
[ Upstream commit 6273dd3ffb54ec581855b82ae77331b66028249c ]
The BO cache timer callback schedules time_work, and time_work can rearm
the timer through vc4_bo_cache_free_old().
vc4_bo_cache_destroy() deletes the timer and then cancels the work, which
does not break that cycle: the work being cancelled can rearm the timer,
and the timer then queues work again after teardown.
Use timer_shutdown_sync() instead, so the timer cannot be rearmed and the
cycle ends with cancel_work_sync().
Fixes: c826a6e10644 ("drm/vc4: Add a BO cache.")
Cc: stable@vger.kernel.org
Signed-off-by: Linmao Li <lilinmao@kylinos.cn>
Link: https://patch.msgid.link/20260720084426.1632508-1-lilinmao@kylinos.cn
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/vc4/vc4_bo.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index 212c86acca482..57935b5c640a1 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -1050,7 +1050,7 @@ static void vc4_bo_cache_destroy(struct drm_device *dev, void *unused)
struct vc4_dev *vc4 = to_vc4_dev(dev);
int i;
- del_timer(&vc4->bo_cache.time_timer);
+ timer_shutdown_sync(&vc4->bo_cache.time_timer);
cancel_work_sync(&vc4->bo_cache.time_work);
vc4_bo_cache_purge(dev);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 382/869] drm/amdgpu: Use dbg level for VBIOS check messages
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (380 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 381/869] drm/vc4: Shut down BO cache timer before teardown Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 383/869] drm/amdgpu: Add wrapper for freeing vbios memory Greg Kroah-Hartman
` (487 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Lijo Lazar, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lijo Lazar <lijo.lazar@amd.com>
[ Upstream commit 635c659fceed82f934623188471ff604e098aab7 ]
Driver has different ways to fetch VBIOS. If one of the methods doesn't
find an authentic one, it will show misleading info messages eventhough
a subsequent method finds a valid VBIOS. Keep the message level at debug
and add device context.
Signed-off-by: Lijo Lazar <lijo.lazar@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Stable-dep-of: 65bff2661760 ("drm/amdgpu: Release VFCT ACPI table reference")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 26 +++++++++++++-----------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
index e665430898244..53641234b9cf8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -48,35 +48,37 @@
/* Check if current bios is an ATOM BIOS.
* Return true if it is ATOM BIOS. Otherwise, return false.
*/
-static bool check_atom_bios(uint8_t *bios, size_t size)
+static bool check_atom_bios(struct amdgpu_device *adev, size_t size)
{
uint16_t tmp, bios_header_start;
+ uint8_t *bios = adev->bios;
if (!bios || size < 0x49) {
- DRM_INFO("vbios mem is null or mem size is wrong\n");
+ dev_dbg(adev->dev, "VBIOS mem is null or mem size is wrong\n");
return false;
}
if (!AMD_IS_VALID_VBIOS(bios)) {
- DRM_INFO("BIOS signature incorrect %x %x\n", bios[0], bios[1]);
+ dev_dbg(adev->dev, "VBIOS signature incorrect %x %x\n", bios[0],
+ bios[1]);
return false;
}
bios_header_start = bios[0x48] | (bios[0x49] << 8);
if (!bios_header_start) {
- DRM_INFO("Can't locate bios header\n");
+ dev_dbg(adev->dev, "Can't locate VBIOS header\n");
return false;
}
tmp = bios_header_start + 4;
if (size < tmp) {
- DRM_INFO("BIOS header is broken\n");
+ dev_dbg(adev->dev, "VBIOS header is broken\n");
return false;
}
if (!memcmp(bios + tmp, "ATOM", 4) ||
!memcmp(bios + tmp, "MOTA", 4)) {
- DRM_DEBUG("ATOMBIOS detected\n");
+ dev_dbg(adev->dev, "ATOMBIOS detected\n");
return true;
}
@@ -119,7 +121,7 @@ static bool amdgpu_read_bios_from_vram(struct amdgpu_device *adev)
memcpy_fromio(adev->bios, bios, size);
iounmap(bios);
- if (!check_atom_bios(adev->bios, size)) {
+ if (!check_atom_bios(adev, size)) {
kfree(adev->bios);
return false;
}
@@ -147,7 +149,7 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)
memcpy_fromio(adev->bios, bios, size);
pci_unmap_rom(adev->pdev, bios);
- if (!check_atom_bios(adev->bios, size)) {
+ if (!check_atom_bios(adev, size)) {
kfree(adev->bios);
return false;
}
@@ -187,7 +189,7 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
/* read complete BIOS */
amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
- if (!check_atom_bios(adev->bios, len)) {
+ if (!check_atom_bios(adev, len)) {
kfree(adev->bios);
return false;
}
@@ -217,7 +219,7 @@ static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
memcpy_fromio(adev->bios, bios, romlen);
iounmap(bios);
- if (!check_atom_bios(adev->bios, romlen))
+ if (!check_atom_bios(adev, romlen))
goto free_bios;
adev->bios_size = romlen;
@@ -325,7 +327,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
break;
}
- if (!check_atom_bios(adev->bios, size)) {
+ if (!check_atom_bios(adev, size)) {
kfree(adev->bios);
return false;
}
@@ -425,7 +427,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
vhdr->ImageLength,
GFP_KERNEL);
- if (!check_atom_bios(adev->bios, vhdr->ImageLength)) {
+ if (!check_atom_bios(adev, vhdr->ImageLength)) {
kfree(adev->bios);
return false;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 383/869] drm/amdgpu: Add wrapper for freeing vbios memory
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (381 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 382/869] drm/amdgpu: Use dbg level for VBIOS check messages Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 384/869] drm/amdgpu: Release VFCT ACPI table reference Greg Kroah-Hartman
` (486 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lijo Lazar, Alex Deucher,
Hawking Zhang, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lijo Lazar <lijo.lazar@amd.com>
[ Upstream commit e986e89659e18ba986db044df58f165042817dc3 ]
Use bios_release wrapper to release memory allocated for vbios image and
reset the variables.
v2:
Use the same wrapper for clean up in sw_fini (Alex Deucher)
Signed-off-by: Lijo Lazar <lijo.lazar@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Stable-dep-of: 65bff2661760 ("drm/amdgpu: Release VFCT ACPI table reference")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 +
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 20 ++++++++++++++------
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 +--
3 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index b667da0ec68a3..06b80396c6c96 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -409,6 +409,7 @@ bool amdgpu_get_bios(struct amdgpu_device *adev);
bool amdgpu_read_bios(struct amdgpu_device *adev);
bool amdgpu_soc15_read_bios_from_rom(struct amdgpu_device *adev,
u8 *bios, u32 length_bytes);
+void amdgpu_bios_release(struct amdgpu_device *adev);
/*
* Clocks
*/
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
index 53641234b9cf8..58a23bd19bf5d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -85,6 +85,13 @@ static bool check_atom_bios(struct amdgpu_device *adev, size_t size)
return false;
}
+void amdgpu_bios_release(struct amdgpu_device *adev)
+{
+ kfree(adev->bios);
+ adev->bios = NULL;
+ adev->bios_size = 0;
+}
+
/* If you boot an IGP board with a discrete card as the primary,
* the IGP rom is not accessible via the rom bar as the IGP rom is
* part of the system bios. On boot, the system bios puts a
@@ -122,7 +129,7 @@ static bool amdgpu_read_bios_from_vram(struct amdgpu_device *adev)
iounmap(bios);
if (!check_atom_bios(adev, size)) {
- kfree(adev->bios);
+ amdgpu_bios_release(adev);
return false;
}
@@ -150,7 +157,7 @@ bool amdgpu_read_bios(struct amdgpu_device *adev)
pci_unmap_rom(adev->pdev, bios);
if (!check_atom_bios(adev, size)) {
- kfree(adev->bios);
+ amdgpu_bios_release(adev);
return false;
}
@@ -190,7 +197,7 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
amdgpu_asic_read_bios_from_rom(adev, adev->bios, len);
if (!check_atom_bios(adev, len)) {
- kfree(adev->bios);
+ amdgpu_bios_release(adev);
return false;
}
@@ -226,7 +233,8 @@ static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
return true;
free_bios:
- kfree(adev->bios);
+ amdgpu_bios_release(adev);
+
return false;
}
@@ -328,7 +336,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
}
if (!check_atom_bios(adev, size)) {
- kfree(adev->bios);
+ amdgpu_bios_release(adev);
return false;
}
adev->bios_size = size;
@@ -428,7 +436,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
GFP_KERNEL);
if (!check_atom_bios(adev, vhdr->ImageLength)) {
- kfree(adev->bios);
+ amdgpu_bios_release(adev);
return false;
}
adev->bios_size = vhdr->ImageLength;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index cd05ddacd8116..3e74e8dc2e186 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -4793,8 +4793,7 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
if (amdgpu_emu_mode != 1)
amdgpu_atombios_fini(adev);
- kfree(adev->bios);
- adev->bios = NULL;
+ amdgpu_bios_release(adev);
kfree(adev->fru_info);
adev->fru_info = NULL;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 384/869] drm/amdgpu: Release VFCT ACPI table reference
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (382 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 383/869] drm/amdgpu: Add wrapper for freeing vbios memory Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 385/869] drm/i915/mst: limit DP MST ESI service loop Greg Kroah-Hartman
` (485 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alex Deucher, Mario Limonciello,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <mario.limonciello@amd.com>
[ Upstream commit 65bff26617607c1331283232016c0e89088c5b78 ]
amdgpu_acpi_vfct_bios() fetches the VFCT table with acpi_get_table()
but never releases it. acpi_get_table() takes a reference on the
table (incrementing its validation_count and mapping it on the 0->1
transition); without a paired acpi_put_table() the mapping is leaked
on every call, whether or not a matching VBIOS image is found.
Route all exit paths after the table is acquired through a common
acpi_put_table(). The VBIOS image is copied out with kmemdup() before
the table is released, so it remains valid for the caller.
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Link: https://patch.msgid.link/20260708193518.702584-3-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 ca5988682b4cba4cd125a0fa99b2de1239164ae4)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
index 58a23bd19bf5d..dec312b0f3b0a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -401,13 +401,14 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
acpi_size tbl_size;
UEFI_ACPI_VFCT *vfct;
unsigned int offset;
+ bool r = false;
if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
return false;
tbl_size = hdr->length;
if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
dev_info(adev->dev, "ACPI VFCT table present but broken (too short #1),skipping\n");
- return false;
+ goto out;
}
vfct = (UEFI_ACPI_VFCT *)hdr;
@@ -420,13 +421,13 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
offset += sizeof(VFCT_IMAGE_HEADER);
if (offset > tbl_size) {
dev_info(adev->dev, "ACPI VFCT image header truncated,skipping\n");
- return false;
+ goto out;
}
offset += vhdr->ImageLength;
if (offset > tbl_size) {
dev_info(adev->dev, "ACPI VFCT image truncated,skipping\n");
- return false;
+ goto out;
}
if (vhdr->ImageLength &&
@@ -437,15 +438,19 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
if (!check_atom_bios(adev, vhdr->ImageLength)) {
amdgpu_bios_release(adev);
- return false;
+ goto out;
}
adev->bios_size = vhdr->ImageLength;
- return true;
+ r = true;
+ goto out;
}
}
dev_info(adev->dev, "ACPI VFCT table present but broken (too short #2),skipping\n");
- return false;
+
+out:
+ acpi_put_table(hdr);
+ return r;
}
#else
static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 385/869] drm/i915/mst: limit DP MST ESI service loop
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (383 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 384/869] drm/amdgpu: Release VFCT ACPI table reference Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 386/869] drm/i915/gt: Fix NULL deref on sched_engine alloc failure Greg Kroah-Hartman
` (484 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Martin Hodo, Ville Syrjälä,
Imre Deak, Jani Nikula, Rodrigo Vivi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <jani.nikula@intel.com>
[ Upstream commit 005771c18c5b2c98cb4e7517661aea460990fd3f ]
The loop in intel_dp_check_mst_status() keeps servicing interrupts
originating from the sink without bound. Add an upper bound to the new
interrupts occurring during interrupt processing to not get stuck on
potentially stuck sink devices. Use arbitrary 32 tries to clear incoming
interrupts in one go.
Discovered using AI-assisted static analysis confirmed by Intel Product
Security.
Note: The condition likely pre-dates the commit in the Fixes: tag, but
this is about as far back as a backport has any chance of
succeeding. Before that, the retry had a goto.
Reported-by: Martin Hodo <martin.hodo@intel.com>
Fixes: 3c0ec2c2d594 ("drm/i915: Flatten intel_dp_check_mst_status() a bit")
Cc: stable@vger.kernel.org # v5.8+
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Reviewed-by: Imre Deak <imre.deak@intel.com>
Link: https://patch.msgid.link/20260625142204.1078287-1-jani.nikula@intel.com
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
(cherry picked from commit b4ea5272133059acb493cc36599071a9e852ec2e)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/i915/display/intel_dp.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 63c335d3d9ce8..b1ba117cfce86 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -5202,10 +5202,11 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
struct intel_encoder *encoder = &dig_port->base;
bool link_ok = true;
bool reprobe_needed = false;
+ int tries = 33;
drm_WARN_ON_ONCE(&i915->drm, intel_dp->mst.active_links < 0);
- for (;;) {
+ while (--tries) {
u8 esi[4] = {};
u8 ack[4] = {};
@@ -5248,6 +5249,11 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
if (!link_ok || intel_dp->link.force_retrain)
intel_encoder_link_check_queue_work(encoder, 0);
+ if (!tries) {
+ drm_dbg_kms(&i915->drm, "DPRX ESI not clearing, device may be stuck\n");
+ reprobe_needed = true;
+ }
+
return !reprobe_needed;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 386/869] drm/i915/gt: Fix NULL deref on sched_engine alloc failure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (384 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 385/869] drm/i915/mst: limit DP MST ESI service loop Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 387/869] drm/amdkfd: Check bounds on CRIU restore queue type and mqd size Greg Kroah-Hartman
` (483 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Martin Hodo, Matthew Brost,
Daniele Ceraolo Spurio, Tvrtko Ursulin, Joonas Lahtinen,
Andi Shyti, Rodrigo Vivi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
[ Upstream commit 82ec992c404c3dc774c5e9f3d4aa858e97187675 ]
Avoid using intel_context_put() before intel_context_init() in
execlists_create_virtual() as the kref_put() inside would lead
to NULL deref on the IOCTL path when sched_engine allocation fails.
Discovered using AI-assisted static analysis confirmed by
Intel Product Security.
Reported-by: Martin Hodo <martin.hodo@intel.com>
Fixes: 3e28d37146db ("drm/i915: Move priolist to new i915_sched_engine object")
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Tvrtko Ursulin <tursulin@ursulin.net>
Cc: <stable@vger.kernel.org> # v5.15+
Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
Signed-off-by: Tvrtko Ursulin <tursulin@ursulin.net>
Link: https://lore.kernel.org/r/20260701114513.221254-1-joonas.lahtinen@linux.intel.com
(cherry picked from commit 4f2a12f2d50e9f48227656e4dcbd6423506be31d)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../drm/i915/gt/intel_execlists_submission.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
index 72090f52fb850..c8501f823991c 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
@@ -3935,11 +3935,11 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
struct drm_i915_private *i915 = siblings[0]->i915;
struct virtual_engine *ve;
unsigned int n;
- int err;
+ int err = -ENOMEM;
ve = kzalloc(struct_size(ve, siblings, count), GFP_KERNEL);
if (!ve)
- return ERR_PTR(-ENOMEM);
+ goto err;
ve->base.i915 = i915;
ve->base.gt = siblings[0]->gt;
@@ -3971,10 +3971,8 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
intel_engine_init_execlists(&ve->base);
ve->base.sched_engine = i915_sched_engine_create(ENGINE_VIRTUAL);
- if (!ve->base.sched_engine) {
- err = -ENOMEM;
- goto err_put;
- }
+ if (!ve->base.sched_engine)
+ goto err_noput;
ve->base.sched_engine->private_data = &ve->base;
ve->base.cops = &virtual_context_ops;
@@ -3990,10 +3988,8 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
intel_context_init(&ve->context, &ve->base);
ve->base.breadcrumbs = intel_breadcrumbs_create(NULL);
- if (!ve->base.breadcrumbs) {
- err = -ENOMEM;
+ if (!ve->base.breadcrumbs)
goto err_put;
- }
for (n = 0; n < count; n++) {
struct intel_engine_cs *sibling = siblings[n];
@@ -4068,8 +4064,13 @@ execlists_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
virtual_engine_initial_hint(ve);
return &ve->context;
+err_noput:
+ kfree(ve);
+ goto err;
+
err_put:
intel_context_put(&ve->context);
+err:
return ERR_PTR(err);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 387/869] drm/amdkfd: Check bounds on CRIU restore queue type and mqd size
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (385 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 386/869] drm/i915/gt: Fix NULL deref on sched_engine alloc failure Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 388/869] idpf: fix max_vport related crash on allocation error during init Greg Kroah-Hartman
` (482 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Yat Sin, David Francis,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Francis <David.Francis@amd.com>
[ Upstream commit 47ea05f246bebc81c7796f56265cffd812cf0601 ]
We weren't checking whether the values provided in the private
data in kfd CRIU restore were within bounds.
For queue type, add a KFD_QUEUE_TYPE_MAX and ensure the provided
type is less than it.
For mqd_size, add new function mqd_size_from_queue_type and confirm
that the provided mqd_size matches expectations.
Reviewed-by: David Yat Sin <david.yatsin@amd.com>
Signed-off-by: David Francis <David.Francis@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit f19d8086f6644083c913d70bfdeee20e1b6f46a5)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../drm/amd/amdkfd/kfd_device_queue_manager.c | 6 +++++
.../drm/amd/amdkfd/kfd_device_queue_manager.h | 2 ++
drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 3 ++-
.../amd/amdkfd/kfd_process_queue_manager.c | 24 +++++++++++++------
4 files changed, 27 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index d03160a463d0f..8a6c59af4a4ba 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -3575,6 +3575,12 @@ bool kfd_dqm_is_queue_in_process(struct device_queue_manager *dqm,
dqm_unlock(dqm);
return r;
}
+
+size_t mqd_size_from_queue_type(struct device_queue_manager *dqm, enum kfd_queue_type type)
+{
+ return dqm->mqd_mgrs[get_mqd_type_from_queue_type(type)]->mqd_size;
+}
+
#if defined(CONFIG_DEBUG_FS)
static void seq_reg_dump(struct seq_file *m,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
index 09ab36f8e8c69..c03b6e6fb3688 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
@@ -327,6 +327,8 @@ int debug_refresh_runlist(struct device_queue_manager *dqm);
bool kfd_dqm_is_queue_in_process(struct device_queue_manager *dqm,
struct qcm_process_device *qpd,
int doorbell_off, u32 *queue_format);
+size_t mqd_size_from_queue_type(struct device_queue_manager *dqm,
+ enum kfd_queue_type type);
static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
{
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 8f7e44afba635..939a6c92351b6 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -440,7 +440,8 @@ enum kfd_queue_type {
KFD_QUEUE_TYPE_HIQ,
KFD_QUEUE_TYPE_DIQ,
KFD_QUEUE_TYPE_SDMA_XGMI,
- KFD_QUEUE_TYPE_SDMA_BY_ENG_ID
+ KFD_QUEUE_TYPE_SDMA_BY_ENG_ID,
+ KFD_QUEUE_TYPE_MAX,
};
enum kfd_queue_format {
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index be3f821dfd566..bf3c7d055fc33 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -1015,6 +1015,23 @@ int kfd_criu_restore_queue(struct kfd_process *p,
goto exit;
}
+ pdd = kfd_process_device_data_by_id(p, q_data->gpu_id);
+ if (!pdd) {
+ pr_err("Failed to get pdd\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (q_data->type >= KFD_QUEUE_TYPE_MAX) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (q_data->mqd_size != mqd_size_from_queue_type(pdd->dev->dqm, q_data->type)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
*priv_data_offset += sizeof(*q_data);
q_extra_data_size = (uint64_t)q_data->ctl_stack_size + q_data->mqd_size;
@@ -1037,13 +1054,6 @@ int kfd_criu_restore_queue(struct kfd_process *p,
*priv_data_offset += q_extra_data_size;
- pdd = kfd_process_device_data_by_id(p, q_data->gpu_id);
- if (!pdd) {
- pr_err("Failed to get pdd\n");
- ret = -EINVAL;
- goto exit;
- }
-
/* data stored in this order: mqd, ctl_stack */
mqd = q_extra_data;
ctl_stack = mqd + q_data->mqd_size;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 388/869] idpf: fix max_vport related crash on allocation error during init
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (386 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 387/869] drm/amdkfd: Check bounds on CRIU restore queue type and mqd size Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 389/869] LoongArch: BPF: Zero-extend signed ALU32 div/mod results Greg Kroah-Hartman
` (481 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Madhu Chittim, Emil Tantilov,
Aleksandr Loktionov, Simon Horman, Samuel Salin, Tony Nguyen,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emil Tantilov <emil.s.tantilov@intel.com>
[ Upstream commit 237f1f7653b8729169af11fae79f01b90d00b87e ]
Set adapter->max_vports only after successful allocation of vports, netdevs
and vport_config buffers. This fixes possible crashes on reset or rmmod,
following failed allocation on init
[ 305.981402] idpf 0000:83:00.0: enabling device (0100 -> 0102)
[ 305.994464] idpf 0000:83:00.0: Device HW Reset initiated
[ 320.416872] BUG: kernel NULL pointer dereference, address: 0000000000000000
[ 320.416918] #PF: supervisor read access in kernel mode
[ 320.416942] #PF: error_code(0x0000) - not-present page
[ 320.416963] PGD 2099657067 P4D 0
[ 320.416983] Oops: Oops: 0000 [#1] SMP NOPTI
...
[ 320.417093] RIP: 0010:idpf_remove+0x118/0x200 [idpf]
[ 320.417130] Code: 8b bb 98 09 00 00 e8 17 0f 5b e5 48 8b bb e8 08 00 00 e8 0b 0f 5b e5 66 83 bb 28 06 00 00 00 48 8b bb 20 06 00 00 74 49 31 ed <48> 8b 04 ef 48 85 c0 74 2f 48 8b 78 20 e8 66 58 91 e5 48 8b 83 20
[ 320.417183] RSP: 0018:ff7322212903fdb8 EFLAGS: 00010246
[ 320.417205] RAX: 0000000000000000 RBX: ff4463de40300000 RCX: ff7322212903fd4c
[ 320.417228] RDX: 0000000000000001 RSI: ffffffffa7f7d100 RDI: 0000000000000000
[ 320.417250] RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000000
[ 320.417272] R10: 0000000000000001 R11: ff4463de3a638f58 R12: ff4463be89ac7000
[ 320.417294] R13: ff4463be89ac7198 R14: ff4463be94fc7198 R15: ffffffffc0f10f20
[ 320.417317] FS: 00007f963c0e6740(0000) GS:ff4463fdd65d8000(0000) knlGS:0000000000000000
[ 320.417342] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 320.417362] CR2: 0000000000000000 CR3: 00000020ba674002 CR4: 0000000000773ef0
[ 320.417385] PKRU: 55555554
[ 320.417398] Call Trace:
[ 320.417412] <TASK>
[ 320.417429] pci_device_remove+0x42/0xb0
[ 320.417459] device_release_driver_internal+0x1a9/0x210
[ 320.417492] driver_detach+0x4b/0x90
[ 320.417516] bus_remove_driver+0x70/0x100
[ 320.417539] pci_unregister_driver+0x2e/0xb0
[ 320.417564] __do_sys_delete_module.constprop.0+0x190/0x2f0
[ 320.417592] ? kmem_cache_free+0x31e/0x550
[ 320.417619] ? lockdep_hardirqs_on_prepare+0xde/0x190
[ 320.417644] ? do_syscall_64+0x38/0x6b0
[ 320.417665] do_syscall_64+0xc8/0x6b0
[ 320.417683] ? clear_bhb_loop+0x30/0x80
[ 320.417706] entry_SYSCALL_64_after_hwframe+0x76/0x7e
[ 320.417727] RIP: 0033:0x7f963bb30beb
Fixes: 0fe45467a104 ("idpf: add create vport and netdev configuration")
Reviewed-by: Madhu Chittim <madhu.chittim@intel.com>
Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Samuel Salin <Samuel.salin@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Link: https://patch.msgid.link/20260717185340.3595286-13-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 4e49e4673dd63..92cc3ba37b6d7 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -2999,7 +2999,6 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
pci_sriov_set_totalvfs(adapter->pdev, idpf_get_max_vfs(adapter));
num_max_vports = idpf_get_max_vports(adapter);
- adapter->max_vports = num_max_vports;
adapter->vports = kcalloc(num_max_vports, sizeof(*adapter->vports),
GFP_KERNEL);
if (!adapter->vports)
@@ -3022,6 +3021,12 @@ int idpf_vc_core_init(struct idpf_adapter *adapter)
goto err_netdev_alloc;
}
+ /* Set max_vports only after vports, netdevs and vport_config buffers
+ * are allocated to make sure max_vport bound loops don't end up
+ * crashing, following allocation errors on init.
+ */
+ adapter->max_vports = num_max_vports;
+
/* Start the mailbox task before requesting vectors. This will ensure
* vector information response from mailbox is handled
*/
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 389/869] LoongArch: BPF: Zero-extend signed ALU32 div/mod results
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (387 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 388/869] idpf: fix max_vport related crash on allocation error during init Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 390/869] cifs: prevent readdir from changing file size due to stale directory metadata Greg Kroah-Hartman
` (480 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Tiezhu Yang, Nicholas Dudar,
Huacai Chen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicholas Dudar <main.kalliope@gmail.com>
[ Upstream commit dacd348b8a993373576fe2ee2d8b114740ba57a6 ]
ALU32 operations write a 32-bit result and leave the upper 32 bits of
the BPF register zero. The LoongArch JIT sign-extends the result of
signed ALU32 BPF_DIV and BPF_MOD (off=1), so a negative 32-bit quotient
or remainder leaves bits 63:32 set in JITted code while the verifier
and interpreter model those bits as zero.
Keep sign-extension on the operands, which signed divide needs, and
zero-extend the ALU32 result after the divide or modulo instruction,
matching the unsigned ALU32 div/mod paths and every other ALU32
operation in this JIT.
Fixes: 2425c9e002d2 ("LoongArch: BPF: Support signed div instructions")
Fixes: 7b6b13d32965 ("LoongArch: BPF: Support signed mod instructions")
Assisted-by: Claude:claude-opus-4-8
Acked-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Tested-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/loongarch/net/bpf_jit.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
index 29a26b5e7416f..f1aaa4367fc88 100644
--- a/arch/loongarch/net/bpf_jit.c
+++ b/arch/loongarch/net/bpf_jit.c
@@ -564,7 +564,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
move_reg(ctx, t1, src);
emit_sext_32(ctx, t1, is32);
emit_insn(ctx, divd, dst, dst, t1);
- emit_sext_32(ctx, dst, is32);
+ emit_zext_32(ctx, dst, is32);
}
break;
@@ -581,7 +581,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
emit_sext_32(ctx, t1, is32);
emit_sext_32(ctx, dst, is32);
emit_insn(ctx, divd, dst, dst, t1);
- emit_sext_32(ctx, dst, is32);
+ emit_zext_32(ctx, dst, is32);
}
break;
@@ -599,7 +599,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
move_reg(ctx, t1, src);
emit_sext_32(ctx, t1, is32);
emit_insn(ctx, modd, dst, dst, t1);
- emit_sext_32(ctx, dst, is32);
+ emit_zext_32(ctx, dst, is32);
}
break;
@@ -616,7 +616,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
emit_sext_32(ctx, t1, is32);
emit_sext_32(ctx, dst, is32);
emit_insn(ctx, modd, dst, dst, t1);
- emit_sext_32(ctx, dst, is32);
+ emit_zext_32(ctx, dst, is32);
}
break;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 390/869] cifs: prevent readdir from changing file size due to stale directory metadata
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (388 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 389/869] LoongArch: BPF: Zero-extend signed ALU32 div/mod results Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 391/869] cifs: fix cifsFileInfo leak on kmalloc failure in deferred close drain paths Greg Kroah-Hartman
` (479 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Frank Sorenson, Steve French,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frank Sorenson <sorenson@redhat.com>
[ Upstream commit e8a8d54c2d508891c142a928fc7d298c4c8bd0dd ]
Windows Server's directory enumeration metadata lags behind the actual
file size after a write+close or rename. A concurrent readdir() in the
window between close() returning to userspace and stat() being called
overwrites the correct cached i_size with the stale server value, causing
stat() to return the wrong size.
Once _cifsFileInfo_put() removes the last writable handle from
openFileList, is_size_safe_to_change() permits readdir to overwrite
i_size. smb2_close_getattr() then stamps cifs_i->time = jiffies, making
the corrupt cached value appear fresh to the next stat().
The existing check (see Fixes:) only blocked stale size updates while
an active RW lease was held, not after the last writable handle closes.
Add cifsInodeInfo->time_last_write, written via smp_store_release() at
writable close and on setattr/truncate. is_size_safe_to_change() checks
is_inode_writable() first (acquiring open_file_lock), then rejects a
readdir size update if time_last_write falls within acregmax jiffies.
The spinlock release in _cifsFileInfo_put() forms a store-release barrier
that pairs with the spin_lock() (load-acquire) in is_inode_writable(),
ensuring the subsequent smp_load_acquire() on time_last_write observes
any update from a concurrent close(). When a size update is rejected and
the server value differs from the cached one, cifs_i->time is cleared to
force a fresh QUERY_INFO on the next stat().
readdir is also blocked from changing i_size while writable handles are
open or an RW lease is held, even on direct-IO mounts.
For deferred close (closetimeo > 0), time_last_write is refreshed at the
actual server close in smb2_deferred_work_close() and in the
cifs_close_deferred_file*() drain paths invoked by lease/oplock breaks
and tcon teardown, anchoring the protection window to the real close time
rather than the earlier userspace close.
time_last_write == 0 skips the time_before() check to avoid false
positives near boot on 32-bit systems where jiffies starts close to
INITIAL_JIFFIES.
Does not reproduce against Samba or with actimeo=0.
Fixes: e4b61f3b1c67 ("cifs: prevent updating file size from server if we have a read/write lease")
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Stable-dep-of: c2f2e83e3bbc ("cifs: fix cifsFileInfo leak on kmalloc failure in deferred close drain paths")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/cifsfs.c | 1 +
fs/smb/client/cifsglob.h | 1 +
fs/smb/client/file.c | 70 ++++++++++++++++++++++++++++++++++++----
fs/smb/client/inode.c | 6 ++++
fs/smb/client/misc.c | 27 ++++++++++++++--
5 files changed, 96 insertions(+), 9 deletions(-)
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 804a7e2f2c6d1..23ffe878dc3eb 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -434,6 +434,7 @@ cifs_alloc_inode(struct super_block *sb)
return NULL;
cifs_inode->cifsAttrs = 0x20; /* default */
cifs_inode->time = 0;
+ cifs_inode->time_last_write = 0;
/*
* Until the file is open and we have gotten oplock info back from the
* server, can not assume caching of file data or metadata.
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 697cdbd2d824e..0fbb3cd0daf5d 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1535,6 +1535,7 @@ struct cifsInodeInfo {
spinlock_t writers_lock;
unsigned int writers; /* Number of writers on this inode */
unsigned long time; /* jiffies of last update of inode */
+ unsigned long time_last_write; /* jiffies of last writable close or truncate */
u64 uniqueid; /* server inode number */
u64 createtime; /* creation time on server */
__u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for this inode */
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
index ee3cc2b2fda41..0728858193bce 100644
--- a/fs/smb/client/file.c
+++ b/fs/smb/client/file.c
@@ -1325,11 +1325,21 @@ void smb2_deferred_work_close(struct work_struct *work)
{
struct cifsFileInfo *cfile = container_of(work,
struct cifsFileInfo, deferred.work);
+ struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
- spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
+ spin_lock(&cinode->deferred_lock);
cifs_del_deferred_close(cfile);
cfile->deferred_close_scheduled = false;
- spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
+ spin_unlock(&cinode->deferred_lock);
+ /*
+ * Refresh time_last_write immediately before the actual server close
+ * so the protection window is anchored to the real close time, not
+ * the earlier userspace close time stored by cifs_close().
+ */
+ if (OPEN_FMODE(cfile->f_flags) & FMODE_WRITE) {
+ /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */
+ smp_store_release(&cinode->time_last_write, jiffies);
+ }
_cifsFileInfo_put(cfile, true, false);
}
@@ -1358,6 +1368,10 @@ int cifs_close(struct inode *inode, struct file *file)
if (file->private_data != NULL) {
cfile = file->private_data;
file->private_data = NULL;
+ if (file->f_mode & FMODE_WRITE) {
+ /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */
+ smp_store_release(&cinode->time_last_write, jiffies);
+ }
dclose = kmalloc(sizeof(struct cifs_deferred_close), GFP_KERNEL);
if ((cfile->status_file_deleted == false) &&
(smb2_can_defer_close(inode, dclose))) {
@@ -3046,15 +3060,27 @@ static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file,
bool from_readdir)
{
+ struct cifs_sb_info *cifs_sb;
+ unsigned long tlw;
+
if (!cifsInode)
return true;
+ cifs_sb = CIFS_SB(cifsInode->netfs.inode.i_sb);
+
if (is_inode_writable(cifsInode) ||
((cifsInode->oplock & CIFS_CACHE_RW_FLG) != 0 && from_readdir)) {
/* This inode is open for write at least once */
- struct cifs_sb_info *cifs_sb;
- cifs_sb = CIFS_SB(cifsInode->netfs.inode.i_sb);
+ /*
+ * Readdir data is unreliable when we have writable handles or
+ * an exclusive lease -- never allow it to change i_size, even
+ * on direct-IO mounts where the server's directory metadata
+ * can still lag behind the actual file state.
+ */
+ if (from_readdir)
+ return false;
+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
/* since no page cache to corrupt on directio
we can change size safely */
@@ -3065,8 +3091,40 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file,
return true;
return false;
- } else
- return true;
+ }
+
+ /*
+ * No writable handles open. Check whether we are within the attribute
+ * cache validity window of a recent local modification.
+ *
+ * For the close() path: cifs_close() calls smp_store_release() on
+ * time_last_write before _cifsFileInfo_put() removes the handle under
+ * open_file_lock. That spin_unlock() is a store-release that pairs
+ * with the spin_lock() (load-acquire) in is_inode_writable() above,
+ * so if is_inode_writable() returned false the smp_load_acquire()
+ * below is guaranteed to observe any time_last_write update from a
+ * concurrent close().
+ *
+ * For the setattr/truncate paths: those callers use smp_store_release()
+ * directly; the smp_load_acquire() below pairs with that store. There
+ * is no shared lock between setattr and readdir, so this relies on
+ * acquire-release semantics alone. The store propagation latency on
+ * weakly-ordered architectures (nanoseconds) is negligible relative to
+ * the acregmax window (seconds) and the readdir RPC round-trip
+ * (milliseconds), making this a sound design choice in practice.
+ *
+ * time_last_write == 0 means the inode has never been written locally;
+ * skip the window check to avoid false positives near boot time when
+ * jiffies is still close to INITIAL_JIFFIES on 32-bit systems.
+ */
+ if (from_readdir) {
+ /* Pairs with smp_store_release() at close and truncate sites. */
+ tlw = smp_load_acquire(&cifsInode->time_last_write);
+ if (tlw && time_before(jiffies, tlw + cifs_sb->ctx->acregmax))
+ return false;
+ }
+
+ return true;
}
void cifs_oplock_break(struct work_struct *work)
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index acb3220e5b703..db8a96e04e4d7 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -242,6 +242,8 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
* calculating num blocks.
*/
inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
+ } else if (from_readdir && i_size_read(inode) != fattr->cf_eof) {
+ cifs_i->time = 0;
}
if (S_ISLNK(fattr->cf_mode) && fattr->cf_symlink_target) {
@@ -3188,6 +3190,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
if ((attrs->ia_valid & ATTR_SIZE) &&
attrs->ia_size != i_size_read(inode)) {
+ /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */
+ smp_store_release(&cifsInode->time_last_write, jiffies);
truncate_setsize(inode, attrs->ia_size);
netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
@@ -3407,6 +3411,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if ((attrs->ia_valid & ATTR_SIZE) &&
attrs->ia_size != i_size_read(inode)) {
+ /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */
+ smp_store_release(&cifsInode->time_last_write, jiffies);
truncate_setsize(inode, attrs->ia_size);
netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c
index 5ac8faeda4f7d..edfe24392bbdc 100644
--- a/fs/smb/client/misc.c
+++ b/fs/smb/client/misc.c
@@ -798,7 +798,14 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
spin_unlock(&cifs_inode->open_file_lock);
list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
- _cifsFileInfo_put(tmp_list->cfile, false, false);
+ struct cifsFileInfo *cfile = tmp_list->cfile;
+
+ if (OPEN_FMODE(cfile->f_flags) & FMODE_WRITE) {
+ /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */
+ smp_store_release(&CIFS_I(d_inode(cfile->dentry))->time_last_write,
+ jiffies);
+ }
+ _cifsFileInfo_put(cfile, false, false);
list_del(&tmp_list->list);
kfree(tmp_list);
}
@@ -830,7 +837,14 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)
spin_unlock(&tcon->open_file_lock);
list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
- _cifsFileInfo_put(tmp_list->cfile, true, false);
+ struct cifsFileInfo *cfile = tmp_list->cfile;
+
+ if (OPEN_FMODE(cfile->f_flags) & FMODE_WRITE) {
+ /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */
+ smp_store_release(&CIFS_I(d_inode(cfile->dentry))->time_last_write,
+ jiffies);
+ }
+ _cifsFileInfo_put(cfile, true, false);
list_del(&tmp_list->list);
kfree(tmp_list);
}
@@ -899,7 +913,14 @@ void cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon,
spin_unlock(&tcon->open_file_lock);
list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
- _cifsFileInfo_put(tmp_list->cfile, true, false);
+ struct cifsFileInfo *cfile = tmp_list->cfile;
+
+ if (OPEN_FMODE(cfile->f_flags) & FMODE_WRITE) {
+ /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */
+ smp_store_release(&CIFS_I(d_inode(cfile->dentry))->time_last_write,
+ jiffies);
+ }
+ _cifsFileInfo_put(cfile, true, false);
list_del(&tmp_list->list);
kfree(tmp_list);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 391/869] cifs: fix cifsFileInfo leak on kmalloc failure in deferred close drain paths
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (389 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 390/869] cifs: prevent readdir from changing file size due to stale directory metadata Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 392/869] tipc: serialize udp bearer replicast list updates Greg Kroah-Hartman
` (478 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Frank Sorenson, Steve French,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frank Sorenson <sorenson@redhat.com>
[ Upstream commit c2f2e83e3bbc5483730fd4ee903182761f1ae50f ]
In cifs_close_deferred_file(), cifs_close_all_deferred_files(), and
cifs_close_deferred_file_under_dentry(), when a pending deferred close
is cancelled via cancel_delayed_work(), the subsequent kmalloc_obj() to
add the file to the local processing list may fail under memory pressure.
The loop breaks immediately, but the cancelled work is no longer pending
(it would have called _cifsFileInfo_put()), and the cfile is never added
to file_head for processing. The cifsFileInfo reference and the open
server handle both leak.
Fix by saving the cfile that failed allocation in a local variable,
breaking as before, and calling _cifsFileInfo_put() on it after
releasing the lock. Any files later in the iteration are unaffected
since their deferred work is still pending and will fire normally.
Fixes: e3fc065682eb ("cifs: Deferred close performance improvements")
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/misc.c | 45 ++++++++++++++++++++++++++++++++++++++------
1 file changed, 39 insertions(+), 6 deletions(-)
diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c
index edfe24392bbdc..41c1c18fb0f17 100644
--- a/fs/smb/client/misc.c
+++ b/fs/smb/client/misc.c
@@ -772,7 +772,7 @@ cifs_del_deferred_close(struct cifsFileInfo *cfile)
void
cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
{
- struct cifsFileInfo *cfile = NULL;
+ struct cifsFileInfo *cfile = NULL, *failed_cfile = NULL;
struct file_list *tmp_list, *tmp_next_list;
LIST_HEAD(file_head);
@@ -788,8 +788,10 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
spin_unlock(&cifs_inode->deferred_lock);
tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
- if (tmp_list == NULL)
+ if (tmp_list == NULL) {
+ failed_cfile = cfile;
break;
+ }
tmp_list->cfile = cfile;
list_add_tail(&tmp_list->list, &file_head);
}
@@ -797,6 +799,15 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
}
spin_unlock(&cifs_inode->open_file_lock);
+ if (failed_cfile) {
+ if (OPEN_FMODE(failed_cfile->f_flags) & FMODE_WRITE) {
+ /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */
+ smp_store_release(&CIFS_I(d_inode(failed_cfile->dentry))->time_last_write,
+ jiffies);
+ }
+ _cifsFileInfo_put(failed_cfile, false, false);
+ }
+
list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
struct cifsFileInfo *cfile = tmp_list->cfile;
@@ -814,7 +825,7 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
void
cifs_close_all_deferred_files(struct cifs_tcon *tcon)
{
- struct cifsFileInfo *cfile;
+ struct cifsFileInfo *cfile, *failed_cfile = NULL;
struct file_list *tmp_list, *tmp_next_list;
LIST_HEAD(file_head);
@@ -827,8 +838,10 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)
spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
- if (tmp_list == NULL)
+ if (tmp_list == NULL) {
+ failed_cfile = cfile;
break;
+ }
tmp_list->cfile = cfile;
list_add_tail(&tmp_list->list, &file_head);
}
@@ -836,6 +849,15 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)
}
spin_unlock(&tcon->open_file_lock);
+ if (failed_cfile) {
+ if (OPEN_FMODE(failed_cfile->f_flags) & FMODE_WRITE) {
+ /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */
+ smp_store_release(&CIFS_I(d_inode(failed_cfile->dentry))->time_last_write,
+ jiffies);
+ }
+ _cifsFileInfo_put(failed_cfile, true, false);
+ }
+
list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
struct cifsFileInfo *cfile = tmp_list->cfile;
@@ -891,7 +913,7 @@ void cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon,
struct dentry *dentry)
{
struct file_list *tmp_list, *tmp_next_list;
- struct cifsFileInfo *cfile;
+ struct cifsFileInfo *cfile, *failed_cfile = NULL;
LIST_HEAD(file_head);
spin_lock(&tcon->open_file_lock);
@@ -904,14 +926,25 @@ void cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon,
spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
- if (tmp_list == NULL)
+ if (tmp_list == NULL) {
+ failed_cfile = cfile;
break;
+ }
tmp_list->cfile = cfile;
list_add_tail(&tmp_list->list, &file_head);
}
}
spin_unlock(&tcon->open_file_lock);
+ if (failed_cfile) {
+ if (OPEN_FMODE(failed_cfile->f_flags) & FMODE_WRITE) {
+ /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */
+ smp_store_release(&CIFS_I(d_inode(failed_cfile->dentry))->time_last_write,
+ jiffies);
+ }
+ _cifsFileInfo_put(failed_cfile, true, false);
+ }
+
list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
struct cifsFileInfo *cfile = tmp_list->cfile;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 392/869] tipc: serialize udp bearer replicast list updates
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (390 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 391/869] cifs: fix cifsFileInfo leak on kmalloc failure in deferred close drain paths Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 393/869] fwctl/bnxt_en: Refactor aux bus functions to be more generic Greg Kroah-Hartman
` (477 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Xiang Mei, Tung Nguyen, Weiming Shi,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <bestswngs@gmail.com>
[ Upstream commit 350e592ff4e30e48ffb55e142d11a73e63f4869c ]
tipc_udp_rcast_add() and cleanup_bearer() both update ub->rcast.list with
list_add_rcu() / list_del_rcu(), but nothing serializes them. The add runs
from the encap receive softirq (via tipc_udp_rcast_disc()) without
rtnl_lock(), so it can race the cleanup delete and corrupt the list:
list_del corruption. prev->next should be ffff8880298d7ab8,
but was ffff88802449ad38. (prev=ffff888027e3ec98)
kernel BUG at lib/list_debug.c:62!
RIP: __list_del_entry_valid_or_report+0x17a/0x200
Workqueue: events cleanup_bearer
Call Trace:
cleanup_bearer (net/tipc/udp_media.c:811)
process_one_work (kernel/workqueue.c:3302)
worker_thread (kernel/workqueue.c:3466)
The bearer can be enabled from an unprivileged user namespace, as the
TIPCv2 generic-netlink ops carry no GENL_ADMIN_PERM.
Add a spinlock to struct udp_bearer and take it around the list_add_rcu()
in tipc_udp_rcast_add() and the list_del_rcu() loop in cleanup_bearer() so
the two writers can no longer corrupt the list.
Reject a duplicate peer under the same lock before allocating, and remove
tipc_udp_is_known_peer(). The old lockless pre-check in
tipc_udp_rcast_disc() was racy: two softirqs discovering the same peer
could both find it absent and add it twice.
cleanup_bearer() runs from a workqueue after tipc_udp_disable() clears the
bearer's up bit, so an encap softirq can still reach tipc_udp_rcast_add()
and add a peer after cleanup_bearer() has already emptied the list, leaking
that entry when the bearer is freed. Mark the bearer disabled under
rcast_lock once the list is emptied and refuse further additions.
Fixes: ef20cd4dd163 ("tipc: introduce UDP replicast")
Reported-by: Xiang Mei <xmei5@asu.edu>
Suggested-by: Tung Nguyen <tung.quang.nguyen@est.tech>
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
Reviewed-by: Tung Nguyen <tung.quang.nguyen@est.tech>
Link: https://patch.msgid.link/20260716025203.9332-2-bestswngs@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/tipc/udp_media.c | 56 +++++++++++++++++++++-----------------------
1 file changed, 27 insertions(+), 29 deletions(-)
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
index 1b8d6bbf8a8e6..2a37b274bcb95 100644
--- a/net/tipc/udp_media.c
+++ b/net/tipc/udp_media.c
@@ -94,6 +94,8 @@ struct udp_replicast {
* @ifindex: local address scope
* @work: used to schedule deferred work on a bearer
* @rcast: associated udp_replicast container
+ * @rcast_lock: serialize updates to @rcast.list against concurrent updaters
+ * @disabled: bearer is being torn down; reject further @rcast.list additions
*/
struct udp_bearer {
struct tipc_bearer __rcu *bearer;
@@ -101,6 +103,8 @@ struct udp_bearer {
u32 ifindex;
struct work_struct work;
struct udp_replicast rcast;
+ spinlock_t rcast_lock;
+ bool disabled;
};
static int tipc_udp_is_mcast_addr(struct udp_media_addr *addr)
@@ -279,26 +283,6 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
return err;
}
-static bool tipc_udp_is_known_peer(struct tipc_bearer *b,
- struct udp_media_addr *addr)
-{
- struct udp_replicast *rcast, *tmp;
- struct udp_bearer *ub;
-
- ub = rcu_dereference_rtnl(b->media_ptr);
- if (!ub) {
- pr_err_ratelimited("UDP bearer instance not found\n");
- return false;
- }
-
- list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
- if (!memcmp(&rcast->addr, addr, sizeof(struct udp_media_addr)))
- return true;
- }
-
- return false;
-}
-
static int tipc_udp_rcast_add(struct tipc_bearer *b,
struct udp_media_addr *addr)
{
@@ -309,16 +293,34 @@ static int tipc_udp_rcast_add(struct tipc_bearer *b,
if (!ub)
return -ENODEV;
+ spin_lock_bh(&ub->rcast_lock);
+ if (ub->disabled) {
+ spin_unlock_bh(&ub->rcast_lock);
+ return 0;
+ }
+ list_for_each_entry(rcast, &ub->rcast.list, list) {
+ if (!memcmp(&rcast->addr, addr, sizeof(*addr))) {
+ spin_unlock_bh(&ub->rcast_lock);
+ return 0;
+ }
+ }
+
rcast = kmalloc(sizeof(*rcast), GFP_ATOMIC);
- if (!rcast)
+ if (!rcast) {
+ spin_unlock_bh(&ub->rcast_lock);
return -ENOMEM;
+ }
if (dst_cache_init(&rcast->dst_cache, GFP_ATOMIC)) {
+ spin_unlock_bh(&ub->rcast_lock);
kfree(rcast);
return -ENOMEM;
}
memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr));
+ list_add_rcu(&rcast->list, &ub->rcast.list);
+ b->bcast_addr.broadcast = TIPC_REPLICAST_SUPPORT;
+ spin_unlock_bh(&ub->rcast_lock);
if (ntohs(addr->proto) == ETH_P_IP)
pr_info("New replicast peer: %pI4\n", &rcast->addr.ipv4);
@@ -326,8 +328,6 @@ static int tipc_udp_rcast_add(struct tipc_bearer *b,
else if (ntohs(addr->proto) == ETH_P_IPV6)
pr_info("New replicast peer: %pI6\n", &rcast->addr.ipv6);
#endif
- b->bcast_addr.broadcast = TIPC_REPLICAST_SUPPORT;
- list_add_rcu(&rcast->list, &ub->rcast.list);
return 0;
}
@@ -362,9 +362,6 @@ static int tipc_udp_rcast_disc(struct tipc_bearer *b, struct sk_buff *skb)
return 0;
}
- if (likely(tipc_udp_is_known_peer(b, &src)))
- return 0;
-
return tipc_udp_rcast_add(b, &src);
}
@@ -646,9 +643,6 @@ int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr)
return -EINVAL;
}
- if (tipc_udp_is_known_peer(b, &addr))
- return 0;
-
return tipc_udp_rcast_add(b, &addr);
}
@@ -680,6 +674,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
return -ENOMEM;
INIT_LIST_HEAD(&ub->rcast.list);
+ spin_lock_init(&ub->rcast_lock);
if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
goto err;
@@ -809,11 +804,14 @@ static void cleanup_bearer(struct work_struct *work)
struct udp_replicast *rcast, *tmp;
struct tipc_net *tn;
+ spin_lock_bh(&ub->rcast_lock);
list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
dst_cache_destroy(&rcast->dst_cache);
list_del_rcu(&rcast->list);
kfree_rcu(rcast, rcu);
}
+ ub->disabled = true;
+ spin_unlock_bh(&ub->rcast_lock);
tn = tipc_net(sock_net(ub->ubsock->sk));
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 393/869] fwctl/bnxt_en: Refactor aux bus functions to be more generic
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (391 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 392/869] tipc: serialize udp bearer replicast list updates Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 394/869] bnxt_en: Handle partially initialized auxiliary devices Greg Kroah-Hartman
` (476 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Andy Gospodarek, Leon Romanovsky,
Pavan Chebbi, Jason Gunthorpe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavan Chebbi <pavan.chebbi@broadcom.com>
[ Upstream commit 2c7c85c8c7881d57c5fa1114f4b0dbd7fc53a36f ]
Up until now there was only one auxiliary device that bnxt
created and that was for RoCE driver. bnxt fwctl is also
going to use an aux bus device that bnxt should create.
This requires some nomenclature changes and refactoring of
the existing bnxt aux dev functions.
Convert 'aux_priv' and 'edev' members of struct bnxt into
arrays where each element contains supported auxbus device's
data. Move struct bnxt_aux_priv from bnxt.h to ulp.h because
that is where it belongs. Make aux bus init/uninit/add/del
functions more generic which will loop through all the aux
device types. Make bnxt_ulp_start/stop functions (the only
other common functions applicable to any aux device) loop
through the aux devices to update their config and states.
Make callers of bnxt_ulp_start() call it only when there
are no errors.
Also, as an improvement in code, bnxt_register_dev() can skip
unnecessary dereferencing of edev from bp, instead use the
edev pointer from the function parameter.
Future patches will reuse these functions to add an aux bus
device for fwctl.
Link: https://patch.msgid.link/r/20260314151605.932749-3-pavan.chebbi@broadcom.com
Reviewed-by: Andy Gospodarek <gospo@broadcom.com>
Reviewed-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Stable-dep-of: 1cb8553c02e9 ("bnxt_en: Handle partially initialized auxiliary devices")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 47 ++-
drivers/net/ethernet/broadcom/bnxt/bnxt.h | 19 +-
.../net/ethernet/broadcom/bnxt/bnxt_devlink.c | 8 +-
.../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +-
drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 336 +++++++++++-------
drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h | 25 +-
6 files changed, 272 insertions(+), 165 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 867be7b4142b2..4749119180c4b 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -6674,7 +6674,8 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic)
#endif
if ((bp->flags & BNXT_FLAG_STRIP_VLAN) || def_vlan)
req->flags |= cpu_to_le32(VNIC_CFG_REQ_FLAGS_VLAN_STRIP_MODE);
- if (vnic->vnic_id == BNXT_VNIC_DEFAULT && bnxt_ulp_registered(bp->edev))
+ if (vnic->vnic_id == BNXT_VNIC_DEFAULT &&
+ bnxt_ulp_registered(bp->edev[BNXT_AUXDEV_RDMA]))
req->flags |= cpu_to_le32(bnxt_get_roce_vnic_mode(bp));
return hwrm_req_send(bp, req);
@@ -7758,6 +7759,7 @@ static int bnxt_get_avail_msix(struct bnxt *bp, int num);
static int __bnxt_reserve_rings(struct bnxt *bp)
{
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
struct bnxt_hw_rings hwr = {0};
int rx_rings, old_rx_rings, rc;
int cp = bp->cp_nr_rings;
@@ -7768,7 +7770,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
if (!bnxt_need_reserve_rings(bp))
return 0;
- if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(bp->edev)) {
+ if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(edev)) {
ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
if (!ulp_msix)
bnxt_set_ulp_stat_ctxs(bp, 0);
@@ -7821,8 +7823,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
}
rx_rings = min_t(int, rx_rings, hwr.grp);
hwr.cp = min_t(int, hwr.cp, bp->cp_nr_rings);
- if (bnxt_ulp_registered(bp->edev) &&
- hwr.stat > bnxt_get_ulp_stat_ctxs(bp))
+ if (bnxt_ulp_registered(edev) && hwr.stat > bnxt_get_ulp_stat_ctxs(bp))
hwr.stat -= bnxt_get_ulp_stat_ctxs(bp);
hwr.cp = min_t(int, hwr.cp, hwr.stat);
rc = bnxt_trim_rings(bp, &rx_rings, &hwr.tx, hwr.cp, sh);
@@ -7861,7 +7862,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
!netif_is_rxfh_configured(bp->dev))
bnxt_set_dflt_rss_indir_tbl(bp, NULL);
- if (!bnxt_ulp_registered(bp->edev) && BNXT_NEW_RM(bp)) {
+ if (!bnxt_ulp_registered(edev) && BNXT_NEW_RM(bp)) {
int resv_msix, resv_ctx, ulp_ctxs;
struct bnxt_hw_resc *hw_resc;
@@ -11099,6 +11100,7 @@ static void bnxt_clear_int_mode(struct bnxt *bp)
int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
{
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
bool irq_cleared = false;
bool irq_change = false;
int tcs = bp->num_tc;
@@ -11108,7 +11110,7 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
if (!bnxt_need_reserve_rings(bp))
return 0;
- if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(bp->edev)) {
+ if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(edev)) {
int ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
if (ulp_msix > bp->ulp_num_msix_want)
@@ -13997,7 +13999,7 @@ static void bnxt_fw_echo_reply(struct bnxt *bp)
static void bnxt_ulp_restart(struct bnxt *bp)
{
bnxt_ulp_stop(bp);
- bnxt_ulp_start(bp, 0);
+ bnxt_ulp_start(bp);
}
static void bnxt_sp_task(struct work_struct *work)
@@ -14157,7 +14159,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
hwr.cp_p5 = hwr.tx + rx;
rc = bnxt_hwrm_check_rings(bp, &hwr);
if (!rc && pci_msix_can_alloc_dyn(bp->pdev)) {
- if (!bnxt_ulp_registered(bp->edev)) {
+ if (!bnxt_ulp_registered(bp->edev[BNXT_AUXDEV_RDMA])) {
hwr.cp += bnxt_get_ulp_msix_num(bp);
hwr.cp = min_t(int, hwr.cp, bnxt_get_max_func_irqs(bp));
}
@@ -14659,7 +14661,7 @@ static void bnxt_fw_reset_task(struct work_struct *work)
bnxt_dl_health_fw_status_update(bp, true);
}
rtnl_unlock();
- bnxt_ulp_start(bp, 0);
+ bnxt_ulp_start(bp);
bnxt_reenable_sriov(bp);
rtnl_lock();
bnxt_vf_reps_alloc(bp);
@@ -14681,7 +14683,8 @@ static void bnxt_fw_reset_task(struct work_struct *work)
bnxt_fw_reset_abort(bp, rc);
rtnl_unlock();
ulp_start:
- bnxt_ulp_start(bp, rc);
+ if (!rc)
+ bnxt_ulp_start(bp);
}
static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev)
@@ -15654,12 +15657,13 @@ static void bnxt_remove_one(struct pci_dev *pdev)
if (BNXT_PF(bp))
bnxt_sriov_disable(bp);
- bnxt_rdma_aux_device_del(bp);
+ bnxt_aux_devices_del(bp);
unregister_netdev(dev);
bnxt_ptp_clear(bp);
- bnxt_rdma_aux_device_uninit(bp);
+ bnxt_aux_devices_uninit(bp);
+ bnxt_auxdev_id_free(bp, bp->auxdev_id);
bnxt_free_l2_filters(bp, true);
bnxt_free_ntp_fltrs(bp, true);
@@ -16283,7 +16287,9 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
__bnxt_set_rx_skb_mode(bp, false);
bnxt_set_tpa_flags(bp);
bnxt_set_ring_params(bp);
- bnxt_rdma_aux_device_init(bp);
+ mutex_init(&bp->auxdev_lock);
+ if (!bnxt_auxdev_id_alloc(bp))
+ bnxt_aux_devices_init(bp);
rc = bnxt_set_dflt_rings(bp, true);
if (rc) {
if (BNXT_VF(bp) && rc == -ENODEV) {
@@ -16345,7 +16351,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
bnxt_dl_fw_reporters_create(bp);
- bnxt_rdma_aux_device_add(bp);
+ bnxt_aux_devices_add(bp);
bnxt_print_device_info(bp);
@@ -16353,7 +16359,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
init_err_cleanup:
- bnxt_rdma_aux_device_uninit(bp);
+ bnxt_aux_devices_uninit(bp);
+ bnxt_auxdev_id_free(bp, bp->auxdev_id);
bnxt_dl_unregister(bp);
init_err_dl:
bnxt_shutdown_tc(bp);
@@ -16481,9 +16488,10 @@ static int bnxt_resume(struct device *device)
resume_exit:
rtnl_unlock();
- bnxt_ulp_start(bp, rc);
- if (!rc)
+ if (!rc) {
+ bnxt_ulp_start(bp);
bnxt_reenable_sriov(bp);
+ }
return rc;
}
@@ -16657,9 +16665,10 @@ static void bnxt_io_resume(struct pci_dev *pdev)
netif_device_attach(netdev);
rtnl_unlock();
- bnxt_ulp_start(bp, err);
- if (!err)
+ if (!err) {
+ bnxt_ulp_start(bp);
bnxt_reenable_sriov(bp);
+ }
}
static const struct pci_error_handlers bnxt_err_handler = {
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index c10f8ad8bfbd4..105945aa3ffcc 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -24,12 +24,12 @@
#include <linux/interrupt.h>
#include <linux/rhashtable.h>
#include <linux/crash_dump.h>
-#include <linux/auxiliary_bus.h>
#include <net/devlink.h>
#include <net/dst_metadata.h>
#include <net/xdp.h>
#include <linux/dim.h>
#include <linux/io-64-nonatomic-lo-hi.h>
+#include "bnxt_ulp.h"
#ifdef CONFIG_TEE_BNXT_FW
#include <linux/firmware/broadcom/tee_bnxt_fw.h>
#endif
@@ -2049,12 +2049,6 @@ struct bnxt_fw_health {
#define BNXT_FW_IF_RETRY 10
#define BNXT_FW_SLOT_RESET_RETRY 4
-struct bnxt_aux_priv {
- struct auxiliary_device aux_dev;
- struct bnxt_en_dev *edev;
- int id;
-};
-
enum board_idx {
BCM57301,
BCM57302,
@@ -2288,8 +2282,8 @@ struct bnxt {
#define BNXT_CHIP_P5_AND_MINUS(bp) \
(BNXT_CHIP_P3(bp) || BNXT_CHIP_P4(bp) || BNXT_CHIP_P5(bp))
- struct bnxt_aux_priv *aux_priv;
- struct bnxt_en_dev *edev;
+ struct bnxt_aux_priv *aux_priv[__BNXT_AUXDEV_MAX];
+ struct bnxt_en_dev *edev[__BNXT_AUXDEV_MAX];
struct bnxt_napi **bnapi;
@@ -2669,6 +2663,13 @@ struct bnxt {
struct bnxt_ctx_pg_info *fw_crash_mem;
u32 fw_crash_len;
+ int auxdev_id;
+ /* synchronize validity checks of available aux devices */
+ struct mutex auxdev_lock;
+ u8 auxdev_state[__BNXT_AUXDEV_MAX];
+#define BNXT_ADEV_STATE_NONE 0
+#define BNXT_ADEV_STATE_INIT 1
+#define BNXT_ADEV_STATE_ADD 2
};
#define BNXT_NUM_RX_RING_STATS 8
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
index 901fd36757ed6..06d3fd9ad7a42 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
@@ -443,12 +443,12 @@ static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change,
NL_SET_ERR_MSG_MOD(extack,
"reload is unsupported while VFs are allocated or being configured");
rtnl_unlock();
- bnxt_ulp_start(bp, 0);
+ bnxt_ulp_start(bp);
return -EOPNOTSUPP;
}
if (bp->dev->reg_state == NETREG_UNREGISTERED) {
rtnl_unlock();
- bnxt_ulp_start(bp, 0);
+ bnxt_ulp_start(bp);
return -ENODEV;
}
if (netif_running(bp->dev))
@@ -571,8 +571,8 @@ static int bnxt_dl_reload_up(struct devlink *dl, enum devlink_reload_action acti
dev_close(bp->dev);
}
rtnl_unlock();
- if (action == DEVLINK_RELOAD_ACTION_DRIVER_REINIT)
- bnxt_ulp_start(bp, rc);
+ if (!rc && action == DEVLINK_RELOAD_ACTION_DRIVER_REINIT)
+ bnxt_ulp_start(bp);
return rc;
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index d883e2e57da09..5bedd6bd5f30b 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -4871,7 +4871,7 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,
memset(buf, 0, sizeof(u64) * bp->num_tests);
if (etest->flags & ETH_TEST_FL_OFFLINE &&
- bnxt_ulp_registered(bp->edev)) {
+ bnxt_ulp_registered(bp->edev[BNXT_AUXDEV_RDMA])) {
etest->flags |= ETH_TEST_FL_FAILED;
netdev_warn(dev, "Offline tests cannot be run with RoCE driver loaded\n");
return;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
index 1867552a8bdbe..3896007b87644 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
@@ -28,9 +28,32 @@
static DEFINE_IDA(bnxt_aux_dev_ids);
+struct bnxt_aux_device {
+ const char *name;
+};
+
+static void bnxt_auxdev_set_state(struct bnxt *bp, int idx, int state)
+{
+ bp->auxdev_state[idx] = state;
+}
+
+static bool bnxt_auxdev_is_init(struct bnxt *bp, int idx)
+{
+ return (bp->auxdev_state[idx] == BNXT_ADEV_STATE_INIT);
+}
+
+static bool bnxt_auxdev_is_active(struct bnxt *bp, int idx)
+{
+ return (bp->auxdev_state[idx] == BNXT_ADEV_STATE_ADD);
+}
+
+static struct bnxt_aux_device bnxt_aux_devices[__BNXT_AUXDEV_MAX] = {{
+ .name = "rdma",
+}};
+
static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent)
{
- struct bnxt_en_dev *edev = bp->edev;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
int num_msix, i;
if (!edev->ulp_tbl->msix_requested) {
@@ -50,55 +73,69 @@ static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent)
int bnxt_get_ulp_msix_num(struct bnxt *bp)
{
- if (bp->edev)
- return bp->edev->ulp_num_msix_vec;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (edev)
+ return edev->ulp_num_msix_vec;
return 0;
}
void bnxt_set_ulp_msix_num(struct bnxt *bp, int num)
{
- if (bp->edev)
- bp->edev->ulp_num_msix_vec = num;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (edev)
+ edev->ulp_num_msix_vec = num;
}
int bnxt_get_ulp_msix_num_in_use(struct bnxt *bp)
{
- if (bnxt_ulp_registered(bp->edev))
- return bp->edev->ulp_num_msix_vec;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (bnxt_ulp_registered(edev))
+ return edev->ulp_num_msix_vec;
return 0;
}
int bnxt_get_ulp_stat_ctxs(struct bnxt *bp)
{
- if (bp->edev)
- return bp->edev->ulp_num_ctxs;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (edev)
+ return edev->ulp_num_ctxs;
return 0;
}
void bnxt_set_ulp_stat_ctxs(struct bnxt *bp, int num_ulp_ctx)
{
- if (bp->edev)
- bp->edev->ulp_num_ctxs = num_ulp_ctx;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (edev)
+ edev->ulp_num_ctxs = num_ulp_ctx;
}
int bnxt_get_ulp_stat_ctxs_in_use(struct bnxt *bp)
{
- if (bnxt_ulp_registered(bp->edev))
- return bp->edev->ulp_num_ctxs;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (bnxt_ulp_registered(edev))
+ return edev->ulp_num_ctxs;
return 0;
}
void bnxt_set_dflt_ulp_stat_ctxs(struct bnxt *bp)
{
- if (bp->edev) {
- bp->edev->ulp_num_ctxs = BNXT_MIN_ROCE_STAT_CTXS;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (edev) {
+ edev->ulp_num_ctxs = BNXT_MIN_ROCE_STAT_CTXS;
/* Reserve one additional stat_ctx for PF0 (except
* on 1-port NICs) as it also creates one stat_ctx
* for PF1 in case of RoCE bonding.
*/
if (BNXT_PF(bp) && !bp->pf.port_id &&
bp->port_count > 1)
- bp->edev->ulp_num_ctxs++;
+ edev->ulp_num_ctxs++;
}
}
@@ -134,7 +171,7 @@ int bnxt_register_dev(struct bnxt_en_dev *edev,
edev->ulp_tbl->msix_requested = bnxt_get_ulp_msix_num(bp);
- bnxt_fill_msix_vecs(bp, bp->edev->msix_entries);
+ bnxt_fill_msix_vecs(bp, edev->msix_entries);
edev->flags |= BNXT_EN_FLAG_MSIX_REQUESTED;
exit:
mutex_unlock(&edev->en_dev_lock);
@@ -223,20 +260,27 @@ EXPORT_SYMBOL(bnxt_send_msg);
void bnxt_ulp_stop(struct bnxt *bp)
{
- struct bnxt_aux_priv *aux_priv = bp->aux_priv;
- struct bnxt_en_dev *edev = bp->edev;
-
- if (!edev)
- return;
-
- mutex_lock(&edev->en_dev_lock);
- if (!bnxt_ulp_registered(edev) ||
- (edev->flags & BNXT_EN_FLAG_ULP_STOPPED))
- goto ulp_stop_exit;
+ int i;
- edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
- if (aux_priv) {
+ mutex_lock(&bp->auxdev_lock);
+ for (i = 0; i < __BNXT_AUXDEV_MAX; i++) {
+ struct bnxt_aux_priv *aux_priv;
struct auxiliary_device *adev;
+ struct bnxt_en_dev *edev;
+
+ if (!bnxt_auxdev_is_active(bp, i))
+ continue;
+
+ aux_priv = bp->aux_priv[i];
+ edev = bp->edev[i];
+ mutex_lock(&edev->en_dev_lock);
+ if (!bnxt_ulp_registered(edev) ||
+ (edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) {
+ mutex_unlock(&edev->en_dev_lock);
+ continue;
+ }
+
+ edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
adev = &aux_priv->aux_dev;
if (adev->dev.driver) {
@@ -247,29 +291,35 @@ void bnxt_ulp_stop(struct bnxt *bp)
edev->en_state = bp->state;
adrv->suspend(adev, pm);
}
+ mutex_unlock(&edev->en_dev_lock);
}
-ulp_stop_exit:
- mutex_unlock(&edev->en_dev_lock);
+ mutex_unlock(&bp->auxdev_lock);
}
-void bnxt_ulp_start(struct bnxt *bp, int err)
+void bnxt_ulp_start(struct bnxt *bp)
{
- struct bnxt_aux_priv *aux_priv = bp->aux_priv;
- struct bnxt_en_dev *edev = bp->edev;
+ int i;
- if (!edev || err)
- return;
+ mutex_lock(&bp->auxdev_lock);
+ for (i = 0; i < __BNXT_AUXDEV_MAX; i++) {
+ struct bnxt_aux_priv *aux_priv;
+ struct auxiliary_device *adev;
+ struct bnxt_en_dev *edev;
- mutex_lock(&edev->en_dev_lock);
- if (!bnxt_ulp_registered(edev) ||
- !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED))
- goto ulp_start_exit;
+ if (!bnxt_auxdev_is_active(bp, i))
+ continue;
- if (edev->ulp_tbl->msix_requested)
- bnxt_fill_msix_vecs(bp, edev->msix_entries);
+ aux_priv = bp->aux_priv[i];
+ edev = bp->edev[i];
+ mutex_lock(&edev->en_dev_lock);
+ if (!bnxt_ulp_registered(edev) ||
+ !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) {
+ goto clear_flag_continue;
+ }
+
+ if (edev->ulp_tbl->msix_requested)
+ bnxt_fill_msix_vecs(bp, edev->msix_entries);
- if (aux_priv) {
- struct auxiliary_device *adev;
adev = &aux_priv->aux_dev;
if (adev->dev.driver) {
@@ -279,21 +329,22 @@ void bnxt_ulp_start(struct bnxt *bp, int err)
edev->en_state = bp->state;
adrv->resume(adev);
}
+clear_flag_continue:
+ edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
+ mutex_unlock(&edev->en_dev_lock);
}
-ulp_start_exit:
- edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
- mutex_unlock(&edev->en_dev_lock);
+ mutex_unlock(&bp->auxdev_lock);
}
void bnxt_ulp_irq_stop(struct bnxt *bp)
{
- struct bnxt_en_dev *edev = bp->edev;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
struct bnxt_ulp_ops *ops;
if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
return;
- if (bnxt_ulp_registered(bp->edev)) {
+ if (bnxt_ulp_registered(edev)) {
struct bnxt_ulp *ulp = edev->ulp_tbl;
if (!ulp->msix_requested)
@@ -308,13 +359,13 @@ void bnxt_ulp_irq_stop(struct bnxt *bp)
void bnxt_ulp_irq_restart(struct bnxt *bp, int err)
{
- struct bnxt_en_dev *edev = bp->edev;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
struct bnxt_ulp_ops *ops;
if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
return;
- if (bnxt_ulp_registered(bp->edev)) {
+ if (bnxt_ulp_registered(edev)) {
struct bnxt_ulp *ulp = edev->ulp_tbl;
struct bnxt_msix_entry *ent = NULL;
@@ -355,18 +406,21 @@ int bnxt_register_async_events(struct bnxt_en_dev *edev,
}
EXPORT_SYMBOL(bnxt_register_async_events);
-void bnxt_rdma_aux_device_uninit(struct bnxt *bp)
+void bnxt_aux_devices_uninit(struct bnxt *bp)
{
struct bnxt_aux_priv *aux_priv;
struct auxiliary_device *adev;
-
- /* Skip if no auxiliary device init was done. */
- if (!bp->aux_priv)
- return;
-
- aux_priv = bp->aux_priv;
- adev = &aux_priv->aux_dev;
- auxiliary_device_uninit(adev);
+ int idx;
+
+ mutex_lock(&bp->auxdev_lock);
+ for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) {
+ if (bnxt_auxdev_is_init(bp, idx)) {
+ aux_priv = bp->aux_priv[idx];
+ adev = &aux_priv->aux_dev;
+ auxiliary_device_uninit(adev);
+ }
+ }
+ mutex_unlock(&bp->auxdev_lock);
}
static void bnxt_aux_dev_release(struct device *dev)
@@ -375,20 +429,25 @@ static void bnxt_aux_dev_release(struct device *dev)
container_of(dev, struct bnxt_aux_priv, aux_dev.dev);
struct bnxt *bp = netdev_priv(aux_priv->edev->net);
- ida_free(&bnxt_aux_dev_ids, aux_priv->id);
kfree(aux_priv->edev->ulp_tbl);
- bp->edev = NULL;
+ bp->edev[aux_priv->id] = NULL;
kfree(aux_priv->edev);
+ bp->aux_priv[aux_priv->id] = NULL;
kfree(aux_priv);
- bp->aux_priv = NULL;
}
-void bnxt_rdma_aux_device_del(struct bnxt *bp)
+void bnxt_aux_devices_del(struct bnxt *bp)
{
- if (!bp->edev)
- return;
+ int idx;
- auxiliary_device_delete(&bp->aux_priv->aux_dev);
+ mutex_lock(&bp->auxdev_lock);
+ for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) {
+ if (bnxt_auxdev_is_active(bp, idx)) {
+ auxiliary_device_delete(&bp->aux_priv[idx]->aux_dev);
+ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_INIT);
+ }
+ }
+ mutex_unlock(&bp->auxdev_lock);
}
static void bnxt_set_edev_info(struct bnxt_en_dev *edev, struct bnxt *bp)
@@ -414,83 +473,106 @@ static void bnxt_set_edev_info(struct bnxt_en_dev *edev, struct bnxt *bp)
edev->bar0 = bp->bar0;
}
-void bnxt_rdma_aux_device_add(struct bnxt *bp)
+void bnxt_aux_devices_add(struct bnxt *bp)
{
struct auxiliary_device *aux_dev;
- int rc;
-
- if (!bp->edev)
- return;
-
- aux_dev = &bp->aux_priv->aux_dev;
- rc = auxiliary_device_add(aux_dev);
- if (rc) {
- netdev_warn(bp->dev, "Failed to add auxiliary device for ROCE\n");
- auxiliary_device_uninit(aux_dev);
- bp->flags &= ~BNXT_FLAG_ROCE_CAP;
+ int rc, idx;
+
+ mutex_lock(&bp->auxdev_lock);
+ for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) {
+ if (bnxt_auxdev_is_init(bp, idx)) {
+ aux_dev = &bp->aux_priv[idx]->aux_dev;
+ rc = auxiliary_device_add(aux_dev);
+ if (rc) {
+ netdev_warn(bp->dev, "Failed to add auxiliary device for ROCE\n");
+ auxiliary_device_uninit(aux_dev);
+ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_NONE);
+ if (idx == BNXT_AUXDEV_RDMA)
+ bp->flags &= ~BNXT_FLAG_ROCE_CAP;
+ continue;
+ }
+ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_ADD);
+ }
}
+ mutex_unlock(&bp->auxdev_lock);
}
-void bnxt_rdma_aux_device_init(struct bnxt *bp)
+void bnxt_aux_devices_init(struct bnxt *bp)
{
struct auxiliary_device *aux_dev;
struct bnxt_aux_priv *aux_priv;
struct bnxt_en_dev *edev;
struct bnxt_ulp *ulp;
- int rc;
+ int rc, idx;
+
+ mutex_lock(&bp->auxdev_lock);
+ for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) {
+ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_NONE);
+
+ if (idx == BNXT_AUXDEV_RDMA &&
+ !(bp->flags & BNXT_FLAG_ROCE_CAP))
+ continue;
+
+ aux_priv = kzalloc_obj(*aux_priv);
+ if (!aux_priv)
+ goto next_auxdev;
+
+ aux_dev = &aux_priv->aux_dev;
+ aux_dev->id = bp->auxdev_id;
+ aux_dev->name = bnxt_aux_devices[idx].name;
+ aux_dev->dev.parent = &bp->pdev->dev;
+ aux_dev->dev.release = bnxt_aux_dev_release;
+
+ rc = auxiliary_device_init(aux_dev);
+ if (rc) {
+ kfree(aux_priv);
+ goto next_auxdev;
+ }
+ bp->aux_priv[idx] = aux_priv;
- if (!(bp->flags & BNXT_FLAG_ROCE_CAP))
- return;
+ /* From this point, all cleanup will happen via the .release
+ * callback & any error unwinding will need to include a call
+ * to auxiliary_device_uninit.
+ */
+ edev = kzalloc_obj(*edev);
+ if (!edev)
+ goto aux_dev_uninit;
- aux_priv = kzalloc(sizeof(*bp->aux_priv), GFP_KERNEL);
- if (!aux_priv)
- goto exit;
+ aux_priv->edev = edev;
+ bnxt_set_edev_info(edev, bp);
- aux_priv->id = ida_alloc(&bnxt_aux_dev_ids, GFP_KERNEL);
- if (aux_priv->id < 0) {
- netdev_warn(bp->dev,
- "ida alloc failed for ROCE auxiliary device\n");
- kfree(aux_priv);
- goto exit;
- }
+ ulp = kzalloc_obj(*ulp);
+ if (!ulp)
+ goto aux_dev_uninit;
- aux_dev = &aux_priv->aux_dev;
- aux_dev->id = aux_priv->id;
- aux_dev->name = "rdma";
- aux_dev->dev.parent = &bp->pdev->dev;
- aux_dev->dev.release = bnxt_aux_dev_release;
+ edev->ulp_tbl = ulp;
+ bp->edev[idx] = edev;
+ if (idx == BNXT_AUXDEV_RDMA)
+ bp->ulp_num_msix_want = bnxt_set_dflt_ulp_msix(bp);
+ aux_priv->id = idx;
+ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_INIT);
- rc = auxiliary_device_init(aux_dev);
- if (rc) {
- ida_free(&bnxt_aux_dev_ids, aux_priv->id);
- kfree(aux_priv);
- goto exit;
+ continue;
+aux_dev_uninit:
+ auxiliary_device_uninit(aux_dev);
+next_auxdev:
+ if (idx == BNXT_AUXDEV_RDMA)
+ bp->flags &= ~BNXT_FLAG_ROCE_CAP;
}
- bp->aux_priv = aux_priv;
-
- /* From this point, all cleanup will happen via the .release callback &
- * any error unwinding will need to include a call to
- * auxiliary_device_uninit.
- */
- edev = kzalloc(sizeof(*edev), GFP_KERNEL);
- if (!edev)
- goto aux_dev_uninit;
-
- aux_priv->edev = edev;
-
- ulp = kzalloc(sizeof(*ulp), GFP_KERNEL);
- if (!ulp)
- goto aux_dev_uninit;
+ mutex_unlock(&bp->auxdev_lock);
+}
- edev->ulp_tbl = ulp;
- bp->edev = edev;
- bnxt_set_edev_info(edev, bp);
- bp->ulp_num_msix_want = bnxt_set_dflt_ulp_msix(bp);
+int bnxt_auxdev_id_alloc(struct bnxt *bp)
+{
+ bp->auxdev_id = ida_alloc(&bnxt_aux_dev_ids, GFP_KERNEL);
+ if (bp->auxdev_id < 0)
+ return bp->auxdev_id;
- return;
+ return 0;
+}
-aux_dev_uninit:
- auxiliary_device_uninit(aux_dev);
-exit:
- bp->flags &= ~BNXT_FLAG_ROCE_CAP;
+void bnxt_auxdev_id_free(struct bnxt *bp, int id)
+{
+ if (bp->auxdev_id >= 0)
+ ida_free(&bnxt_aux_dev_ids, id);
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h
index b76a231ca7dac..6e1f26c8c0571 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h
@@ -10,6 +10,8 @@
#ifndef BNXT_ULP_H
#define BNXT_ULP_H
+#include <linux/auxiliary_bus.h>
+
#define BNXT_ROCE_ULP 0
#define BNXT_MAX_ULP 1
@@ -23,6 +25,17 @@
struct hwrm_async_event_cmpl;
struct bnxt;
+enum bnxt_auxdev_type {
+ BNXT_AUXDEV_RDMA = 0,
+ __BNXT_AUXDEV_MAX
+};
+
+struct bnxt_aux_priv {
+ struct auxiliary_device aux_dev;
+ struct bnxt_en_dev *edev;
+ int id;
+};
+
struct bnxt_msix_entry {
u32 vector;
u32 ring_idx;
@@ -109,19 +122,21 @@ void bnxt_set_ulp_stat_ctxs(struct bnxt *bp, int num_ctxs);
int bnxt_get_ulp_stat_ctxs_in_use(struct bnxt *bp);
void bnxt_set_dflt_ulp_stat_ctxs(struct bnxt *bp);
void bnxt_ulp_stop(struct bnxt *bp);
-void bnxt_ulp_start(struct bnxt *bp, int err);
+void bnxt_ulp_start(struct bnxt *bp);
void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs);
void bnxt_ulp_irq_stop(struct bnxt *bp);
void bnxt_ulp_irq_restart(struct bnxt *bp, int err);
void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl);
-void bnxt_rdma_aux_device_uninit(struct bnxt *bp);
-void bnxt_rdma_aux_device_del(struct bnxt *bp);
-void bnxt_rdma_aux_device_add(struct bnxt *bp);
-void bnxt_rdma_aux_device_init(struct bnxt *bp);
+void bnxt_aux_devices_uninit(struct bnxt *bp);
+void bnxt_aux_devices_del(struct bnxt *bp);
+void bnxt_aux_devices_add(struct bnxt *bp);
+void bnxt_aux_devices_init(struct bnxt *bp);
int bnxt_register_dev(struct bnxt_en_dev *edev, struct bnxt_ulp_ops *ulp_ops,
void *handle);
void bnxt_unregister_dev(struct bnxt_en_dev *edev);
int bnxt_send_msg(struct bnxt_en_dev *edev, struct bnxt_fw_msg *fw_msg);
int bnxt_register_async_events(struct bnxt_en_dev *edev,
unsigned long *events_bmap, u16 max_id);
+int bnxt_auxdev_id_alloc(struct bnxt *bp);
+void bnxt_auxdev_id_free(struct bnxt *bp, int id);
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 394/869] bnxt_en: Handle partially initialized auxiliary devices
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (392 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 393/869] fwctl/bnxt_en: Refactor aux bus functions to be more generic Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 395/869] drm/xe/guc: Keep scheduler timeline name alive Greg Kroah-Hartman
` (475 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ruoyu Wang, Pavan Chebbi,
Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <ruoyuw560@gmail.com>
[ Upstream commit 1cb8553c02e93e5a150cebd42f9ee3db0ece4707 ]
bnxt_aux_devices_init() calls auxiliary_device_init() before all fields
used by bnxt_aux_dev_release() are initialized. After
auxiliary_device_init() succeeds, later errors must unwind with
auxiliary_device_uninit(), which invokes the release callback.
The release callback assumes that aux_priv->id, aux_priv->edev,
edev->net and edev->ulp_tbl are all populated. If allocation fails
after auxiliary_device_init(), the release path can otherwise dereference
or clear partially initialized state.
Allocate and attach the bnxt_en_dev and ULP table before calling
auxiliary_device_init(), so the release callback only sees a fully
initialized auxiliary private object. If auxiliary_device_init() itself
fails, free those allocations directly because device_initialize() has not
run and the release callback will not be invoked.
This issue was found by a static analysis checker and confirmed by manual
source review.
Fixes: 194fad5b2781 ("bnxt_en: Refactor bnxt_rdma_aux_device_init/uninit functions")
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Link: https://patch.msgid.link/20260711163716.3996929-1-ruoyuw560@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 39 ++++++++++---------
1 file changed, 20 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
index 3896007b87644..d806724a45f66 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
@@ -517,6 +517,18 @@ void bnxt_aux_devices_init(struct bnxt *bp)
if (!aux_priv)
goto next_auxdev;
+ edev = kzalloc_obj(*edev);
+ if (!edev)
+ goto aux_priv_free;
+ aux_priv->edev = edev;
+ bnxt_set_edev_info(edev, bp);
+
+ ulp = kzalloc_obj(*ulp);
+ if (!ulp)
+ goto edev_free;
+ edev->ulp_tbl = ulp;
+ aux_priv->id = idx;
+
aux_dev = &aux_priv->aux_dev;
aux_dev->id = bp->auxdev_id;
aux_dev->name = bnxt_aux_devices[idx].name;
@@ -524,37 +536,26 @@ void bnxt_aux_devices_init(struct bnxt *bp)
aux_dev->dev.release = bnxt_aux_dev_release;
rc = auxiliary_device_init(aux_dev);
- if (rc) {
- kfree(aux_priv);
- goto next_auxdev;
- }
+ if (rc)
+ goto ulp_free;
bp->aux_priv[idx] = aux_priv;
/* From this point, all cleanup will happen via the .release
* callback & any error unwinding will need to include a call
* to auxiliary_device_uninit.
*/
- edev = kzalloc_obj(*edev);
- if (!edev)
- goto aux_dev_uninit;
-
- aux_priv->edev = edev;
- bnxt_set_edev_info(edev, bp);
-
- ulp = kzalloc_obj(*ulp);
- if (!ulp)
- goto aux_dev_uninit;
-
- edev->ulp_tbl = ulp;
bp->edev[idx] = edev;
if (idx == BNXT_AUXDEV_RDMA)
bp->ulp_num_msix_want = bnxt_set_dflt_ulp_msix(bp);
- aux_priv->id = idx;
bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_INIT);
continue;
-aux_dev_uninit:
- auxiliary_device_uninit(aux_dev);
+ulp_free:
+ kfree(ulp);
+edev_free:
+ kfree(edev);
+aux_priv_free:
+ kfree(aux_priv);
next_auxdev:
if (idx == BNXT_AUXDEV_RDMA)
bp->flags &= ~BNXT_FLAG_ROCE_CAP;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 395/869] drm/xe/guc: Keep scheduler timeline name alive
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (393 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 394/869] bnxt_en: Handle partially initialized auxiliary devices Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 396/869] Bluetooth: hci_sync: extend conn_hash lookup critical sections Greg Kroah-Hartman
` (474 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Thomas Hellström, Rodrigo Vivi,
Himal Prasad Ghimiray, Matthew Brost, Arvind Yadav,
Tvrtko Ursulin, Tejas Upadhyay, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arvind Yadav <arvind.yadav@intel.com>
[ Upstream commit 299bc6d50b1bed7d1f408391736712f01a0855e2 ]
The scheduler keeps a pointer to the timeline name, but q->name
is freed with the exec queue while scheduler fences can still
reference it.
Store the name in struct xe_guc_exec_queue so it shares
the scheduler's RCU-deferred lifetime.
Fixes: 6bd90e700b42 ("drm/xe: Make dma-fences compliant with the safe access rules")
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Arvind Yadav <arvind.yadav@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Acked-by: Matthew Brost <matthew.brost@intel.com>
Link: https://patch.msgid.link/20260714064402.2457257-1-arvind.yadav@intel.com
Signed-off-by: Tejas Upadhyay <tejas.upadhyay@intel.com>
(cherry picked from commit 41075f0eb5dcbd3b065d15f15ef7bbe9315188e8)
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/xe/xe_guc_exec_queue_types.h | 5 +++++
drivers/gpu/drm/xe/xe_guc_submit.c | 4 +++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/xe/xe_guc_exec_queue_types.h b/drivers/gpu/drm/xe/xe_guc_exec_queue_types.h
index a3f421e2adc03..5282d0eb94747 100644
--- a/drivers/gpu/drm/xe/xe_guc_exec_queue_types.h
+++ b/drivers/gpu/drm/xe/xe_guc_exec_queue_types.h
@@ -10,6 +10,7 @@
#include <linux/workqueue.h>
#include "xe_gpu_scheduler_types.h"
+#include "xe_hw_fence_types.h"
struct dma_fence;
struct xe_exec_queue;
@@ -24,6 +25,10 @@ struct xe_guc_exec_queue {
struct rcu_head rcu;
/** @sched: GPU scheduler for this xe_exec_queue */
struct xe_gpu_scheduler sched;
+ /**
+ * @name: Scheduler timeline name, kept with @sched until RCU free.
+ */
+ char name[MAX_FENCE_NAME_LEN];
/** @entity: Scheduler entity for this xe_exec_queue */
struct xe_sched_entity entity;
/**
diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c
index 51bd4a0f2a18b..ed95176b0e1e8 100644
--- a/drivers/gpu/drm/xe/xe_guc_submit.c
+++ b/drivers/gpu/drm/xe/xe_guc_submit.c
@@ -1472,7 +1472,7 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
err = xe_sched_init(&ge->sched, &drm_sched_ops, &xe_sched_ops,
NULL, q->lrc[0]->ring.size / MAX_JOB_SIZE_BYTES, 64,
timeout, guc_to_gt(guc)->ordered_wq, NULL,
- q->name, gt_to_xe(q->gt)->drm.dev);
+ ge->name, gt_to_xe(q->gt)->drm.dev);
if (err)
goto err_free;
@@ -1499,6 +1499,8 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
xe_exec_queue_assign_name(q, q->guc->id);
+ strscpy(ge->name, q->name, sizeof(ge->name));
+
trace_xe_exec_queue_create(q);
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 396/869] Bluetooth: hci_sync: extend conn_hash lookup critical sections
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (394 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 395/869] drm/xe/guc: Keep scheduler timeline name alive Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 397/869] bpf: Disable migration when destroying sock storage Greg Kroah-Hartman
` (473 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pauli Virtanen,
Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <pav@iki.fi>
[ Upstream commit d5efd6e4b8b0634af6843178fe1a7dd2b2178a3d ]
Using RCU-protected pointers outside the critical sections without
refcount is incorrect and may result to UAF.
Extend critical section to cover both hci_conn_hash lookup and use of
the returned conn.
Add surrounding rcu_read_lock() also when return value is not used, in
preparation for RCU lockdep requirement to hci_lookup_le_connect().
This avoids concurrent deletion of the conn before we are done
dereferencing it.
Also, make sure to hold hdev->lock when accessing hdev->accept_list.
Fixes: 6d0417e4e1cf ("Bluetooth: hci_conn: Fix not setting conn_timeout for Broadcast Receiver")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/hci_sync.c | 42 +++++++++++++++++++++++++++++++++++++---
1 file changed, 39 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index b0ab43145e47f..3e3706231458d 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -1077,14 +1077,19 @@ static int hci_set_random_addr_sync(struct hci_dev *hdev, bdaddr_t *rpa)
* In this kind of scenario skip the update and let the random
* address be updated at the next cycle.
*/
+ rcu_read_lock();
+
if (bacmp(&hdev->random_addr, BDADDR_ANY) &&
(hci_dev_test_flag(hdev, HCI_LE_ADV) ||
hci_lookup_le_connect(hdev))) {
bt_dev_dbg(hdev, "Deferring random address update");
hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
+ rcu_read_unlock();
return 0;
}
+ rcu_read_unlock();
+
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_RANDOM_ADDR,
6, rpa, HCI_CMD_TIMEOUT);
}
@@ -2757,12 +2762,17 @@ static int hci_pause_addr_resolution(struct hci_dev *hdev)
/* Cannot disable addr resolution if scanning is enabled or
* when initiating an LE connection.
*/
+ rcu_read_lock();
+
if (hci_dev_test_flag(hdev, HCI_LE_SCAN) ||
hci_lookup_le_connect(hdev)) {
+ rcu_read_unlock();
bt_dev_err(hdev, "Command not allowed when scan/LE connect");
return -EPERM;
}
+ rcu_read_unlock();
+
/* Cannot disable addr resolution if advertising is enabled. */
err = hci_pause_advertising_sync(hdev);
if (err) {
@@ -2900,6 +2910,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
if (hci_dev_test_flag(hdev, HCI_PA_SYNC)) {
struct hci_conn *conn;
+ rcu_read_lock();
+
conn = hci_conn_hash_lookup_create_pa_sync(hdev);
if (conn) {
struct conn_params pa;
@@ -2909,6 +2921,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
bacpy(&pa.addr, &conn->dst);
pa.addr_type = conn->dst_type;
+ rcu_read_unlock();
+
/* Clear first since there could be addresses left
* behind.
*/
@@ -2918,6 +2932,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
err = hci_le_add_accept_list_sync(hdev, &pa,
&num_entries);
goto done;
+ } else {
+ rcu_read_unlock();
}
}
@@ -2928,10 +2944,13 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
* the controller.
*/
list_for_each_entry_safe(b, t, &hdev->le_accept_list, list) {
- if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type))
+ rcu_read_lock();
+
+ if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type)) {
+ rcu_read_unlock();
continue;
+ }
- /* Pointers not dereferenced, no locks needed */
pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns,
&b->bdaddr,
b->bdaddr_type);
@@ -2939,6 +2958,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
&b->bdaddr,
b->bdaddr_type);
+ rcu_read_unlock();
+
/* If the device is not likely to connect or report,
* remove it from the acceptlist.
*/
@@ -3071,6 +3092,8 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
if (sent) {
struct hci_conn *conn;
+ rcu_read_lock();
+
conn = hci_conn_hash_lookup_ba(hdev, PA_LINK,
&bdaddr);
if (conn) {
@@ -3095,8 +3118,12 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
phy++;
}
+ rcu_read_unlock();
+
if (num_phy)
goto done;
+ } else {
+ rcu_read_unlock();
}
}
}
@@ -3347,12 +3374,16 @@ int hci_update_passive_scan_sync(struct hci_dev *hdev)
/* If there is at least one pending LE connection, we should
* keep the background scan running.
*/
+ bool exists;
/* If controller is connecting, we should not start scanning
* since some controllers are not able to scan and connect at
* the same time.
*/
- if (hci_lookup_le_connect(hdev))
+ rcu_read_lock();
+ exists = hci_lookup_le_connect(hdev);
+ rcu_read_unlock();
+ if (exists)
return 0;
bt_dev_dbg(hdev, "start background scanning");
@@ -3570,6 +3601,7 @@ int hci_write_fast_connectable_sync(struct hci_dev *hdev, bool enable)
}
static bool disconnected_accept_list_entries(struct hci_dev *hdev)
+ __must_hold(&hdev->lock)
{
struct bdaddr_list *b;
@@ -3610,12 +3642,16 @@ int hci_update_scan_sync(struct hci_dev *hdev)
if (hdev->scanning_paused)
return 0;
+ hci_dev_lock(hdev);
+
if (hci_dev_test_flag(hdev, HCI_CONNECTABLE) ||
disconnected_accept_list_entries(hdev))
scan = SCAN_PAGE;
else
scan = SCAN_DISABLED;
+ hci_dev_unlock(hdev);
+
if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
scan |= SCAN_INQUIRY;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 397/869] bpf: Disable migration when destroying sock storage
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (395 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 396/869] Bluetooth: hci_sync: extend conn_hash lookup critical sections Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 398/869] bpf: Disable migration when cloning " Greg Kroah-Hartman
` (472 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Hou Tao, Alexei Starovoitov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hou Tao <houtao1@huawei.com>
[ Upstream commit 7d1032d1e3031ef38d1a360380d755f75cb639b8 ]
When destroying sock storage, it invokes bpf_local_storage_destroy() to
remove all storage elements saved in the sock storage. The destroy
procedure will call bpf_selem_free() to free the element, and
bpf_selem_free() calls bpf_obj_free_fields() to free the special fields
in map value (e.g., kptr). Since kptrs may be allocated from bpf memory
allocator, migrate_{disable|enable} pairs are necessary for the freeing
of these kptrs.
To simplify reasoning about when migrate_disable() is needed for the
freeing of these dynamically-allocated kptrs, let the caller to
guarantee migration is disabled before invoking bpf_obj_free_fields().
Therefore, the patch adds migrate_{disable|enable} pair in
bpf_sock_storage_free(). The migrate_{disable|enable} pairs in the
underlying implementation of bpf_obj_free_fields() will be removed by
The following patch.
Signed-off-by: Hou Tao <houtao1@huawei.com>
Link: https://lore.kernel.org/r/20250108010728.207536-8-houtao@huaweicloud.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Stable-dep-of: 7cbd0c4cebe4 ("bpf: Fix UAF in sock clone early bailouts")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/core/bpf_sk_storage.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index bc01b3aa6b0fa..5cd1220cc7a5e 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -50,15 +50,16 @@ void bpf_sk_storage_free(struct sock *sk)
{
struct bpf_local_storage *sk_storage;
+ migrate_disable();
rcu_read_lock();
sk_storage = rcu_dereference(sk->sk_bpf_storage);
- if (!sk_storage) {
- rcu_read_unlock();
- return;
- }
+ if (!sk_storage)
+ goto out;
bpf_local_storage_destroy(sk_storage);
+out:
rcu_read_unlock();
+ migrate_enable();
}
static void bpf_sk_storage_map_free(struct bpf_map *map)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 398/869] bpf: Disable migration when cloning sock storage
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (396 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 397/869] bpf: Disable migration when destroying sock storage Greg Kroah-Hartman
@ 2026-10-17 15:53 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 399/869] rcu: add rcu_read_lock_dont_migrate() Greg Kroah-Hartman
` (471 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:53 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Hou Tao, Alexei Starovoitov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hou Tao <houtao1@huawei.com>
[ Upstream commit dfccfc47bde53f5df5bf42486d12a8a2ecdcea60 ]
bpf_sk_storage_clone() will call bpf_selem_free() to free the clone
element when the allocation of new sock storage fails. bpf_selem_free()
will call check_and_free_fields() to free the special fields in the
element. Since the allocated element is not visible to bpf syscall or
bpf program when bpf_local_storage_alloc() fails, these special fields
in the element must be all zero when invoking bpf_selem_free().
To be uniform with other callers of bpf_selem_free(), disabling
migration when cloning sock storage. Adding migrate_{disable|enable}
pair also benefits the potential switching from kzalloc to bpf memory
allocator for sock storage.
Signed-off-by: Hou Tao <houtao1@huawei.com>
Link: https://lore.kernel.org/r/20250108010728.207536-9-houtao@huaweicloud.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Stable-dep-of: 7cbd0c4cebe4 ("bpf: Fix UAF in sock clone early bailouts")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/core/bpf_sk_storage.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index 5cd1220cc7a5e..50ce498742596 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -161,6 +161,7 @@ int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)
RCU_INIT_POINTER(newsk->sk_bpf_storage, NULL);
+ migrate_disable();
rcu_read_lock();
sk_storage = rcu_dereference(sk->sk_bpf_storage);
@@ -213,6 +214,7 @@ int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)
out:
rcu_read_unlock();
+ migrate_enable();
/* In case of an error, don't free anything explicitly here, the
* caller is responsible to call bpf_sk_storage_free.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 399/869] rcu: add rcu_read_lock_dont_migrate()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (397 preceding siblings ...)
2026-10-17 15:53 ` [PATCH 6.12 398/869] bpf: Disable migration when cloning " Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 400/869] bpf: Use rcu_read_lock_dont_migrate in bpf_sk_storage.c Greg Kroah-Hartman
` (470 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Menglong Dong, Paul E. McKenney,
Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Menglong Dong <menglong8.dong@gmail.com>
[ Upstream commit 1b93c03fb319d72a1f5f4723abd5df15ce40f4e2 ]
migrate_disable() is called to disable migration in the kernel, and it is
often used together with rcu_read_lock().
However, with PREEMPT_RCU disabled, it's unnecessary, as rcu_read_lock()
will always disable preemption, which will also disable migration.
Introduce rcu_read_lock_dont_migrate() and rcu_read_unlock_migrate(),
which will do the migration enable and disable only when PREEMPT_RCU.
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
Link: https://lore.kernel.org/r/20250821090609.42508-2-dongml2@chinatelecom.cn
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Stable-dep-of: 7cbd0c4cebe4 ("bpf: Fix UAF in sock clone early bailouts")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/rcupdate.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 0844ab3288519..05cc0d07f5890 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -971,6 +971,20 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
preempt_enable_notrace();
}
+static __always_inline void rcu_read_lock_dont_migrate(void)
+{
+ if (IS_ENABLED(CONFIG_PREEMPT_RCU))
+ migrate_disable();
+ rcu_read_lock();
+}
+
+static inline void rcu_read_unlock_migrate(void)
+{
+ rcu_read_unlock();
+ if (IS_ENABLED(CONFIG_PREEMPT_RCU))
+ migrate_enable();
+}
+
/**
* RCU_INIT_POINTER() - initialize an RCU protected pointer
* @p: The pointer to be initialized.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 400/869] bpf: Use rcu_read_lock_dont_migrate in bpf_sk_storage.c
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (398 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 399/869] rcu: add rcu_read_lock_dont_migrate() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 401/869] bpf: Fix UAF in sock clone early bailouts Greg Kroah-Hartman
` (469 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Fushuai Wang, Martin KaFai Lau,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fushuai Wang <wangfushuai@baidu.com>
[ Upstream commit 0db4941d9dae159d887e7e2eac7e54e60c3aac87 ]
Use rcu_read_lock_dont_migrate() and rcu_read_unlock_migrate() in
bpf_sk_storage.c to obtain better performance when PREEMPT_RCU is
not enabled.
Signed-off-by: Fushuai Wang <wangfushuai@baidu.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://patch.msgid.link/20251007074011.12916-1-wangfushuai@baidu.com
Stable-dep-of: 7cbd0c4cebe4 ("bpf: Fix UAF in sock clone early bailouts")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/core/bpf_sk_storage.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index 50ce498742596..135570dfcffe6 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -50,16 +50,14 @@ void bpf_sk_storage_free(struct sock *sk)
{
struct bpf_local_storage *sk_storage;
- migrate_disable();
- rcu_read_lock();
+ rcu_read_lock_dont_migrate();
sk_storage = rcu_dereference(sk->sk_bpf_storage);
if (!sk_storage)
goto out;
bpf_local_storage_destroy(sk_storage);
out:
- rcu_read_unlock();
- migrate_enable();
+ rcu_read_unlock_migrate();
}
static void bpf_sk_storage_map_free(struct bpf_map *map)
@@ -161,8 +159,7 @@ int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)
RCU_INIT_POINTER(newsk->sk_bpf_storage, NULL);
- migrate_disable();
- rcu_read_lock();
+ rcu_read_lock_dont_migrate();
sk_storage = rcu_dereference(sk->sk_bpf_storage);
if (!sk_storage || hlist_empty(&sk_storage->list))
@@ -213,8 +210,7 @@ int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)
}
out:
- rcu_read_unlock();
- migrate_enable();
+ rcu_read_unlock_migrate();
/* In case of an error, don't free anything explicitly here, the
* caller is responsible to call bpf_sk_storage_free.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 401/869] bpf: Fix UAF in sock clone early bailouts
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (399 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 400/869] bpf: Use rcu_read_lock_dont_migrate in bpf_sk_storage.c Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 402/869] firmware: arm_ffa: Fix out-of-bound writes in ffa_setup_and_transmit() Greg Kroah-Hartman
` (468 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Matt Bobrowski, Daniel Borkmann,
Kuniyuki Iwashima, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Bobrowski <mattbobrowski@google.com>
[ Upstream commit 7cbd0c4cebe4c9f678d15e6b9ba975e1155a107f ]
Similar to recent commit 9b51a6155d14 ("bpf,fork: wipe ->bpf_storage
before bailouts that access it"), sk_clone() performs an initial
shallow copy of the socket field ->sk_bpf_storage via sock_copy()
for the cloned socket newsk.
If sk_clone() bails out early (e.g. if sk_filter_charge() fails) prior
to calling bpf_sk_storage_clone(), newsk->sk_bpf_storage still points
to the parent socket's BPF local storage. When newsk is subsequently
freed via sk_free(), the deallocation path (__sk_destruct() ->
bpf_sk_storage_free()) destroys the parent socket's BPF local storage,
leading to a use-after-free (UAF) on the parent socket.
Fix this by resetting newsk->sk_bpf_storage to NULL immediately after
sock_copy() in sk_clone(), and remove the now redundant initialization
from bpf_sk_storage_clone().
Fixes: 6ac99e8f23d4 ("bpf: Introduce bpf sk local storage")
Fixes: f12dd75959b0 ("bpf: net: Set sk_bpf_storage back to NULL for cloned sk")
Signed-off-by: Matt Bobrowski <mattbobrowski@google.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20260709025316.999913-1-mattbobrowski@google.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/core/bpf_sk_storage.c | 2 --
net/core/sock.c | 3 +++
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index 135570dfcffe6..a09bc55ebd75a 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -157,8 +157,6 @@ int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)
struct bpf_local_storage_elem *selem;
int ret = 0;
- RCU_INIT_POINTER(newsk->sk_bpf_storage, NULL);
-
rcu_read_lock_dont_migrate();
sk_storage = rcu_dereference(sk->sk_bpf_storage);
diff --git a/net/core/sock.c b/net/core/sock.c
index 75db38fdfd35f..181a66488ec21 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -2411,6 +2411,9 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
sock_copy(newsk, sk);
newsk->sk_prot_creator = prot;
+#ifdef CONFIG_BPF_SYSCALL
+ RCU_INIT_POINTER(newsk->sk_bpf_storage, NULL);
+#endif
/* SANITY */
if (likely(newsk->sk_net_refcnt)) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 402/869] firmware: arm_ffa: Fix out-of-bound writes in ffa_setup_and_transmit()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (400 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 401/869] bpf: Fix UAF in sock clone early bailouts Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 403/869] wifi: cfg80211: use wiphy work for socket owner autodisconnect Greg Kroah-Hartman
` (467 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sudeep Holla, Mostafa Saleh,
Sebastian Ene, Marc Zyngier, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mostafa Saleh <smostafa@google.com>
[ Upstream commit 3383ffb7ef937317361713ffcc21921a7848511a ]
Sashiko (locally) reports multiple out-of-bound issues in
ffa_setup_and_transmit:
1) Writing ep_mem_access->reserved can write out of bounds for FFA
versions < 1.2 as ffa_emad_size_get() returns 16 bytes in that case
while reserved has an offset of 24.
Instead of zeroing fields, memset the struct to zero first based on
the FFA version.
2) Make sure there is enough size to write constituents.
While at it, convert the only sizeof() in the driver that uses a
type instead of variable.
Reviewed-by: Sudeep Holla <sudeep.holla@kernel.org>
Fixes: 111a833dc5cb ("firmware: arm_ffa: Set reserved/MBZ fields to zero in the memory descriptors")
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
Link: https://patch.msgid.link/20260702103848.1647249-2-sebastianene@google.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/firmware/arm_ffa/driver.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index 62222c9cfc3e6..58939ca2d7dfa 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -637,11 +637,10 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
drv_info->version);
for (idx = 0; idx < args->nattrs; idx++, ep_mem_access++) {
+ memset(ep_mem_access, 0, sizeof(*ep_mem_access));
ep_mem_access->receiver = args->attrs[idx].receiver;
ep_mem_access->attrs = args->attrs[idx].attrs;
ep_mem_access->composite_off = composite_offset;
- ep_mem_access->flag = 0;
- ep_mem_access->reserved = 0;
}
mem_region->handle = 0;
mem_region->ep_count = args->nattrs;
@@ -684,7 +683,7 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
constituents = buffer;
}
- if ((void *)constituents - buffer > max_fragsize) {
+ if ((void *)constituents + sizeof(*constituents) - buffer > max_fragsize) {
pr_err("Memory Region Fragment > Tx Buffer size\n");
return -EFAULT;
}
@@ -693,7 +692,7 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
constituents->pg_cnt = args->sg->length / FFA_PAGE_SIZE;
constituents->reserved = 0;
constituents++;
- frag_len += sizeof(struct ffa_mem_region_addr_range);
+ frag_len += sizeof(*constituents);
} while ((args->sg = sg_next(args->sg)));
return ffa_transmit_fragment(func_id, addr, buf_sz, frag_len,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 403/869] wifi: cfg80211: use wiphy work for socket owner autodisconnect
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (401 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 402/869] firmware: arm_ffa: Fix out-of-bound writes in ffa_setup_and_transmit() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 404/869] wifi: mac80211: refactor populating mesh related fields in sinfo Greg Kroah-Hartman
` (466 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johannes Berg, Cen Zhang,
Johannes Berg, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <zzzccc427@gmail.com>
[ Upstream commit 0c2ed186bbe14304415476d6707b747dddcd8583 ]
nl80211_netlink_notify() walks the cfg80211 wireless device list when a
NETLINK_GENERIC socket is released. If the socket owns a connection, the
notifier queues the embedded wdev->disconnect_wk work item.
That work is a plain work_struct today. NETDEV_GOING_DOWN cancels it, but a
NETLINK_URELEASE notifier that already observed conn_owner_nlportid can
queue it after that cancel returns. _cfg80211_unregister_wdev() then
removes the wdev from the list and waits for RCU readers, but
synchronize_net() does not drain work queued by such a reader.
Make the autodisconnect work a wiphy_work instead. The callback already
needs the wiphy mutex, and wiphy_work runs under that mutex. This lets
teardown cancel pending autodisconnect work while holding the mutex,
without a cancel_work_sync() vs. worker locking concern.
Also cancel the wiphy work after list_del_rcu() and synchronize_net(). Any
NETLINK_URELEASE notifier that had already reached the wdev list has then
either queued the work and it is removed, or can no longer find the wdev.
Fixes: bd2522b16884 ("cfg80211: NL80211_ATTR_SOCKET_OWNER support for CMD_CONNECT")
Suggested-by: Johannes Berg <johannes@sipsolutions.net>
Assisted-by: Codex:gpt-5.5
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Link: https://patch.msgid.link/20260706152418.779226-1-zzzccc427@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/cfg80211.h | 2 +-
net/wireless/core.c | 7 ++++---
net/wireless/core.h | 2 +-
net/wireless/nl80211.c | 3 ++-
net/wireless/sme.c | 6 ++----
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ede91e4709ee5..a04b98eff1666 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -6389,7 +6389,7 @@ struct wireless_dev {
enum ieee80211_bss_type conn_bss_type;
u32 conn_owner_nlportid;
- struct work_struct disconnect_wk;
+ struct wiphy_work disconnect_wk;
u8 disconnect_bssid[ETH_ALEN];
struct list_head event_list;
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 7c278b8694393..e4b7917455fb4 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1280,6 +1280,7 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
list_del_rcu(&wdev->list);
synchronize_net();
rdev->devlist_generation++;
+ wiphy_work_cancel(wdev->wiphy, &wdev->disconnect_wk);
cfg80211_mlme_purge_registrations(wdev);
@@ -1463,7 +1464,7 @@ void cfg80211_init_wdev(struct wireless_dev *wdev)
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
wdev->netdev->priv_flags |= IFF_DONT_BRIDGE;
- INIT_WORK(&wdev->disconnect_wk, cfg80211_autodisconnect_wk);
+ wiphy_work_init(&wdev->disconnect_wk, cfg80211_autodisconnect_wk);
}
void cfg80211_register_wdev(struct cfg80211_registered_device *rdev,
@@ -1571,9 +1572,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
scoped_guard(wiphy, &rdev->wiphy) {
cfg80211_leave(rdev, wdev);
cfg80211_remove_links(wdev);
+ /* since we just did cfg80211_leave() nothing to do there */
+ wiphy_work_cancel(wdev->wiphy, &wdev->disconnect_wk);
}
- /* since we just did cfg80211_leave() nothing to do there */
- cancel_work_sync(&wdev->disconnect_wk);
break;
case NETDEV_DOWN:
wiphy_lock(&rdev->wiphy);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index b02b456cfca37..505acfe4a16d6 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -418,7 +418,7 @@ void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *peer_addr,
const u8 *td_bitmap, u8 td_bitmap_len);
int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);
-void cfg80211_autodisconnect_wk(struct work_struct *work);
+void cfg80211_autodisconnect_wk(struct wiphy *wiphy, struct wiphy_work *work);
/* SME implementation */
void cfg80211_conn_work(struct work_struct *work);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 6261befa1e949..dddd15f2d6b57 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -20153,7 +20153,8 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
wdev->nl_owner_dead = true;
schedule_work(&rdev->destroy_work);
} else if (wdev->conn_owner_nlportid == notify->portid) {
- schedule_work(&wdev->disconnect_wk);
+ wiphy_work_queue(wdev->wiphy,
+ &wdev->disconnect_wk);
}
cfg80211_release_pmsr(wdev, notify->portid);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index ab57648ca5774..059b01bdb630b 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -1578,13 +1578,11 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
* Used to clean up after the connection / connection attempt owner socket
* disconnects
*/
-void cfg80211_autodisconnect_wk(struct work_struct *work)
+void cfg80211_autodisconnect_wk(struct wiphy *wiphy, struct wiphy_work *work)
{
struct wireless_dev *wdev =
container_of(work, struct wireless_dev, disconnect_wk);
- struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
-
- guard(wiphy)(wdev->wiphy);
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
if (wdev->conn_owner_nlportid) {
switch (wdev->iftype) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 404/869] wifi: mac80211: refactor populating mesh related fields in sinfo
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (402 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 403/869] wifi: cfg80211: use wiphy work for socket owner autodisconnect Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 405/869] wifi: cfg80211: add link_station_info structure to support MLO statistics Greg Kroah-Hartman
` (465 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sarika Sharma, Johannes Berg,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sarika Sharma <quic_sarishar@quicinc.com>
[ Upstream commit e5328c14590d034dc586e56aaab88e966d06efa7 ]
Introduce the sta_set_mesh_sinfo() to populate mesh related
fields in sinfo structure for station statistics.
This will allow for the simplified population of other fields in the
sinfo structure for link level in a subsequent patch to add support
for MLO station statistics.
No functionality changes added.
Signed-off-by: Sarika Sharma <quic_sarishar@quicinc.com>
Link: https://patch.msgid.link/20250213171632.1646538-3-quic_sarishar@quicinc.com
[reword since it's just an internal thing]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Stable-dep-of: aa2eb6252518 ("wifi: mac80211: defer link RX stats percpu free to RCU")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mac80211/sta_info.c | 64 ++++++++++++++++++++++-------------------
1 file changed, 35 insertions(+), 29 deletions(-)
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 122697fbd84b1..e5781b8355d5e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2573,6 +2573,39 @@ static inline u64 sta_get_stats_bytes(struct ieee80211_sta_rx_stats *rxstats)
return value;
}
+#ifdef CONFIG_MAC80211_MESH
+static void sta_set_mesh_sinfo(struct sta_info *sta,
+ struct station_info *sinfo)
+{
+ struct ieee80211_local *local = sta->sdata->local;
+
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_LLID) |
+ BIT_ULL(NL80211_STA_INFO_PLID) |
+ BIT_ULL(NL80211_STA_INFO_PLINK_STATE) |
+ BIT_ULL(NL80211_STA_INFO_LOCAL_PM) |
+ BIT_ULL(NL80211_STA_INFO_PEER_PM) |
+ BIT_ULL(NL80211_STA_INFO_NONPEER_PM) |
+ BIT_ULL(NL80211_STA_INFO_CONNECTED_TO_GATE) |
+ BIT_ULL(NL80211_STA_INFO_CONNECTED_TO_AS);
+
+ sinfo->llid = sta->mesh->llid;
+ sinfo->plid = sta->mesh->plid;
+ sinfo->plink_state = sta->mesh->plink_state;
+ if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_T_OFFSET);
+ sinfo->t_offset = sta->mesh->t_offset;
+ }
+ sinfo->local_pm = sta->mesh->local_pm;
+ sinfo->peer_pm = sta->mesh->peer_pm;
+ sinfo->nonpeer_pm = sta->mesh->nonpeer_pm;
+ sinfo->connected_to_gate = sta->mesh->connected_to_gate;
+ sinfo->connected_to_as = sta->mesh->connected_to_as;
+
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_LINK_METRIC);
+ sinfo->airtime_link_metric = airtime_link_metric_get(local, sta);
+}
+#endif
+
void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
bool tidstats)
{
@@ -2757,31 +2790,10 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
sta_set_tidstats(sta, &sinfo->pertid[i], i);
}
- if (ieee80211_vif_is_mesh(&sdata->vif)) {
#ifdef CONFIG_MAC80211_MESH
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_LLID) |
- BIT_ULL(NL80211_STA_INFO_PLID) |
- BIT_ULL(NL80211_STA_INFO_PLINK_STATE) |
- BIT_ULL(NL80211_STA_INFO_LOCAL_PM) |
- BIT_ULL(NL80211_STA_INFO_PEER_PM) |
- BIT_ULL(NL80211_STA_INFO_NONPEER_PM) |
- BIT_ULL(NL80211_STA_INFO_CONNECTED_TO_GATE) |
- BIT_ULL(NL80211_STA_INFO_CONNECTED_TO_AS);
-
- sinfo->llid = sta->mesh->llid;
- sinfo->plid = sta->mesh->plid;
- sinfo->plink_state = sta->mesh->plink_state;
- if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_T_OFFSET);
- sinfo->t_offset = sta->mesh->t_offset;
- }
- sinfo->local_pm = sta->mesh->local_pm;
- sinfo->peer_pm = sta->mesh->peer_pm;
- sinfo->nonpeer_pm = sta->mesh->nonpeer_pm;
- sinfo->connected_to_gate = sta->mesh->connected_to_gate;
- sinfo->connected_to_as = sta->mesh->connected_to_as;
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ sta_set_mesh_sinfo(sta, sinfo);
#endif
- }
sinfo->bss_param.flags = 0;
if (sdata->vif.bss_conf.use_cts_prot)
@@ -2837,12 +2849,6 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
sinfo->filled |=
BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);
}
-
- if (ieee80211_vif_is_mesh(&sdata->vif)) {
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_LINK_METRIC);
- sinfo->airtime_link_metric =
- airtime_link_metric_get(local, sta);
- }
}
u32 sta_get_expected_throughput(struct sta_info *sta)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 405/869] wifi: cfg80211: add link_station_info structure to support MLO statistics
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (403 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 404/869] wifi: mac80211: refactor populating mesh related fields in sinfo Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 406/869] wifi: mac80211: defer link RX stats percpu free to RCU Greg Kroah-Hartman
` (464 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sarika Sharma, Johannes Berg,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sarika Sharma <quic_sarishar@quicinc.com>
[ Upstream commit d2329fff7e527e8b350086be2e7cbf0d190177a3 ]
Current implementation of NL80211_GET_STATION does not work for
multi-link operation(MLO) since in case of MLO only deflink (or one
of the links) is considered and not all links.
Therefore to support for MLO, add link_station_info structure
to account link level statistics for station.
Additionally, add valid_links in station_info structure to indicate
bitmap of valid links for MLO. This will be helpful to check the link
related statistics during MLO.
Signed-off-by: Sarika Sharma <quic_sarishar@quicinc.com>
Link: https://patch.msgid.link/20250528054420.3050133-3-quic_sarishar@quicinc.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Stable-dep-of: aa2eb6252518 ("wifi: mac80211: defer link RX stats percpu free to RCU")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/cfg80211.h | 101 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 101 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index a04b98eff1666..83558dec5132d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2049,6 +2049,99 @@ struct cfg80211_tid_stats {
#define IEEE80211_MAX_CHAINS 4
+/**
+ * struct link_station_info - link station information
+ *
+ * Link station information filled by driver for get_station() and
+ * dump_station().
+ * @filled: bit flag of flags using the bits of &enum nl80211_sta_info to
+ * indicate the relevant values in this struct for them
+ * @connected_time: time(in secs) since a link of station is last connected
+ * @inactive_time: time since last activity for link station(tx/rx)
+ * in milliseconds
+ * @assoc_at: bootime (ns) of the last association of link of station
+ * @rx_bytes: bytes (size of MPDUs) received from this link of station
+ * @tx_bytes: bytes (size of MPDUs) transmitted to this link of station
+ * @signal: The signal strength, type depends on the wiphy's signal_type.
+ * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
+ * @signal_avg: Average signal strength, type depends on the wiphy's
+ * signal_type. For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_
+ * @chains: bitmask for filled values in @chain_signal, @chain_signal_avg
+ * @chain_signal: per-chain signal strength of last received packet in dBm
+ * @chain_signal_avg: per-chain signal strength average in dBm
+ * @txrate: current unicast bitrate from this link of station
+ * @rxrate: current unicast bitrate to this link of station
+ * @rx_packets: packets (MSDUs & MMPDUs) received from this link of station
+ * @tx_packets: packets (MSDUs & MMPDUs) transmitted to this link of station
+ * @tx_retries: cumulative retry counts (MPDUs) for this link of station
+ * @tx_failed: number of failed transmissions (MPDUs) (retries exceeded, no ACK)
+ * @rx_dropped_misc: Dropped for un-specified reason.
+ * @bss_param: current BSS parameters
+ * @beacon_loss_count: Number of times beacon loss event has triggered.
+ * @expected_throughput: expected throughput in kbps (including 802.11 headers)
+ * towards this station.
+ * @rx_beacon: number of beacons received from this peer
+ * @rx_beacon_signal_avg: signal strength average (in dBm) for beacons received
+ * from this peer
+ * @rx_duration: aggregate PPDU duration(usecs) for all the frames from a peer
+ * @tx_duration: aggregate PPDU duration(usecs) for all the frames to a peer
+ * @airtime_weight: current airtime scheduling weight
+ * @pertid: per-TID statistics, see &struct cfg80211_tid_stats, using the last
+ * (IEEE80211_NUM_TIDS) index for MSDUs not encapsulated in QoS-MPDUs.
+ * Note that this doesn't use the @filled bit, but is used if non-NULL.
+ * @ack_signal: signal strength (in dBm) of the last ACK frame.
+ * @avg_ack_signal: average rssi value of ack packet for the no of msdu's has
+ * been sent.
+ * @rx_mpdu_count: number of MPDUs received from this station
+ * @fcs_err_count: number of packets (MPDUs) received from this station with
+ * an FCS error. This counter should be incremented only when TA of the
+ * received packet with an FCS error matches the peer MAC address.
+ * @addr: For MLO STA connection, filled with address of the link of station.
+ */
+struct link_station_info {
+ u64 filled;
+ u32 connected_time;
+ u32 inactive_time;
+ u64 assoc_at;
+ u64 rx_bytes;
+ u64 tx_bytes;
+ s8 signal;
+ s8 signal_avg;
+
+ u8 chains;
+ s8 chain_signal[IEEE80211_MAX_CHAINS];
+ s8 chain_signal_avg[IEEE80211_MAX_CHAINS];
+
+ struct rate_info txrate;
+ struct rate_info rxrate;
+ u32 rx_packets;
+ u32 tx_packets;
+ u32 tx_retries;
+ u32 tx_failed;
+ u32 rx_dropped_misc;
+ struct sta_bss_parameters bss_param;
+
+ u32 beacon_loss_count;
+
+ u32 expected_throughput;
+
+ u64 tx_duration;
+ u64 rx_duration;
+ u64 rx_beacon;
+ u8 rx_beacon_signal_avg;
+
+ u16 airtime_weight;
+
+ s8 ack_signal;
+ s8 avg_ack_signal;
+ struct cfg80211_tid_stats *pertid;
+
+ u32 rx_mpdu_count;
+ u32 fcs_err_count;
+
+ u8 addr[ETH_ALEN] __aligned(2);
+};
+
/**
* struct station_info - station information
*
@@ -2133,6 +2226,11 @@ struct cfg80211_tid_stats {
* dump_station() callbacks. User space needs this information to determine
* the accepted and rejected affiliated links of the connected station.
* @assoc_resp_ies_len: Length of @assoc_resp_ies buffer in octets.
+ * @valid_links: bitmap of valid links, or 0 for non-MLO. Drivers fill this
+ * information in cfg80211_new_sta(), cfg80211_del_sta_sinfo(),
+ * get_station() and dump_station() callbacks.
+ * @links: reference to Link sta entries for MLO STA, all link specific
+ * information is accessed through links[link_id].
*/
struct station_info {
u64 filled;
@@ -2198,6 +2296,9 @@ struct station_info {
u8 mld_addr[ETH_ALEN] __aligned(2);
const u8 *assoc_resp_ies;
size_t assoc_resp_ies_len;
+
+ u16 valid_links;
+ struct link_station_info *links[IEEE80211_MLD_MAX_NUM_LINKS];
};
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 406/869] wifi: mac80211: defer link RX stats percpu free to RCU
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (404 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 405/869] wifi: cfg80211: add link_station_info structure to support MLO statistics Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 407/869] wifi: cfg80211: Fix an error handling path in cfg80211_wext_siwscan() Greg Kroah-Hartman
` (463 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johannes Berg, Kaixuan Li, Maoyi Xie,
Johannes Berg, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <maoyixie.tju@gmail.com>
[ Upstream commit aa2eb62525188269cdd402a583b9a8ed94657ff0 ]
sta_remove_link() frees a removed MLO link's RX stats percpu buffer right
away, but defers only the link container to RCU:
sta_info_free_link(&alloc->info);
kfree_rcu(alloc, rcu_head);
The RX fast path reads link_sta under rcu_read_lock and writes the percpu
stats. A reader that resolved link_sta before the removal keeps the
pointer. The container stays alive from the kfree_rcu, so the read still
works. But the percpu block it points to is already freed. This needs
uses_rss. That is when pcpu_rx_stats exists.
The full STA teardown frees the deflink stats only after
synchronize_net(). The link removal path had no such barrier. The race is
hard to win in practice, but the free should still wait for RCU.
Free the link together with its data from a single RCU callback, so the
percpu block is reclaimed only after readers drain.
Fixes: c71420db653a ("wifi: mac80211: RCU-ify link STA pointers")
Link: https://lore.kernel.org/r/20260626080158.3589711-1-maoyixie.tju@gmail.com
Suggested-by: Johannes Berg <johannes@sipsolutions.net>
Co-developed-by: Kaixuan Li <kaixuan.li@ntu.edu.sg>
Signed-off-by: Kaixuan Li <kaixuan.li@ntu.edu.sg>
Signed-off-by: Maoyi Xie <maoyixie.tju@gmail.com>
Link: https://patch.msgid.link/20260627083028.3826810-1-maoyixie.tju@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mac80211/sta_info.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index e5781b8355d5e..09f212134c823 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -355,6 +355,15 @@ static void sta_info_free_link(struct link_sta_info *link_sta)
free_percpu(link_sta->pcpu_rx_stats);
}
+static void sta_link_free_rcu(struct rcu_head *head)
+{
+ struct sta_link_alloc *alloc =
+ container_of(head, struct sta_link_alloc, rcu_head);
+
+ sta_info_free_link(&alloc->info);
+ kfree(alloc);
+}
+
static void sta_remove_link(struct sta_info *sta, unsigned int link_id,
bool unhash)
{
@@ -379,10 +388,8 @@ static void sta_remove_link(struct sta_info *sta, unsigned int link_id,
sta->sta.valid_links &= ~BIT(link_id);
RCU_INIT_POINTER(sta->link[link_id], NULL);
RCU_INIT_POINTER(sta->sta.link[link_id], NULL);
- if (alloc) {
- sta_info_free_link(&alloc->info);
- kfree_rcu(alloc, rcu_head);
- }
+ if (alloc)
+ call_rcu(&alloc->rcu_head, sta_link_free_rcu);
ieee80211_sta_recalc_aggregates(&sta->sta);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 407/869] wifi: cfg80211: Fix an error handling path in cfg80211_wext_siwscan()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (405 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 406/869] wifi: mac80211: defer link RX stats percpu free to RCU Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 408/869] RDMA/irdma: Prevent user-triggered null deref on QP create Greg Kroah-Hartman
` (462 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christophe JAILLET, Johannes Berg,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
[ Upstream commit c6659f66d4ee4841aafae5659d2ef5e4c5c63cb6 ]
If the test against IEEE80211_MAX_SSID_LEN fails, then 'creq' leaks.
Use the existing error handling path to fix it.
Fixes: 2a5193119269 ("cfg80211/nl80211: scanning (and mac80211 update to use it)")
Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
Link: https://patch.msgid.link/a1be7eea4da0da18f90589af252bb76a18a61978.1781984889.git.christophe.jaillet@wanadoo.fr
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/wireless/scan.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 520dcc16920a8..890e5f77de6b8 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -3574,8 +3574,10 @@ int cfg80211_wext_siwscan(struct net_device *dev,
/* translate "Scan for SSID" request */
if (wreq) {
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
- if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
- return -EINVAL;
+ if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) {
+ err = -EINVAL;
+ goto out;
+ }
memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len);
creq->ssids[0].ssid_len = wreq->essid_len;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 408/869] RDMA/irdma: Prevent user-triggered null deref on QP create
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (406 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 407/869] wifi: cfg80211: Fix an error handling path in cfg80211_wext_siwscan() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 409/869] sched_ext: Dont warn on core-sched forced idle in put_prev_task_scx() Greg Kroah-Hartman
` (461 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jacob Moroni, David Hu,
Jason Gunthorpe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jacob Moroni <jmoroni@google.com>
[ Upstream commit b9b0889071569d43623c260074e159cd8f26adb1 ]
Previously, the user QP creation path would only attempt to
populate iwqp->iwpbl if the user-provided req.user_wqe_bufs
field was non-zero. The problem is that iwqp->iwpbl is
unconditionally dereferenced later on in irdma_setup_virt_qp.
While there was a check for iwqp->iwpbl != NULL, this check
would only occur if req.user_wqe_bufs was non-zero. The end
result is that a user could send a zero user_wqe_bufs value
and trigger a null ptr deref.
Fix this by unconditionally calling irdma_get_pbl and bailing
if it fails, similar to the CQ and SRQ paths.
Fixes: b48c24c2d710 ("RDMA/irdma: Implement device supported verb APIs")
Link: https://patch.msgid.link/r/20260617164013.280790-1-jmoroni@google.com
Signed-off-by: Jacob Moroni <jmoroni@google.com>
Reviewed-by: David Hu <xuehaohu@google.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/irdma/verbs.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c
index 97fa345635524..f86249226b60e 100644
--- a/drivers/infiniband/hw/irdma/verbs.c
+++ b/drivers/infiniband/hw/irdma/verbs.c
@@ -602,18 +602,18 @@ static int irdma_setup_umode_qp(struct ib_udata *udata,
iwqp->ctx_info.qp_compl_ctx = req.user_compl_ctx;
iwqp->user_mode = 1;
- if (req.user_wqe_bufs) {
- info->qp_uk_init_info.legacy_mode = ucontext->legacy_mode;
- spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
- iwqp->iwpbl = irdma_get_pbl((unsigned long)req.user_wqe_bufs,
- &ucontext->qp_reg_mem_list);
- spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
- if (!iwqp->iwpbl) {
- ret = -ENODATA;
- ibdev_dbg(&iwdev->ibdev, "VERBS: no pbl info\n");
- return ret;
- }
+ info->qp_uk_init_info.legacy_mode = ucontext->legacy_mode;
+
+ spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
+ iwqp->iwpbl = irdma_get_pbl((unsigned long)req.user_wqe_bufs,
+ &ucontext->qp_reg_mem_list);
+ spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
+
+ if (!iwqp->iwpbl) {
+ ret = -ENODATA;
+ ibdev_dbg(&iwdev->ibdev, "VERBS: no pbl info\n");
+ return ret;
}
if (!ucontext->use_raw_attrs) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 409/869] sched_ext: Dont warn on core-sched forced idle in put_prev_task_scx()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (407 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 408/869] RDMA/irdma: Prevent user-triggered null deref on QP create Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 410/869] xfrm: fix stale skb->prev after async crypto steals a GSO segment Greg Kroah-Hartman
` (460 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Tejun Heo, Andrea Righi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tejun Heo <tj@kernel.org>
[ Upstream commit b7d9c359e5cf867f7eb23df3bb1c6b9e58af24da ]
put_prev_task_scx() warns when a runnable task drops to a lower sched_class
without SCX_OPS_ENQ_LAST, on the assumption that balance_one() would have
kept it running. Core scheduling breaks that: a forced-idle SMT sibling
reschedules through the core_pick fast path in pick_next_task(), which skips
pick_task_scx() and thus balance_one(), so a runnable task can drop to idle
with ENQ_LAST unset.
Gate the warning on sched_cpu_cookie_match(): a cookie mismatch means core
scheduling forced the idle, while a match (or core scheduling off) still
catches a genuine missing-ENQ_LAST drop.
Fixes: 7c65ae81ea86 ("sched_ext: Don't call put_prev_task_scx() before picking the next task")
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/sched/ext.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 39dc9d3cfc079..876adf5568ed1 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -3085,9 +3085,14 @@ static void put_prev_task_scx(struct rq *rq, struct task_struct *p,
* sched_class, %SCX_OPS_ENQ_LAST must be set. Tell
* ops.enqueue() that @p is the only one available for this cpu,
* which should trigger an explicit follow-up scheduling event.
+ *
+ * Core scheduling can force this CPU idle while @p stays
+ * runnable. @p's cookie then won't match the core's, so skip
+ * the warning in that case.
*/
if (sched_class_above(&ext_sched_class, next->sched_class)) {
- WARN_ON_ONCE(!static_branch_unlikely(&scx_ops_enq_last));
+ WARN_ON_ONCE(sched_cpu_cookie_match(rq, p) &&
+ !static_branch_unlikely(&scx_ops_enq_last));
do_enqueue_task(rq, p, SCX_ENQ_LAST, -1);
} else {
do_enqueue_task(rq, p, 0, -1);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 410/869] xfrm: fix stale skb->prev after async crypto steals a GSO segment
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (408 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 409/869] sched_ext: Dont warn on core-sched forced idle in put_prev_task_scx() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 411/869] LoongArch: Fix address space mismatch in kexec command line lookup Greg Kroah-Hartman
` (459 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Petr Wozniak, Steffen Klassert,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Wozniak <petr.wozniak@gmail.com>
[ Upstream commit 3f4c3919baf0944ad96580467c302bc6c7758b00 ]
skb_gso_segment() leaves the segment list head with ->prev pointing at
the last segment, an invariant validate_xmit_skb_list() relies on when
it sets its tail pointer (tail = skb->prev).
When validate_xmit_xfrm() walks a GSO list and some segments are stolen
by async crypto (->xmit() returns -EINPROGRESS), those segments are
unlinked from the list but the head ->prev is never updated. If the
last segment is the one stolen, the returned head still has ->prev
pointing at it, even though it is now owned by the crypto engine and may
be freed. validate_xmit_skb_list() later does tail->next = skb, writing
through that stale pointer -- a use-after-free.
Repoint skb->prev at the last retained segment before returning.
Fixes: f53c723902d1 ("net: Add asynchronous callbacks for xfrm on layer 2.")
Signed-off-by: Petr Wozniak <petr.wozniak@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/xfrm/xfrm_device.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
index 7744ed8e4c83f..084cc90613d68 100644
--- a/net/xfrm/xfrm_device.c
+++ b/net/xfrm/xfrm_device.c
@@ -226,6 +226,14 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
pskb = skb2;
}
+ /* skb_gso_segment() set skb->prev to the last segment, but async
+ * crypto may have stolen it above without updating ->prev. Repoint
+ * it at the last retained segment so validate_xmit_skb_list() does
+ * not chain onto a segment now owned by the crypto engine.
+ */
+ if (skb)
+ skb->prev = pskb;
+
return skb;
}
EXPORT_SYMBOL_GPL(validate_xmit_xfrm);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 411/869] LoongArch: Fix address space mismatch in kexec command line lookup
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (409 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 410/869] xfrm: fix stale skb->prev after async crypto steals a GSO segment Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 412/869] drm/amd/display: use kvzalloc to allocate struct dc Greg Kroah-Hartman
` (458 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, kernel test robot, Kexin Liu,
George Guo, Huacai Chen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: George Guo <guodongtai@kylinos.cn>
[ Upstream commit 485ed44db5694d8d2e5027f63ad608e705286f30 ]
When searching the loaded segments for the "kexec" command line marker,
the kexec_load(2) path (file_mode == 0) passes the user-space segment
buffer straight to strncmp() through a bogus (char __user *) cast. This
dereferences a user pointer in kernel context, which is wrong and is
flagged by sparse:
arch/loongarch/kernel/machine_kexec.c:84:51: sparse: incorrect type in
argument 2 (different address spaces) @@ expected char const * @@ got
char [noderef] __user *
Here copy the marker-sized prefix of each segment into a small on-stack
buffer with copy_from_user() before comparing, and skip segments that
fault. The subsequent copy_from_user() that stages the full command line
into the safe area is left unchanged.
Cc: stable@vger.kernel.org
Fixes: 4a03b2ac06a5 ("LoongArch: Add kexec support")
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202605051639.aEPioXdD-lkp@intel.com/
Co-developed-by: Kexin Liu <liukexin@kylinos.cn>
Signed-off-by: Kexin Liu <liukexin@kylinos.cn>
Signed-off-by: George Guo <guodongtai@kylinos.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/loongarch/kernel/machine_kexec.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
index 8ef4e4595d61a..182226c67970e 100644
--- a/arch/loongarch/kernel/machine_kexec.c
+++ b/arch/loongarch/kernel/machine_kexec.c
@@ -62,6 +62,7 @@ static void kexec_image_info(const struct kimage *kimage)
int machine_kexec_prepare(struct kimage *kimage)
{
int i;
+ char head[8];
char *bootloader = "kexec";
void *cmdline_ptr = (void *)KEXEC_CMDLINE_ADDR;
@@ -72,7 +73,9 @@ int machine_kexec_prepare(struct kimage *kimage)
/* Find the command line */
for (i = 0; i < kimage->nr_segments; i++) {
- if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) {
+ if (copy_from_user(head, kimage->segment[i].buf, strlen(bootloader)))
+ continue;
+ if (!strncmp(bootloader, head, strlen(bootloader))) {
if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE))
kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr;
break;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 412/869] drm/amd/display: use kvzalloc to allocate struct dc
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (410 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 411/869] LoongArch: Fix address space mismatch in kexec command line lookup Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 413/869] net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains Greg Kroah-Hartman
` (457 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Mario Limonciello (AMD),
Honglei Huang, Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Honglei Huang <honghuan@amd.com>
[ Upstream commit 75050390151a14802be433c3856ddcb483cecd24 ]
struct dc has grown large over time (most of it the two inlined
dc_scratch_space copies) and now sits close to the page allocator's 4 MiB
contiguous allocation limit. Its actual size is not fixed by the source
alone, it also depends on the compiler and the .config, so it can easily
cross 4 MiB, e.g. with a newer GCC or a config change.
dc_create() allocates it with kzalloc(). Once struct dc exceeds 4 MiB the
request is rounded up to order 11 (8 MiB), which is above MAX_PAGE_ORDER,
so the page allocator warns and returns NULL. dc_create() then fails, DM
init fails and amdgpu probe aborts with -EINVAL:
WARNING: mm/page_alloc.c:5197 at __alloc_frozen_pages_noprof+0x2f9/0x380
dc_create+0x38/0x660 [amdgpu]
amdgpu_dm_init+0x2d9/0x510 [amdgpu]
dm_hw_init+0x1b/0x90 [amdgpu]
amdgpu_device_init.cold+0x150d/0x1e13 [amdgpu]
amdgpu_driver_load_kms+0x19/0x80 [amdgpu]
amdgpu_pci_probe+0x1e2/0x4c0 [amdgpu]
dc_create() then returns NULL and DM init fails, which aborts the whole
GPU init and makes amdgpu probe fail with -EINVAL ("hw_init of IP block
<dm> failed -22"), leaving the display unusable. The subsequent
amdgpu_irq_put() warnings during teardown are just fallout of unwinding
a half-initialized device.
struct dc is a software-only bookkeeping structure that is never handed
to hardware DMA and is only ever kept as an opaque pointer, so it does
not require physically contiguous memory. Allocate it with kvzalloc()
(and free it with kvfree()) so that the allocator can fall back to
vmalloc() when a contiguous allocation of that size is not available,
which also avoids the MAX_PAGE_ORDER warning entirely.
v2:
- Rebase to amd-staging-drm-next.
Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/5406
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Signed-off-by: Honglei Huang <honghuan@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 991e0516a8072f2292681c6ae98a924ab0e32575)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/display/dc/core/dc.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 070cca8b521b6..ad1cc546ba48d 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -1377,7 +1377,7 @@ static void disable_vbios_mode_if_required(
struct dc *dc_create(const struct dc_init_data *init_params)
{
- struct dc *dc = kzalloc(sizeof(*dc), GFP_KERNEL);
+ struct dc *dc = kvzalloc(sizeof(*dc), GFP_KERNEL);
unsigned int full_pipe_count;
if (!dc)
@@ -1425,7 +1425,7 @@ struct dc *dc_create(const struct dc_init_data *init_params)
destruct_dc:
dc_destruct(dc);
- kfree(dc);
+ kvfree(dc);
return NULL;
}
@@ -1474,7 +1474,7 @@ void dc_deinit_callbacks(struct dc *dc)
void dc_destroy(struct dc **dc)
{
dc_destruct(*dc);
- kfree(*dc);
+ kvfree(*dc);
*dc = NULL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 413/869] net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (411 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 412/869] drm/amd/display: use kvzalloc to allocate struct dc Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 414/869] drm/amdkfd: clamp v9 CRIU control stack checkpoint copy to BO size Greg Kroah-Hartman
` (456 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Victor Nogueira, Jamal Hadi Salim,
Daniel Borkmann, Sebastian Andrzej Siewior, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <jhs@mojatatu.com>
[ Upstream commit ec48b3be2c8595dd290be883dbd4fb8b2f9f5d5e ]
When a TC filter attached to a qdisc filter chain returns
TC_ACT_REDIRECT (ex: via an eBPF program calling bpf_redirect() or an
act_bpf action), the redirect was silently lost i.e no qdisc classify
function handled TC_ACT_REDIRECT, so the packet fell through the
switch and was enqueued normally instead of being redirected.
This has been broken since bpf_redirect() was introduced for TC in
commit 27b29f63058d ("bpf: add bpf_redirect() helper"). We got lucky
for a long time because bpf_net_context was a per-CPU variable that
was always available.
commit 401cb7dae813 ("net: Reference bpf_redirect_info via task_struct
on PREEMPT_RT.") turned bpf_net_context into a task_struct member that
is only set up by explicit callers. Without a caller setting it up,
bpf_redirect() itself crashes with a NULL pointer dereference in
bpf_net_ctx_get_ri(). However, even with bpf_net_context available,
TC_ACT_REDIRECT from qdisc filter chains cannot be honored without
adding skb_do_redirect() calls to every qdisc classify function, which
would require changes across net/sched/. Isolate it to ebpf core where
it belongs.
Instead, add a tcf_classify_qdisc() inline helper in pkt_cls.h, as a
wrapper around tcf_classify() for use by qdisc classify functions and
tcf_qevent_handle(). When the classify verdict is TC_ACT_REDIRECT,
the wrapper converts it to TC_ACT_SHOT, dropping the packet rather
than letting it continue silently. Dropping is preferred over
letting the packet through because the user immediately sees packet
loss. Silently passing the packet through would hide the problem and
leave the user wondering why their redirect is not working.
The clsact fast path, tc_run() continues to call tcf_classify() directly
and is unaffected: TC_ACT_REDIRECT is returned as-is and handled by
sch_handle_egress/ingress() calling skb_do_redirect() as before.
Fixes: 27b29f63058d ("bpf: add bpf_redirect() helper")
Fixes: 401cb7dae813 ("net: Reference bpf_redirect_info via task_struct on PREEMPT_RT.")
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Link: https://patch.msgid.link/20260706185609.330006-3-daniel@iogearbox.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/pkt_cls.h | 14 +++++++++++++-
net/sched/cls_api.c | 4 +---
net/sched/sch_cake.c | 2 +-
net/sched/sch_drr.c | 2 +-
net/sched/sch_ets.c | 2 +-
net/sched/sch_fq_codel.c | 2 +-
net/sched/sch_fq_pie.c | 2 +-
net/sched/sch_hfsc.c | 2 +-
net/sched/sch_htb.c | 2 +-
net/sched/sch_multiq.c | 2 +-
net/sched/sch_prio.c | 2 +-
net/sched/sch_qfq.c | 2 +-
net/sched/sch_sfb.c | 2 +-
net/sched/sch_sfq.c | 2 +-
14 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index ea2c69fdc8396..28ce971bddc9a 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -156,8 +156,20 @@ static inline int tcf_classify(struct sk_buff *skb,
{
return TC_ACT_UNSPEC;
}
-
#endif
+static inline int tcf_classify_qdisc(struct sk_buff *skb,
+ const struct tcf_proto *tp,
+ struct tcf_result *res, bool compat_mode)
+{
+ int ret = tcf_classify(skb, NULL, tp, res, compat_mode);
+
+ /* TC_ACT_REDIRECT from qdisc filter chains is not supported.
+ * Use BPF via tcx or mirred redirect instead.
+ */
+ if (unlikely(ret == TC_ACT_REDIRECT))
+ ret = TC_ACT_SHOT;
+ return ret;
+}
static inline unsigned long
__cls_set_class(unsigned long *clp, unsigned long cl)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 748be0e76a49d..f8d1cc0f23c15 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -4071,9 +4071,7 @@ struct sk_buff *tcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, stru
fl = rcu_dereference_bh(qe->filter_chain);
- switch (tcf_classify(skb, NULL, fl, &cl_res, false)) {
- case TC_ACT_REDIRECT:
- fallthrough;
+ switch (tcf_classify_qdisc(skb, fl, &cl_res, false)) {
case TC_ACT_SHOT:
qdisc_qstats_drop(sch);
__qdisc_drop(skb, to_free);
diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
index 43908ec231696..7eb3e7485539f 100644
--- a/net/sched/sch_cake.c
+++ b/net/sched/sch_cake.c
@@ -1704,7 +1704,7 @@ static u32 cake_classify(struct Qdisc *sch, struct cake_tin_data **t,
goto hash;
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
- result = tcf_classify(skb, NULL, filter, &res, false);
+ result = tcf_classify_qdisc(skb, filter, &res, false);
if (result >= 0) {
#ifdef CONFIG_NET_CLS_ACT
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index ba802db279932..8035ffeef2e92 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -313,7 +313,7 @@ static struct drr_class *drr_classify(struct sk_buff *skb, struct Qdisc *sch,
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
fl = rcu_dereference_bh(q->filter_list);
- result = tcf_classify(skb, NULL, fl, &res, false);
+ result = tcf_classify_qdisc(skb, fl, &res, false);
if (result >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c
index 27e549646dee1..03f5bb812a274 100644
--- a/net/sched/sch_ets.c
+++ b/net/sched/sch_ets.c
@@ -389,7 +389,7 @@ static struct ets_class *ets_classify(struct sk_buff *skb, struct Qdisc *sch,
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
if (TC_H_MAJ(skb->priority) != sch->handle) {
fl = rcu_dereference_bh(q->filter_list);
- err = tcf_classify(skb, NULL, fl, &res, false);
+ err = tcf_classify_qdisc(skb, fl, &res, false);
#ifdef CONFIG_NET_CLS_ACT
switch (err) {
case TC_ACT_STOLEN:
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
index 7cfe8eaf3331c..4da7525c3e7cf 100644
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -91,7 +91,7 @@ static unsigned int fq_codel_classify(struct sk_buff *skb, struct Qdisc *sch,
return fq_codel_hash(q, skb) + 1;
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
- result = tcf_classify(skb, NULL, filter, &res, false);
+ result = tcf_classify_qdisc(skb, filter, &res, false);
if (result >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c
index d2588cc40d04e..a3c41e81fa80a 100644
--- a/net/sched/sch_fq_pie.c
+++ b/net/sched/sch_fq_pie.c
@@ -96,7 +96,7 @@ static unsigned int fq_pie_classify(struct sk_buff *skb, struct Qdisc *sch,
return fq_pie_hash(q, skb) + 1;
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
- result = tcf_classify(skb, NULL, filter, &res, false);
+ result = tcf_classify_qdisc(skb, filter, &res, false);
if (result >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index df3501dfe01a8..b7c7121c36114 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1154,7 +1154,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
head = &q->root;
drift = HFSC_CLASSIFY_MAX_DRIFT;
tcf = rcu_dereference_bh(q->root.filter_list);
- while (tcf && (result = tcf_classify(skb, NULL, tcf, &res, false)) >= 0) {
+ while (tcf && (result = tcf_classify_qdisc(skb, tcf, &res, false)) >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
case TC_ACT_QUEUED:
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 36cc9a343b546..e44a5ef99a830 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -243,7 +243,7 @@ static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch,
}
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
- while (tcf && (result = tcf_classify(skb, NULL, tcf, &res, false)) >= 0) {
+ while (tcf && (result = tcf_classify_qdisc(skb, tcf, &res, false)) >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
case TC_ACT_QUEUED:
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
index e50a37b7cec1a..7962fc0292a5e 100644
--- a/net/sched/sch_multiq.c
+++ b/net/sched/sch_multiq.c
@@ -36,7 +36,7 @@ multiq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
int err;
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
- err = tcf_classify(skb, NULL, fl, &res, false);
+ err = tcf_classify_qdisc(skb, fl, &res, false);
#ifdef CONFIG_NET_CLS_ACT
switch (err) {
case TC_ACT_STOLEN:
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 9e2b9a490db23..6f4388cf10488 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -39,7 +39,7 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
if (TC_H_MAJ(skb->priority) != sch->handle) {
fl = rcu_dereference_bh(q->filter_list);
- err = tcf_classify(skb, NULL, fl, &res, false);
+ err = tcf_classify_qdisc(skb, fl, &res, false);
#ifdef CONFIG_NET_CLS_ACT
switch (err) {
case TC_ACT_STOLEN:
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
index c7c8e8dde31d1..70a08f1950100 100644
--- a/net/sched/sch_qfq.c
+++ b/net/sched/sch_qfq.c
@@ -712,7 +712,7 @@ static struct qfq_class *qfq_classify(struct sk_buff *skb, struct Qdisc *sch,
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
fl = rcu_dereference_bh(q->filter_list);
- result = tcf_classify(skb, NULL, fl, &res, false);
+ result = tcf_classify_qdisc(skb, fl, &res, false);
if (result >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
index 9a2edaf8352ad..cd2fba8caa649 100644
--- a/net/sched/sch_sfb.c
+++ b/net/sched/sch_sfb.c
@@ -260,7 +260,7 @@ static bool sfb_classify(struct sk_buff *skb, struct tcf_proto *fl,
struct tcf_result res;
int result;
- result = tcf_classify(skb, NULL, fl, &res, false);
+ result = tcf_classify_qdisc(skb, fl, &res, false);
if (result >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index cc7d8e484238c..4fd6a9f4e6dab 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -171,7 +171,7 @@ static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
return sfq_hash(q, skb) + 1;
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
- result = tcf_classify(skb, NULL, fl, &res, false);
+ result = tcf_classify_qdisc(skb, fl, &res, false);
if (result >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 414/869] drm/amdkfd: clamp v9 CRIU control stack checkpoint copy to BO size
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (412 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 413/869] net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 415/869] ovl: check access to copy_file_range source with src mounter creds Greg Kroah-Hartman
` (455 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yongqiang Sun, David Francis,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongqiang Sun <Yongqiang.Sun@amd.com>
[ Upstream commit 426ffae6ecc7ec77d32bf8be065c21a1b881b084 ]
CRIU checkpoint copies the MQD control stack using cp_hqd_cntl_stack_size
from hardware without bounding it to the allocated BO region. If the HW
field is larger than the queue's control stack allocation, memcpy reads
past the BO into adjacent GTT memory and can leak kernel data to userspace.
Store the page-aligned control stack BO size in mqd_manager and clamp
checkpoint copies and reported checkpoint sizes to
min(cp_hqd_cntl_stack_size, mm->ctl_stack_size). Apply the same bound
for multi-XCC v9.4.3 checkpoint layout.
Signed-off-by: Yongqiang Sun <Yongqiang.Sun@amd.com>
Reviewed-by: David Francis <David.Francis@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 6c2abd0ec09e86c6323010673766f76050e28aa3)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
index 6a69988b2d4fc..194a1c79cf042 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
@@ -27,6 +27,7 @@
#include <linux/uaccess.h>
#include "kfd_priv.h"
#include "kfd_mqd_manager.h"
+#include "kfd_topology.h"
#include "v9_structs.h"
#include "gc/gc_9_0_offset.h"
#include "gc/gc_9_0_sh_mask.h"
@@ -375,20 +376,26 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd,
static void get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size)
{
struct v9_mqd *m = get_mqd(mqd);
+ struct kfd_topology_device *topo_dev = kfd_topology_device_by_id(mm->dev->id);
+ u32 bo_size = topo_dev ? ALIGN(topo_dev->node_props.ctl_stack_size, PAGE_SIZE) : 0;
- *ctl_stack_size = m->cp_hqd_cntl_stack_size;
+ *ctl_stack_size = min_t(u32, m->cp_hqd_cntl_stack_size, bo_size);
}
static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, void *ctl_stack_dst)
{
struct v9_mqd *m;
+ struct kfd_topology_device *topo_dev = kfd_topology_device_by_id(mm->dev->id);
+ u32 bo_size = topo_dev ? ALIGN(topo_dev->node_props.ctl_stack_size, PAGE_SIZE) : 0;
+ u32 ctl_stack_copy_size;
/* Control stack is located one page after MQD. */
void *ctl_stack = (void *)((uintptr_t)mqd + PAGE_SIZE);
m = get_mqd(mqd);
+ ctl_stack_copy_size = min_t(u32, m->cp_hqd_cntl_stack_size, bo_size);
memcpy(mqd_dst, m, sizeof(struct v9_mqd));
- memcpy(ctl_stack_dst, ctl_stack, m->cp_hqd_cntl_stack_size);
+ memcpy(ctl_stack_dst, ctl_stack, ctl_stack_copy_size);
}
static void restore_mqd(struct mqd_manager *mm, void **mqd,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 415/869] ovl: check access to copy_file_range source with src mounter creds
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (413 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 414/869] drm/amdkfd: clamp v9 CRIU control stack checkpoint copy to BO size Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 416/869] s390/zcrypt: Fix buffer over-read in cca_cipher2protkey Greg Kroah-Hartman
` (454 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Amir Goldstein,
Christian Brauner (Amutable), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <amir73il@gmail.com>
[ Upstream commit a1e0eb8f55cfe09bb31a202a388babc411292656 ]
Commit 5dae222a5ff0c ("vfs: allow copy_file_range to copy across devices")
allowed filesystems that implement the copy_file_range() f_op to decide
if they want to access cross-sb copy from/to the same fs type.
The same commit added checks to verify same sb copy for filesystems that
implement ->copy_file_range() and do not support cross-sb copy at the
time, namely, to ceph, fuse and nfs.
The two remaining fs which implement ->copy_file_range(), cifs and
overlayfs started to support cross-sb copy from this time.
While overlayfs does support cross-sb copy when the two underlying files
are on the same base fs, the copy operation on the two real files from
two different overalyfs filesystems is performed with the mounter
creds of the destination overlayfs and the read permission access hook
for the source file was called with the wrong creds.
This could cause either deny of access to copy which would otherwise be
allowed (e.g. with splice) or allow read access to file which would
otherwise be denied.
Fix the latter case by explicitly verifying read access to source file
with the source overlayfs mounter creds.
The former case remains a quirk of cross-sb overlayfs copy, but
userspace could fall back to regular copy so no harm done.
Fixes: 5dae222a5ff0c ("vfs: allow copy_file_range to copy across devices")
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Link: https://patch.msgid.link/20260712122421.203113-1-amir73il@gmail.com
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/overlayfs/file.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
index 3765e1defa198..3a1f120b2af66 100644
--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -488,6 +488,7 @@ static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
struct file *file_out, loff_t pos_out,
loff_t len, unsigned int flags, enum ovl_copyop op)
{
+ struct inode *inode_in = file_inode(file_in);
struct inode *inode_out = file_inode(file_out);
struct fd real_in, real_out;
const struct cred *old_cred;
@@ -512,7 +513,20 @@ static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
goto out_unlock;
}
- old_cred = ovl_override_creds(file_inode(file_out)->i_sb);
+ /*
+ * For cross-sb copy, vfs_copy_file_range() will verify read access with
+ * the mounter creds of the dest fs mounter, so we need to explicitly
+ * verify read access with the source mounter creds.
+ */
+ if (unlikely(inode_in->i_sb != inode_out->i_sb)) {
+ old_cred = ovl_override_creds(inode_in->i_sb);
+ ret = rw_verify_area(READ, fd_file(real_in), &pos_in, len);
+ revert_creds(old_cred);
+ if (unlikely(ret))
+ goto out_fdput;
+ }
+
+ old_cred = ovl_override_creds(inode_out->i_sb);
switch (op) {
case OVL_COPY:
ret = vfs_copy_file_range(fd_file(real_in), pos_in,
@@ -535,6 +549,7 @@ static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
/* Update size */
ovl_file_modified(file_out);
+out_fdput:
fdput(real_in);
fdput(real_out);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 416/869] s390/zcrypt: Fix buffer over-read in cca_cipher2protkey
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (414 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 415/869] ovl: check access to copy_file_range source with src mounter creds Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 417/869] wifi: mac80211: validate extension-frame layout before RX Greg Kroah-Hartman
` (453 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ingo Franzki, Harald Freudenberger,
Vasily Gorbik, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <freude@linux.ibm.com>
[ Upstream commit 36b230835b8a008266aad22168ca52afacc8a58d ]
Add validation of both the actual key buffer size and token length
fields in all the cca_check_sec*token() functions. Additionally check
in cca_gencipherkey() for possible underflow with returned key size.
The CCA token structures contain user-controlled len fields that
were used in operations without proper validation against both the
actual buffer size and minimum token structure size. An attacker
could set this field larger than the actual buffer size, leading to
reading beyond buffer boundaries. This may result in a kernel crash or
exposure of memory via sending this as part of a request down to the
crypto card. Also an attacker could have used a very small len value
and thus enforce a buffer under-run which may produce similar effects
as a over-read.
So now a key must
- key buf length must be at least sizeof the token struct
- the key len field inside the token must fit into the range of
sizeof key token struct ... key buf length
Fixes: 4bc123b18ce6 ("s390/zcrypt: Add low level functions for CCA AES cipher keys")
Cc: stable@vger.kernel.org
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/s390/crypto/pkey_cca.c | 11 +++--
drivers/s390/crypto/zcrypt_ccamisc.c | 64 +++++++++++++++++++++++-----
drivers/s390/crypto/zcrypt_ccamisc.h | 6 +--
3 files changed, 62 insertions(+), 19 deletions(-)
diff --git a/drivers/s390/crypto/pkey_cca.c b/drivers/s390/crypto/pkey_cca.c
index 9370513817209..6c4dac5fa256e 100644
--- a/drivers/s390/crypto/pkey_cca.c
+++ b/drivers/s390/crypto/pkey_cca.c
@@ -227,7 +227,7 @@ static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
/* CCA AES data key */
if (keylen != sizeof(struct secaeskeytoken))
return -EINVAL;
- if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0))
+ if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, keylen, 0))
return -EINVAL;
} else if (hdr->type == TOKTYPE_CCA_INTERNAL &&
hdr->version == TOKVER_CCA_VLSC) {
@@ -235,12 +235,10 @@ static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE)
return -EINVAL;
if (cca_check_secaescipherkey(pkey_dbf_info,
- 3, key, 0, 1))
+ 3, key, keylen, 0, 1))
return -EINVAL;
} else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {
/* CCA ECC (private) key */
- if (keylen < sizeof(struct eccprivkeytoken))
- return -EINVAL;
if (cca_check_sececckeytoken(pkey_dbf_info, 3, key, keylen, 1))
return -EINVAL;
} else {
@@ -474,7 +472,7 @@ static int cca_verifykey(const u8 *key, u32 keylen,
hdr->version == TOKVER_CCA_AES) {
struct secaeskeytoken *t = (struct secaeskeytoken *)key;
- rc = cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0);
+ rc = cca_check_secaeskeytoken(pkey_dbf_info, 3, key, keylen, 0);
if (rc)
goto out;
*keytype = PKEY_TYPE_CCA_DATA;
@@ -501,7 +499,8 @@ static int cca_verifykey(const u8 *key, u32 keylen,
hdr->version == TOKVER_CCA_VLSC) {
struct cipherkeytoken *t = (struct cipherkeytoken *)key;
- rc = cca_check_secaescipherkey(pkey_dbf_info, 3, key, 0, 1);
+ rc = cca_check_secaescipherkey(pkey_dbf_info, 3,
+ key, keylen, 0, 1);
if (rc)
goto out;
*keytype = PKEY_TYPE_CCA_CIPHER;
diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c
index 48d36d5a87118..c84aa0bdfcae3 100644
--- a/drivers/s390/crypto/zcrypt_ccamisc.c
+++ b/drivers/s390/crypto/zcrypt_ccamisc.c
@@ -46,12 +46,18 @@ static DEFINE_SPINLOCK(cca_info_list_lock);
* also checked. Returns 0 on success or errno value on failure.
*/
int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl,
- const u8 *token, int keybitsize)
+ const u8 *token, u32 keysize, int keybitsize)
{
struct secaeskeytoken *t = (struct secaeskeytoken *)token;
#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
+ if (keysize < sizeof(*t)) {
+ if (dbg)
+ DBF("%s keysize %u < min token size %zu\n",
+ __func__, keysize, sizeof(*t));
+ return -EINVAL;
+ }
if (t->type != TOKTYPE_CCA_INTERNAL) {
if (dbg)
DBF("%s token check failed, type 0x%02x != 0x%02x\n",
@@ -85,14 +91,20 @@ EXPORT_SYMBOL(cca_check_secaeskeytoken);
* Returns 0 on success or errno value on failure.
*/
int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl,
- const u8 *token, int keybitsize,
- int checkcpacfexport)
+ const u8 *token, u32 keysize,
+ int keybitsize, int checkcpacfexport)
{
struct cipherkeytoken *t = (struct cipherkeytoken *)token;
bool keybitsizeok = true;
#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
+ if (keysize < sizeof(*t)) {
+ if (dbg)
+ DBF("%s keysize %u < min token size %zu\n",
+ __func__, keysize, sizeof(*t));
+ return -EINVAL;
+ }
if (t->type != TOKTYPE_CCA_INTERNAL) {
if (dbg)
DBF("%s token check failed, type 0x%02x != 0x%02x\n",
@@ -105,6 +117,18 @@ int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl,
__func__, (int)t->version, TOKVER_CCA_VLSC);
return -EINVAL;
}
+ if (t->len > keysize) {
+ if (dbg)
+ DBF("%s token check failed, len %d > keysize %u\n",
+ __func__, (int)t->len, keysize);
+ return -EINVAL;
+ }
+ if (t->len < sizeof(*t)) {
+ if (dbg)
+ DBF("%s token check failed, len %d < min token size %zu\n",
+ __func__, (int)t->len, sizeof(*t));
+ return -EINVAL;
+ }
if (t->algtype != 0x02) {
if (dbg)
DBF("%s token check failed, algtype 0x%02x != 0x02\n",
@@ -179,6 +203,12 @@ int cca_check_sececckeytoken(debug_info_t *dbg, int dbflvl,
#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
+ if (keysize < sizeof(*t)) {
+ if (dbg)
+ DBF("%s keysize %u < min token size %zu\n",
+ __func__, keysize, sizeof(*t));
+ return -EINVAL;
+ }
if (t->type != TOKTYPE_CCA_INTERNAL_PKA) {
if (dbg)
DBF("%s token check failed, type 0x%02x != 0x%02x\n",
@@ -191,6 +221,12 @@ int cca_check_sececckeytoken(debug_info_t *dbg, int dbflvl,
__func__, (int)t->len, keysize);
return -EINVAL;
}
+ if (t->len < sizeof(*t)) {
+ if (dbg)
+ DBF("%s token check failed, len %d < min token size %zu\n",
+ __func__, (int)t->len, sizeof(*t));
+ return -EINVAL;
+ }
if (t->secid != 0x20) {
if (dbg)
DBF("%s token check failed, secid 0x%02x != 0x20\n",
@@ -414,7 +450,8 @@ int cca_genseckey(u16 cardnr, u16 domain,
/* check secure key token */
rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR,
- prepparm->lv3.keyblock.tok, 8 * keysize);
+ prepparm->lv3.keyblock.tok,
+ seckeysize, 8 * keysize);
if (rc) {
rc = -EIO;
goto out;
@@ -552,7 +589,8 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
/* check secure key token */
rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR,
- prepparm->lv3.keyblock.tok, 8 * keysize);
+ prepparm->lv3.keyblock.tok,
+ seckeysize, 8 * keysize);
if (rc) {
rc = -EIO;
goto out;
@@ -811,6 +849,7 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
} kb;
} __packed * prepparm;
struct cipherkeytoken *t;
+ u32 keybuflen;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
@@ -904,23 +943,28 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
}
/* and some checks on the generated key */
+ t = (struct cipherkeytoken *)prepparm->kb.tlv1.gen_key;
+ if (prepparm->kb.tlv1.len < 2 * sizeof(uint16_t) + sizeof(*t)) {
+ rc = -EIO;
+ goto out;
+ }
+ keybuflen = prepparm->kb.tlv1.len - 2 * sizeof(uint16_t);
rc = cca_check_secaescipherkey(zcrypt_dbf_info, DBF_ERR,
prepparm->kb.tlv1.gen_key,
- keybitsize, 1);
+ keybuflen, keybitsize, 1);
if (rc) {
rc = -EIO;
goto out;
}
/* copy the generated vlsc key token */
- t = (struct cipherkeytoken *)prepparm->kb.tlv1.gen_key;
if (keybuf) {
- if (*keybufsize >= t->len)
- memcpy(keybuf, t, t->len);
+ if (*keybufsize >= keybuflen)
+ memcpy(keybuf, t, keybuflen);
else
rc = -EINVAL;
}
- *keybufsize = t->len;
+ *keybufsize = keybuflen;
out:
free_cprbmem(mem, PARMBSIZE, 0);
diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h
index aed7e83845426..bdddebcaad782 100644
--- a/drivers/s390/crypto/zcrypt_ccamisc.h
+++ b/drivers/s390/crypto/zcrypt_ccamisc.h
@@ -135,7 +135,7 @@ struct eccprivkeytoken {
* also checked. Returns 0 on success or errno value on failure.
*/
int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl,
- const u8 *token, int keybitsize);
+ const u8 *token, u32 keysize, int keybitsize);
/*
* Simple check if the token is a valid CCA secure AES cipher key
@@ -145,8 +145,8 @@ int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl,
* Returns 0 on success or errno value on failure.
*/
int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl,
- const u8 *token, int keybitsize,
- int checkcpacfexport);
+ const u8 *token, u32 keysize,
+ int keybitsize, int checkcpacfexport);
/*
* Simple check if the token is a valid CCA secure ECC private
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 417/869] wifi: mac80211: validate extension-frame layout before RX
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (415 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 416/869] s390/zcrypt: Fix buffer over-read in cca_cipher2protkey Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 418/869] wifi: ieee80211: validate MLE common info length Greg Kroah-Hartman
` (452 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Zhao Li, Johannes Berg, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <enderaoelyther@gmail.com>
[ Upstream commit 57d503ce32eccfa7650065ca4c560f7e29a2e676 ]
Extension frames only have the extension header at the regular 802.11
header offset. The generic RX path can still reach helpers and interface
dispatch code that read regular header address fields before unsupported
extension subtypes are dropped.
mac80211 currently only handles S1G beacon extension frames. Drop other
extension subtypes before they can reach regular-header RX processing.
For S1G beacons, linearize the SKB with the management-frame path and
require the fixed S1G beacon header, including optional fixed fields
indicated by frame control, before generic RX dispatch.
Route S1G beacons through the station/default-link RX path without
regular-header station lookup. Avoid regular-header address reads in the
mac80211 RX paths that process S1G extension beacons, including
accept-frame, duplicate-detection, address-copy, and MLO
address-translation paths.
Also make ieee80211_get_bssid() length-safe before returning the S1G
source-address pointer.
Fixes: 09a740ce352e ("mac80211: receive and process S1G beacons")
Cc: stable@vger.kernel.org
Signed-off-by: Zhao Li <enderaoelyther@gmail.com>
Link: https://patch.msgid.link/20260611161943.91069-5-enderaoelyther@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mac80211/rx.c | 34 ++++++++++++++++++++++++++++++++--
net/mac80211/util.c | 3 +++
2 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index e7f940a890dd4..261add4790307 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1425,6 +1425,9 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
if (status->flag & RX_FLAG_DUP_VALIDATED)
return RX_CONTINUE;
+ if (ieee80211_is_ext(hdr->frame_control))
+ return RX_CONTINUE;
+
/*
* Drop duplicate 802.11 retransmissions
* (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
@@ -4447,8 +4450,12 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
struct ieee80211_hdr *hdr = (void *)skb->data;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
- bool multicast = is_multicast_ether_addr(hdr->addr1) ||
- ieee80211_is_s1g_beacon(hdr->frame_control);
+ bool multicast;
+
+ if (ieee80211_is_s1g_beacon(hdr->frame_control))
+ return sdata->vif.type == NL80211_IFTYPE_STATION && bssid;
+
+ multicast = is_multicast_ether_addr(hdr->addr1);
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
@@ -5087,6 +5094,11 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
hdr = (struct ieee80211_hdr *)rx->skb->data;
}
+ if (ieee80211_is_s1g_beacon(hdr->frame_control)) {
+ ieee80211_invoke_rx_handlers(rx);
+ return true;
+ }
+
if (unlikely(rx->sta && rx->sta->sta.mlo) &&
is_unicast_ether_addr(hdr->addr1) &&
!ieee80211_is_probe_resp(hdr->frame_control) &&
@@ -5171,6 +5183,13 @@ static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx,
struct sta_info *sta;
int link_id = -1;
+ if (ieee80211_is_s1g_beacon(hdr->frame_control)) {
+ if (!ieee80211_rx_data_set_sta(rx, NULL, -1))
+ return false;
+
+ return ieee80211_prepare_and_rx_handle(rx, skb, consume);
+ }
+
/*
* Look up link station first, in case there's a
* chance that they might have a link address that
@@ -5230,6 +5249,17 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
err = -ENOBUFS;
else
err = skb_linearize(skb);
+ } else if (ieee80211_is_s1g_beacon(fc)) {
+ size_t s1g_hdr_len = offsetof(struct ieee80211_ext,
+ u.s1g_beacon.variable) +
+ ieee80211_s1g_optional_len(fc);
+
+ if (skb->len < s1g_hdr_len)
+ err = -ENOBUFS;
+ else
+ err = skb_linearize(skb);
+ } else if (ieee80211_is_ext(fc)) {
+ err = -EINVAL;
} else {
err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 2dfb9c089b470..091a1f51eb15f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -73,6 +73,9 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
if (ieee80211_is_s1g_beacon(fc)) {
struct ieee80211_ext *ext = (void *) hdr;
+ if (len < offsetofend(struct ieee80211_ext, u.s1g_beacon.sa))
+ return NULL;
+
return ext->u.s1g_beacon.sa;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 418/869] wifi: ieee80211: validate MLE common info length
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (416 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 417/869] wifi: mac80211: validate extension-frame layout before RX Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 419/869] ata: libata-core: Disable LPM on Silicon Motion MD619{H,G}XCLDE3TC Greg Kroah-Hartman
` (451 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Zhao Li, Johannes Berg, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <enderaoelyther@gmail.com>
[ Upstream commit 293baeae9b2434a3e432629d7720b5603db2d77e ]
ieee80211_mle_common_size() uses the first common-info octet as the
common information length for all known MLE types. However,
ieee80211_mle_size_ok() only validates that octet for Basic, Probe
Request, and TDLS MLEs.
Reconfiguration MLEs also skipped the length octet when calculating the
minimum common size, and Priority Access MLEs skipped validation of the
advertised common information length.
Account for the Reconfiguration common-info length octet and validate
the advertised common information length for all known MLE types. Keep
unknown-type handling unchanged.
Fixes: 0f48b8b88aa9 ("wifi: ieee80211: add definitions for multi-link element")
Cc: stable@vger.kernel.org
Signed-off-by: Zhao Li <enderaoelyther@gmail.com>
Link: https://patch.msgid.link/20260611173506.36838-2-enderaoelyther@gmail.com
[remove now misleading comment]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/ieee80211.h | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 85bf3ac6db570..59e7c0a81cee7 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -5348,7 +5348,7 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
const struct ieee80211_multi_link_elem *mle = (const void *)data;
u8 fixed = sizeof(*mle);
u8 common = 0;
- bool check_common_len = false;
+ u8 common_len;
u16 control;
if (!data || len < fixed)
@@ -5359,7 +5359,6 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
switch (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE)) {
case IEEE80211_ML_CONTROL_TYPE_BASIC:
common += sizeof(struct ieee80211_mle_basic_common_info);
- check_common_len = true;
if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID)
common += 1;
if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT)
@@ -5377,15 +5376,14 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
common += sizeof(struct ieee80211_mle_preq_common_info);
if (control & IEEE80211_MLC_PREQ_PRES_MLD_ID)
common += 1;
- check_common_len = true;
break;
case IEEE80211_ML_CONTROL_TYPE_RECONF:
+ common += 1;
if (control & IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR)
common += ETH_ALEN;
break;
case IEEE80211_ML_CONTROL_TYPE_TDLS:
common += sizeof(struct ieee80211_mle_tdls_common_info);
- check_common_len = true;
break;
case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS:
common = ETH_ALEN + 1;
@@ -5398,11 +5396,9 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
if (len < fixed + common)
return false;
- if (!check_common_len)
- return true;
+ common_len = mle->variable[0];
- /* if present, common length is the first octet there */
- return mle->variable[0] >= common;
+ return common_len >= common && common_len <= len - fixed;
}
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 419/869] ata: libata-core: Disable LPM on Silicon Motion MD619{H,G}XCLDE3TC
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (417 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 418/869] wifi: ieee80211: validate MLE common info length Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 420/869] ata: libata-core: Add NOLPM quirk for PNY CS900 1TB SSD Greg Kroah-Hartman
` (450 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Yihang Li, Niklas Cassel,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Niklas Cassel <cassel@kernel.org>
[ Upstream commit 6ce0dd9f54ea9773c0aedfaab7b858fc68a848ba ]
According to a user report, the Silicon Motion MD619HXCLDE3TC SSD and
the Silicon Motion MD619GXCLDE3TC SSD have problems with LPM.
Reported-by: Yihang Li <liyihang9@h-partners.com>
Closes: https://lore.kernel.org/linux-ide/20251121073502.3388239-1-liyihang9@h-partners.com/
Signed-off-by: Niklas Cassel <cassel@kernel.org>
Stable-dep-of: 462775c62019 ("ata: libata-core: Add NOLPM quirk for PNY CS900 1TB SSD")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ata/libata-core.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index caf77faf7a33f..e07f82ca68f18 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4226,6 +4226,10 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
/* Apacer models with LPM issues */
{ "Apacer AS340*", NULL, ATA_QUIRK_NOLPM },
+ /* Silicon Motion models with LPM issues */
+ { "MD619HXCLDE3TC", "TCVAID", ATA_QUIRK_NOLPM },
+ { "MD619GXCLDE3TC", "TCV35D", ATA_QUIRK_NOLPM },
+
/* These specific Samsung models/firmware-revs do not handle LPM well */
{ "SAMSUNG MZMPC128HBFU-000MV", "CXM14M1Q", ATA_QUIRK_NOLPM },
{ "SAMSUNG SSD PM830 mSATA *", "CXM13D1Q", ATA_QUIRK_NOLPM },
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 420/869] ata: libata-core: Add NOLPM quirk for PNY CS900 1TB SSD
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (418 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 419/869] ata: libata-core: Disable LPM on Silicon Motion MD619{H,G}XCLDE3TC Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 421/869] mmc: vub300: Use devm_mmc_alloc_host() helper Greg Kroah-Hartman
` (449 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bryam Vargas, Niklas Cassel,
Damien Le Moal, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <hexlabsecurity@proton.me>
[ Upstream commit 462775c620197adaabc983ce847e5b9878ff4cb0 ]
The PNY CS900 1TB SSD (Phison PS3111-S11, DRAM-less) drops off the bus
after entering Device-Initiated Slumber during idle. With the default
med_power_with_dipm policy the link goes down (SStatus 1 SControl 300)
and does not recover, forcing the filesystem read-only. Forcing
max_performance keeps the link stable across prolonged idle.
Add a NOLPM quirk so link power management is disabled for this drive
specifically, leaving it intact for other devices on the host.
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Reviewed-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ata/libata-core.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index e07f82ca68f18..fe3ed016b6d18 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4226,6 +4226,9 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
/* Apacer models with LPM issues */
{ "Apacer AS340*", NULL, ATA_QUIRK_NOLPM },
+ /* PNY CS900 (Phison PS3111-S11, DRAM-less) drops the link on DIPM */
+ { "PNY CS900 1TB SSD", NULL, ATA_QUIRK_NOLPM },
+
/* Silicon Motion models with LPM issues */
{ "MD619HXCLDE3TC", "TCVAID", ATA_QUIRK_NOLPM },
{ "MD619GXCLDE3TC", "TCV35D", ATA_QUIRK_NOLPM },
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 421/869] mmc: vub300: Use devm_mmc_alloc_host() helper
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (419 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 420/869] ata: libata-core: Add NOLPM quirk for PNY CS900 1TB SSD Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 422/869] mmc: vub300: fix use-after-free on disconnect Greg Kroah-Hartman
` (448 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Huacai Chen, Binbin Zhou,
Ulf Hansson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Binbin Zhou <zhoubinbin@loongson.cn>
[ Upstream commit dcfdd698dc521c6046e9b80c16281575efb25d23 ]
Use new function devm_mmc_alloc_host() to simplify the code.
Reviewed-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
Link: https://lore.kernel.org/r/f023d2caa02fab405f089c5170b686529857fb70.1748933789.git.zhoubinbin@loongson.cn
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Stable-dep-of: a3b5f242997a ("mmc: vub300: fix use-after-free on probe failure")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/mmc/host/vub300.c | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index 35393f534de2b..2b0623cf34c90 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -369,13 +369,11 @@ struct vub300_mmc_host {
static void vub300_delete(struct kref *kref)
{ /* kref callback - softirq */
struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref);
- struct mmc_host *mmc = vub300->mmc;
usb_free_urb(vub300->command_out_urb);
vub300->command_out_urb = NULL;
usb_free_urb(vub300->command_res_urb);
vub300->command_res_urb = NULL;
usb_put_dev(vub300->udev);
- mmc_free_host(mmc);
/*
* and hence also frees vub300
* which is contained at the end of struct mmc
@@ -2122,7 +2120,7 @@ static int vub300_probe(struct usb_interface *interface,
goto error1;
}
/* this also allocates memory for our VUB300 mmc host device */
- mmc = mmc_alloc_host(sizeof(struct vub300_mmc_host), &udev->dev);
+ mmc = devm_mmc_alloc_host(&udev->dev, sizeof(*vub300));
if (!mmc) {
retval = -ENOMEM;
dev_err(&udev->dev, "not enough memory for the mmc_host\n");
@@ -2279,7 +2277,7 @@ static int vub300_probe(struct usb_interface *interface,
dev_err(&vub300->udev->dev,
"Could not find two sets of bulk-in/out endpoint pairs\n");
retval = -EINVAL;
- goto error5;
+ goto error4;
}
retval =
usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
@@ -2288,14 +2286,14 @@ static int vub300_probe(struct usb_interface *interface,
0x0000, 0x0000, &vub300->hc_info,
sizeof(vub300->hc_info), 1000);
if (retval < 0)
- goto error5;
+ goto error4;
retval =
usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
SET_ROM_WAIT_STATES,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
firmware_rom_wait_states, 0x0000, NULL, 0, 1000);
if (retval < 0)
- goto error5;
+ goto error4;
dev_info(&vub300->udev->dev,
"operating_mode = %s %s %d MHz %s %d byte USB packets\n",
(mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
@@ -2310,7 +2308,7 @@ static int vub300_probe(struct usb_interface *interface,
0x0000, 0x0000, &vub300->system_port_status,
sizeof(vub300->system_port_status), 1000);
if (retval < 0) {
- goto error5;
+ goto error4;
} else if (sizeof(vub300->system_port_status) == retval) {
vub300->card_present =
(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
@@ -2318,7 +2316,7 @@ static int vub300_probe(struct usb_interface *interface,
(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
} else {
retval = -EINVAL;
- goto error5;
+ goto error4;
}
usb_set_intfdata(interface, vub300);
INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
@@ -2348,8 +2346,6 @@ static int vub300_probe(struct usb_interface *interface,
return 0;
error6:
del_timer_sync(&vub300->inactivity_timer);
-error5:
- mmc_free_host(mmc);
/*
* and hence also frees vub300
* which is contained at the end of struct mmc
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 422/869] mmc: vub300: fix use-after-free on disconnect
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (420 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 421/869] mmc: vub300: Use devm_mmc_alloc_host() helper Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 423/869] mmc: vub300: rename probe error labels Greg Kroah-Hartman
` (447 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Binbin Zhou, Johan Hovold,
Ulf Hansson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <johan@kernel.org>
[ Upstream commit 8f4d20a710225ec7a565f6a0459862d3b1f32330 ]
The vub300 driver maintains an explicit reference count for the
controller and its driver data and the last reference can in theory be
dropped after the driver has been unbound.
This specifically means that the controller allocation must not be
device managed as that can lead to use-after-free.
Note that the lifetime is currently also incorrectly tied the parent USB
device rather than interface, which can lead to memory leaks if the
driver is unbound without its device being physically disconnected (e.g.
on probe deferral).
Fix both issues by reverting to non-managed allocation of the controller.
Fixes: dcfdd698dc52 ("mmc: vub300: Use devm_mmc_alloc_host() helper")
Cc: stable@vger.kernel.org # 6.17+
Cc: Binbin Zhou <zhoubinbin@loongson.cn>
Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Stable-dep-of: a3b5f242997a ("mmc: vub300: fix use-after-free on probe failure")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/mmc/host/vub300.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index 2b0623cf34c90..937b9644f958c 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -369,11 +369,14 @@ struct vub300_mmc_host {
static void vub300_delete(struct kref *kref)
{ /* kref callback - softirq */
struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref);
+ struct mmc_host *mmc = vub300->mmc;
+
usb_free_urb(vub300->command_out_urb);
vub300->command_out_urb = NULL;
usb_free_urb(vub300->command_res_urb);
vub300->command_res_urb = NULL;
usb_put_dev(vub300->udev);
+ mmc_free_host(mmc);
/*
* and hence also frees vub300
* which is contained at the end of struct mmc
@@ -2120,7 +2123,7 @@ static int vub300_probe(struct usb_interface *interface,
goto error1;
}
/* this also allocates memory for our VUB300 mmc host device */
- mmc = devm_mmc_alloc_host(&udev->dev, sizeof(*vub300));
+ mmc = mmc_alloc_host(sizeof(*vub300), &udev->dev);
if (!mmc) {
retval = -ENOMEM;
dev_err(&udev->dev, "not enough memory for the mmc_host\n");
@@ -2277,7 +2280,7 @@ static int vub300_probe(struct usb_interface *interface,
dev_err(&vub300->udev->dev,
"Could not find two sets of bulk-in/out endpoint pairs\n");
retval = -EINVAL;
- goto error4;
+ goto err_free_host;
}
retval =
usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
@@ -2286,14 +2289,14 @@ static int vub300_probe(struct usb_interface *interface,
0x0000, 0x0000, &vub300->hc_info,
sizeof(vub300->hc_info), 1000);
if (retval < 0)
- goto error4;
+ goto err_free_host;
retval =
usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
SET_ROM_WAIT_STATES,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
firmware_rom_wait_states, 0x0000, NULL, 0, 1000);
if (retval < 0)
- goto error4;
+ goto err_free_host;
dev_info(&vub300->udev->dev,
"operating_mode = %s %s %d MHz %s %d byte USB packets\n",
(mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
@@ -2308,7 +2311,7 @@ static int vub300_probe(struct usb_interface *interface,
0x0000, 0x0000, &vub300->system_port_status,
sizeof(vub300->system_port_status), 1000);
if (retval < 0) {
- goto error4;
+ goto err_free_host;
} else if (sizeof(vub300->system_port_status) == retval) {
vub300->card_present =
(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
@@ -2316,7 +2319,7 @@ static int vub300_probe(struct usb_interface *interface,
(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
} else {
retval = -EINVAL;
- goto error4;
+ goto err_free_host;
}
usb_set_intfdata(interface, vub300);
INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
@@ -2341,11 +2344,14 @@ static int vub300_probe(struct usb_interface *interface,
interface_to_InterfaceNumber(interface));
retval = mmc_add_host(mmc);
if (retval)
- goto error6;
+ goto err_delete_timer;
return 0;
-error6:
- del_timer_sync(&vub300->inactivity_timer);
+
+err_delete_timer:
+ timer_delete_sync(&vub300->inactivity_timer);
+err_free_host:
+ mmc_free_host(mmc);
/*
* and hence also frees vub300
* which is contained at the end of struct mmc
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 423/869] mmc: vub300: rename probe error labels
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (421 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 422/869] mmc: vub300: fix use-after-free on disconnect Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 424/869] mmc: vub300: fix use-after-free on probe failure Greg Kroah-Hartman
` (446 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Johan Hovold, Ulf Hansson,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <johan@kernel.org>
[ Upstream commit 5b8b35d6f4fa758dd5e8ae18526ea1c73f6787e0 ]
Error labels should be named after what they do.
Rename the probe error labels.
Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Stable-dep-of: a3b5f242997a ("mmc: vub300: fix use-after-free on probe failure")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/mmc/host/vub300.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index 937b9644f958c..73d4af7e9b32c 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -2115,19 +2115,19 @@ static int vub300_probe(struct usb_interface *interface,
command_out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!command_out_urb) {
retval = -ENOMEM;
- goto error0;
+ goto err_put_udev;
}
command_res_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!command_res_urb) {
retval = -ENOMEM;
- goto error1;
+ goto err_free_out_urb;
}
/* this also allocates memory for our VUB300 mmc host device */
mmc = mmc_alloc_host(sizeof(*vub300), &udev->dev);
if (!mmc) {
retval = -ENOMEM;
dev_err(&udev->dev, "not enough memory for the mmc_host\n");
- goto error4;
+ goto err_free_res_urb;
}
/* MMC core transfer sizes tunable parameters */
mmc->caps = 0;
@@ -2356,12 +2356,13 @@ static int vub300_probe(struct usb_interface *interface,
* and hence also frees vub300
* which is contained at the end of struct mmc
*/
-error4:
+err_free_res_urb:
usb_free_urb(command_res_urb);
-error1:
+err_free_out_urb:
usb_free_urb(command_out_urb);
-error0:
+err_put_udev:
usb_put_dev(udev);
+
return retval;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 424/869] mmc: vub300: fix use-after-free on probe failure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (422 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 423/869] mmc: vub300: rename probe error labels Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 425/869] dm-verity: fix buffer overflow in FEC calculation Greg Kroah-Hartman
` (445 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Guangshuo Li, Johan Hovold,
Ulf Hansson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <lgs201920130244@gmail.com>
[ Upstream commit a3b5f242997a3be7404112fd48784881560aea57 ]
The vub300 driver lifetime-manages its controller state using
vub300->kref, with vub300_delete() freeing the mmc host when the last
reference is dropped. The probe error path after the inactivity timer has
been armed still bypasses that lifetime rule, however, and falls through
to mmc_free_host() directly if mmc_add_host() fails.
The race window is between arming the inactivity timer and reaching the
probe error unwind after mmc_add_host() fails:
probe thread timer/workqueue
------------ ---------------
kref_init(&vub300->kref) ref = 1
kref_get(&vub300->kref) ref = 2, timer ref
add_timer(inactivity_timer) fires after one second
|
| race window
|<---------------------------------------------------->
|
mmc_add_host(mmc)
inactivity timer fires
vub300_queue_dead_work()
kref_get() ref = 3
queue_work(deadwork)
mmc_add_host() fails
timer_delete_sync()
mmc_free_host(mmc)
frees vub300
deadwork runs
use-after-free
The inactivity timeout is one second, so this would require
mmc_add_host() to both fail and take more than one second to do so. This
is unlikely to happen in practice, but the error path is still wrong.
timer_delete_sync() only waits for the timer callback itself. It does
not flush deadwork that the callback may already have queued. As a
result, queued deadwork can still hold a kref while the probe error path
directly frees the backing mmc host, including the vub300 storage.
Fix this by using the same lifetime mechanism as disconnect. Clear
vub300->interface so that the timer callback and any queued deadwork
return early and drop their references, then drop the initial probe
reference and return without falling through to err_free_host.
Fixes: 0613ad2401f8 ("mmc: vub300: fix return value check of mmc_add_host()")
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
Reviewed-by: Johan Hovold <johan@kernel.org>
Cc: stable@vger.kernel.org
Signed-off-by: Ulf Hansson <ulfh@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/mmc/host/vub300.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index 73d4af7e9b32c..63989479ae838 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -2344,12 +2344,16 @@ static int vub300_probe(struct usb_interface *interface,
interface_to_InterfaceNumber(interface));
retval = mmc_add_host(mmc);
if (retval)
- goto err_delete_timer;
+ goto err_stop_io;
return 0;
-err_delete_timer:
- timer_delete_sync(&vub300->inactivity_timer);
+err_stop_io:
+ vub300->interface = NULL;
+ kref_put(&vub300->kref, vub300_delete);
+
+ return retval;
+
err_free_host:
mmc_free_host(mmc);
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 425/869] dm-verity: fix buffer overflow in FEC calculation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (423 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 424/869] mmc: vub300: fix use-after-free on probe failure Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 426/869] ocfs2: correct l_next_free_rec in online check Greg Kroah-Hartman
` (444 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Mikulas Patocka, Sami Tolvanen,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <mpatocka@redhat.com>
[ Upstream commit 31d6e6c0ba8d5a7bd59660035a089307100c5e8e ]
There's a buffer overflow in dm-verity-fec:
if (neras && *neras <= v->fec->roots)
fio->erasures[(*neras)++] = i;
This allows *neras to reach roots + 1 (the post-increment pushes it past
roots). This value is then passed as no_eras to decode_rs8(). Inside the
RS decoder (lib/reed_solomon/decode_rs.c:113-121), the erasure locator
polynomial loop writes lambda[j] where j can reach nroots + 1 — one
element past the end of lambda[] (which is sized nroots + 1, valid
indices 0..nroots). The out-of-bounds write lands on syn[0], corrupting
the syndrome buffer.
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Assisted-by: Claude:claude-opus-4-6
Cc: stable@vger.kernel.org
Fixes: a739ff3f543a ("dm verity: add support for forward error correction")
Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/dm-verity-fec.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
index 56813d02d5465..b6115ac9c8256 100644
--- a/drivers/md/dm-verity-fec.c
+++ b/drivers/md/dm-verity-fec.c
@@ -263,7 +263,7 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
(unsigned long long)block, PTR_ERR(bbuf));
/* assume the block is corrupted */
- if (neras && *neras <= v->fec->roots)
+ if (neras && *neras < v->fec->roots)
fio->erasures[(*neras)++] = i;
continue;
@@ -281,7 +281,7 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
* skip if we have already found the theoretical
* maximum number (i.e. fec->roots) of erasures
*/
- if (neras && *neras <= v->fec->roots &&
+ if (neras && *neras < v->fec->roots &&
fec_is_erasure(v, io, want_digest, bbuf))
fio->erasures[(*neras)++] = i;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 426/869] ocfs2: correct l_next_free_rec in online check
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (424 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 425/869] dm-verity: fix buffer overflow in FEC calculation Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 427/869] ocfs2: add suballoc slot check in ocfs2_validate_inode_block() Greg Kroah-Hartman
` (443 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Julian Sun, Joseph Qi, Mark Fasheh,
Joel Becker, Junxiao Bi, Changwei Ge, Jun Piao, Andrew Morton,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Julian Sun <sunjunchao2870@gmail.com>
[ Upstream commit fdbb6cd96ed51da002bd9a5a142586a74a436784 ]
Correct the value of l_next_free_rec to l_count during the online check,
as done in the check_el() function in ocfs2_tools.
Link: https://lkml.kernel.org/r/20250106023432.1320904-2-sunjunchao2870@gmail.com
Signed-off-by: Julian Sun <sunjunchao2870@gmail.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Stable-dep-of: 452a8467be81 ("ocfs2: fix UBSAN array-index-out-of-bounds in ocfs2_sum_rightmost_rec")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/inode.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 9a56c57f9ded2..5c540d0af8aa2 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -233,6 +233,20 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
return inode;
}
+static int ocfs2_dinode_has_extents(struct ocfs2_dinode *di)
+{
+ /* inodes flagged with other stuff in id2 */
+ if (di->i_flags & (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL |
+ OCFS2_CHAIN_FL | OCFS2_DEALLOC_FL))
+ return 0;
+ /* i_flags doesn't indicate when id2 is a fast symlink */
+ if (S_ISLNK(di->i_mode) && di->i_size && di->i_clusters == 0)
+ return 0;
+ if (di->i_dyn_features & OCFS2_INLINE_DATA_FL)
+ return 0;
+
+ return 1;
+}
/*
* here's how inodes get read from disk:
@@ -1728,6 +1742,16 @@ static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
le32_to_cpu(di->i_fs_generation));
}
+ if (ocfs2_dinode_has_extents(di) &&
+ le16_to_cpu(di->id2.i_list.l_next_free_rec) > le16_to_cpu(di->id2.i_list.l_count)) {
+ di->id2.i_list.l_next_free_rec = di->id2.i_list.l_count;
+ changed = 1;
+ mlog(ML_ERROR,
+ "Filecheck: reset dinode #%llu: l_next_free_rec to %u\n",
+ (unsigned long long)bh->b_blocknr,
+ le16_to_cpu(di->id2.i_list.l_next_free_rec));
+ }
+
if (changed || ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check)) {
ocfs2_compute_meta_ecc(sb, bh->b_data, &di->i_check);
mark_buffer_dirty(bh);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 427/869] ocfs2: add suballoc slot check in ocfs2_validate_inode_block()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (425 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 426/869] ocfs2: correct l_next_free_rec in online check Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 428/869] ocfs2: add extra consistency checks for chain allocator dinodes Greg Kroah-Hartman
` (442 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dmitry Antipov,
syzbot+900962ac9bf1860033f2, Joseph Qi, Mark Fasheh, Joel Becker,
Junxiao Bi, Changwei Ge, Jun Piao, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Antipov <dmantipov@yandex.ru>
[ Upstream commit fe7a283b39160153b6d1bd7f61b0a9d5d44987a8 ]
In 'ocfs2_validate_inode_block()', add suballoc slot check similar to one
in 'ocfs2_get_suballoc_slot_bit()', thus preventing an out-of-bounds
accesses for 'local_system_inodes' in 'get_local_system_inode()'.
Most likely this fixes
https://syzkaller.appspot.com/bug?extid=a77d690840e60bc2ddd8 as well.
Link: https://lkml.kernel.org/r/20250826095106.666980-1-dmantipov@yandex.ru
Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
Reported-by: syzbot+900962ac9bf1860033f2@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=900962ac9bf1860033f2
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Stable-dep-of: 452a8467be81 ("ocfs2: fix UBSAN array-index-out-of-bounds in ocfs2_sum_rightmost_rec")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/inode.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 5c540d0af8aa2..9104f088c86d8 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -1577,6 +1577,14 @@ int ocfs2_validate_inode_block(struct super_block *sb,
}
}
+ if (le16_to_cpu(di->i_suballoc_slot) != (u16)OCFS2_INVALID_SLOT &&
+ (u32)le16_to_cpu(di->i_suballoc_slot) > OCFS2_SB(sb)->max_slots - 1) {
+ rc = ocfs2_error(sb, "Invalid dinode %llu: suballoc slot %u\n",
+ (unsigned long long)bh->b_blocknr,
+ le16_to_cpu(di->i_suballoc_slot));
+ goto bail;
+ }
+
rc = 0;
bail:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 428/869] ocfs2: add extra consistency checks for chain allocator dinodes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (426 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 427/869] ocfs2: add suballoc slot check in ocfs2_validate_inode_block() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 429/869] ocfs2: validate i_refcount_loc when refcount flag is set Greg Kroah-Hartman
` (441 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dmitry Antipov,
syzbot+77026564530dbc29b854, syzbot+5054473a31f78f735416,
Joseph Qi, Junxiao Bi, Jun Piao, Deepanshu Kartikey, Heming Zhao,
Joel Becker, Mark Fasheh, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Antipov <dmantipov@yandex.ru>
[ Upstream commit e1c70505ee8158c1108340d9cd67182ade93af4a ]
When validating chain allocator dinode in 'ocfs2_validate_inode_block()',
add an extra checks whether a) the maximum amount of chain records in
'struct ocfs2_chain_list' matches the value calculated based on the
filesystem block size, and b) the next free slot index is within the valid
range.
Link: https://lkml.kernel.org/r/20251030153003.1934585-1-dmantipov@yandex.ru
Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
Reported-by: syzbot+77026564530dbc29b854@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=77026564530dbc29b854
Reported-by: syzbot+5054473a31f78f735416@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=5054473a31f78f735416
Suggested-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Deepanshu Kartikey <kartikey406@gmail.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Mark Fasheh <mark@fasheh.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Adapted for this tree: the inline-data i_clusters check this change sits
next to is already present earlier in ocfs2_validate_inode_block(), so only
the new chain allocator dinode checks are added.
Stable-dep-of: 452a8467be81 ("ocfs2: fix UBSAN array-index-out-of-bounds in ocfs2_sum_rightmost_rec")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/inode.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 9104f088c86d8..e3aba593e189f 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -1585,6 +1585,23 @@ int ocfs2_validate_inode_block(struct super_block *sb,
goto bail;
}
+ if (le32_to_cpu(di->i_flags) & OCFS2_CHAIN_FL) {
+ struct ocfs2_chain_list *cl = &di->id2.i_chain;
+
+ if (le16_to_cpu(cl->cl_count) != ocfs2_chain_recs_per_inode(sb)) {
+ rc = ocfs2_error(sb, "Invalid dinode %llu: chain list count %u\n",
+ (unsigned long long)bh->b_blocknr,
+ le16_to_cpu(cl->cl_count));
+ goto bail;
+ }
+ if (le16_to_cpu(cl->cl_next_free_rec) > le16_to_cpu(cl->cl_count)) {
+ rc = ocfs2_error(sb, "Invalid dinode %llu: chain list index %u\n",
+ (unsigned long long)bh->b_blocknr,
+ le16_to_cpu(cl->cl_next_free_rec));
+ goto bail;
+ }
+ }
+
rc = 0;
bail:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 429/869] ocfs2: validate i_refcount_loc when refcount flag is set
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (427 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 428/869] ocfs2: add extra consistency checks for chain allocator dinodes Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 430/869] ocfs2: fix UBSAN array-index-out-of-bounds in ocfs2_sum_rightmost_rec Greg Kroah-Hartman
` (440 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Deepanshu Kartikey,
syzbot+6d832e79d3efe1c46743, Joseph Qi, Mark Fasheh, Joel Becker,
Junxiao Bi, Changwei Ge, Jun Piao, Heming Zhao, Andrew Morton,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Deepanshu Kartikey <kartikey406@gmail.com>
[ Upstream commit 688dab01c3bb14cb559878aaf7019bfba4a79275 ]
Add validation in ocfs2_validate_inode_block() to check that if an inode
has OCFS2_HAS_REFCOUNT_FL set, it must also have a valid i_refcount_loc.
A corrupted filesystem image can have this inconsistent state, which later
triggers a BUG_ON in ocfs2_remove_refcount_tree() when the inode is being
wiped during unlink.
Catch this corruption early during inode validation to fail gracefully
instead of crashing the kernel.
Link: https://lkml.kernel.org/r/20251212055826.20929-1-kartikey406@gmail.com
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
Reported-by: syzbot+6d832e79d3efe1c46743@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=6d832e79d3efe1c46743
Tested-by: syzbot+6d832e79d3efe1c46743@syzkaller.appspotmail.com
Link: https://lore.kernel.org/all/20251208084407.3021466-1-kartikey406@gmail.com/T/ [v1]
Link: https://lore.kernel.org/all/20251212045646.9988-1-kartikey406@gmail.com/T/ [v2]
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Stable-dep-of: 452a8467be81 ("ocfs2: fix UBSAN array-index-out-of-bounds in ocfs2_sum_rightmost_rec")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/inode.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index e3aba593e189f..03a3fc96e534f 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -1602,6 +1602,13 @@ int ocfs2_validate_inode_block(struct super_block *sb,
}
}
+ if ((le16_to_cpu(di->i_dyn_features) & OCFS2_HAS_REFCOUNT_FL) &&
+ !di->i_refcount_loc) {
+ rc = ocfs2_error(sb, "Inode #%llu has refcount flag but no i_refcount_loc\n",
+ (unsigned long long)bh->b_blocknr);
+ goto bail;
+ }
+
rc = 0;
bail:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 430/869] ocfs2: fix UBSAN array-index-out-of-bounds in ocfs2_sum_rightmost_rec
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (428 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 429/869] ocfs2: validate i_refcount_loc when refcount flag is set Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 431/869] KVM: arm64: vgic: Handle race between interrupt affinity change and LPI disabling Greg Kroah-Hartman
` (439 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ian Bridges,
syzbot+be16e33db01e6644db7a, Joseph Qi, Mark Fasheh, Joel Becker,
Junxiao Bi, Changwei Ge, Jun Piao, Heming Zhao, Andrew Morton,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Bridges <icb@fastmail.org>
[ Upstream commit 452a8467be8143747292218212671deeb186d2ae ]
[BUG]
On-disk corruption setting l_next_free_rec to 0 in an inode's embedded
extent list triggers a UBSAN panic on the next write to that file.
[CAUSE]
ocfs2_sum_rightmost_rec() computes
i = le16_to_cpu(el->l_next_free_rec) - 1
and accesses el->l_recs[i] without validating i. When l_next_free_rec
is 0, i becomes -1; when l_next_free_rec exceeds l_count, i falls
past the end of the array. Either case violates the
__counted_by_le(l_count) annotation on l_recs[] and triggers UBSAN.
[FIX]
Validate the inode's embedded extent list when the inode is read, in
ocfs2_validate_inode_block(): l_count must be non-zero and no larger
than the inode block can hold, and l_next_free_rec must not exceed
l_count. A corrupt list is rejected at read time, before the b-tree
code can index l_recs[] out of bounds.
Link: https://lore.kernel.org/ain_780qc0P4ypNd@dev
Signed-off-by: Ian Bridges <icb@fastmail.org>
Reported-by: syzbot+be16e33db01e6644db7a@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=be16e33db01e6644db7a
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/inode.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 03a3fc96e534f..4f7b03f34a4c0 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -1609,6 +1609,38 @@ int ocfs2_validate_inode_block(struct super_block *sb,
goto bail;
}
+ if (ocfs2_dinode_has_extents(di)) {
+ struct ocfs2_extent_list *el = &di->id2.i_list;
+ u16 count = le16_to_cpu(el->l_count);
+ u16 next_free = le16_to_cpu(el->l_next_free_rec);
+
+ if (count == 0) {
+ rc = ocfs2_error(sb,
+ "Invalid dinode %llu: extent list l_count is zero\n",
+ (unsigned long long)bh->b_blocknr);
+ goto bail;
+ }
+ /*
+ * The exact capacity depends on i_xattr_inline_size, another
+ * unvalidated on-disk field. Inline xattrs only shrink the
+ * list, so the no-xattr maximum is a safe upper bound that a
+ * valid l_count never exceeds.
+ */
+ if (count > ocfs2_extent_recs_per_inode(sb)) {
+ rc = ocfs2_error(sb,
+ "Invalid dinode %llu: extent list l_count %u exceeds max %u\n",
+ (unsigned long long)bh->b_blocknr, count,
+ ocfs2_extent_recs_per_inode(sb));
+ goto bail;
+ }
+ if (next_free > count) {
+ rc = ocfs2_error(sb,
+ "Invalid dinode %llu: extent list l_next_free_rec %u exceeds l_count %u\n",
+ (unsigned long long)bh->b_blocknr, next_free, count);
+ goto bail;
+ }
+ }
+
rc = 0;
bail:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 431/869] KVM: arm64: vgic: Handle race between interrupt affinity change and LPI disabling
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (429 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 430/869] ocfs2: fix UBSAN array-index-out-of-bounds in ocfs2_sum_rightmost_rec Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 432/869] ipv4: igmp: Fix potential memory leaks in igmp_mod_timer() and igmp_stop_timer() Greg Kroah-Hartman
` (438 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Hyunwoo Kim, Marc Zyngier,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Zyngier <maz@kernel.org>
[ Upstream commit 7258770e5814f15e8308ebda82ac9acf6964ba8e ]
Hyunwoo Kim reports some really bad races should the following
situation occur:
- LPI-I is pending in vcpu-B's AP list
- vcpu-A writes to vcpu-B's RD to disable its LPIs
- vcpu-C moves I from B to C
If the last two race nicely enough, vgic_prune_ap_list() can drop
the irq and AP list locks, reacquire them, and in the interval
the irq has been freed. UAF follows.
The fix is two-fold:
- Before dropping the irq and ap_list locks, take a reference on
the irq
- Do not try to handle migration of the pending bit: there is no
expectation that this state is retained, as per the architecture
With that, we're sure that the interrupt is still around, and we
safely remove it from the AP list as it has no target at this
stage (unless another interrupt fires, but that's another story).
Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
Tested-by: Hyunwoo Kim <imv4bel@gmail.com>
Link: https://lore.kernel.org/r/ailsCnyoS82r_QRz@v4bel
Link: https://patch.msgid.link/20260615181625.3029352-1-maz@kernel.org
Fixes: 5dd4b924e390a ("KVM: arm/arm64: vgic: Add refcounting for IRQs")
Signed-off-by: Marc Zyngier <maz@kernel.org>
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm64/kvm/vgic/vgic.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 497b7af5caa4d..967d8111642cf 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -144,6 +144,7 @@ void vgic_flush_pending_lpis(struct kvm_vcpu *vcpu)
list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
if (irq->intid >= VGIC_MIN_LPI) {
raw_spin_lock(&irq->irq_lock);
+ irq->pending_latch = false;
list_del(&irq->ap_list);
irq->vcpu = NULL;
raw_spin_unlock(&irq->irq_lock);
@@ -661,7 +662,11 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
continue;
}
- /* This interrupt looks like it has to be migrated. */
+ /*
+ * This interrupt looks like it has to be migrated,
+ * make sure it is kept alive while locks are dropped.
+ */
+ vgic_get_irq_kref(irq);
raw_spin_unlock(&irq->irq_lock);
raw_spin_unlock(&vgic_cpu->ap_list_lock);
@@ -706,6 +711,8 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
raw_spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
raw_spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
+ vgic_put_irq(vcpu->kvm, irq);
+
if (target_vcpu_needs_kick) {
kvm_make_request(KVM_REQ_IRQ_PENDING, target_vcpu);
kvm_vcpu_kick(target_vcpu);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 432/869] ipv4: igmp: Fix potential memory leaks in igmp_mod_timer() and igmp_stop_timer()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (430 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 431/869] KVM: arm64: vgic: Handle race between interrupt affinity change and LPI disabling Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 433/869] net/liquidio: drop cached VF pci_dev LUT Greg Kroah-Hartman
` (437 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Dumazet, Ido Schimmel,
Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 3546deaa0c30a14c7cdb5dc8f2432cb428f0cd36 ]
When a timer is deleted and not re-armed in igmp_mod_timer(), or stopped
in igmp_stop_timer(), the code currently decrements the reference counter
of the multicast list entry @im using refcount_dec(&im->refcnt).
However, both functions can be called from the RCU reader path:
- igmp_mod_timer() via igmp_heard_query() -> for_each_pmc_rcu()
- igmp_stop_timer() via igmp_rcv() -> igmp_heard_report()
If the group im was concurrently removed from the list by ip_mc_dec_group(),
its reference count might have already been decremented to 1.
In this case, timer_delete() succeeds, and refcount_dec() decrements
the refcount from 1 to 0. Since refcount_dec() does not free the object
when it hits 0 (unlike ip_ma_put()), the im structure is leaked.
Fix this by using ip_ma_put(im) instead of refcount_dec(&im->refcnt),
and deferring the put until after the spinlock is released.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260705181756.963063-4-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv4/igmp.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 3f503d60a7dbe..e827537ec15b0 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -220,13 +220,18 @@ static void ip_sf_list_clear_all(struct ip_sf_list *psf)
static void igmp_stop_timer(struct ip_mc_list *im)
{
+ bool put = false;
+
spin_lock_bh(&im->lock);
if (del_timer(&im->timer))
- refcount_dec(&im->refcnt);
+ put = true;
im->tm_running = 0;
im->reporter = 0;
im->unsolicit_count = 0;
spin_unlock_bh(&im->lock);
+
+ if (put)
+ ip_ma_put(im);
}
/* It must be called with locked im->lock */
@@ -269,6 +274,8 @@ static void igmp_ifc_start_timer(struct in_device *in_dev, int delay)
static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
{
+ bool put = false;
+
spin_lock_bh(&im->lock);
im->unsolicit_count = 0;
if (del_timer(&im->timer)) {
@@ -278,10 +285,13 @@ static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
spin_unlock_bh(&im->lock);
return;
}
- refcount_dec(&im->refcnt);
+ put = true;
}
igmp_start_timer(im, max_delay);
spin_unlock_bh(&im->lock);
+
+ if (put)
+ ip_ma_put(im);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 433/869] net/liquidio: drop cached VF pci_dev LUT
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (431 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 432/869] ipv4: igmp: Fix potential memory leaks in igmp_mod_timer() and igmp_stop_timer() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 434/869] Bluetooth: 6lowpan: avoid untracked enable work Greg Kroah-Hartman
` (436 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Yuho Choi, Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <dbgh9129@gmail.com>
[ Upstream commit 5c0e3ba4f500fd4314ceb42f07f16bc445156431 ]
The PF SR-IOV enable path caches VF pci_dev pointers in
dpiring_to_vfpcidev_lut[] by iterating with pci_get_device(). Those
entries do not own a reference, because the iterator drops the previous
device reference on each step. The cached pointer is then dereferenced
later when handling OCTEON_VF_FLR_REQUEST.
Replace the cached VF mapping with runtime lookup on the mailbox DPI
ring: derive the VF index from q_no, resolve the VF via exported PCI
IOV helpers, validate it with the PF pointer and VF ID, then issue
pcie_flr() and drop the reference with pci_dev_put(). Remove the
unused VF lookup table initialization and cleanup.
Fixes: ca6139ffc67ee ("liquidio CN23XX: sysfs VF config support")
Fixes: 8c978d059224 ("liquidio CN23XX: Mailbox support")
Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
Link: https://patch.msgid.link/20260701040847.1897845-1-dbgh9129@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../net/ethernet/cavium/liquidio/lio_main.c | 27 ---------------
.../ethernet/cavium/liquidio/octeon_device.h | 3 --
.../ethernet/cavium/liquidio/octeon_mailbox.c | 33 ++++++++++++++++++-
3 files changed, 32 insertions(+), 31 deletions(-)
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c
index ebb82767b6e53..630cacd338fd8 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -3789,9 +3789,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
static int octeon_enable_sriov(struct octeon_device *oct)
{
unsigned int num_vfs_alloced = oct->sriov_info.num_vfs_alloced;
- struct pci_dev *vfdev;
int err;
- u32 u;
if (OCTEON_CN23XX_PF(oct) && num_vfs_alloced) {
err = pci_enable_sriov(oct->pci_dev,
@@ -3804,23 +3802,6 @@ static int octeon_enable_sriov(struct octeon_device *oct)
return err;
}
oct->sriov_info.sriov_enabled = 1;
-
- /* init lookup table that maps DPI ring number to VF pci_dev
- * struct pointer
- */
- u = 0;
- vfdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
- OCTEON_CN23XX_VF_VID, NULL);
- while (vfdev) {
- if (vfdev->is_virtfn &&
- (vfdev->physfn == oct->pci_dev)) {
- oct->sriov_info.dpiring_to_vfpcidev_lut[u] =
- vfdev;
- u += oct->sriov_info.rings_per_vf;
- }
- vfdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
- OCTEON_CN23XX_VF_VID, vfdev);
- }
}
return num_vfs_alloced;
@@ -3828,8 +3809,6 @@ static int octeon_enable_sriov(struct octeon_device *oct)
static int lio_pci_sriov_disable(struct octeon_device *oct)
{
- int u;
-
if (pci_vfs_assigned(oct->pci_dev)) {
dev_err(&oct->pci_dev->dev, "VFs are still assigned to VMs.\n");
return -EPERM;
@@ -3837,12 +3816,6 @@ static int lio_pci_sriov_disable(struct octeon_device *oct)
pci_disable_sriov(oct->pci_dev);
- u = 0;
- while (u < MAX_POSSIBLE_VFS) {
- oct->sriov_info.dpiring_to_vfpcidev_lut[u] = NULL;
- u += oct->sriov_info.rings_per_vf;
- }
-
oct->sriov_info.num_vfs_alloced = 0;
dev_info(&oct->pci_dev->dev, "oct->pf_num:%d disabled VFs\n",
oct->pf_num);
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.h b/drivers/net/ethernet/cavium/liquidio/octeon_device.h
index d26364c2ac81c..555c7ef4c04a9 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_device.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.h
@@ -390,9 +390,6 @@ struct octeon_sriov_info {
struct lio_trusted_vf trusted_vf;
- /*lookup table that maps DPI ring number to VF pci_dev struct pointer*/
- struct pci_dev *dpiring_to_vfpcidev_lut[MAX_POSSIBLE_VFS];
-
u64 vf_macaddr[MAX_POSSIBLE_VFS];
u16 vf_vlantci[MAX_POSSIBLE_VFS];
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c
index ad685f5d0a136..697fcdc41e3cd 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c
@@ -26,6 +26,31 @@
#include "octeon_mailbox.h"
#include "cn23xx_pf_device.h"
+static struct pci_dev *lio_vf_pci_dev_by_qno(struct octeon_device *oct, u32 q_no)
+{
+ struct pci_dev *vfdev = NULL;
+ int vfidx;
+
+ if (!oct->sriov_info.rings_per_vf)
+ return NULL;
+
+ if (q_no % oct->sriov_info.rings_per_vf)
+ return NULL;
+
+ vfidx = q_no / oct->sriov_info.rings_per_vf;
+ if (vfidx >= oct->sriov_info.num_vfs_alloced)
+ return NULL;
+
+ while ((vfdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
+ OCTEON_CN23XX_VF_VID, vfdev))) {
+ if (pci_physfn(vfdev) && pci_physfn(vfdev) == oct->pci_dev &&
+ pci_iov_vf_id(vfdev) == vfidx)
+ return vfdev;
+ }
+
+ return NULL;
+}
+
/**
* octeon_mbox_read:
* @mbox: Pointer mailbox
@@ -237,6 +262,7 @@ static int octeon_mbox_process_cmd(struct octeon_mbox *mbox,
struct octeon_mbox_cmd *mbox_cmd)
{
struct octeon_device *oct = mbox->oct_dev;
+ struct pci_dev *vfdev;
switch (mbox_cmd->msg.s.cmd) {
case OCTEON_VF_ACTIVE:
@@ -260,7 +286,12 @@ static int octeon_mbox_process_cmd(struct octeon_mbox *mbox,
dev_info(&oct->pci_dev->dev,
"got a request for FLR from VF that owns DPI ring %u\n",
mbox->q_no);
- pcie_flr(oct->sriov_info.dpiring_to_vfpcidev_lut[mbox->q_no]);
+ vfdev = lio_vf_pci_dev_by_qno(oct, mbox->q_no);
+ if (!vfdev)
+ break;
+
+ pcie_flr(vfdev);
+ pci_dev_put(vfdev);
break;
case OCTEON_PF_CHANGED_VF_MACADDR:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 434/869] Bluetooth: 6lowpan: avoid untracked enable work
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (432 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 433/869] net/liquidio: drop cached VF pci_dev LUT Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 435/869] net/mlx5e: Fix publication race for priv->channel_stats[] Greg Kroah-Hartman
` (435 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Cen Zhang, Luiz Augusto von Dentz,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <zzzccc427@gmail.com>
[ Upstream commit 352a59dc1f4a41314b6f827c17e16af7ca88271a ]
lowpan_enable_set() allocates a temporary work item and schedules
do_enable_set() on system_wq, then returns to debugfs. The debugfs active
operation has ended at that point, but the worker still executes module
text and manipulates enable_6lowpan and listen_chan.
bt_6lowpan_exit() removes the debugfs files and immediately closes and
puts listen_chan. It has no pointer to the queued work item, so it cannot
cancel or flush it before tearing down the state that the worker uses.
The buggy scenario involves two paths, with each column showing the order
within that path:
debugfs enable write module exit
1. lowpan_enable_set() allocates 1. bt_6lowpan_exit() removes
set_enable work the debugfs file
2. schedule_work() queues 2. bt_6lowpan_exit() closes
do_enable_set() and puts listen_chan
3. the write operation returns 3. module teardown can continue
4. do_enable_set() later runs
against stale state
Run the enable state transition synchronously in lowpan_enable_set()
instead. The simple debugfs setter can sleep, and this file already handles
the 6LoWPAN control write synchronously under the same set_lock. Once the
setter returns, debugfs removal covers the whole operation and exit can no
longer race with an untracked work item.
Validation reproduced this kernel report:
BUG: KASAN: slab-use-after-free in do_enable_set+0x113/0x2e0
Workqueue: events do_enable_set [bluetooth_6lowpan]
The buggy address belongs to the object at ffff888109cb8000
Fixes: 90305829635d ("Bluetooth: 6lowpan: Converting rwlocks to use RCU")
Assisted-by: Codex:gpt-5.5
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/6lowpan.c | 27 ++++-----------------------
1 file changed, 4 insertions(+), 23 deletions(-)
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 89de21ec62a1d..1cb37fbb668f9 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -1065,23 +1065,15 @@ static void disconnect_all_peers(void)
} while (nchans);
}
-struct set_enable {
- struct work_struct work;
- bool flag;
-};
-
-static void do_enable_set(struct work_struct *work)
+static void do_enable_set(bool flag)
{
- struct set_enable *set_enable = container_of(work,
- struct set_enable, work);
-
- if (!set_enable->flag || enable_6lowpan != set_enable->flag)
+ if (!flag || enable_6lowpan != flag)
/* Disconnect existing connections if 6lowpan is
* disabled
*/
disconnect_all_peers();
- enable_6lowpan = set_enable->flag;
+ enable_6lowpan = flag;
mutex_lock(&set_lock);
if (listen_chan) {
@@ -1091,22 +1083,11 @@ static void do_enable_set(struct work_struct *work)
listen_chan = bt_6lowpan_listen();
mutex_unlock(&set_lock);
-
- kfree(set_enable);
}
static int lowpan_enable_set(void *data, u64 val)
{
- struct set_enable *set_enable;
-
- set_enable = kzalloc(sizeof(*set_enable), GFP_KERNEL);
- if (!set_enable)
- return -ENOMEM;
-
- set_enable->flag = !!val;
- INIT_WORK(&set_enable->work, do_enable_set);
-
- schedule_work(&set_enable->work);
+ do_enable_set(!!val);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 435/869] net/mlx5e: Fix publication race for priv->channel_stats[]
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (433 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 434/869] Bluetooth: 6lowpan: avoid untracked enable work Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 436/869] netfs: Clean up some whitespace in trace header Greg Kroah-Hartman
` (434 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Feng Liu, Eran Ben Elisha,
Cosmin Ratiu, Nimrod Oren, Tariq Toukan, Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Feng Liu <feliu@nvidia.com>
[ Upstream commit 5a799714e8ca0bce9ea40694f49914cf1adbbaa9 ]
mlx5e_channel_stats_alloc() publishes a new entry to
priv->channel_stats[] and then increments priv->stats_nch as a
publication token, but neither store carries any memory barrier:
priv->channel_stats[ix] = kvzalloc_node(...);
if (!priv->channel_stats[ix])
return -ENOMEM;
priv->stats_nch++;
Concurrent readers compute the loop bound from priv->stats_nch and
then dereference priv->channel_stats[i] using plain accesses, e.g.
for (i = 0; i < priv->stats_nch; i++) {
struct mlx5e_channel_stats *cs = priv->channel_stats[i];
... cs->rq.packets ...
}
On weakly-ordered architectures (ARM, PowerPC, RISC-V) the writes to
channel_stats[ix] and stats_nch may become visible to other CPUs out
of program order. A reader can observe stats_nch == N while still
seeing channel_stats[N-1] == NULL, leading to a NULL pointer
dereference in the channel_stats loop.
This has been observed in production on BlueField-3 DPUs (arm64),
where ovs-vswitchd queries netdev statistics over netlink during NIC
bringup, racing mlx5e_open_channel() -> mlx5e_channel_stats_alloc()
on another CPU:
Unable to handle kernel NULL pointer dereference at virtual address 0x840
Hardware name: BlueField-3 DPU
pc : mlx5e_fold_sw_stats64+0x30/0x180 [mlx5_core]
Call trace:
mlx5e_fold_sw_stats64+0x30/0x180 [mlx5_core]
dev_get_stats+0x50/0xc0
ovs_vport_get_stats+0x38/0xac [openvswitch]
ovs_vport_cmd_fill_info+0x194/0x290 [openvswitch]
ovs_vport_cmd_get+0xbc/0x10c [openvswitch]
genl_family_rcv_msg_doit+0xd0/0x160
genl_rcv_msg+0xec/0x1f0
netlink_rcv_skb+0x64/0x130
genl_rcv+0x40/0x60
netlink_unicast+0x2fc/0x370
netlink_sendmsg+0x1dc/0x454
...
__arm64_sys_sendmsg+0x2c/0x40
Add mlx5e_stats_nch_write() and mlx5e_stats_nch_read() helpers in en.h
that wrap the smp_store_release()/smp_load_acquire() pair on stats_nch.
The release/acquire pair establishes the contract:
stats_nch == N => channel_stats[0..N-1] are visible and non-NULL.
Publish the stats_nch increment via mlx5e_stats_nch_write() in the
writer (mlx5e_channel_stats_alloc()), and read stats_nch via
mlx5e_stats_nch_read() in all readers: mlx5e RX/TX queue stats,
mlx5e_get_base_stats(), ethtool channels stats, IPoIB stats, the
sw_stats fold and the HV VHCA stats agent.
Fixes: fa691d0c9c08 ("net/mlx5e: Allocate per-channel stats dynamically at first usage")
Signed-off-by: Feng Liu <feliu@nvidia.com>
Reviewed-by: Eran Ben Elisha <eranbe@nvidia.com>
Reviewed-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Nimrod Oren <noren@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Link: https://patch.msgid.link/20260630115151.729219-4-tariqt@nvidia.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/mellanox/mlx5/core/en.h | 12 ++++++++++++
.../ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c | 10 ++++++----
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 14 ++++++++------
drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 9 +++++----
.../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 3 ++-
5 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index a0a9a11b0fb92..d9541cfd65152 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -947,6 +947,18 @@ struct mlx5e_priv {
struct mlx5_devcom_comp_dev *devcom;
};
+static inline u16 mlx5e_stats_nch_read(const struct mlx5e_priv *priv)
+{
+ /* Pairs with smp_store_release in mlx5e_stats_nch_write(). */
+ return smp_load_acquire(&priv->stats_nch);
+}
+
+static inline void mlx5e_stats_nch_write(struct mlx5e_priv *priv, u16 n)
+{
+ /* Pairs with smp_load_acquire in mlx5e_stats_nch_read(). */
+ smp_store_release(&priv->stats_nch, n);
+}
+
struct mlx5e_dev {
struct net_device *netdev;
struct devlink_port dl_port;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c
index 1856d211339f2..adfb49ff42aa9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c
@@ -33,9 +33,10 @@ mlx5e_hv_vhca_fill_ring_stats(struct mlx5e_priv *priv, int ch,
static void mlx5e_hv_vhca_fill_stats(struct mlx5e_priv *priv, void *data,
int buf_len)
{
+ u16 nch = mlx5e_stats_nch_read(priv);
int ch, i = 0;
- for (ch = 0; ch < priv->stats_nch; ch++) {
+ for (ch = 0; ch < nch; ch++) {
void *buf = data + i;
if (WARN_ON_ONCE(buf +
@@ -50,8 +51,9 @@ static void mlx5e_hv_vhca_fill_stats(struct mlx5e_priv *priv, void *data,
static int mlx5e_hv_vhca_stats_buf_size(struct mlx5e_priv *priv)
{
- return (sizeof(struct mlx5e_hv_vhca_per_ring_stats) *
- priv->stats_nch);
+ u16 nch = mlx5e_stats_nch_read(priv);
+
+ return sizeof(struct mlx5e_hv_vhca_per_ring_stats) * nch;
}
static int mlx5e_hv_vhca_stats_buf_max_size(struct mlx5e_priv *priv)
@@ -106,7 +108,7 @@ static void mlx5e_hv_vhca_stats_control(struct mlx5_hv_vhca_agent *agent,
sagent = &priv->stats_agent;
block->version = MLX5_HV_VHCA_STATS_VERSION;
- block->rings = priv->stats_nch;
+ block->rings = mlx5e_stats_nch_read(priv);
if (!block->command) {
cancel_delayed_work_sync(&priv->stats_agent.work);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index f6c15fce4a025..fd3cf53ff17a9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -2605,7 +2605,7 @@ static int mlx5e_channel_stats_alloc(struct mlx5e_priv *priv, int ix, int cpu)
GFP_KERNEL, cpu_to_node(cpu));
if (!priv->channel_stats[ix])
return -ENOMEM;
- priv->stats_nch++;
+ mlx5e_stats_nch_write(priv, priv->stats_nch + 1);
return 0;
}
@@ -3822,9 +3822,10 @@ static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
void mlx5e_fold_sw_stats64(struct mlx5e_priv *priv, struct rtnl_link_stats64 *s)
{
+ u16 nch = mlx5e_stats_nch_read(priv);
int i;
- for (i = 0; i < priv->stats_nch; i++) {
+ for (i = 0; i < nch; i++) {
struct mlx5e_channel_stats *channel_stats = priv->channel_stats[i];
struct mlx5e_rq_stats *xskrq_stats = &channel_stats->xskrq;
struct mlx5e_rq_stats *rq_stats = &channel_stats->rq;
@@ -5290,7 +5291,7 @@ static void mlx5e_get_queue_stats_rx(struct net_device *dev, int i,
struct mlx5e_rq_stats *rq_stats;
ASSERT_RTNL();
- if (mlx5e_is_uplink_rep(priv) || !priv->stats_nch)
+ if (mlx5e_is_uplink_rep(priv) || !mlx5e_stats_nch_read(priv))
return;
channel_stats = priv->channel_stats[i];
@@ -5310,7 +5311,7 @@ static void mlx5e_get_queue_stats_tx(struct net_device *dev, int i,
struct mlx5e_sq_stats *sq_stats;
ASSERT_RTNL();
- if (!priv->stats_nch)
+ if (!mlx5e_stats_nch_read(priv))
return;
/* no special case needed for ptp htb etc since txq2sq_stats is kept up
@@ -5327,6 +5328,7 @@ static void mlx5e_get_base_stats(struct net_device *dev,
struct netdev_queue_stats_tx *tx)
{
struct mlx5e_priv *priv = netdev_priv(dev);
+ u16 nch = mlx5e_stats_nch_read(priv);
struct mlx5e_ptp *ptp_channel;
int i, tc;
@@ -5336,7 +5338,7 @@ static void mlx5e_get_base_stats(struct net_device *dev,
rx->bytes = 0;
rx->alloc_fail = 0;
- for (i = priv->channels.params.num_channels; i < priv->stats_nch; i++) {
+ for (i = priv->channels.params.num_channels; i < nch; i++) {
struct netdev_queue_stats_rx rx_i = {0};
mlx5e_get_queue_stats_rx(dev, i, &rx_i);
@@ -5361,7 +5363,7 @@ static void mlx5e_get_base_stats(struct net_device *dev,
tx->packets = 0;
tx->bytes = 0;
- for (i = 0; i < priv->stats_nch; i++) {
+ for (i = 0; i < nch; i++) {
struct mlx5e_channel_stats *channel_stats = priv->channel_stats[i];
/* handle two cases:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
index 2f077ad1e810b..652cae2feb013 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
@@ -528,6 +528,7 @@ static void mlx5e_stats_update_stats_rq_page_pool(struct mlx5e_channel *c)
static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(sw)
{
struct mlx5e_sw_stats *s = &priv->stats.sw;
+ u16 nch = mlx5e_stats_nch_read(priv);
int i;
memset(s, 0, sizeof(*s));
@@ -535,7 +536,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(sw)
for (i = 0; i < priv->channels.num; i++) /* for active channels only */
mlx5e_stats_update_stats_rq_page_pool(priv->channels.c[i]);
- for (i = 0; i < priv->stats_nch; i++) {
+ for (i = 0; i < nch; i++) {
struct mlx5e_channel_stats *channel_stats =
priv->channel_stats[i];
@@ -2438,7 +2439,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(ptp) { return; }
static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(channels)
{
- int max_nch = priv->stats_nch;
+ int max_nch = mlx5e_stats_nch_read(priv);
return (NUM_RQ_STATS * max_nch) +
(NUM_CH_STATS * max_nch) +
@@ -2451,8 +2452,8 @@ static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(channels)
static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(channels)
{
+ int max_nch = mlx5e_stats_nch_read(priv);
bool is_xsk = priv->xsk.ever_used;
- int max_nch = priv->stats_nch;
int i, j, tc;
for (i = 0; i < max_nch; i++)
@@ -2484,8 +2485,8 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(channels)
static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(channels)
{
+ int max_nch = mlx5e_stats_nch_read(priv);
bool is_xsk = priv->xsk.ever_used;
- int max_nch = priv->stats_nch;
int i, j, tc;
for (i = 0; i < max_nch; i++)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
index 0979d672d47f3..2c71e2ac40c59 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
@@ -114,10 +114,11 @@ void mlx5i_cleanup(struct mlx5e_priv *priv)
static void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv)
{
+ u16 nch = mlx5e_stats_nch_read(priv);
struct rtnl_link_stats64 s = {};
int i, j;
- for (i = 0; i < priv->stats_nch; i++) {
+ for (i = 0; i < nch; i++) {
struct mlx5e_channel_stats *channel_stats;
struct mlx5e_rq_stats *rq_stats;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 436/869] netfs: Clean up some whitespace in trace header
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (434 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 435/869] net/mlx5e: Fix publication race for priv->channel_stats[] Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 437/869] netfs: Use a folio_queue allocation and free functions Greg Kroah-Hartman
` (433 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Jeff Layton, netfs,
linux-fsdevel, Christian Brauner, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit d3d3ec86568090cc5a4501b745274114de6881e0 ]
Clean up some whitespace in the netfs trace header.
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/r/20241216204124.3752367-2-dhowells@redhat.com
cc: Jeff Layton <jlayton@kernel.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: dbd6f56d975b ("netfs: Fix netfs_create_write_req() to handle async cache object creation")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/trace/events/netfs.h | 130 +++++++++++++++++------------------
1 file changed, 65 insertions(+), 65 deletions(-)
diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h
index 1d9b068bb1758..59452f12dcbee 100644
--- a/include/trace/events/netfs.h
+++ b/include/trace/events/netfs.h
@@ -258,13 +258,13 @@ TRACE_EVENT(netfs_read,
TP_ARGS(rreq, start, len, what),
TP_STRUCT__entry(
- __field(unsigned int, rreq )
- __field(unsigned int, cookie )
- __field(loff_t, i_size )
- __field(loff_t, start )
- __field(size_t, len )
- __field(enum netfs_read_trace, what )
- __field(unsigned int, netfs_inode )
+ __field(unsigned int, rreq)
+ __field(unsigned int, cookie)
+ __field(loff_t, i_size)
+ __field(loff_t, start)
+ __field(size_t, len)
+ __field(enum netfs_read_trace, what)
+ __field(unsigned int, netfs_inode)
),
TP_fast_assign(
@@ -292,10 +292,10 @@ TRACE_EVENT(netfs_rreq,
TP_ARGS(rreq, what),
TP_STRUCT__entry(
- __field(unsigned int, rreq )
- __field(unsigned int, flags )
- __field(enum netfs_io_origin, origin )
- __field(enum netfs_rreq_trace, what )
+ __field(unsigned int, rreq)
+ __field(unsigned int, flags)
+ __field(enum netfs_io_origin, origin)
+ __field(enum netfs_rreq_trace, what)
),
TP_fast_assign(
@@ -319,15 +319,15 @@ TRACE_EVENT(netfs_sreq,
TP_ARGS(sreq, what),
TP_STRUCT__entry(
- __field(unsigned int, rreq )
- __field(unsigned short, index )
- __field(short, error )
- __field(unsigned short, flags )
- __field(enum netfs_io_source, source )
- __field(enum netfs_sreq_trace, what )
- __field(size_t, len )
- __field(size_t, transferred )
- __field(loff_t, start )
+ __field(unsigned int, rreq)
+ __field(unsigned short, index)
+ __field(short, error)
+ __field(unsigned short, flags)
+ __field(enum netfs_io_source, source)
+ __field(enum netfs_sreq_trace, what)
+ __field(size_t, len)
+ __field(size_t, transferred)
+ __field(loff_t, start)
),
TP_fast_assign(
@@ -359,15 +359,15 @@ TRACE_EVENT(netfs_failure,
TP_ARGS(rreq, sreq, error, what),
TP_STRUCT__entry(
- __field(unsigned int, rreq )
- __field(short, index )
- __field(short, error )
- __field(unsigned short, flags )
- __field(enum netfs_io_source, source )
- __field(enum netfs_failure, what )
- __field(size_t, len )
- __field(size_t, transferred )
- __field(loff_t, start )
+ __field(unsigned int, rreq)
+ __field(short, index)
+ __field(short, error)
+ __field(unsigned short, flags)
+ __field(enum netfs_io_source, source)
+ __field(enum netfs_failure, what)
+ __field(size_t, len)
+ __field(size_t, transferred)
+ __field(loff_t, start)
),
TP_fast_assign(
@@ -398,9 +398,9 @@ TRACE_EVENT(netfs_rreq_ref,
TP_ARGS(rreq_debug_id, ref, what),
TP_STRUCT__entry(
- __field(unsigned int, rreq )
- __field(int, ref )
- __field(enum netfs_rreq_ref_trace, what )
+ __field(unsigned int, rreq)
+ __field(int, ref)
+ __field(enum netfs_rreq_ref_trace, what)
),
TP_fast_assign(
@@ -422,10 +422,10 @@ TRACE_EVENT(netfs_sreq_ref,
TP_ARGS(rreq_debug_id, subreq_debug_index, ref, what),
TP_STRUCT__entry(
- __field(unsigned int, rreq )
- __field(unsigned int, subreq )
- __field(int, ref )
- __field(enum netfs_sreq_ref_trace, what )
+ __field(unsigned int, rreq)
+ __field(unsigned int, subreq)
+ __field(int, ref)
+ __field(enum netfs_sreq_ref_trace, what)
),
TP_fast_assign(
@@ -473,10 +473,10 @@ TRACE_EVENT(netfs_write_iter,
TP_ARGS(iocb, from),
TP_STRUCT__entry(
- __field(unsigned long long, start )
- __field(size_t, len )
- __field(unsigned int, flags )
- __field(unsigned int, ino )
+ __field(unsigned long long, start)
+ __field(size_t, len)
+ __field(unsigned int, flags)
+ __field(unsigned int, ino)
),
TP_fast_assign(
@@ -497,12 +497,12 @@ TRACE_EVENT(netfs_write,
TP_ARGS(wreq, what),
TP_STRUCT__entry(
- __field(unsigned int, wreq )
- __field(unsigned int, cookie )
- __field(unsigned int, ino )
- __field(enum netfs_write_trace, what )
- __field(unsigned long long, start )
- __field(unsigned long long, len )
+ __field(unsigned int, wreq)
+ __field(unsigned int, cookie)
+ __field(unsigned int, ino)
+ __field(enum netfs_write_trace, what)
+ __field(unsigned long long, start)
+ __field(unsigned long long, len)
),
TP_fast_assign(
@@ -530,10 +530,10 @@ TRACE_EVENT(netfs_collect,
TP_ARGS(wreq),
TP_STRUCT__entry(
- __field(unsigned int, wreq )
- __field(unsigned int, len )
- __field(unsigned long long, transferred )
- __field(unsigned long long, start )
+ __field(unsigned int, wreq)
+ __field(unsigned int, len)
+ __field(unsigned long long, transferred)
+ __field(unsigned long long, start)
),
TP_fast_assign(
@@ -556,12 +556,12 @@ TRACE_EVENT(netfs_collect_sreq,
TP_ARGS(wreq, subreq),
TP_STRUCT__entry(
- __field(unsigned int, wreq )
- __field(unsigned int, subreq )
- __field(unsigned int, stream )
- __field(unsigned int, len )
- __field(unsigned int, transferred )
- __field(unsigned long long, start )
+ __field(unsigned int, wreq)
+ __field(unsigned int, subreq)
+ __field(unsigned int, stream)
+ __field(unsigned int, len)
+ __field(unsigned int, transferred)
+ __field(unsigned long long, start)
),
TP_fast_assign(
@@ -587,11 +587,11 @@ TRACE_EVENT(netfs_collect_folio,
TP_ARGS(wreq, folio, fend, collected_to),
TP_STRUCT__entry(
- __field(unsigned int, wreq )
- __field(unsigned long, index )
- __field(unsigned long long, fend )
- __field(unsigned long long, cleaned_to )
- __field(unsigned long long, collected_to )
+ __field(unsigned int, wreq)
+ __field(unsigned long, index)
+ __field(unsigned long long, fend)
+ __field(unsigned long long, cleaned_to)
+ __field(unsigned long long, collected_to)
),
TP_fast_assign(
@@ -616,10 +616,10 @@ TRACE_EVENT(netfs_collect_state,
TP_ARGS(wreq, collected_to, notes),
TP_STRUCT__entry(
- __field(unsigned int, wreq )
- __field(unsigned int, notes )
- __field(unsigned long long, collected_to )
- __field(unsigned long long, cleaned_to )
+ __field(unsigned int, wreq)
+ __field(unsigned int, notes)
+ __field(unsigned long long, collected_to)
+ __field(unsigned long long, cleaned_to)
),
TP_fast_assign(
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 437/869] netfs: Use a folio_queue allocation and free functions
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (435 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 436/869] netfs: Clean up some whitespace in trace header Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 438/869] netfs: Add a tracepoint to log the lifespan of folio_queue structs Greg Kroah-Hartman
` (432 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Jeff Layton, netfs,
linux-fsdevel, Christian Brauner, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit eb1181594417dafad0f75808ead71f6d5170c1ea ]
Provide and use folio_queue allocation and free functions to combine the
allocation, initialisation and stat (un)accounting steps that are repeated
in several places.
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/r/20241216204124.3752367-4-dhowells@redhat.com
cc: Jeff Layton <jlayton@kernel.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: dbd6f56d975b ("netfs: Fix netfs_create_write_req() to handle async cache object creation")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/netfs/buffered_read.c | 12 +++---------
fs/netfs/misc.c | 38 ++++++++++++++++++++++++++++++++++----
include/linux/netfs.h | 5 +++++
3 files changed, 42 insertions(+), 13 deletions(-)
diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c
index ec78ad094cf4a..e0822ecabb342 100644
--- a/fs/netfs/buffered_read.c
+++ b/fs/netfs/buffered_read.c
@@ -131,11 +131,9 @@ static ssize_t netfs_prepare_read_iterator(struct netfs_io_subrequest *subreq)
struct folio_queue *tail = rreq->buffer_tail, *new;
size_t added;
- new = kmalloc(sizeof(*new), GFP_NOFS);
+ new = netfs_folioq_alloc(GFP_NOFS);
if (!new)
return -ENOMEM;
- netfs_stat(&netfs_n_folioq);
- folioq_init(new);
new->prev = tail;
tail->next = new;
rreq->buffer_tail = new;
@@ -363,11 +361,9 @@ static int netfs_prime_buffer(struct netfs_io_request *rreq)
struct folio_batch put_batch;
size_t added;
- folioq = kmalloc(sizeof(*folioq), GFP_KERNEL);
+ folioq = netfs_folioq_alloc(GFP_KERNEL);
if (!folioq)
return -ENOMEM;
- netfs_stat(&netfs_n_folioq);
- folioq_init(folioq);
rreq->buffer = folioq;
rreq->buffer_tail = folioq;
rreq->submitted = rreq->start;
@@ -440,12 +436,10 @@ static int netfs_create_singular_buffer(struct netfs_io_request *rreq, struct fo
{
struct folio_queue *folioq;
- folioq = kmalloc(sizeof(*folioq), GFP_KERNEL);
+ folioq = netfs_folioq_alloc(GFP_KERNEL);
if (!folioq)
return -ENOMEM;
- netfs_stat(&netfs_n_folioq);
- folioq_init(folioq);
folioq_append(folioq, folio);
BUG_ON(folioq_folio(folioq, 0) != folio);
BUG_ON(folioq_folio_order(folioq, 0) != folio_order(folio));
diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c
index 8bdacbf15226c..fbd239e6d3114 100644
--- a/fs/netfs/misc.c
+++ b/fs/netfs/misc.c
@@ -9,6 +9,38 @@
#include <linux/rmap.h>
#include "internal.h"
+/**
+ * netfs_folioq_alloc - Allocate a folio_queue struct
+ * @gfp: Allocation constraints
+ *
+ * Allocate, initialise and account the folio_queue struct.
+ */
+struct folio_queue *netfs_folioq_alloc(gfp_t gfp)
+{
+ struct folio_queue *fq;
+
+ fq = kmalloc(sizeof(*fq), gfp);
+ if (fq) {
+ netfs_stat(&netfs_n_folioq);
+ folioq_init(fq);
+ }
+ return fq;
+}
+EXPORT_SYMBOL(netfs_folioq_alloc);
+
+/**
+ * netfs_folioq_free - Free a folio_queue struct
+ * @folioq: The object to free
+ *
+ * Free and unaccount the folio_queue struct.
+ */
+void netfs_folioq_free(struct folio_queue *folioq)
+{
+ netfs_stat_d(&netfs_n_folioq);
+ kfree(folioq);
+}
+EXPORT_SYMBOL(netfs_folioq_free);
+
/*
* Make sure there's space in the rolling queue.
*/
@@ -88,8 +120,7 @@ struct folio_queue *netfs_delete_buffer_head(struct netfs_io_request *wreq)
if (next)
next->prev = NULL;
- netfs_stat_d(&netfs_n_folioq);
- kfree(head);
+ netfs_folioq_free(head);
wreq->buffer = next;
return next;
}
@@ -112,8 +143,7 @@ void netfs_clear_buffer(struct netfs_io_request *rreq)
folio_put(folio);
}
}
- netfs_stat_d(&netfs_n_folioq);
- kfree(p);
+ netfs_folioq_free(p);
}
}
diff --git a/include/linux/netfs.h b/include/linux/netfs.h
index f8e0d9fa745a2..5180292bd2d10 100644
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -21,6 +21,7 @@
enum netfs_sreq_ref_trace;
typedef struct mempool_s mempool_t;
+struct folio_queue;
/**
* folio_start_private_2 - Start an fscache write on a folio. [DEPRECATED]
@@ -455,6 +456,10 @@ void netfs_end_io_write(struct inode *inode);
int netfs_start_io_direct(struct inode *inode);
void netfs_end_io_direct(struct inode *inode);
+/* Miscellaneous APIs. */
+struct folio_queue *netfs_folioq_alloc(gfp_t gfp);
+void netfs_folioq_free(struct folio_queue *folioq);
+
/**
* netfs_inode - Get the netfs inode context from the inode
* @inode: The inode to query
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 438/869] netfs: Add a tracepoint to log the lifespan of folio_queue structs
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (436 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 437/869] netfs: Use a folio_queue allocation and free functions Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 439/869] netfs: Abstract out a rolling folio buffer implementation Greg Kroah-Hartman
` (431 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Jeff Layton, netfs,
linux-fsdevel, Christian Brauner, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit aabcabf2746062253565b33aa3f8d25999a5ac01 ]
Add a tracepoint to log the lifespan of folio_queue structs. For tracing
illustrative purposes, folio_queues are tagged with the debug ID of
whatever they're related to (typically a netfs_io_request) and a debug ID
of their own.
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/r/20241216204124.3752367-5-dhowells@redhat.com
cc: Jeff Layton <jlayton@kernel.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: dbd6f56d975b ("netfs: Fix netfs_create_write_req() to handle async cache object creation")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/netfs/buffered_read.c | 10 ++++++---
fs/netfs/internal.h | 3 ++-
fs/netfs/misc.c | 31 +++++++++++++++++----------
fs/netfs/read_collect.c | 8 +++++--
fs/netfs/write_issue.c | 2 +-
fs/smb/client/smb2ops.c | 2 +-
include/linux/folio_queue.h | 12 ++++++++---
include/linux/netfs.h | 6 ++++--
include/trace/events/netfs.h | 41 ++++++++++++++++++++++++++++++++++--
lib/kunit_iov_iter.c | 4 ++--
10 files changed, 91 insertions(+), 28 deletions(-)
diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c
index e0822ecabb342..3aa49f6ddde6d 100644
--- a/fs/netfs/buffered_read.c
+++ b/fs/netfs/buffered_read.c
@@ -131,7 +131,8 @@ static ssize_t netfs_prepare_read_iterator(struct netfs_io_subrequest *subreq)
struct folio_queue *tail = rreq->buffer_tail, *new;
size_t added;
- new = netfs_folioq_alloc(GFP_NOFS);
+ new = netfs_folioq_alloc(rreq->debug_id, GFP_NOFS,
+ netfs_trace_folioq_alloc_read_prep);
if (!new)
return -ENOMEM;
new->prev = tail;
@@ -361,9 +362,11 @@ static int netfs_prime_buffer(struct netfs_io_request *rreq)
struct folio_batch put_batch;
size_t added;
- folioq = netfs_folioq_alloc(GFP_KERNEL);
+ folioq = netfs_folioq_alloc(rreq->debug_id, GFP_KERNEL,
+ netfs_trace_folioq_alloc_read_prime);
if (!folioq)
return -ENOMEM;
+
rreq->buffer = folioq;
rreq->buffer_tail = folioq;
rreq->submitted = rreq->start;
@@ -436,7 +439,8 @@ static int netfs_create_singular_buffer(struct netfs_io_request *rreq, struct fo
{
struct folio_queue *folioq;
- folioq = netfs_folioq_alloc(GFP_KERNEL);
+ folioq = netfs_folioq_alloc(rreq->debug_id, GFP_KERNEL,
+ netfs_trace_folioq_alloc_read_sing);
if (!folioq)
return -ENOMEM;
diff --git a/fs/netfs/internal.h b/fs/netfs/internal.h
index 668c4b3f78134..b0c7576951c25 100644
--- a/fs/netfs/internal.h
+++ b/fs/netfs/internal.h
@@ -58,7 +58,8 @@ static inline void netfs_proc_del_rreq(struct netfs_io_request *rreq) {}
/*
* misc.c
*/
-struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq);
+struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq,
+ enum netfs_folioq_trace trace);
int netfs_buffer_append_folio(struct netfs_io_request *rreq, struct folio *folio,
bool needs_put);
struct folio_queue *netfs_delete_buffer_head(struct netfs_io_request *wreq);
diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c
index fbd239e6d3114..71a0d553f4d43 100644
--- a/fs/netfs/misc.c
+++ b/fs/netfs/misc.c
@@ -11,18 +11,25 @@
/**
* netfs_folioq_alloc - Allocate a folio_queue struct
+ * @rreq_id: Associated debugging ID for tracing purposes
* @gfp: Allocation constraints
+ * @trace: Trace tag to indicate the purpose of the allocation
*
- * Allocate, initialise and account the folio_queue struct.
+ * Allocate, initialise and account the folio_queue struct and log a trace line
+ * to mark the allocation.
*/
-struct folio_queue *netfs_folioq_alloc(gfp_t gfp)
+struct folio_queue *netfs_folioq_alloc(unsigned int rreq_id, gfp_t gfp,
+ unsigned int /*enum netfs_folioq_trace*/ trace)
{
+ static atomic_t debug_ids;
struct folio_queue *fq;
fq = kmalloc(sizeof(*fq), gfp);
if (fq) {
netfs_stat(&netfs_n_folioq);
- folioq_init(fq);
+ folioq_init(fq, rreq_id);
+ fq->debug_id = atomic_inc_return(&debug_ids);
+ trace_netfs_folioq(fq, trace);
}
return fq;
}
@@ -31,11 +38,14 @@ EXPORT_SYMBOL(netfs_folioq_alloc);
/**
* netfs_folioq_free - Free a folio_queue struct
* @folioq: The object to free
+ * @trace: Trace tag to indicate which free
*
* Free and unaccount the folio_queue struct.
*/
-void netfs_folioq_free(struct folio_queue *folioq)
+void netfs_folioq_free(struct folio_queue *folioq,
+ unsigned int /*enum netfs_trace_folioq*/ trace)
{
+ trace_netfs_folioq(folioq, trace);
netfs_stat_d(&netfs_n_folioq);
kfree(folioq);
}
@@ -44,7 +54,8 @@ EXPORT_SYMBOL(netfs_folioq_free);
/*
* Make sure there's space in the rolling queue.
*/
-struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq)
+struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq,
+ enum netfs_folioq_trace trace)
{
struct folio_queue *tail = rreq->buffer_tail, *prev;
unsigned int prev_nr_slots = 0;
@@ -60,11 +71,9 @@ struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq)
prev_nr_slots = folioq_nr_slots(tail);
}
- tail = kmalloc(sizeof(*tail), GFP_NOFS);
+ tail = netfs_folioq_alloc(rreq->debug_id, GFP_NOFS, trace);
if (!tail)
return ERR_PTR(-ENOMEM);
- netfs_stat(&netfs_n_folioq);
- folioq_init(tail);
tail->prev = prev;
if (prev)
/* [!] NOTE: After we set prev->next, the consumer is entirely
@@ -99,7 +108,7 @@ int netfs_buffer_append_folio(struct netfs_io_request *rreq, struct folio *folio
struct folio_queue *tail;
unsigned int slot, order = folio_order(folio);
- tail = netfs_buffer_make_space(rreq);
+ tail = netfs_buffer_make_space(rreq, netfs_trace_folioq_alloc_append_folio);
if (IS_ERR(tail))
return PTR_ERR(tail);
@@ -120,7 +129,7 @@ struct folio_queue *netfs_delete_buffer_head(struct netfs_io_request *wreq)
if (next)
next->prev = NULL;
- netfs_folioq_free(head);
+ netfs_folioq_free(head, netfs_trace_folioq_delete);
wreq->buffer = next;
return next;
}
@@ -143,7 +152,7 @@ void netfs_clear_buffer(struct netfs_io_request *rreq)
folio_put(folio);
}
}
- netfs_folioq_free(p);
+ netfs_folioq_free(p, netfs_trace_folioq_clear);
}
}
diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c
index 782d7b7301964..c420c231f8d05 100644
--- a/fs/netfs/read_collect.c
+++ b/fs/netfs/read_collect.c
@@ -103,6 +103,7 @@ static bool netfs_consume_read_data(struct netfs_io_subrequest *subreq, bool was
subreq->transferred, subreq->len))
subreq->transferred = subreq->len;
+ trace_netfs_folioq(folioq, netfs_trace_folioq_read_progress);
next_folio:
fsize = PAGE_SIZE << subreq->curr_folio_order;
fpos = round_down(subreq->start + subreq->consumed, fsize);
@@ -119,9 +120,11 @@ static bool netfs_consume_read_data(struct netfs_io_subrequest *subreq, bool was
if (folioq) {
struct folio *folio = folioq_folio(folioq, slot);
- pr_err("folioq: orders=%02x%02x%02x%02x\n",
+ pr_err("folioq: fq=%x orders=%02x%02x%02x%02x %px\n",
+ folioq->debug_id,
folioq->orders[0], folioq->orders[1],
- folioq->orders[2], folioq->orders[3]);
+ folioq->orders[2], folioq->orders[3],
+ folioq);
if (folio)
pr_err("folio: %llx-%llx ix=%llx o=%u qo=%u\n",
fpos, fend - 1, folio_pos(folio), folio_order(folio),
@@ -222,6 +225,7 @@ static bool netfs_consume_read_data(struct netfs_io_subrequest *subreq, bool was
slot = 0;
folioq = folioq->next;
subreq->curr_folioq = folioq;
+ trace_netfs_folioq(folioq, netfs_trace_folioq_read_progress);
}
subreq->curr_folioq_slot = slot;
if (folioq && folioq_folio(folioq, slot))
diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c
index 7431c0a4252c4..d1fa5851a7b29 100644
--- a/fs/netfs/write_issue.c
+++ b/fs/netfs/write_issue.c
@@ -161,7 +161,7 @@ static void netfs_prepare_write(struct netfs_io_request *wreq,
*/
if (iov_iter_is_folioq(wreq_iter) &&
wreq_iter->folioq_slot >= folioq_nr_slots(wreq_iter->folioq)) {
- netfs_buffer_make_space(wreq);
+ netfs_buffer_make_space(wreq, netfs_trace_folioq_prep_write);
}
subreq = netfs_alloc_subrequest(wreq);
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 95eff9e7c660c..3bf0b25feed9e 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -4713,7 +4713,7 @@ static struct folio_queue *cifs_alloc_folioq_buffer(ssize_t size)
p = kmalloc(sizeof(*p), GFP_NOFS);
if (!p)
goto nomem;
- folioq_init(p);
+ folioq_init(p, 0);
if (tail) {
tail->next = p;
p->prev = tail;
diff --git a/include/linux/folio_queue.h b/include/linux/folio_queue.h
index 3abe614ef5f06..4d3f8074c137a 100644
--- a/include/linux/folio_queue.h
+++ b/include/linux/folio_queue.h
@@ -37,16 +37,20 @@ struct folio_queue {
#if PAGEVEC_SIZE > BITS_PER_LONG
#error marks is not big enough
#endif
+ unsigned int rreq_id;
+ unsigned int debug_id;
};
/**
* folioq_init - Initialise a folio queue segment
* @folioq: The segment to initialise
+ * @rreq_id: The request identifier to use in tracelines.
*
- * Initialise a folio queue segment. Note that the folio pointers are
- * left uninitialised.
+ * Initialise a folio queue segment and set an identifier to be used in traces.
+ *
+ * Note that the folio pointers are left uninitialised.
*/
-static inline void folioq_init(struct folio_queue *folioq)
+static inline void folioq_init(struct folio_queue *folioq, unsigned int rreq_id)
{
folio_batch_init(&folioq->vec);
folioq->next = NULL;
@@ -54,6 +58,8 @@ static inline void folioq_init(struct folio_queue *folioq)
folioq->marks = 0;
folioq->marks2 = 0;
folioq->marks3 = 0;
+ folioq->rreq_id = rreq_id;
+ folioq->debug_id = 0;
}
/**
diff --git a/include/linux/netfs.h b/include/linux/netfs.h
index 5180292bd2d10..2704d3157a165 100644
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -457,8 +457,10 @@ int netfs_start_io_direct(struct inode *inode);
void netfs_end_io_direct(struct inode *inode);
/* Miscellaneous APIs. */
-struct folio_queue *netfs_folioq_alloc(gfp_t gfp);
-void netfs_folioq_free(struct folio_queue *folioq);
+struct folio_queue *netfs_folioq_alloc(unsigned int rreq_id, gfp_t gfp,
+ unsigned int trace /*enum netfs_folioq_trace*/);
+void netfs_folioq_free(struct folio_queue *folioq,
+ unsigned int trace /*enum netfs_trace_folioq*/);
/**
* netfs_inode - Get the netfs inode context from the inode
diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h
index 59452f12dcbee..4abb38b9e9488 100644
--- a/include/trace/events/netfs.h
+++ b/include/trace/events/netfs.h
@@ -199,6 +199,16 @@
EM(netfs_trace_donate_to_next, "to-next") \
E_(netfs_trace_donate_to_deferred_next, "defer-next")
+#define netfs_folioq_traces \
+ EM(netfs_trace_folioq_alloc_append_folio, "alloc-apf") \
+ EM(netfs_trace_folioq_alloc_read_prep, "alloc-r-prep") \
+ EM(netfs_trace_folioq_alloc_read_prime, "alloc-r-prime") \
+ EM(netfs_trace_folioq_alloc_read_sing, "alloc-r-sing") \
+ EM(netfs_trace_folioq_clear, "clear") \
+ EM(netfs_trace_folioq_delete, "delete") \
+ EM(netfs_trace_folioq_prep_write, "prep-wr") \
+ E_(netfs_trace_folioq_read_progress, "r-progress")
+
#ifndef __NETFS_DECLARE_TRACE_ENUMS_ONCE_ONLY
#define __NETFS_DECLARE_TRACE_ENUMS_ONCE_ONLY
@@ -217,6 +227,7 @@ enum netfs_sreq_ref_trace { netfs_sreq_ref_traces } __mode(byte);
enum netfs_folio_trace { netfs_folio_traces } __mode(byte);
enum netfs_collect_contig_trace { netfs_collect_contig_traces } __mode(byte);
enum netfs_donate_trace { netfs_donate_traces } __mode(byte);
+enum netfs_folioq_trace { netfs_folioq_traces } __mode(byte);
#endif
@@ -240,6 +251,7 @@ netfs_sreq_ref_traces;
netfs_folio_traces;
netfs_collect_contig_traces;
netfs_donate_traces;
+netfs_folioq_traces;
/*
* Now redefine the EM() and E_() macros to map the enums to the strings that
@@ -325,6 +337,7 @@ TRACE_EVENT(netfs_sreq,
__field(unsigned short, flags)
__field(enum netfs_io_source, source)
__field(enum netfs_sreq_trace, what)
+ __field(u8, slot)
__field(size_t, len)
__field(size_t, transferred)
__field(loff_t, start)
@@ -340,15 +353,16 @@ TRACE_EVENT(netfs_sreq,
__entry->len = sreq->len;
__entry->transferred = sreq->transferred;
__entry->start = sreq->start;
+ __entry->slot = sreq->curr_folioq_slot;
),
- TP_printk("R=%08x[%x] %s %s f=%02x s=%llx %zx/%zx e=%d",
+ TP_printk("R=%08x[%x] %s %s f=%02x s=%llx %zx/%zx s=%u e=%d",
__entry->rreq, __entry->index,
__print_symbolic(__entry->source, netfs_sreq_sources),
__print_symbolic(__entry->what, netfs_sreq_traces),
__entry->flags,
__entry->start, __entry->transferred, __entry->len,
- __entry->error)
+ __entry->slot, __entry->error)
);
TRACE_EVENT(netfs_failure,
@@ -753,6 +767,29 @@ TRACE_EVENT(netfs_donate,
__entry->amount)
);
+TRACE_EVENT(netfs_folioq,
+ TP_PROTO(const struct folio_queue *fq,
+ enum netfs_folioq_trace trace),
+
+ TP_ARGS(fq, trace),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, rreq)
+ __field(unsigned int, id)
+ __field(enum netfs_folioq_trace, trace)
+ ),
+
+ TP_fast_assign(
+ __entry->rreq = fq ? fq->rreq_id : 0;
+ __entry->id = fq ? fq->debug_id : 0;
+ __entry->trace = trace;
+ ),
+
+ TP_printk("R=%08x fq=%x %s",
+ __entry->rreq, __entry->id,
+ __print_symbolic(__entry->trace, netfs_folioq_traces))
+ );
+
#undef EM
#undef E_
#endif /* _TRACE_NETFS_H */
diff --git a/lib/kunit_iov_iter.c b/lib/kunit_iov_iter.c
index 13e15687675a8..10a560feb66e2 100644
--- a/lib/kunit_iov_iter.c
+++ b/lib/kunit_iov_iter.c
@@ -392,7 +392,7 @@ static void __init iov_kunit_load_folioq(struct kunit *test,
if (folioq_full(p)) {
p->next = kzalloc(sizeof(struct folio_queue), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p->next);
- folioq_init(p->next);
+ folioq_init(p->next, 0);
p->next->prev = p;
p = p->next;
}
@@ -409,7 +409,7 @@ static struct folio_queue *iov_kunit_create_folioq(struct kunit *test)
folioq = kzalloc(sizeof(struct folio_queue), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, folioq);
kunit_add_action_or_reset(test, iov_kunit_destroy_folioq, folioq);
- folioq_init(folioq);
+ folioq_init(folioq, 0);
return folioq;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 439/869] netfs: Abstract out a rolling folio buffer implementation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (437 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 438/869] netfs: Add a tracepoint to log the lifespan of folio_queue structs Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 440/869] netfs: Drop the was_async arg from netfs_read_subreq_terminated() Greg Kroah-Hartman
` (430 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Jeff Layton, netfs,
linux-fsdevel, Christian Brauner, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit 06fa229ceb36898e68022b5654c017d2c6582d7d ]
A rolling buffer is a series of folios held in a list of folio_queues. New
folios and folio_queue structs may be inserted at the head simultaneously
with spent ones being removed from the tail without the need for locking.
The rolling buffer includes an iov_iter and it has to be careful managing
this as the list of folio_queues is extended such that an oops doesn't
incurred because the iterator was pointing to the end of a folio_queue
segment that got appended to and then removed.
We need to use the mechanism twice, once for read and once for write, and,
in future patches, we will use a second rolling buffer to handle bounce
buffering for content encryption.
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/r/20241216204124.3752367-6-dhowells@redhat.com
cc: Jeff Layton <jlayton@kernel.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: dbd6f56d975b ("netfs: Fix netfs_create_write_req() to handle async cache object creation")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/netfs/Makefile | 1 +
fs/netfs/buffered_read.c | 119 ++++-------------
fs/netfs/direct_read.c | 14 +-
fs/netfs/direct_write.c | 10 +-
fs/netfs/internal.h | 4 -
fs/netfs/misc.c | 147 ---------------------
fs/netfs/objects.c | 2 +-
fs/netfs/read_pgpriv2.c | 32 ++---
fs/netfs/read_retry.c | 2 +-
fs/netfs/rolling_buffer.c | 226 +++++++++++++++++++++++++++++++++
fs/netfs/write_collect.c | 19 +--
fs/netfs/write_issue.c | 26 ++--
include/linux/netfs.h | 10 +-
include/linux/rolling_buffer.h | 61 +++++++++
include/trace/events/netfs.h | 2 +
15 files changed, 375 insertions(+), 300 deletions(-)
create mode 100644 fs/netfs/rolling_buffer.c
create mode 100644 include/linux/rolling_buffer.h
diff --git a/fs/netfs/Makefile b/fs/netfs/Makefile
index d08b0bfb67569..7492c4aa331e2 100644
--- a/fs/netfs/Makefile
+++ b/fs/netfs/Makefile
@@ -13,6 +13,7 @@ netfs-y := \
read_collect.o \
read_pgpriv2.o \
read_retry.o \
+ rolling_buffer.o \
write_collect.o \
write_issue.o
diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c
index 3aa49f6ddde6d..03bb1bbbbaa2a 100644
--- a/fs/netfs/buffered_read.c
+++ b/fs/netfs/buffered_read.c
@@ -63,37 +63,6 @@ static int netfs_begin_cache_read(struct netfs_io_request *rreq, struct netfs_in
return fscache_begin_read_operation(&rreq->cache_resources, netfs_i_cookie(ctx));
}
-/*
- * Decant the list of folios to read into a rolling buffer.
- */
-static size_t netfs_load_buffer_from_ra(struct netfs_io_request *rreq,
- struct folio_queue *folioq,
- struct folio_batch *put_batch)
-{
- unsigned int order, nr;
- size_t size = 0;
-
- nr = __readahead_batch(rreq->ractl, (struct page **)folioq->vec.folios,
- ARRAY_SIZE(folioq->vec.folios));
- folioq->vec.nr = nr;
- for (int i = 0; i < nr; i++) {
- struct folio *folio = folioq_folio(folioq, i);
-
- trace_netfs_folio(folio, netfs_folio_trace_read);
- order = folio_order(folio);
- folioq->orders[i] = order;
- size += PAGE_SIZE << order;
-
- if (!folio_batch_add(put_batch, folio))
- folio_batch_release(put_batch);
- }
-
- for (int i = nr; i < folioq_nr_slots(folioq); i++)
- folioq_clear(folioq, i);
-
- return size;
-}
-
/*
* netfs_prepare_read_iterator - Prepare the subreq iterator for I/O
* @subreq: The subrequest to be set up
@@ -128,18 +97,12 @@ static ssize_t netfs_prepare_read_iterator(struct netfs_io_subrequest *subreq)
folio_batch_init(&put_batch);
while (rreq->submitted < subreq->start + rsize) {
- struct folio_queue *tail = rreq->buffer_tail, *new;
- size_t added;
-
- new = netfs_folioq_alloc(rreq->debug_id, GFP_NOFS,
- netfs_trace_folioq_alloc_read_prep);
- if (!new)
- return -ENOMEM;
- new->prev = tail;
- tail->next = new;
- rreq->buffer_tail = new;
- added = netfs_load_buffer_from_ra(rreq, new, &put_batch);
- rreq->iter.count += added;
+ ssize_t added;
+
+ added = rolling_buffer_load_from_ra(&rreq->buffer, rreq->ractl,
+ &put_batch);
+ if (added < 0)
+ return added;
rreq->submitted += added;
}
folio_batch_release(&put_batch);
@@ -147,7 +110,7 @@ static ssize_t netfs_prepare_read_iterator(struct netfs_io_subrequest *subreq)
subreq->len = rsize;
if (unlikely(rreq->io_streams[0].sreq_max_segs)) {
- size_t limit = netfs_limit_iter(&rreq->iter, 0, rsize,
+ size_t limit = netfs_limit_iter(&rreq->buffer.iter, 0, rsize,
rreq->io_streams[0].sreq_max_segs);
if (limit < rsize) {
@@ -156,20 +119,16 @@ static ssize_t netfs_prepare_read_iterator(struct netfs_io_subrequest *subreq)
}
}
- subreq->io_iter = rreq->iter;
+ subreq->io_iter = rreq->buffer.iter;
if (iov_iter_is_folioq(&subreq->io_iter)) {
- if (subreq->io_iter.folioq_slot >= folioq_nr_slots(subreq->io_iter.folioq)) {
- subreq->io_iter.folioq = subreq->io_iter.folioq->next;
- subreq->io_iter.folioq_slot = 0;
- }
subreq->curr_folioq = (struct folio_queue *)subreq->io_iter.folioq;
subreq->curr_folioq_slot = subreq->io_iter.folioq_slot;
subreq->curr_folio_order = subreq->curr_folioq->orders[subreq->curr_folioq_slot];
}
iov_iter_truncate(&subreq->io_iter, subreq->len);
- iov_iter_advance(&rreq->iter, subreq->len);
+ rolling_buffer_advance(&rreq->buffer, subreq->len);
return subreq->len;
}
@@ -352,34 +311,6 @@ static int netfs_wait_for_read(struct netfs_io_request *rreq)
return ret;
}
-/*
- * Set up the initial folioq of buffer folios in the rolling buffer and set the
- * iterator to refer to it.
- */
-static int netfs_prime_buffer(struct netfs_io_request *rreq)
-{
- struct folio_queue *folioq;
- struct folio_batch put_batch;
- size_t added;
-
- folioq = netfs_folioq_alloc(rreq->debug_id, GFP_KERNEL,
- netfs_trace_folioq_alloc_read_prime);
- if (!folioq)
- return -ENOMEM;
-
- rreq->buffer = folioq;
- rreq->buffer_tail = folioq;
- rreq->submitted = rreq->start;
- iov_iter_folio_queue(&rreq->iter, ITER_DEST, folioq, 0, 0, 0);
-
- folio_batch_init(&put_batch);
- added = netfs_load_buffer_from_ra(rreq, folioq, &put_batch);
- folio_batch_release(&put_batch);
- rreq->iter.count += added;
- rreq->submitted += added;
- return 0;
-}
-
/**
* netfs_readahead - Helper to manage a read request
* @ractl: The description of the readahead request
@@ -419,7 +350,8 @@ void netfs_readahead(struct readahead_control *ractl)
netfs_rreq_expand(rreq, ractl);
rreq->ractl = ractl;
- if (netfs_prime_buffer(rreq) < 0)
+ rreq->submitted = rreq->start;
+ if (rolling_buffer_init(&rreq->buffer, rreq->debug_id, ITER_DEST) < 0)
goto cleanup_free;
netfs_read_to_pagecache(rreq);
@@ -435,22 +367,18 @@ EXPORT_SYMBOL(netfs_readahead);
/*
* Create a rolling buffer with a single occupying folio.
*/
-static int netfs_create_singular_buffer(struct netfs_io_request *rreq, struct folio *folio)
+static int netfs_create_singular_buffer(struct netfs_io_request *rreq, struct folio *folio,
+ unsigned int rollbuf_flags)
{
- struct folio_queue *folioq;
+ ssize_t added;
- folioq = netfs_folioq_alloc(rreq->debug_id, GFP_KERNEL,
- netfs_trace_folioq_alloc_read_sing);
- if (!folioq)
+ if (rolling_buffer_init(&rreq->buffer, rreq->debug_id, ITER_DEST) < 0)
return -ENOMEM;
- folioq_append(folioq, folio);
- BUG_ON(folioq_folio(folioq, 0) != folio);
- BUG_ON(folioq_folio_order(folioq, 0) != folio_order(folio));
- rreq->buffer = folioq;
- rreq->buffer_tail = folioq;
- rreq->submitted = rreq->start + rreq->len;
- iov_iter_folio_queue(&rreq->iter, ITER_DEST, folioq, 0, 0, rreq->len);
+ added = rolling_buffer_append(&rreq->buffer, folio, rollbuf_flags);
+ if (added < 0)
+ return added;
+ rreq->submitted = rreq->start + added;
rreq->ractl = (struct readahead_control *)1UL;
return 0;
}
@@ -518,7 +446,7 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
}
if (to < flen)
bvec_set_folio(&bvec[i++], folio, flen - to, to);
- iov_iter_bvec(&rreq->iter, ITER_DEST, bvec, i, rreq->len);
+ iov_iter_bvec(&rreq->buffer.iter, ITER_DEST, bvec, i, rreq->len);
rreq->submitted = rreq->start + flen;
netfs_read_to_pagecache(rreq);
@@ -588,7 +516,7 @@ int netfs_read_folio(struct file *file, struct folio *folio)
trace_netfs_read(rreq, rreq->start, rreq->len, netfs_read_trace_readpage);
/* Set up the output buffer */
- ret = netfs_create_singular_buffer(rreq, folio);
+ ret = netfs_create_singular_buffer(rreq, folio, 0);
if (ret < 0)
goto discard;
@@ -745,7 +673,7 @@ int netfs_write_begin(struct netfs_inode *ctx,
trace_netfs_read(rreq, pos, len, netfs_read_trace_write_begin);
/* Set up the output buffer */
- ret = netfs_create_singular_buffer(rreq, folio);
+ ret = netfs_create_singular_buffer(rreq, folio, 0);
if (ret < 0)
goto error_put;
@@ -810,11 +738,10 @@ int netfs_prefetch_for_write(struct file *file, struct folio *folio,
trace_netfs_read(rreq, start, flen, netfs_read_trace_prefetch_for_write);
/* Set up the output buffer */
- ret = netfs_create_singular_buffer(rreq, folio);
+ ret = netfs_create_singular_buffer(rreq, folio, NETFS_ROLLBUF_PAGECACHE_MARK);
if (ret < 0)
goto error_put;
- folioq_mark2(rreq->buffer, 0);
netfs_read_to_pagecache(rreq);
ret = netfs_wait_for_read(rreq);
netfs_put_request(rreq, false, netfs_rreq_trace_put_return);
diff --git a/fs/netfs/direct_read.c b/fs/netfs/direct_read.c
index 917b7edc34ef5..80ba521107dce 100644
--- a/fs/netfs/direct_read.c
+++ b/fs/netfs/direct_read.c
@@ -25,7 +25,7 @@ static void netfs_prepare_dio_read_iterator(struct netfs_io_subrequest *subreq)
subreq->len = rsize;
if (unlikely(rreq->io_streams[0].sreq_max_segs)) {
- size_t limit = netfs_limit_iter(&rreq->iter, 0, rsize,
+ size_t limit = netfs_limit_iter(&rreq->buffer.iter, 0, rsize,
rreq->io_streams[0].sreq_max_segs);
if (limit < rsize) {
@@ -36,9 +36,9 @@ static void netfs_prepare_dio_read_iterator(struct netfs_io_subrequest *subreq)
trace_netfs_sreq(subreq, netfs_sreq_trace_prepare);
- subreq->io_iter = rreq->iter;
+ subreq->io_iter = rreq->buffer.iter;
iov_iter_truncate(&subreq->io_iter, subreq->len);
- iov_iter_advance(&rreq->iter, subreq->len);
+ iov_iter_advance(&rreq->buffer.iter, subreq->len);
}
/*
@@ -199,15 +199,15 @@ ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *i
* the request.
*/
if (user_backed_iter(iter)) {
- ret = netfs_extract_user_iter(iter, rreq->len, &rreq->iter, 0);
+ ret = netfs_extract_user_iter(iter, rreq->len, &rreq->buffer.iter, 0);
if (ret < 0)
goto out;
- rreq->direct_bv = (struct bio_vec *)rreq->iter.bvec;
+ rreq->direct_bv = (struct bio_vec *)rreq->buffer.iter.bvec;
rreq->direct_bv_count = ret;
rreq->direct_bv_unpin = iov_iter_extract_will_pin(iter);
- rreq->len = iov_iter_count(&rreq->iter);
+ rreq->len = iov_iter_count(&rreq->buffer.iter);
} else {
- rreq->iter = *iter;
+ rreq->buffer.iter = *iter;
rreq->len = orig_count;
rreq->direct_bv_unpin = false;
iov_iter_advance(iter, orig_count);
diff --git a/fs/netfs/direct_write.c b/fs/netfs/direct_write.c
index 59f1b36a43c7c..0f8fb01ec84f9 100644
--- a/fs/netfs/direct_write.c
+++ b/fs/netfs/direct_write.c
@@ -72,12 +72,12 @@ ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *
* request.
*/
if (user_backed_iter(iter)) {
- n = netfs_extract_user_iter(iter, len, &wreq->iter, 0);
+ n = netfs_extract_user_iter(iter, len, &wreq->buffer.iter, 0);
if (n < 0) {
ret = n;
goto out;
}
- wreq->direct_bv = (struct bio_vec *)wreq->iter.bvec;
+ wreq->direct_bv = (struct bio_vec *)wreq->buffer.iter.bvec;
wreq->direct_bv_count = n;
wreq->direct_bv_unpin = iov_iter_extract_will_pin(iter);
} else {
@@ -86,10 +86,8 @@ ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *
* (eg. a bio_vec array) will persist till the end of
* the op.
*/
- wreq->iter = *iter;
+ wreq->buffer.iter = *iter;
}
-
- wreq->io_iter = wreq->iter;
}
__set_bit(NETFS_RREQ_USE_IO_ITER, &wreq->flags);
@@ -101,7 +99,7 @@ ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *
__set_bit(NETFS_RREQ_UPLOAD_TO_SERVER, &wreq->flags);
if (async)
wreq->iocb = iocb;
- wreq->len = iov_iter_count(&wreq->io_iter);
+ wreq->len = iov_iter_count(&wreq->buffer.iter);
wreq->cleanup = netfs_cleanup_dio_write;
ret = netfs_unbuffered_write(wreq, is_sync_kiocb(iocb), wreq->len);
if (ret < 0) {
diff --git a/fs/netfs/internal.h b/fs/netfs/internal.h
index b0c7576951c25..102bc07f3f55b 100644
--- a/fs/netfs/internal.h
+++ b/fs/netfs/internal.h
@@ -60,10 +60,6 @@ static inline void netfs_proc_del_rreq(struct netfs_io_request *rreq) {}
*/
struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq,
enum netfs_folioq_trace trace);
-int netfs_buffer_append_folio(struct netfs_io_request *rreq, struct folio *folio,
- bool needs_put);
-struct folio_queue *netfs_delete_buffer_head(struct netfs_io_request *wreq);
-void netfs_clear_buffer(struct netfs_io_request *rreq);
void netfs_reset_iter(struct netfs_io_subrequest *subreq);
int netfs_clear_stale_pre_isize(struct inode *inode, unsigned long long from,
unsigned long long to, bool nowait);
diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c
index 71a0d553f4d43..b9ed14ae338e4 100644
--- a/fs/netfs/misc.c
+++ b/fs/netfs/misc.c
@@ -9,153 +9,6 @@
#include <linux/rmap.h>
#include "internal.h"
-/**
- * netfs_folioq_alloc - Allocate a folio_queue struct
- * @rreq_id: Associated debugging ID for tracing purposes
- * @gfp: Allocation constraints
- * @trace: Trace tag to indicate the purpose of the allocation
- *
- * Allocate, initialise and account the folio_queue struct and log a trace line
- * to mark the allocation.
- */
-struct folio_queue *netfs_folioq_alloc(unsigned int rreq_id, gfp_t gfp,
- unsigned int /*enum netfs_folioq_trace*/ trace)
-{
- static atomic_t debug_ids;
- struct folio_queue *fq;
-
- fq = kmalloc(sizeof(*fq), gfp);
- if (fq) {
- netfs_stat(&netfs_n_folioq);
- folioq_init(fq, rreq_id);
- fq->debug_id = atomic_inc_return(&debug_ids);
- trace_netfs_folioq(fq, trace);
- }
- return fq;
-}
-EXPORT_SYMBOL(netfs_folioq_alloc);
-
-/**
- * netfs_folioq_free - Free a folio_queue struct
- * @folioq: The object to free
- * @trace: Trace tag to indicate which free
- *
- * Free and unaccount the folio_queue struct.
- */
-void netfs_folioq_free(struct folio_queue *folioq,
- unsigned int /*enum netfs_trace_folioq*/ trace)
-{
- trace_netfs_folioq(folioq, trace);
- netfs_stat_d(&netfs_n_folioq);
- kfree(folioq);
-}
-EXPORT_SYMBOL(netfs_folioq_free);
-
-/*
- * Make sure there's space in the rolling queue.
- */
-struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq,
- enum netfs_folioq_trace trace)
-{
- struct folio_queue *tail = rreq->buffer_tail, *prev;
- unsigned int prev_nr_slots = 0;
-
- if (WARN_ON_ONCE(!rreq->buffer && tail) ||
- WARN_ON_ONCE(rreq->buffer && !tail))
- return ERR_PTR(-EIO);
-
- prev = tail;
- if (prev) {
- if (!folioq_full(tail))
- return tail;
- prev_nr_slots = folioq_nr_slots(tail);
- }
-
- tail = netfs_folioq_alloc(rreq->debug_id, GFP_NOFS, trace);
- if (!tail)
- return ERR_PTR(-ENOMEM);
- tail->prev = prev;
- if (prev)
- /* [!] NOTE: After we set prev->next, the consumer is entirely
- * at liberty to delete prev.
- */
- WRITE_ONCE(prev->next, tail);
-
- rreq->buffer_tail = tail;
- if (!rreq->buffer) {
- rreq->buffer = tail;
- iov_iter_folio_queue(&rreq->io_iter, ITER_SOURCE, tail, 0, 0, 0);
- } else {
- /* Make sure we don't leave the master iterator pointing to a
- * block that might get immediately consumed.
- */
- if (rreq->io_iter.folioq == prev &&
- rreq->io_iter.folioq_slot == prev_nr_slots) {
- rreq->io_iter.folioq = tail;
- rreq->io_iter.folioq_slot = 0;
- }
- }
- rreq->buffer_tail_slot = 0;
- return tail;
-}
-
-/*
- * Append a folio to the rolling queue.
- */
-int netfs_buffer_append_folio(struct netfs_io_request *rreq, struct folio *folio,
- bool needs_put)
-{
- struct folio_queue *tail;
- unsigned int slot, order = folio_order(folio);
-
- tail = netfs_buffer_make_space(rreq, netfs_trace_folioq_alloc_append_folio);
- if (IS_ERR(tail))
- return PTR_ERR(tail);
-
- rreq->io_iter.count += PAGE_SIZE << order;
-
- slot = folioq_append(tail, folio);
- /* Store the counter after setting the slot. */
- smp_store_release(&rreq->buffer_tail_slot, slot);
- return 0;
-}
-
-/*
- * Delete the head of a rolling queue.
- */
-struct folio_queue *netfs_delete_buffer_head(struct netfs_io_request *wreq)
-{
- struct folio_queue *head = wreq->buffer, *next = head->next;
-
- if (next)
- next->prev = NULL;
- netfs_folioq_free(head, netfs_trace_folioq_delete);
- wreq->buffer = next;
- return next;
-}
-
-/*
- * Clear out a rolling queue.
- */
-void netfs_clear_buffer(struct netfs_io_request *rreq)
-{
- struct folio_queue *p;
-
- while ((p = rreq->buffer)) {
- rreq->buffer = p->next;
- for (int slot = 0; slot < folioq_count(p); slot++) {
- struct folio *folio = folioq_folio(p, slot);
- if (!folio)
- continue;
- if (folioq_is_marked(p, slot)) {
- trace_netfs_folio(folio, netfs_folio_trace_put);
- folio_put(folio);
- }
- }
- netfs_folioq_free(p, netfs_trace_folioq_clear);
- }
-}
-
/*
* Reset the subrequest iterator to refer just to the region remaining to be
* read. The iterator may or may not have been advanced by socket ops or
diff --git a/fs/netfs/objects.c b/fs/netfs/objects.c
index eb8411bd0a743..f10fd56efa177 100644
--- a/fs/netfs/objects.c
+++ b/fs/netfs/objects.c
@@ -143,7 +143,7 @@ static void netfs_free_request(struct work_struct *work)
}
kvfree(rreq->direct_bv);
}
- netfs_clear_buffer(rreq);
+ rolling_buffer_clear(&rreq->buffer);
if (atomic_dec_and_test(&ictx->io_count))
wake_up_var(&ictx->io_count);
diff --git a/fs/netfs/read_pgpriv2.c b/fs/netfs/read_pgpriv2.c
index e72f5e6748342..838f92eed1c23 100644
--- a/fs/netfs/read_pgpriv2.c
+++ b/fs/netfs/read_pgpriv2.c
@@ -34,8 +34,9 @@ void netfs_pgpriv2_mark_copy_to_cache(struct netfs_io_subrequest *subreq,
* [DEPRECATED] Cancel PG_private_2 on all marked folios in the event of an
* unrecoverable error.
*/
-static void netfs_pgpriv2_cancel(struct folio_queue *folioq)
+static void netfs_pgpriv2_cancel(struct rolling_buffer *buffer)
{
+ struct folio_queue *folioq = buffer->tail;
struct folio *folio;
int slot;
@@ -94,7 +95,7 @@ static int netfs_pgpriv2_copy_folio(struct netfs_io_request *wreq, struct folio
trace_netfs_folio(folio, netfs_folio_trace_store_copy);
/* Attach the folio to the rolling buffer. */
- if (netfs_buffer_append_folio(wreq, folio, false) < 0)
+ if (rolling_buffer_append(&wreq->buffer, folio, 0) < 0)
return -ENOMEM;
cache->submit_extendable_to = fsize;
@@ -109,7 +110,7 @@ static int netfs_pgpriv2_copy_folio(struct netfs_io_request *wreq, struct folio
do {
ssize_t part;
- wreq->io_iter.iov_offset = cache->submit_off;
+ wreq->buffer.iter.iov_offset = cache->submit_off;
atomic64_set(&wreq->issued_to, fpos + cache->submit_off);
cache->submit_extendable_to = fsize - cache->submit_off;
@@ -122,8 +123,8 @@ static int netfs_pgpriv2_copy_folio(struct netfs_io_request *wreq, struct folio
cache->submit_len -= part;
} while (cache->submit_len > 0);
- wreq->io_iter.iov_offset = 0;
- iov_iter_advance(&wreq->io_iter, fsize);
+ wreq->buffer.iter.iov_offset = 0;
+ rolling_buffer_advance(&wreq->buffer, fsize);
atomic64_set(&wreq->issued_to, fpos + fsize);
if (flen < fsize)
@@ -151,7 +152,7 @@ void netfs_pgpriv2_write_to_the_cache(struct netfs_io_request *rreq)
goto couldnt_start;
/* Need the first folio to be able to set up the op. */
- for (folioq = rreq->buffer; folioq; folioq = folioq->next) {
+ for (folioq = rreq->buffer.tail; folioq; folioq = folioq->next) {
if (folioq->marks3) {
slot = __ffs(folioq->marks3);
break;
@@ -199,7 +200,7 @@ void netfs_pgpriv2_write_to_the_cache(struct netfs_io_request *rreq)
netfs_put_request(wreq, false, netfs_rreq_trace_put_return);
_leave(" = %d", error);
couldnt_start:
- netfs_pgpriv2_cancel(rreq->buffer);
+ netfs_pgpriv2_cancel(&rreq->buffer);
}
/*
@@ -208,13 +209,13 @@ void netfs_pgpriv2_write_to_the_cache(struct netfs_io_request *rreq)
*/
bool netfs_pgpriv2_unlock_copied_folios(struct netfs_io_request *wreq)
{
- struct folio_queue *folioq = wreq->buffer;
+ struct folio_queue *folioq = wreq->buffer.tail;
unsigned long long collected_to = wreq->collected_to;
- unsigned int slot = wreq->buffer_head_slot;
+ unsigned int slot = wreq->buffer.first_tail_slot;
bool made_progress = false;
if (slot >= folioq_nr_slots(folioq)) {
- folioq = netfs_delete_buffer_head(wreq);
+ folioq = rolling_buffer_delete_spent(&wreq->buffer);
slot = 0;
}
@@ -253,9 +254,9 @@ bool netfs_pgpriv2_unlock_copied_folios(struct netfs_io_request *wreq)
folioq_clear(folioq, slot);
slot++;
if (slot >= folioq_nr_slots(folioq)) {
- if (READ_ONCE(wreq->buffer_tail) == folioq)
- break;
- folioq = netfs_delete_buffer_head(wreq);
+ folioq = rolling_buffer_delete_spent(&wreq->buffer);
+ if (!folioq)
+ goto done;
slot = 0;
}
@@ -263,7 +264,8 @@ bool netfs_pgpriv2_unlock_copied_folios(struct netfs_io_request *wreq)
break;
}
- wreq->buffer = folioq;
- wreq->buffer_head_slot = slot;
+ wreq->buffer.tail = folioq;
+done:
+ wreq->buffer.first_tail_slot = slot;
return made_progress;
}
diff --git a/fs/netfs/read_retry.c b/fs/netfs/read_retry.c
index a5487b00ec563..1c66c6e5c84b4 100644
--- a/fs/netfs/read_retry.c
+++ b/fs/netfs/read_retry.c
@@ -244,7 +244,7 @@ void netfs_unlock_abandoned_read_pages(struct netfs_io_request *rreq)
{
struct folio_queue *p;
- for (p = rreq->buffer; p; p = p->next) {
+ for (p = rreq->buffer.tail; p; p = p->next) {
for (int slot = 0; slot < folioq_count(p); slot++) {
struct folio *folio = folioq_folio(p, slot);
diff --git a/fs/netfs/rolling_buffer.c b/fs/netfs/rolling_buffer.c
new file mode 100644
index 0000000000000..75d97af14b4ab
--- /dev/null
+++ b/fs/netfs/rolling_buffer.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Rolling buffer helpers
+ *
+ * Copyright (C) 2024 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#include <linux/bitops.h>
+#include <linux/pagemap.h>
+#include <linux/rolling_buffer.h>
+#include <linux/slab.h>
+#include "internal.h"
+
+static atomic_t debug_ids;
+
+/**
+ * netfs_folioq_alloc - Allocate a folio_queue struct
+ * @rreq_id: Associated debugging ID for tracing purposes
+ * @gfp: Allocation constraints
+ * @trace: Trace tag to indicate the purpose of the allocation
+ *
+ * Allocate, initialise and account the folio_queue struct and log a trace line
+ * to mark the allocation.
+ */
+struct folio_queue *netfs_folioq_alloc(unsigned int rreq_id, gfp_t gfp,
+ unsigned int /*enum netfs_folioq_trace*/ trace)
+{
+ struct folio_queue *fq;
+
+ fq = kmalloc(sizeof(*fq), gfp);
+ if (fq) {
+ netfs_stat(&netfs_n_folioq);
+ folioq_init(fq, rreq_id);
+ fq->debug_id = atomic_inc_return(&debug_ids);
+ trace_netfs_folioq(fq, trace);
+ }
+ return fq;
+}
+EXPORT_SYMBOL(netfs_folioq_alloc);
+
+/**
+ * netfs_folioq_free - Free a folio_queue struct
+ * @folioq: The object to free
+ * @trace: Trace tag to indicate which free
+ *
+ * Free and unaccount the folio_queue struct.
+ */
+void netfs_folioq_free(struct folio_queue *folioq,
+ unsigned int /*enum netfs_trace_folioq*/ trace)
+{
+ trace_netfs_folioq(folioq, trace);
+ netfs_stat_d(&netfs_n_folioq);
+ kfree(folioq);
+}
+EXPORT_SYMBOL(netfs_folioq_free);
+
+/*
+ * Initialise a rolling buffer. We allocate an empty folio queue struct to so
+ * that the pointers can be independently driven by the producer and the
+ * consumer.
+ */
+int rolling_buffer_init(struct rolling_buffer *roll, unsigned int rreq_id,
+ unsigned int direction)
+{
+ struct folio_queue *fq;
+
+ fq = netfs_folioq_alloc(rreq_id, GFP_NOFS, netfs_trace_folioq_rollbuf_init);
+ if (!fq)
+ return -ENOMEM;
+
+ roll->head = fq;
+ roll->tail = fq;
+ iov_iter_folio_queue(&roll->iter, direction, fq, 0, 0, 0);
+ return 0;
+}
+
+/*
+ * Add another folio_queue to a rolling buffer if there's no space left.
+ */
+int rolling_buffer_make_space(struct rolling_buffer *roll)
+{
+ struct folio_queue *fq, *head = roll->head;
+
+ if (!folioq_full(head))
+ return 0;
+
+ fq = netfs_folioq_alloc(head->rreq_id, GFP_NOFS, netfs_trace_folioq_make_space);
+ if (!fq)
+ return -ENOMEM;
+ fq->prev = head;
+
+ roll->head = fq;
+ if (folioq_full(head)) {
+ /* Make sure we don't leave the master iterator pointing to a
+ * block that might get immediately consumed.
+ */
+ if (roll->iter.folioq == head &&
+ roll->iter.folioq_slot == folioq_nr_slots(head)) {
+ roll->iter.folioq = fq;
+ roll->iter.folioq_slot = 0;
+ }
+ }
+
+ /* Make sure the initialisation is stored before the next pointer.
+ *
+ * [!] NOTE: After we set head->next, the consumer is at liberty to
+ * immediately delete the old head.
+ */
+ smp_store_release(&head->next, fq);
+ return 0;
+}
+
+/*
+ * Decant the list of folios to read into a rolling buffer.
+ */
+ssize_t rolling_buffer_load_from_ra(struct rolling_buffer *roll,
+ struct readahead_control *ractl,
+ struct folio_batch *put_batch)
+{
+ struct folio_queue *fq;
+ struct page **vec;
+ int nr, ix, to;
+ ssize_t size = 0;
+
+ if (rolling_buffer_make_space(roll) < 0)
+ return -ENOMEM;
+
+ fq = roll->head;
+ vec = (struct page **)fq->vec.folios;
+ nr = __readahead_batch(ractl, vec + folio_batch_count(&fq->vec),
+ folio_batch_space(&fq->vec));
+ ix = fq->vec.nr;
+ to = ix + nr;
+ fq->vec.nr = to;
+ for (; ix < to; ix++) {
+ struct folio *folio = folioq_folio(fq, ix);
+ unsigned int order = folio_order(folio);
+
+ fq->orders[ix] = order;
+ size += PAGE_SIZE << order;
+ trace_netfs_folio(folio, netfs_folio_trace_read);
+ if (!folio_batch_add(put_batch, folio))
+ folio_batch_release(put_batch);
+ }
+ WRITE_ONCE(roll->iter.count, roll->iter.count + size);
+
+ /* Store the counter after setting the slot. */
+ smp_store_release(&roll->next_head_slot, to);
+
+ for (; ix < folioq_nr_slots(fq); ix++)
+ folioq_clear(fq, ix);
+
+ return size;
+}
+
+/*
+ * Append a folio to the rolling buffer.
+ */
+ssize_t rolling_buffer_append(struct rolling_buffer *roll, struct folio *folio,
+ unsigned int flags)
+{
+ ssize_t size = folio_size(folio);
+ int slot;
+
+ if (rolling_buffer_make_space(roll) < 0)
+ return -ENOMEM;
+
+ slot = folioq_append(roll->head, folio);
+ if (flags & ROLLBUF_MARK_1)
+ folioq_mark(roll->head, slot);
+ if (flags & ROLLBUF_MARK_2)
+ folioq_mark2(roll->head, slot);
+
+ WRITE_ONCE(roll->iter.count, roll->iter.count + size);
+
+ /* Store the counter after setting the slot. */
+ smp_store_release(&roll->next_head_slot, slot);
+ return size;
+}
+
+/*
+ * Delete a spent buffer from a rolling queue and return the next in line. We
+ * don't return the last buffer to keep the pointers independent, but return
+ * NULL instead.
+ */
+struct folio_queue *rolling_buffer_delete_spent(struct rolling_buffer *roll)
+{
+ struct folio_queue *spent = roll->tail, *next = READ_ONCE(spent->next);
+
+ if (!next)
+ return NULL;
+ next->prev = NULL;
+ netfs_folioq_free(spent, netfs_trace_folioq_delete);
+ roll->tail = next;
+ return next;
+}
+
+/*
+ * Clear out a rolling queue. Folios that have mark 1 set are put.
+ */
+void rolling_buffer_clear(struct rolling_buffer *roll)
+{
+ struct folio_batch fbatch;
+ struct folio_queue *p;
+
+ folio_batch_init(&fbatch);
+
+ while ((p = roll->tail)) {
+ roll->tail = p->next;
+ for (int slot = 0; slot < folioq_count(p); slot++) {
+ struct folio *folio = folioq_folio(p, slot);
+
+ if (!folio)
+ continue;
+ if (folioq_is_marked(p, slot)) {
+ trace_netfs_folio(folio, netfs_folio_trace_put);
+ if (!folio_batch_add(&fbatch, folio))
+ folio_batch_release(&fbatch);
+ }
+ }
+
+ netfs_folioq_free(p, netfs_trace_folioq_clear);
+ }
+
+ folio_batch_release(&fbatch);
+}
diff --git a/fs/netfs/write_collect.c b/fs/netfs/write_collect.c
index ad2edf794f0ff..53790d0dc334d 100644
--- a/fs/netfs/write_collect.c
+++ b/fs/netfs/write_collect.c
@@ -83,9 +83,9 @@ int netfs_folio_written_back(struct folio *folio)
static void netfs_writeback_unlock_folios(struct netfs_io_request *wreq,
unsigned int *notes)
{
- struct folio_queue *folioq = wreq->buffer;
+ struct folio_queue *folioq = wreq->buffer.tail;
unsigned long long collected_to = wreq->collected_to;
- unsigned int slot = wreq->buffer_head_slot;
+ unsigned int slot = wreq->buffer.first_tail_slot;
if (wreq->origin == NETFS_PGPRIV2_COPY_TO_CACHE) {
if (netfs_pgpriv2_unlock_copied_folios(wreq))
@@ -94,7 +94,9 @@ static void netfs_writeback_unlock_folios(struct netfs_io_request *wreq,
}
if (slot >= folioq_nr_slots(folioq)) {
- folioq = netfs_delete_buffer_head(wreq);
+ folioq = rolling_buffer_delete_spent(&wreq->buffer);
+ if (!folioq)
+ return;
slot = 0;
}
@@ -134,9 +136,9 @@ static void netfs_writeback_unlock_folios(struct netfs_io_request *wreq,
folioq_clear(folioq, slot);
slot++;
if (slot >= folioq_nr_slots(folioq)) {
- if (READ_ONCE(wreq->buffer_tail) == folioq)
- break;
- folioq = netfs_delete_buffer_head(wreq);
+ folioq = rolling_buffer_delete_spent(&wreq->buffer);
+ if (!folioq)
+ goto done;
slot = 0;
}
@@ -144,8 +146,9 @@ static void netfs_writeback_unlock_folios(struct netfs_io_request *wreq,
break;
}
- wreq->buffer = folioq;
- wreq->buffer_head_slot = slot;
+ wreq->buffer.tail = folioq;
+done:
+ wreq->buffer.first_tail_slot = slot;
}
/*
diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c
index d1fa5851a7b29..57d3a6b73836b 100644
--- a/fs/netfs/write_issue.c
+++ b/fs/netfs/write_issue.c
@@ -107,6 +107,8 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping,
ictx = netfs_inode(wreq->inode);
if (is_buffered && netfs_is_cache_enabled(ictx))
fscache_begin_write_operation(&wreq->cache_resources, netfs_i_cookie(ictx));
+ if (rolling_buffer_init(&wreq->buffer, wreq->debug_id, ITER_SOURCE) < 0)
+ goto nomem;
wreq->cleaned_to = wreq->start;
@@ -129,6 +131,10 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping,
}
return wreq;
+nomem:
+ wreq->error = -ENOMEM;
+ netfs_put_request(wreq, false, netfs_rreq_trace_put_failed);
+ return ERR_PTR(-ENOMEM);
}
/**
@@ -153,16 +159,15 @@ static void netfs_prepare_write(struct netfs_io_request *wreq,
loff_t start)
{
struct netfs_io_subrequest *subreq;
- struct iov_iter *wreq_iter = &wreq->io_iter;
+ struct iov_iter *wreq_iter = &wreq->buffer.iter;
/* Make sure we don't point the iterator at a used-up folio_queue
* struct being used as a placeholder to prevent the queue from
* collapsing. In such a case, extend the queue.
*/
if (iov_iter_is_folioq(wreq_iter) &&
- wreq_iter->folioq_slot >= folioq_nr_slots(wreq_iter->folioq)) {
- netfs_buffer_make_space(wreq, netfs_trace_folioq_prep_write);
- }
+ wreq_iter->folioq_slot >= folioq_nr_slots(wreq_iter->folioq))
+ rolling_buffer_make_space(&wreq->buffer);
subreq = netfs_alloc_subrequest(wreq);
subreq->source = stream->source;
@@ -325,6 +330,9 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
_enter("");
+ if (rolling_buffer_make_space(&wreq->buffer) < 0)
+ return -ENOMEM;
+
/* netfs_perform_write() may shift i_size around the page or from out
* of the page to beyond it, but cannot move i_size into or through the
* page since we have it locked.
@@ -424,7 +432,7 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
}
/* Attach the folio to the rolling buffer. */
- netfs_buffer_append_folio(wreq, folio, false);
+ rolling_buffer_append(&wreq->buffer, folio, 0);
/* Move the submission point forward to allow for write-streaming data
* not starting at the front of the page. We don't do write-streaming
@@ -471,7 +479,7 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
/* Advance the iterator(s). */
if (stream->submit_off > iter_off) {
- iov_iter_advance(&wreq->io_iter, stream->submit_off - iter_off);
+ rolling_buffer_advance(&wreq->buffer, stream->submit_off - iter_off);
iter_off = stream->submit_off;
}
@@ -489,7 +497,7 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
}
if (fsize > iter_off)
- iov_iter_advance(&wreq->io_iter, fsize - iter_off);
+ rolling_buffer_advance(&wreq->buffer, fsize - iter_off);
atomic64_set(&wreq->issued_to, fpos + fsize);
if (!debug)
@@ -635,7 +643,7 @@ int netfs_advance_writethrough(struct netfs_io_request *wreq, struct writeback_c
int ret;
_enter("R=%x ic=%zu ws=%u cp=%zu tp=%u",
- wreq->debug_id, wreq->iter.count, wreq->wsize, copied, to_page_end);
+ wreq->debug_id, wreq->buffer.iter.count, wreq->wsize, copied, to_page_end);
/* The folio is locked. */
@@ -724,7 +732,7 @@ int netfs_unbuffered_write(struct netfs_io_request *wreq, bool may_wait, size_t
part = netfs_advance_write(wreq, upload, start, len, false);
start += part;
len -= part;
- iov_iter_advance(&wreq->io_iter, part);
+ rolling_buffer_advance(&wreq->buffer, part);
if (test_bit(NETFS_RREQ_PAUSE, &wreq->flags)) {
trace_netfs_rreq(wreq, netfs_rreq_trace_wait_pause);
wait_on_bit(&wreq->flags, NETFS_RREQ_PAUSE, TASK_UNINTERRUPTIBLE);
diff --git a/include/linux/netfs.h b/include/linux/netfs.h
index 2704d3157a165..73f782ce63695 100644
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -18,6 +18,7 @@
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/uio.h>
+#include <linux/rolling_buffer.h>
enum netfs_sreq_ref_trace;
typedef struct mempool_s mempool_t;
@@ -239,10 +240,9 @@ struct netfs_io_request {
struct netfs_io_stream io_streams[2]; /* Streams of parallel I/O operations */
#define NR_IO_STREAMS 2 //wreq->nr_io_streams
struct netfs_group *group; /* Writeback group being written back */
- struct folio_queue *buffer; /* Head of I/O buffer */
- struct folio_queue *buffer_tail; /* Tail of I/O buffer */
- struct iov_iter iter; /* Unencrypted-side iterator */
- struct iov_iter io_iter; /* I/O (Encrypted-side) iterator */
+ struct rolling_buffer buffer; /* Unencrypted buffer */
+#define NETFS_ROLLBUF_PUT_MARK ROLLBUF_MARK_1
+#define NETFS_ROLLBUF_PAGECACHE_MARK ROLLBUF_MARK_2
void *netfs_priv; /* Private data for the netfs */
void *netfs_priv2; /* Private data for the netfs */
struct bio_vec *direct_bv; /* DIO buffer list (when handling iovec-iter) */
@@ -260,8 +260,6 @@ struct netfs_io_request {
long error; /* 0 or error that occurred */
enum netfs_io_origin origin; /* Origin of the request */
bool direct_bv_unpin; /* T if direct_bv[] must be unpinned */
- u8 buffer_head_slot; /* First slot in ->buffer */
- u8 buffer_tail_slot; /* Next slot in ->buffer_tail */
unsigned long long i_size; /* Size of the file */
unsigned long long start; /* Start position */
atomic64_t issued_to; /* Write issuer folio cursor */
diff --git a/include/linux/rolling_buffer.h b/include/linux/rolling_buffer.h
new file mode 100644
index 0000000000000..ac15b1ffdd831
--- /dev/null
+++ b/include/linux/rolling_buffer.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Rolling buffer of folios
+ *
+ * Copyright (C) 2024 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#ifndef _ROLLING_BUFFER_H
+#define _ROLLING_BUFFER_H
+
+#include <linux/folio_queue.h>
+#include <linux/uio.h>
+
+/*
+ * Rolling buffer. Whilst the buffer is live and in use, folios and folio
+ * queue segments can be added to one end by one thread and removed from the
+ * other end by another thread. The buffer isn't allowed to be empty; it must
+ * always have at least one folio_queue in it so that neither side has to
+ * modify both queue pointers.
+ *
+ * The iterator in the buffer is extended as buffers are inserted. It can be
+ * snapshotted to use a segment of the buffer.
+ */
+struct rolling_buffer {
+ struct folio_queue *head; /* Producer's insertion point */
+ struct folio_queue *tail; /* Consumer's removal point */
+ struct iov_iter iter; /* Iterator tracking what's left in the buffer */
+ u8 next_head_slot; /* Next slot in ->head */
+ u8 first_tail_slot; /* First slot in ->tail */
+};
+
+/*
+ * Snapshot of a rolling buffer.
+ */
+struct rolling_buffer_snapshot {
+ struct folio_queue *curr_folioq; /* Queue segment in which current folio resides */
+ unsigned char curr_slot; /* Folio currently being read */
+ unsigned char curr_order; /* Order of folio */
+};
+
+/* Marks to store per-folio in the internal folio_queue structs. */
+#define ROLLBUF_MARK_1 BIT(0)
+#define ROLLBUF_MARK_2 BIT(1)
+
+int rolling_buffer_init(struct rolling_buffer *roll, unsigned int rreq_id,
+ unsigned int direction);
+int rolling_buffer_make_space(struct rolling_buffer *roll);
+ssize_t rolling_buffer_load_from_ra(struct rolling_buffer *roll,
+ struct readahead_control *ractl,
+ struct folio_batch *put_batch);
+ssize_t rolling_buffer_append(struct rolling_buffer *roll, struct folio *folio,
+ unsigned int flags);
+struct folio_queue *rolling_buffer_delete_spent(struct rolling_buffer *roll);
+void rolling_buffer_clear(struct rolling_buffer *roll);
+
+static inline void rolling_buffer_advance(struct rolling_buffer *roll, size_t amount)
+{
+ iov_iter_advance(&roll->iter, amount);
+}
+
+#endif /* _ROLLING_BUFFER_H */
diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h
index 4abb38b9e9488..f68fdb7ca7c02 100644
--- a/include/trace/events/netfs.h
+++ b/include/trace/events/netfs.h
@@ -206,7 +206,9 @@
EM(netfs_trace_folioq_alloc_read_sing, "alloc-r-sing") \
EM(netfs_trace_folioq_clear, "clear") \
EM(netfs_trace_folioq_delete, "delete") \
+ EM(netfs_trace_folioq_make_space, "make-space") \
EM(netfs_trace_folioq_prep_write, "prep-wr") \
+ EM(netfs_trace_folioq_rollbuf_init, "roll-init") \
E_(netfs_trace_folioq_read_progress, "r-progress")
#ifndef __NETFS_DECLARE_TRACE_ENUMS_ONCE_ONLY
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 440/869] netfs: Drop the was_async arg from netfs_read_subreq_terminated()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (438 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 439/869] netfs: Abstract out a rolling folio buffer implementation Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 441/869] netfs: Fix netfs_create_write_req() to handle async cache object creation Greg Kroah-Hartman
` (429 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Linus Torvalds, David Howells,
Jeff Layton, netfs, linux-fsdevel, Christian Brauner, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit 31fc366aa7aa911ebc0744e99c82caee4e97315a ]
Drop the was_async argument from netfs_read_subreq_terminated(). Almost
every caller is either in process context and passes false. Some
filesystems delegate the call to a workqueue to avoid doing the work in
their network message queue parsing thread.
The only exception is netfs_cache_read_terminated() which handles
completion in the cache - which is usually a callback from the backing
filesystem in softirq context, though it can be from process context if an
error occurred. In this case, delegate to a workqueue.
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Link: https://lore.kernel.org/r/CAHk-=wiVC5Cgyz6QKXFu6fTaA6h4CjexDR-OV9kL6Vo5x9v8=A@mail.gmail.com/
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/r/20241216204124.3752367-10-dhowells@redhat.com
cc: Jeff Layton <jlayton@kernel.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: dbd6f56d975b ("netfs: Fix netfs_create_write_req() to handle async cache object creation")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/9p/vfs_addr.c | 2 +-
fs/afs/file.c | 6 ++---
fs/afs/fsclient.c | 2 +-
fs/afs/yfsclient.c | 2 +-
fs/ceph/addr.c | 6 ++---
fs/netfs/buffered_read.c | 6 ++---
fs/netfs/direct_read.c | 2 +-
fs/netfs/internal.h | 3 +--
fs/netfs/objects.c | 2 +-
fs/netfs/read_collect.c | 53 +++++++++-------------------------------
fs/netfs/read_retry.c | 2 +-
fs/nfs/fscache.c | 2 +-
fs/nfs/fscache.h | 2 +-
fs/smb/client/file.c | 2 +-
include/linux/netfs.h | 4 +--
15 files changed, 33 insertions(+), 63 deletions(-)
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 5bf1e5caaa623..b346d4f3eb9db 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -96,7 +96,7 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq)
subreq->transferred += total;
subreq->error = err;
- netfs_read_subreq_terminated(subreq, false);
+ netfs_read_subreq_terminated(subreq);
}
/**
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 56248a078bcaa..f717168da4abb 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -247,7 +247,7 @@ static void afs_fetch_data_notify(struct afs_operation *op)
if (req->pos + req->actual_len >= req->file_size)
__set_bit(NETFS_SREQ_HIT_EOF, &subreq->flags);
subreq->error = error;
- netfs_read_subreq_terminated(subreq, false);
+ netfs_read_subreq_terminated(subreq);
req->subreq = NULL;
} else if (req->done) {
req->done(req);
@@ -304,7 +304,7 @@ int afs_fetch_data(struct afs_vnode *vnode, struct afs_read *req)
if (IS_ERR(op)) {
if (req->subreq) {
req->subreq->error = PTR_ERR(op);
- netfs_read_subreq_terminated(req->subreq, false);
+ netfs_read_subreq_terminated(req->subreq);
}
return PTR_ERR(op);
}
@@ -325,7 +325,7 @@ static void afs_read_worker(struct work_struct *work)
fsreq = afs_alloc_read(GFP_NOFS);
if (!fsreq) {
subreq->error = -ENOMEM;
- return netfs_read_subreq_terminated(subreq, false);
+ return netfs_read_subreq_terminated(subreq);
}
fsreq->subreq = subreq;
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 1f8a7878e9d96..b171078773f09 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -352,7 +352,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
ret = afs_extract_data(call, true);
if (req->subreq) {
req->subreq->transferred += count_before - call->iov_len;
- netfs_read_subreq_progress(req->subreq, false);
+ netfs_read_subreq_progress(req->subreq);
}
if (ret < 0)
return ret;
diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c
index 362845f9aaaef..667b78b485438 100644
--- a/fs/afs/yfsclient.c
+++ b/fs/afs/yfsclient.c
@@ -398,7 +398,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
ret = afs_extract_data(call, true);
if (req->subreq) {
req->subreq->transferred += count_before - call->iov_len;
- netfs_read_subreq_progress(req->subreq, false);
+ netfs_read_subreq_progress(req->subreq);
}
if (ret < 0)
return ret;
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 355555e313102..13508fee6293b 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -255,7 +255,7 @@ static void finish_netfs_read(struct ceph_osd_request *req)
}
subreq->error = err;
trace_netfs_sreq(subreq, netfs_sreq_trace_io_progress);
- netfs_read_subreq_terminated(subreq, false);
+ netfs_read_subreq_terminated(subreq);
iput(req->r_inode);
ceph_dec_osd_stopping_blocker(fsc->mdsc);
}
@@ -317,7 +317,7 @@ static bool ceph_netfs_issue_op_inline(struct netfs_io_subrequest *subreq)
out:
subreq->error = err;
trace_netfs_sreq(subreq, netfs_sreq_trace_io_progress);
- netfs_read_subreq_terminated(subreq, false);
+ netfs_read_subreq_terminated(subreq);
return true;
}
@@ -440,7 +440,7 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq)
ceph_osdc_put_request(req);
if (err) {
subreq->error = err;
- netfs_read_subreq_terminated(subreq, false);
+ netfs_read_subreq_terminated(subreq);
}
doutc(cl, "%llx.%llx result %d\n", ceph_vinop(inode), err);
}
diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c
index 03bb1bbbbaa2a..1228cabbfde3a 100644
--- a/fs/netfs/buffered_read.c
+++ b/fs/netfs/buffered_read.c
@@ -154,7 +154,7 @@ static void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error
} else {
subreq->error = transferred_or_error;
}
- netfs_read_subreq_terminated(subreq, was_async);
+ schedule_work(&subreq->work);
}
/*
@@ -255,7 +255,7 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq)
goto prep_iter_failed;
__set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags);
subreq->error = 0;
- netfs_read_subreq_terminated(subreq, false);
+ netfs_read_subreq_terminated(subreq);
goto done;
}
@@ -287,7 +287,7 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq)
} while (size > 0);
if (atomic_dec_and_test(&rreq->nr_outstanding))
- netfs_rreq_terminated(rreq, false);
+ netfs_rreq_terminated(rreq);
/* Defer error return as we may need to wait for outstanding I/O. */
cmpxchg(&rreq->error, 0, ret);
diff --git a/fs/netfs/direct_read.c b/fs/netfs/direct_read.c
index 80ba521107dce..2c79db1434324 100644
--- a/fs/netfs/direct_read.c
+++ b/fs/netfs/direct_read.c
@@ -100,7 +100,7 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq)
} while (size > 0);
if (atomic_dec_and_test(&rreq->nr_outstanding))
- netfs_rreq_terminated(rreq, false);
+ netfs_rreq_terminated(rreq);
return ret;
}
diff --git a/fs/netfs/internal.h b/fs/netfs/internal.h
index 102bc07f3f55b..7256277edacb8 100644
--- a/fs/netfs/internal.h
+++ b/fs/netfs/internal.h
@@ -86,8 +86,7 @@ static inline void netfs_see_request(struct netfs_io_request *rreq,
/*
* read_collect.c
*/
-void netfs_read_termination_worker(struct work_struct *work);
-void netfs_rreq_terminated(struct netfs_io_request *rreq, bool was_async);
+void netfs_rreq_terminated(struct netfs_io_request *rreq);
/*
* read_pgpriv2.c
diff --git a/fs/netfs/objects.c b/fs/netfs/objects.c
index f10fd56efa177..8c98b70eb3a4f 100644
--- a/fs/netfs/objects.c
+++ b/fs/netfs/objects.c
@@ -56,7 +56,7 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
origin == NETFS_READ_GAPS ||
origin == NETFS_READ_FOR_WRITE ||
origin == NETFS_DIO_READ)
- INIT_WORK(&rreq->work, netfs_read_termination_worker);
+ INIT_WORK(&rreq->work, NULL);
else
INIT_WORK(&rreq->work, netfs_write_collection_worker);
diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c
index c420c231f8d05..63f9ddf4435fd 100644
--- a/fs/netfs/read_collect.c
+++ b/fs/netfs/read_collect.c
@@ -87,7 +87,7 @@ static void netfs_unlock_read_folio(struct netfs_io_subrequest *subreq,
* Unlock any folios that are now completely read. Returns true if the
* subrequest is removed from the list.
*/
-static bool netfs_consume_read_data(struct netfs_io_subrequest *subreq, bool was_async)
+static bool netfs_consume_read_data(struct netfs_io_subrequest *subreq)
{
struct netfs_io_subrequest *prev, *next;
struct netfs_io_request *rreq = subreq->rreq;
@@ -230,8 +230,7 @@ static bool netfs_consume_read_data(struct netfs_io_subrequest *subreq, bool was
subreq->curr_folioq_slot = slot;
if (folioq && folioq_folio(folioq, slot))
subreq->curr_folio_order = folioq->orders[slot];
- if (!was_async)
- cond_resched();
+ cond_resched();
goto next_folio;
}
@@ -369,7 +368,7 @@ static void netfs_rreq_assess_dio(struct netfs_io_request *rreq)
* Note that we're in normal kernel thread context at this point, possibly
* running on a workqueue.
*/
-static void netfs_rreq_assess(struct netfs_io_request *rreq)
+void netfs_rreq_terminated(struct netfs_io_request *rreq)
{
trace_netfs_rreq(rreq, netfs_rreq_trace_assess);
@@ -395,56 +394,29 @@ static void netfs_rreq_assess(struct netfs_io_request *rreq)
netfs_pgpriv2_write_to_the_cache(rreq);
}
-void netfs_read_termination_worker(struct work_struct *work)
-{
- struct netfs_io_request *rreq =
- container_of(work, struct netfs_io_request, work);
- netfs_see_request(rreq, netfs_rreq_trace_see_work);
- netfs_rreq_assess(rreq);
- netfs_put_request(rreq, false, netfs_rreq_trace_put_work_complete);
-}
-
-/*
- * Handle the completion of all outstanding I/O operations on a read request.
- * We inherit a ref from the caller.
- */
-void netfs_rreq_terminated(struct netfs_io_request *rreq, bool was_async)
-{
- if (!was_async)
- return netfs_rreq_assess(rreq);
- if (!work_pending(&rreq->work)) {
- netfs_get_request(rreq, netfs_rreq_trace_get_work);
- if (!queue_work(system_unbound_wq, &rreq->work))
- netfs_put_request(rreq, was_async, netfs_rreq_trace_put_work_nq);
- }
-}
-
/**
* netfs_read_subreq_progress - Note progress of a read operation.
* @subreq: The read request that has terminated.
- * @was_async: True if we're in an asynchronous context.
*
* This tells the read side of netfs lib that a contributory I/O operation has
* made some progress and that it may be possible to unlock some folios.
*
* Before calling, the filesystem should update subreq->transferred to track
* the amount of data copied into the output buffer.
- *
- * If @was_async is true, the caller might be running in softirq or interrupt
- * context and we can't sleep.
*/
-void netfs_read_subreq_progress(struct netfs_io_subrequest *subreq,
- bool was_async)
+void netfs_read_subreq_progress(struct netfs_io_subrequest *subreq)
{
struct netfs_io_request *rreq = subreq->rreq;
+ might_sleep();
+
trace_netfs_sreq(subreq, netfs_sreq_trace_progress);
if (subreq->transferred > subreq->consumed &&
(rreq->origin == NETFS_READAHEAD ||
rreq->origin == NETFS_READPAGE ||
rreq->origin == NETFS_READ_FOR_WRITE)) {
- netfs_consume_read_data(subreq, was_async);
+ netfs_consume_read_data(subreq);
__clear_bit(NETFS_SREQ_NO_PROGRESS, &subreq->flags);
}
}
@@ -453,7 +425,6 @@ EXPORT_SYMBOL(netfs_read_subreq_progress);
/**
* netfs_read_subreq_terminated - Note the termination of an I/O operation.
* @subreq: The I/O request that has terminated.
- * @was_async: True if we're in an asynchronous context.
*
* This tells the read helper that a contributory I/O operation has terminated,
* one way or another, and that it should integrate the results.
@@ -467,7 +438,7 @@ EXPORT_SYMBOL(netfs_read_subreq_progress);
* Before calling, the filesystem should update subreq->transferred to track
* the amount of data copied into the output buffer.
*/
-void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq, bool was_async)
+void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq)
{
struct netfs_io_request *rreq = subreq->rreq;
@@ -501,7 +472,7 @@ void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq, bool was_a
(rreq->origin == NETFS_READAHEAD ||
rreq->origin == NETFS_READPAGE ||
rreq->origin == NETFS_READ_FOR_WRITE)) {
- netfs_consume_read_data(subreq, was_async);
+ netfs_consume_read_data(subreq);
__clear_bit(NETFS_SREQ_NO_PROGRESS, &subreq->flags);
}
rreq->transferred += subreq->transferred;
@@ -543,9 +514,9 @@ void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq, bool was_a
}
if (atomic_dec_and_test(&rreq->nr_outstanding))
- netfs_rreq_terminated(rreq, was_async);
+ netfs_rreq_terminated(rreq);
- netfs_put_subrequest(subreq, was_async, netfs_sreq_trace_put_terminated);
+ netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_terminated);
}
EXPORT_SYMBOL(netfs_read_subreq_terminated);
@@ -561,6 +532,6 @@ void netfs_read_subreq_termination_worker(struct work_struct *work)
struct netfs_io_subrequest *subreq =
container_of(work, struct netfs_io_subrequest, work);
- netfs_read_subreq_terminated(subreq, false);
+ netfs_read_subreq_terminated(subreq);
}
EXPORT_SYMBOL(netfs_read_subreq_termination_worker);
diff --git a/fs/netfs/read_retry.c b/fs/netfs/read_retry.c
index 1c66c6e5c84b4..c195dded05527 100644
--- a/fs/netfs/read_retry.c
+++ b/fs/netfs/read_retry.c
@@ -233,7 +233,7 @@ void netfs_retry_reads(struct netfs_io_request *rreq)
netfs_retry_read_subrequests(rreq);
if (atomic_dec_and_test(&rreq->nr_outstanding))
- netfs_rreq_terminated(rreq, false);
+ netfs_rreq_terminated(rreq);
}
/*
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index be14d30608f6d..e278a1ad1ca3e 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -316,7 +316,7 @@ static void nfs_netfs_issue_read(struct netfs_io_subrequest *sreq)
netfs = nfs_netfs_alloc(sreq);
if (!netfs) {
sreq->error = -ENOMEM;
- return netfs_read_subreq_terminated(sreq, false);
+ return netfs_read_subreq_terminated(sreq);
}
pgio.pg_netfs = netfs; /* used in completion */
diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h
index 1d86f7cc71950..9d86868f49984 100644
--- a/fs/nfs/fscache.h
+++ b/fs/nfs/fscache.h
@@ -75,7 +75,7 @@ static inline void nfs_netfs_put(struct nfs_netfs_io_data *netfs)
netfs->sreq->transferred = min_t(s64, netfs->sreq->len,
atomic64_read(&netfs->transferred));
netfs->sreq->error = netfs->error;
- netfs_read_subreq_terminated(netfs->sreq, false);
+ netfs_read_subreq_terminated(netfs->sreq);
kfree(netfs);
}
static inline void nfs_netfs_inode_init(struct nfs_inode *nfsi)
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
index 0728858193bce..b6eea70554d71 100644
--- a/fs/smb/client/file.c
+++ b/fs/smb/client/file.c
@@ -231,7 +231,7 @@ static void cifs_issue_read(struct netfs_io_subrequest *subreq)
failed:
add_credits_and_wake_if(rdata->server, &rdata->credits, 0);
subreq->error = rc;
- netfs_read_subreq_terminated(subreq, false);
+ netfs_read_subreq_terminated(subreq);
}
/*
diff --git a/include/linux/netfs.h b/include/linux/netfs.h
index 73f782ce63695..ff208bbe6c5a6 100644
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -430,8 +430,8 @@ bool netfs_release_folio(struct folio *folio, gfp_t gfp);
vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_group);
/* (Sub)request management API. */
-void netfs_read_subreq_progress(struct netfs_io_subrequest *subreq, bool was_async);
-void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq, bool was_async);
+void netfs_read_subreq_progress(struct netfs_io_subrequest *subreq);
+void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq);
void netfs_read_subreq_termination_worker(struct work_struct *work);
void netfs_get_subrequest(struct netfs_io_subrequest *subreq,
enum netfs_sreq_ref_trace what);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 441/869] netfs: Fix netfs_create_write_req() to handle async cache object creation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (439 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 440/869] netfs: Drop the was_async arg from netfs_read_subreq_terminated() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 442/869] iomap: guard io_size EOF trim against concurrent truncate underflow Greg Kroah-Hartman
` (428 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Paulo Alcantara,
netfs, linux-fsdevel, Christian Brauner (Amutable), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit dbd6f56d975b23241b7bbb11bb8f562af548a0aa ]
netfs_create_write_req() will skip caching if the fscache cookie is
disabled, but this is a problem because async cache object creation might
not have got far enough yet that has been enabled - thereby causing the
call to fscache_begin_write_operation() to be skipped.
Fix this by removing the checks on the cookie and delegating this to
fscache_begin_write_operation().
Fixes: 7b589a9b45ae ("netfs: Fix handling of USE_PGPRIV2 and WRITE_TO_CACHE flags")
Closes: https://sashiko.dev/#/patchset/20260624115737.2964520-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260625140640.3116900-3-dhowells@redhat.com
cc: Paulo Alcantara <pc@manguebit.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/netfs/write_issue.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c
index 57d3a6b73836b..8143f84e60b4b 100644
--- a/fs/netfs/write_issue.c
+++ b/fs/netfs/write_issue.c
@@ -105,7 +105,7 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping,
_enter("R=%x", wreq->debug_id);
ictx = netfs_inode(wreq->inode);
- if (is_buffered && netfs_is_cache_enabled(ictx))
+ if (is_buffered)
fscache_begin_write_operation(&wreq->cache_resources, netfs_i_cookie(ictx));
if (rolling_buffer_init(&wreq->buffer, wreq->debug_id, ITER_SOURCE) < 0)
goto nomem;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 442/869] iomap: guard io_size EOF trim against concurrent truncate underflow
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (440 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 441/869] netfs: Fix netfs_create_write_req() to handle async cache object creation Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 443/869] afs: Fix reinitialisation of the inode, in particular ->lock_work Greg Kroah-Hartman
` (427 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christoph Hellwig, Morduan Zang,
Christian Brauner (Amutable), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Morduan Zang <zhangdandan@uniontech.com>
[ Upstream commit 55ec50d046c03b3724741957f7b007856e36dbe7 ]
iomap: fix zero padding data issue in concurrent append writes
changed ioend accounting so that io_size tracks only valid data
within EOF. This trims io_size when a writeback range extends
past end_pos:
ioend->io_size += map_len;
if (ioend->io_offset + ioend->io_size > end_pos)
ioend->io_size = end_pos - ioend->io_offset;
However, if end_pos ends up below ioend->io_offset, the subtraction
becomes negative and is stored in size_t io_size, causing an unsigned
wrap to a huge value. This can happen when writeback continues past
byte-level EOF up to a block-aligned range, or when a concurrent
truncate shrinks the file after end_pos was sampled in
iomap_writeback_handle_eof().
A wrapped io_size can mislead append detection and corrupt
completion-time size handling, since filesystem end_io paths consume
io_size for decisions such as on-disk EOF updates and unwritten/COW
completion ranges.
Fix this by clamping io_size to zero when EOF has moved to or before
the ioend start offset. This preserves the original intent of trimming
io_size to valid in-EOF data while avoiding the underflow.
Fixes: 51d20d1dacbe ("iomap: fix zero padding data issue in concurrent append writes")
Suggested-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Morduan Zang <zhangdandan@uniontech.com>
Link: https://patch.msgid.link/9E38E2659B47DC2A+20260624062622.337469-1-zhangdandan@uniontech.com
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/iomap/buffered-io.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index 4703fa7343e7b..02a5fc5105e7e 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -1858,8 +1858,12 @@ static int iomap_add_to_ioend(struct iomap_writepage_ctx *wpc,
* appending writes.
*/
wpc->ioend->io_size += len;
- if (wpc->ioend->io_offset + wpc->ioend->io_size > end_pos)
- wpc->ioend->io_size = end_pos - wpc->ioend->io_offset;
+ if (wpc->ioend->io_offset + wpc->ioend->io_size > end_pos) {
+ if (wpc->ioend->io_offset >= end_pos)
+ wpc->ioend->io_size = 0;
+ else
+ wpc->ioend->io_size = end_pos - wpc->ioend->io_offset;
+ }
wbc_account_cgroup_owner(wbc, folio, len);
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 443/869] afs: Fix reinitialisation of the inode, in particular ->lock_work
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (441 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 442/869] iomap: guard io_size EOF trim against concurrent truncate underflow Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 444/869] xen/pvcalls: bound backend response req_id before indexing rsp[] Greg Kroah-Hartman
` (426 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Marc Dionne,
Thomas Gleixner, linux-afs, Christian Brauner (Amutable),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit 5597fbd1e7c161914f20315a726e54025b0fdadb ]
It seems that initalising afs_vnode::lock_work a single time in the slab's
init function isn't sufficient for work_structs. This results in the
DEBUG_OBJECTS debugging stuff producing a warning occasionally when running
the generic/131 xfstest:
ODEBUG: activate not available (active state 0) object: 0000000016d8760f object type: work_struct hint: afs_lock_work+0x0/0x220
WARNING: lib/debugobjects.c:629 at debug_print_object+0x4b/0x90, CPU#3: locktest/7695
...
CPU: 3 UID: 0 PID: 7695 Comm: locktest Tainted: G S 7.1.0-build3+ #2771 PREEMPT
...
RIP: 0010:debug_print_object+0x65/0x90
...
Call Trace:
<TASK>
? __pfx_afs_lock_work+0x10/0x10
debug_object_activate+0x122/0x170
insert_work+0x25/0x60
__queue_work+0x2e0/0x340
queue_delayed_work_on+0x48/0x70
afs_fl_release_private+0x57/0x70
locks_release_private+0x5c/0xa0
locks_free_lock+0xe/0x20
posix_lock_inode+0x55f/0x5b0
locks_lock_inode_wait+0x81/0x140
? file_write_and_wait_range+0x50/0x70
afs_lock+0xcd/0x110
fcntl_setlk+0x10d/0x260
do_fcntl+0x24e/0x5b0
__do_sys_fcntl+0x6a/0x90
do_syscall_64+0x11e/0x310
entry_SYSCALL_64_after_hwframe+0x71/0x79
Fix this by reinitialising ->lock_work after allocating an inode.
Also, flush ->lock_work when the inode is being evicted to make sure it's
not still running.
Fixes: e8d6c554126b ("AFS: implement file locking")
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260622090856.2746629-13-dhowells@redhat.com
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Thomas Gleixner <tglx@kernel.org>
cc: linux-afs@lists.infradead.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/afs/inode.c | 1 +
fs/afs/super.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index c4f92aaa25275..9b9605971ec55 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -647,6 +647,7 @@ void afs_evict_inode(struct inode *inode)
ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode);
+ flush_delayed_work(&vnode->lock_work);
netfs_wait_for_outstanding_io(inode);
truncate_inode_pages_final(&inode->i_data);
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 89787b0e3c136..32bb1b7a498dc 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -660,7 +660,6 @@ static void afs_i_init_once(void *_vnode)
INIT_LIST_HEAD(&vnode->wb_keys);
INIT_LIST_HEAD(&vnode->pending_locks);
INIT_LIST_HEAD(&vnode->granted_locks);
- INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work);
INIT_LIST_HEAD(&vnode->cb_mmap_link);
seqlock_init(&vnode->cb_lock);
}
@@ -692,6 +691,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb)
init_rwsem(&vnode->rmdir_lock);
INIT_WORK(&vnode->cb_work, afs_invalidate_mmap_work);
+ INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work);
_leave(" = %p", &vnode->netfs.inode);
return &vnode->netfs.inode;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 444/869] xen/pvcalls: bound backend response req_id before indexing rsp[]
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (442 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 443/869] afs: Fix reinitialisation of the inode, in particular ->lock_work Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 445/869] sctp: fix addr_wq_timer race in sctp_free_addr_wq() Greg Kroah-Hartman
` (425 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Juergen Gross, Michael Bommarito,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <michael.bommarito@gmail.com>
[ Upstream commit d33846c8dcc06b83b7acdeac1e8bfbb5c0c26cb2 ]
pvcalls_front_event_handler() takes req_id directly from the
backend-supplied ring response and uses it to index the fixed-size
bedata->rsp[] array for a memcpy() and a store, with no range check. A
malicious or buggy backend can set req_id past PVCALLS_NR_RSP_PER_RING
and drive an out-of-bounds write past the bedata allocation.
req_id was also declared int while the wire field rsp->req_id is u32, so
a range check on the signed value alone is insufficient: a backend
req_id of 0xffffffff becomes -1, passes a >= PVCALLS_NR_RSP_PER_RING
test and indexes bedata->rsp[-1]. Declare req_id as u32 so a single
bound covers both ends.
A backend that sends an out-of-range req_id has violated the wire
protocol, so rather than silently dropping the response, log once and
stop trusting the backend: set bedata->disabled. The event handler then
ignores further responses, and the request paths that wait for a
response return -EIO instead of blocking forever. This mirrors the
fatal-error handling xen-netback uses (xenvif_fatal_tx_err()).
The pvcalls frontend currently trusts its backend, so this is not a
classic-Xen security issue, but it matters for hardening PV frontends
against malicious backends (confidential and disaggregated deployments).
Fixes: 2195046bfd69 ("xen/pvcalls: implement socket command and handle events")
Suggested-by: Juergen Gross <jgross@suse.com>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
Message-ID: <20260617014149.2647404-1-michael.bommarito@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/xen/pvcalls-front.c | 88 ++++++++++++++++++++++++++++++++-----
1 file changed, 76 insertions(+), 12 deletions(-)
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index b72ee9379d77c..d2bdd43703e88 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -32,6 +32,7 @@ struct pvcalls_bedata {
struct xen_pvcalls_front_ring ring;
grant_ref_t ref;
int irq;
+ bool disabled;
struct list_head socket_mappings;
spinlock_t socket_lock;
@@ -131,6 +132,20 @@ static inline int get_request(struct pvcalls_bedata *bedata, int *req_id)
return 0;
}
+/*
+ * Wait for the backend's response to req_id, or for the frontend to be
+ * disabled because the backend violated the wire protocol. Returns 0 once
+ * the response has arrived, or -EIO if the frontend was disabled.
+ */
+static int pvcalls_front_wait_rsp(struct pvcalls_bedata *bedata, u32 req_id)
+{
+ wait_event(bedata->inflight_req,
+ READ_ONCE(bedata->rsp[req_id].req_id) == req_id ||
+ READ_ONCE(bedata->disabled));
+
+ return READ_ONCE(bedata->disabled) ? -EIO : 0;
+}
+
static bool pvcalls_front_write_todo(struct sock_mapping *map)
{
struct pvcalls_data_intf *intf = map->active.ring;
@@ -168,7 +183,8 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
struct pvcalls_bedata *bedata;
struct xen_pvcalls_response *rsp;
uint8_t *src, *dst;
- int req_id = 0, more = 0, done = 0;
+ u32 req_id = 0;
+ int more = 0, done = 0;
if (dev == NULL)
return IRQ_HANDLED;
@@ -179,12 +195,31 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
pvcalls_exit();
return IRQ_HANDLED;
}
+ if (READ_ONCE(bedata->disabled)) {
+ pvcalls_exit();
+ return IRQ_HANDLED;
+ }
again:
while (RING_HAS_UNCONSUMED_RESPONSES(&bedata->ring)) {
rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons);
req_id = rsp->req_id;
+ if (req_id >= PVCALLS_NR_RSP_PER_RING) {
+ /*
+ * The backend supplied a req_id that would index
+ * bedata->rsp[] out of bounds: a protocol violation
+ * from a malicious or buggy backend. Log once, stop
+ * trusting this backend and disable the frontend rather
+ * than silently dropping the response and continuing.
+ */
+ pr_err_once("pvcalls: backend sent out-of-range req_id %u, disabling frontend\n",
+ req_id);
+ WRITE_ONCE(bedata->disabled, true);
+ bedata->ring.rsp_cons++;
+ done = 1;
+ break;
+ }
if (rsp->cmd == PVCALLS_POLL) {
struct sock_mapping *map = (struct sock_mapping *)(uintptr_t)
rsp->u.poll.id;
@@ -217,7 +252,7 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
}
RING_FINAL_CHECK_FOR_RESPONSES(&bedata->ring, more);
- if (more)
+ if (more && !READ_ONCE(bedata->disabled))
goto again;
if (done)
wake_up(&bedata->inflight_req);
@@ -330,8 +365,11 @@ int pvcalls_front_socket(struct socket *sock)
if (notify)
notify_remote_via_irq(bedata->irq);
- wait_event(bedata->inflight_req,
- READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
+ ret = pvcalls_front_wait_rsp(bedata, req_id);
+ if (ret) {
+ pvcalls_exit();
+ return ret;
+ }
/* read req_id, then the content */
smp_rmb();
@@ -476,8 +514,11 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
if (notify)
notify_remote_via_irq(bedata->irq);
- wait_event(bedata->inflight_req,
- READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
+ ret = pvcalls_front_wait_rsp(bedata, req_id);
+ if (ret) {
+ pvcalls_exit_sock(sock);
+ return ret;
+ }
/* read req_id, then the content */
smp_rmb();
@@ -707,8 +748,11 @@ int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
if (notify)
notify_remote_via_irq(bedata->irq);
- wait_event(bedata->inflight_req,
- READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
+ ret = pvcalls_front_wait_rsp(bedata, req_id);
+ if (ret) {
+ pvcalls_exit_sock(sock);
+ return ret;
+ }
/* read req_id, then the content */
smp_rmb();
@@ -756,8 +800,11 @@ int pvcalls_front_listen(struct socket *sock, int backlog)
if (notify)
notify_remote_via_irq(bedata->irq);
- wait_event(bedata->inflight_req,
- READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
+ ret = pvcalls_front_wait_rsp(bedata, req_id);
+ if (ret) {
+ pvcalls_exit_sock(sock);
+ return ret;
+ }
/* read req_id, then the content */
smp_rmb();
@@ -813,6 +860,14 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
}
}
+ if (READ_ONCE(bedata->disabled)) {
+ clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
+ (void *)&map->passive.flags);
+ wake_up(&map->passive.inflight_accept_req);
+ pvcalls_exit_sock(sock);
+ return -EIO;
+ }
+
map2 = kzalloc(sizeof(*map2), GFP_KERNEL);
if (map2 == NULL) {
clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
@@ -873,10 +928,18 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
}
if (wait_event_interruptible(bedata->inflight_req,
- READ_ONCE(bedata->rsp[req_id].req_id) == req_id)) {
+ READ_ONCE(bedata->rsp[req_id].req_id) == req_id ||
+ READ_ONCE(bedata->disabled))) {
pvcalls_exit_sock(sock);
return -EINTR;
}
+ if (READ_ONCE(bedata->disabled)) {
+ clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
+ (void *)&map->passive.flags);
+ wake_up(&map->passive.inflight_accept_req);
+ pvcalls_exit_sock(sock);
+ return -EIO;
+ }
/* read req_id, then the content */
smp_rmb();
@@ -1045,7 +1108,8 @@ int pvcalls_front_release(struct socket *sock)
notify_remote_via_irq(bedata->irq);
wait_event(bedata->inflight_req,
- READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
+ READ_ONCE(bedata->rsp[req_id].req_id) == req_id ||
+ READ_ONCE(bedata->disabled));
if (map->active_socket) {
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 445/869] sctp: fix addr_wq_timer race in sctp_free_addr_wq()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (443 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 444/869] xen/pvcalls: bound backend response req_id before indexing rsp[] Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 446/869] drm/panthor: Always use the IRQ-safe variant when acquiring the fence lock Greg Kroah-Hartman
` (424 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Xin Long, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <lucien.xin@gmail.com>
[ Upstream commit 976c19de0f22a857ba0112f39635f8fd7a257568 ]
sctp_free_addr_wq() previously removed addr_wq_timer using timer_delete()
while holding addr_wq_lock. However, timer_delete() does not guarantee that
a currently running timer handler has completed.
This allows a race with sctp_addr_wq_timeout_handler(), where the handler
may still run after addr_waitq has been freed, acquire addr_wq_lock, and
access freed memory, leading to a use-after-free.
Fix this by calling timer_shutdown_sync() before taking addr_wq_lock. This
guarantees that any in-flight timer handler has finished and prevents the
timer from being re-armed during teardown, making subsequent cleanup safe.
Fixes: 4db67e808640 ("sctp: Make the address lists per network namespace")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/5dc95f295bdb5c3f60e880dd9aa5112dc5c071cc.1782757874.git.lucien.xin@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sctp/protocol.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index c6d74fa517cd8..66ede52383f86 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -693,8 +693,9 @@ static void sctp_free_addr_wq(struct net *net)
struct sctp_sockaddr_entry *addrw;
struct sctp_sockaddr_entry *temp;
+ timer_shutdown_sync(&net->sctp.addr_wq_timer);
+
spin_lock_bh(&net->sctp.addr_wq_lock);
- del_timer(&net->sctp.addr_wq_timer);
list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
list_del(&addrw->list);
kfree(addrw);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 446/869] drm/panthor: Always use the IRQ-safe variant when acquiring the fence lock
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (444 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 445/869] sctp: fix addr_wq_timer race in sctp_free_addr_wq() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 447/869] hwmon: (pmbus/core) honor vrm_version in pmbus_data2reg_vid() Greg Kroah-Hartman
` (423 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, sashiko-bot, Boris Brezillon,
Liviu Dudau, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boris Brezillon <boris.brezillon@collabora.com>
[ Upstream commit 778c57d624974e64535ef1c9d9b4d8e5066153f4 ]
Since dma_fence objects can be shared with other subsystems, they may be
accessed from hardirq context in those drivers, and we have to take
that into account by also using the IRQ-safe variant when acquiring
the lock.
While at it, switch to the guard model.
Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block")
Reported-by: sashiko-bot@kernel.org
Closes: https://sashiko.dev/#/patchset/20260625-panthor-signal-from-irq-v5-0-8836a74e0ef9@collabora.com?part=11
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
Link: https://patch.msgid.link/20260625-panthor-misc-fixes-v1-1-b67ed973fea6@collabora.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/panthor/panthor_sched.c | 34 ++++++++++++-------------
1 file changed, 16 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index c1fc52f1ee426..95649ea56ba88 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -1389,7 +1389,7 @@ cs_slot_process_fault_event_locked(struct panthor_device *ptdev,
u64 cs_extract = queue->iface.output->extract;
struct panthor_job *job;
- spin_lock(&queue->fence_ctx.lock);
+ guard(spinlock_irqsave)(&queue->fence_ctx.lock);
list_for_each_entry(job, &queue->fence_ctx.in_flight_jobs, node) {
if (cs_extract >= job->ringbuf.end)
continue;
@@ -1399,7 +1399,6 @@ cs_slot_process_fault_event_locked(struct panthor_device *ptdev,
dma_fence_set_error(job->done_fence, -EINVAL);
}
- spin_unlock(&queue->fence_ctx.lock);
}
drm_warn(&ptdev->base,
@@ -2057,13 +2056,13 @@ group_term_post_processing(struct panthor_group *group)
if (!queue)
continue;
- spin_lock(&queue->fence_ctx.lock);
- list_for_each_entry_safe(job, tmp, &queue->fence_ctx.in_flight_jobs, node) {
- list_move_tail(&job->node, &faulty_jobs);
- dma_fence_set_error(job->done_fence, err);
- dma_fence_signal_locked(job->done_fence);
+ scoped_guard(spinlock_irqsave, &queue->fence_ctx.lock) {
+ list_for_each_entry_safe(job, tmp, &queue->fence_ctx.in_flight_jobs, node) {
+ list_move_tail(&job->node, &faulty_jobs);
+ dma_fence_set_error(job->done_fence, err);
+ dma_fence_signal_locked(job->done_fence);
+ }
}
- spin_unlock(&queue->fence_ctx.lock);
/* Manually update the syncobj seqno to unblock waiters. */
syncobj = group->syncobjs->kmap + (i * sizeof(*syncobj));
@@ -2902,15 +2901,15 @@ static void group_sync_upd_work(struct work_struct *work)
syncobj = group->syncobjs->kmap + (queue_idx * sizeof(*syncobj));
- spin_lock(&queue->fence_ctx.lock);
- list_for_each_entry_safe(job, job_tmp, &queue->fence_ctx.in_flight_jobs, node) {
- if (syncobj->seqno < job->done_fence->seqno)
- break;
+ scoped_guard(spinlock_irqsave, &queue->fence_ctx.lock) {
+ list_for_each_entry_safe(job, job_tmp, &queue->fence_ctx.in_flight_jobs, node) {
+ if (syncobj->seqno < job->done_fence->seqno)
+ break;
- list_move_tail(&job->node, &done_jobs);
- dma_fence_signal_locked(job->done_fence);
+ list_move_tail(&job->node, &done_jobs);
+ dma_fence_signal_locked(job->done_fence);
+ }
}
- spin_unlock(&queue->fence_ctx.lock);
}
dma_fence_end_signalling(cookie);
@@ -3153,9 +3152,8 @@ queue_run_job(struct drm_sched_job *sched_job)
job->ringbuf.end = job->ringbuf.start + (instrs.count * sizeof(u64));
panthor_job_get(&job->base);
- spin_lock(&queue->fence_ctx.lock);
- list_add_tail(&job->node, &queue->fence_ctx.in_flight_jobs);
- spin_unlock(&queue->fence_ctx.lock);
+ scoped_guard(spinlock_irqsave, &queue->fence_ctx.lock)
+ list_add_tail(&job->node, &queue->fence_ctx.in_flight_jobs);
/* Make sure the ring buffer is updated before the INSERT
* register.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 447/869] hwmon: (pmbus/core) honor vrm_version in pmbus_data2reg_vid()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (445 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 446/869] drm/panthor: Always use the IRQ-safe variant when acquiring the fence lock Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 448/869] sctp: add INIT verification after cookie unpacking Greg Kroah-Hartman
` (422 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Abdurrahman Hussain, Guenter Roeck,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdurrahman Hussain <abdurrahman@nexthop.ai>
[ Upstream commit 828cd614e2af053ca5e1d6da767bbd8a1b5cabfb ]
pmbus_data2reg_vid() hardcoded the VR11 encoding regardless of the
vrm_version configured by the driver, while pmbus_reg2data_vid()
already switched on it. Any driver that selects a non-VR11 VID mode
and exposes a regulator (or hwmon vout setter) sent dangerously
wrong codes to PMBUS_VOUT_COMMAND -- e.g. an nvidia195mv part asked
for 200 mV got the VR11 clamp to 500 mV encoded as 0xB2, which the
chip interprets as 1080 mV.
Mirror pmbus_reg2data_vid() so writes round-trip with reads.
Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
Assisted-by: Claude:claude-opus-4-7 [Claude Code]
Link: https://lore.kernel.org/r/20260620-pmbus-data2reg-vid-v1-1-5518030432c4@nexthop.ai
Fixes: 068c227056b92 ("hwmon: (pmbus) Add support for VR12")
Fixes: d4977c083aeb2 ("hwmon: (pmbus) Add support for Intel VID protocol VR13")
Fixes: 9d72340b6ade9 ("hwmon: (pmbus/core) Add support for Intel IMVP9 and AMD 6.25mV modes")
Fixes: 969a4ec86ca5f ("hwmon: (pmbus/core) Add support for NVIDIA nvidia195mv mode")
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hwmon/pmbus/pmbus_core.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 024d197817375..5061717389dbd 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -1086,9 +1086,24 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
static u16 pmbus_data2reg_vid(struct pmbus_data *data,
struct pmbus_sensor *sensor, s64 val)
{
- val = clamp_val(val, 500, 1600);
-
- return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625);
+ switch (data->info->vrm_version[sensor->page]) {
+ case vr12:
+ val = clamp_val(val, 250, 1520);
+ return 1 + DIV_ROUND_CLOSEST_ULL(val - 250, 5);
+ case vr13:
+ val = clamp_val(val, 500, 3040);
+ return 1 + DIV_ROUND_CLOSEST_ULL(val - 500, 10);
+ case imvp9:
+ val = clamp_val(val, 200, 2740);
+ return 1 + DIV_ROUND_CLOSEST_ULL(val - 200, 10);
+ case amd625mv:
+ val = clamp_val(val, 200, 1550);
+ return DIV_ROUND_CLOSEST_ULL((1550LL - val) * 100LL, 625);
+ case vr11:
+ default:
+ val = clamp_val(val, 500, 1600);
+ return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625);
+ }
}
static u16 pmbus_data2reg(struct pmbus_data *data,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 448/869] sctp: add INIT verification after cookie unpacking
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (446 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 447/869] hwmon: (pmbus/core) honor vrm_version in pmbus_data2reg_vid() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 449/869] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy() Greg Kroah-Hartman
` (421 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Xin Long, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <lucien.xin@gmail.com>
[ Upstream commit 414c5447fe6a200613dd46d7fdc8454622076cb1 ]
In SCTP handshake, the INIT chunk is initially processed by the server
and embedded into the cookie carried in INIT-ACK. The client then
returns this cookie via COOKIE-ECHO, where the server unpacks it and
reconstructs the original INIT chunk.
When cookie authentication is enabled, the cookie contents are protected
against tampering, so reusing the unpacked INIT without re-verification
is safe.
However, when cookie authentication is disabled, the reconstructed INIT
can no longer be trusted. In this case, the INIT must be explicitly
validated after unpacking to avoid processing potentially tampered data.
Add sctp_verify_init() checks after cookie unpacking in COOKIE-ECHO
processing paths (sctp_sf_do_5_1D_ce() and sctp_sf_do_5_2_4_dupcook())
when cookie_auth_enable is disabled. On failure, the new association is
freed and the packet is discarded.
Also tighten cookie validation in sctp_unpack_cookie() by verifying the
embedded chunk type is SCTP_CID_INIT before treating it as an INIT
chunk.
Finally, update sctp_verify_init() to validate parameter bounds using
the actual embedded INIT length instead of chunk->chunk_end, since the
INIT stored in COOKIE-ECHO may not span the entire chunk buffer.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/ebcbbac574815b0850f371b4bdb02f2e602b94d3.1782341592.git.lucien.xin@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sctp/sm_make_chunk.c | 5 ++++-
net/sctp/sm_statefuns.c | 36 +++++++++++++++++++++++++++++++++---
2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index bec5bd6cf1d1f..34692cadea982 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1781,6 +1781,8 @@ struct sctp_association *sctp_unpack_cookie(
bear_cookie = &cookie->c;
ch = (struct sctp_chunkhdr *)(bear_cookie + 1);
+ if (ch->type != SCTP_CID_INIT)
+ goto malformed;
chlen = ntohs(ch->length);
if (chlen < sizeof(struct sctp_init_chunk))
goto malformed;
@@ -2338,7 +2340,8 @@ int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep,
* VIOLATION error. We build the ERROR chunk here and let the normal
* error handling code build and send the packet.
*/
- if (param.v != (void *)chunk->chunk_end)
+ if (param.v != (void *)peer_init +
+ SCTP_PAD4(ntohs(peer_init->chunk_hdr.length)))
return sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
/* The only missing mandatory param possible today is
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index ee4269b75e36a..b16bb0ebb552e 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -708,11 +708,12 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
struct sctp_cmd_seq *commands)
{
struct sctp_ulpevent *ev, *ai_ev = NULL, *auth_ev = NULL;
+ struct sctp_chunk *err_chk_p = NULL;
struct sctp_association *new_asoc;
struct sctp_init_chunk *peer_init;
struct sctp_chunk *chunk = arg;
- struct sctp_chunk *err_chk_p;
struct sctp_chunk *repl;
+ enum sctp_cid cid;
struct sock *sk;
int error = 0;
@@ -786,6 +787,19 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
}
}
+ peer_init = (struct sctp_init_chunk *)(chunk->subh.cookie_hdr + 1);
+ cid = peer_init->chunk_hdr.type;
+ if (!sctp_sk(sk)->hmac &&
+ !sctp_verify_init(net, ep, asoc, cid, peer_init, chunk,
+ &err_chk_p)) {
+ sctp_association_free(new_asoc);
+ if (err_chk_p)
+ sctp_chunk_free(err_chk_p);
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+ }
+ if (err_chk_p)
+ sctp_chunk_free(err_chk_p);
+
if (security_sctp_assoc_request(new_asoc, chunk->head_skb ?: chunk->skb)) {
sctp_association_free(new_asoc);
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
@@ -799,7 +813,6 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
/* This is a brand-new association, so these are not yet side
* effects--it is safe to run them here.
*/
- peer_init = (struct sctp_init_chunk *)(chunk->subh.cookie_hdr + 1);
if (!sctp_process_init(new_asoc, chunk,
&chunk->subh.cookie_hdr->c.peer_addr,
peer_init, GFP_ATOMIC))
@@ -2216,10 +2229,12 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook(
void *arg,
struct sctp_cmd_seq *commands)
{
+ struct sctp_chunk *err_chk_p = NULL;
struct sctp_association *new_asoc;
+ struct sctp_init_chunk *peer_init;
struct sctp_chunk *chunk = arg;
enum sctp_disposition retval;
- struct sctp_chunk *err_chk_p;
+ enum sctp_cid cid;
int error = 0;
char action;
@@ -2288,6 +2303,21 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook(
switch (action) {
case 'A': /* Association restart. */
case 'B': /* Collision case B. */
+ peer_init = (struct sctp_init_chunk *)
+ (chunk->subh.cookie_hdr + 1);
+ cid = peer_init->chunk_hdr.type;
+ if (!sctp_sk(ep->base.sk)->hmac &&
+ !sctp_verify_init(net, ep, asoc, cid, peer_init, chunk,
+ &err_chk_p)) {
+ sctp_association_free(new_asoc);
+ if (err_chk_p)
+ sctp_chunk_free(err_chk_p);
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg,
+ commands);
+ }
+ if (err_chk_p)
+ sctp_chunk_free(err_chk_p);
+ fallthrough;
case 'D': /* Collision case D. */
/* Update socket peer label if first association. */
if (security_sctp_assoc_request((struct sctp_association *)asoc,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 449/869] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (447 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 448/869] sctp: add INIT verification after cookie unpacking Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 450/869] bpf: Guard conntrack opts error writes Greg Kroah-Hartman
` (420 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+e14bc5d4942756023b77,
Eric Dumazet, Jon Maloy, tipc-discussion, Xin Long,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 7116764ca53ff529335d7ab7c364a69f094b23a5 ]
TIPC UDP media bearer teardown calls dst_cache_destroy() on its
replicast caches before calling synchronize_net() to wait for
concurrent RCU readers (transmitters) to finish:
static void cleanup_bearer(struct work_struct *work)
{
...
list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
dst_cache_destroy(&rcast->dst_cache);
list_del_rcu(&rcast->list);
kfree_rcu(rcast, rcu);
}
...
dst_cache_destroy(&ub->rcast.dst_cache);
udp_tunnel_sock_release(ub->sk);
synchronize_net();
...
}
This is highly buggy because dst_cache_destroy() immediately frees the
per-CPU cache memory (free_percpu()) and releases the cached dst
entries without any synchronization.
If a concurrent transmitter (e.g., tipc_udp_xmit()) is running on another
CPU under RCU protection, it can call dst_cache_get() concurrently,
leading to:
1. Use-After-Free on the per-CPU cache pointer itself (crash).
2. "rcuref - imbalanced put()" warning if it attempts to release a
dst that was concurrently released by dst_cache_destroy().
Furthermore, calling kfree(ub) immediately after synchronize_net() without
closing the socket first (or waiting after closing it) leaves a window
where a concurrent receiver (tipc_udp_recv()) could start after
synchronize_net(), access ub, and suffer a UAF when kfree(ub) runs.
To fix this, we must defer dst_cache_destroy() and kfree(ub) until after
we have ensured that no more readers can see the bearer/socket and all
existing readers have finished:
1. Defer rcast entry destruction (both dst_cache_destroy() and kfree())
to an RCU callback using call_rcu_hurry().
Using call_rcu_hurry() ensures the dst entries are released quickly.
2. Release the bearer socket using udp_tunnel_sock_release() (stops
new receive readers).
3. Call synchronize_net() to wait for all outstanding RCU readers
(both transmit and receive) to finish.
4. Now that it is safe, call dst_cache_destroy() on the main bearer
cache, and free ub.
Note: 3) and 4) can be changed later in net-next to also use
call_rcu_hurry() and get rid of the synchronize_net() latency.
Fixes: e9c1a793210f ("tipc: add dst_cache support for udp media")
Reported-by: syzbot+e14bc5d4942756023b77@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/6a396a66.52ae72c2.136ac7.0003.GAE@google.com/T/#u
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Jon Maloy <jmaloy@redhat.com>
Cc: tipc-discussion@lists.sourceforge.net
Reviewed-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/20260623173030.2925059-2-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/tipc/udp_media.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
index 2a37b274bcb95..311ebc6163855 100644
--- a/net/tipc/udp_media.c
+++ b/net/tipc/udp_media.c
@@ -797,6 +797,14 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
return err;
}
+static void rcast_free_rcu(struct rcu_head *rcu)
+{
+ struct udp_replicast *rcast = container_of(rcu, struct udp_replicast, rcu);
+
+ dst_cache_destroy(&rcast->dst_cache);
+ kfree(rcast);
+}
+
/* cleanup_bearer - break the socket/bearer association */
static void cleanup_bearer(struct work_struct *work)
{
@@ -806,20 +814,19 @@ static void cleanup_bearer(struct work_struct *work)
spin_lock_bh(&ub->rcast_lock);
list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
- dst_cache_destroy(&rcast->dst_cache);
list_del_rcu(&rcast->list);
- kfree_rcu(rcast, rcu);
+ call_rcu_hurry(&rcast->rcu, rcast_free_rcu);
}
ub->disabled = true;
spin_unlock_bh(&ub->rcast_lock);
tn = tipc_net(sock_net(ub->ubsock->sk));
- dst_cache_destroy(&ub->rcast.dst_cache);
udp_tunnel_sock_release(ub->ubsock);
- /* Note: could use a call_rcu() to avoid another synchronize_net() */
synchronize_net();
+
+ dst_cache_destroy(&ub->rcast.dst_cache);
atomic_dec(&tn->wq_count);
kfree(ub);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 450/869] bpf: Guard conntrack opts error writes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (448 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 449/869] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 451/869] md/raid10: fix writes_pending leak on write request failures Greg Kroah-Hartman
` (419 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yiyang Chen, Alexei Starovoitov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
[ Upstream commit 6f6183a39533d727deaa5061cadae6dd9e6744d0 ]
The conntrack lookup and allocation kfuncs take an opts pointer
together with an opts__sz argument. The verifier checks only the memory
range described by opts__sz, but the wrappers unconditionally write
opts->error whenever the internal lookup or allocation helper returns an
error.
For an invalid size smaller than the end of opts->error, that write can
land outside the verifier-checked range. Keep returning NULL for invalid
arguments, but only report the error through opts->error when the
supplied size includes the field.
This preserves error reporting for the supported 12-byte and 16-byte
layouts, and for other invalid sizes that still include opts->error.
Fixes: b4c2b9593a1c ("net/netfilter: Add unstable CT lookup helpers for XDP and TC-BPF")
Fixes: d7e79c97c00c ("net: netfilter: Add kfuncs to allocate and insert CT")
Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
Link: https://lore.kernel.org/r/9535e781fe14449b1d4e9bbc3baa7566a93bf512.1781765747.git.chenyy23@mails.tsinghua.edu.cn
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/netfilter/nf_conntrack_bpf.c | 39 +++++++++++---------------------
1 file changed, 13 insertions(+), 26 deletions(-)
diff --git a/net/netfilter/nf_conntrack_bpf.c b/net/netfilter/nf_conntrack_bpf.c
index 4a136fc3a9c0f..c91a935a01706 100644
--- a/net/netfilter/nf_conntrack_bpf.c
+++ b/net/netfilter/nf_conntrack_bpf.c
@@ -64,6 +64,15 @@ enum {
NF_BPF_CT_OPTS_SZ = 16,
};
+static void *bpf_ct_opts_result(struct bpf_ct_opts *opts, u32 opts__sz, void *ret)
+{
+ if (!IS_ERR(ret))
+ return ret;
+ if (opts && opts__sz >= offsetofend(struct bpf_ct_opts, error))
+ opts->error = PTR_ERR(ret);
+ return NULL;
+}
+
static int bpf_nf_ct_tuple_parse(struct bpf_sock_tuple *bpf_tuple,
u32 tuple_len, u8 protonum, u8 dir,
struct nf_conntrack_tuple *tuple)
@@ -298,13 +307,7 @@ bpf_xdp_ct_alloc(struct xdp_md *xdp_ctx, struct bpf_sock_tuple *bpf_tuple,
nfct = __bpf_nf_ct_alloc_entry(dev_net(ctx->rxq->dev), bpf_tuple, tuple__sz,
opts, opts__sz, 10);
- if (IS_ERR(nfct)) {
- if (opts)
- opts->error = PTR_ERR(nfct);
- return NULL;
- }
-
- return (struct nf_conn___init *)nfct;
+ return (struct nf_conn___init *)bpf_ct_opts_result(opts, opts__sz, nfct);
}
/* bpf_xdp_ct_lookup - Lookup CT entry for the given tuple, and acquire a
@@ -333,12 +336,7 @@ bpf_xdp_ct_lookup(struct xdp_md *xdp_ctx, struct bpf_sock_tuple *bpf_tuple,
caller_net = dev_net(ctx->rxq->dev);
nfct = __bpf_nf_ct_lookup(caller_net, bpf_tuple, tuple__sz, opts, opts__sz);
- if (IS_ERR(nfct)) {
- if (opts)
- opts->error = PTR_ERR(nfct);
- return NULL;
- }
- return nfct;
+ return bpf_ct_opts_result(opts, opts__sz, nfct);
}
/* bpf_skb_ct_alloc - Allocate a new CT entry
@@ -366,13 +364,7 @@ bpf_skb_ct_alloc(struct __sk_buff *skb_ctx, struct bpf_sock_tuple *bpf_tuple,
net = skb->dev ? dev_net(skb->dev) : sock_net(skb->sk);
nfct = __bpf_nf_ct_alloc_entry(net, bpf_tuple, tuple__sz, opts, opts__sz, 10);
- if (IS_ERR(nfct)) {
- if (opts)
- opts->error = PTR_ERR(nfct);
- return NULL;
- }
-
- return (struct nf_conn___init *)nfct;
+ return (struct nf_conn___init *)bpf_ct_opts_result(opts, opts__sz, nfct);
}
/* bpf_skb_ct_lookup - Lookup CT entry for the given tuple, and acquire a
@@ -401,12 +393,7 @@ bpf_skb_ct_lookup(struct __sk_buff *skb_ctx, struct bpf_sock_tuple *bpf_tuple,
caller_net = skb->dev ? dev_net(skb->dev) : sock_net(skb->sk);
nfct = __bpf_nf_ct_lookup(caller_net, bpf_tuple, tuple__sz, opts, opts__sz);
- if (IS_ERR(nfct)) {
- if (opts)
- opts->error = PTR_ERR(nfct);
- return NULL;
- }
- return nfct;
+ return bpf_ct_opts_result(opts, opts__sz, nfct);
}
/* bpf_ct_insert_entry - Add the provided entry into a CT map
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 451/869] md/raid10: fix writes_pending leak on write request failures
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (449 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 450/869] bpf: Guard conntrack opts error writes Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 452/869] md/raid1: fix writes_pending and barrier reference leaks on write failures Greg Kroah-Hartman
` (418 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Abd-Alrhman Masalkhi, Yu Kuai,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
[ Upstream commit e045d6ed33f8faa3e3dd6dc33c62ec01e3ad275d ]
raid10_make_request() acquires a writes_pending reference with
md_write_start() before dispatching write requests. Several failure
paths in raid10_write_request() complete the bio and return without
reaching the normal write completion path, causing the corresponding
md_write_end() to be skipped.
Make raid10_write_request() return a status indicating whether the write
request was successfully queued. This allows raid10_make_request() to
release the writes_pending reference with md_write_end() when a write
request fails.
Fixes: 4cf58d952909 ("md/raid10: Handle bio_split() errors")
Fixes: c9aa889b035f ("md: raid10 add nowait support")
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
Link: https://patch.msgid.link/20260613182810.1317258-3-abd.masalkhi@gmail.com
Signed-off-by: Yu Kuai <yukuai@fygo.io>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/raid10.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 468c1dfa9d6fe..fc68e6b05ddfe 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1349,7 +1349,7 @@ static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio)
}
}
-static void raid10_write_request(struct mddev *mddev, struct bio *bio,
+static bool raid10_write_request(struct mddev *mddev, struct bio *bio,
struct r10bio *r10_bio)
{
struct r10conf *conf = mddev->private;
@@ -1366,7 +1366,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
/* Bail out if REQ_NOWAIT is set for the bio */
if (bio->bi_opf & REQ_NOWAIT) {
bio_wouldblock_error(bio);
- return;
+ return false;
}
for (;;) {
prepare_to_wait(&conf->wait_barrier,
@@ -1382,7 +1382,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
sectors = r10_bio->sectors;
if (!regular_request_wait(mddev, conf, bio, sectors)) {
free_r10bio(r10_bio);
- return;
+ return false;
}
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
@@ -1399,7 +1399,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
if (bio->bi_opf & REQ_NOWAIT) {
allow_barrier(conf);
bio_wouldblock_error(bio);
- return;
+ return false;
}
mddev_add_trace_msg(conf->mddev,
"raid10 wait reshape metadata");
@@ -1507,7 +1507,8 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
raid10_write_one_disk(mddev, r10_bio, bio, true, i);
}
one_write_done(r10_bio);
- return;
+ return true;
+
err_handle:
for (k = 0; k < i; k++) {
int d = r10_bio->devs[k].devnum;
@@ -1527,10 +1528,12 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
bio->bi_status = errno_to_blk_status(error);
set_bit(R10BIO_Uptodate, &r10_bio->state);
raid_end_bio_io(r10_bio);
+ return false;
}
-static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
+static bool __make_request(struct mddev *mddev, struct bio *bio, int sectors)
{
+ bool ret;
struct r10conf *conf = mddev->private;
struct r10bio *r10_bio;
@@ -1546,10 +1549,13 @@ static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
memset(r10_bio->devs, 0, sizeof(r10_bio->devs[0]) *
conf->geo.raid_disks);
+ ret = true;
if (bio_data_dir(bio) == READ)
raid10_read_request(mddev, bio, r10_bio, true);
else
- raid10_write_request(mddev, bio, r10_bio);
+ ret = raid10_write_request(mddev, bio, r10_bio);
+
+ return ret;
}
static void raid_end_discard_bio(struct r10bio *r10bio)
@@ -1900,7 +1906,8 @@ static bool raid10_make_request(struct mddev *mddev, struct bio *bio)
sectors = chunk_sects -
(bio->bi_iter.bi_sector &
(chunk_sects - 1));
- __make_request(mddev, bio, sectors);
+ if (!__make_request(mddev, bio, sectors))
+ md_write_end(mddev);
/* In case raid10d snuck in to freeze_array */
wake_up_barrier(conf);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 452/869] md/raid1: fix writes_pending and barrier reference leaks on write failures
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (450 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 451/869] md/raid10: fix writes_pending leak on write request failures Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 453/869] soundwire: fix bug in sdw_add_element_group_count found by syzkaller Greg Kroah-Hartman
` (417 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, sashiko-bot, Abd-Alrhman Masalkhi,
Yu Kuai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
[ Upstream commit 8e065a1602511282fc0da2dc89445e0eb71a681c ]
raid1_make_request() acquires a writes_pending reference with
md_write_start() before calling raid1_write_request(). Several failure
paths in raid1_write_request() complete the bio and return without
reaching the normal write completion path, causing the corresponding
md_write_end() to be skipped.
Make raid1_write_request() return a status indicating whether the write
request was successfully queued. This allows raid1_make_request() to
call md_write_end() when raid1_write_request() fails.
Additionally, if wait_blocked_rdev() fails after wait_barrier()
succeeds, the associated barrier reference is not released.
Call allow_barrier() before returning from that path to keep the barrier
accounting balanced.
Fixes: b1a7ad8b5c4f ("md/raid1: Handle bio_split() errors")
Fixes: f2a38abf5f1c ("md/raid1: Atomic write support")
Fixes: 5aa705039c4f ("md: raid1 add nowait support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260611083514.754922-1-abd.masalkhi@gmail.com?part=1
Closes: https://sashiko.dev/#/patchset/20260611132500.763528-1-abd.masalkhi@gmail.com?part=1
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
Link: https://patch.msgid.link/20260613182810.1317258-2-abd.masalkhi@gmail.com
Signed-off-by: Yu Kuai <yukuai@fygo.io>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/raid1.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 32b2eb2a169c3..91ecf50eba402 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1427,7 +1427,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
raid_end_bio_io(r1_bio);
}
-static void raid1_write_request(struct mddev *mddev, struct bio *bio,
+static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
int max_write_sectors)
{
struct r1conf *conf = mddev->private;
@@ -1447,7 +1447,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
DEFINE_WAIT(w);
if (bio->bi_opf & REQ_NOWAIT) {
bio_wouldblock_error(bio);
- return;
+ return false;
}
for (;;) {
prepare_to_wait(&conf->wait_barrier,
@@ -1469,7 +1469,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
if (!wait_barrier(conf, bio->bi_iter.bi_sector,
bio->bi_opf & REQ_NOWAIT)) {
bio_wouldblock_error(bio);
- return;
+ return false;
}
retry_write:
@@ -1557,7 +1557,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
if (bio->bi_opf & REQ_NOWAIT) {
bio_wouldblock_error(bio);
- return;
+ return false;
}
mddev_add_trace_msg(mddev, "raid1 wait rdev %d blocked",
blocked_rdev->raid_disk);
@@ -1668,7 +1668,8 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
/* In case raid1d snuck in to freeze_array */
wake_up_barrier(conf);
- return;
+ return true;
+
err_handle:
for (k = 0; k < i; k++) {
if (r1_bio->bios[k]) {
@@ -1680,6 +1681,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
bio->bi_status = errno_to_blk_status(error);
set_bit(R1BIO_Uptodate, &r1_bio->state);
raid_end_bio_io(r1_bio);
+ return false;
}
static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
@@ -1703,8 +1705,9 @@ static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
if (bio_data_dir(bio) == READ)
raid1_read_request(mddev, bio, sectors, NULL);
else {
- md_write_start(mddev,bio);
- raid1_write_request(mddev, bio, sectors);
+ md_write_start(mddev, bio);
+ if (!raid1_write_request(mddev, bio, sectors))
+ md_write_end(mddev);
}
return true;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 453/869] soundwire: fix bug in sdw_add_element_group_count found by syzkaller
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (451 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 452/869] md/raid1: fix writes_pending and barrier reference leaks on write failures Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 454/869] net: serialize netif_running() check in enqueue_to_backlog() Greg Kroah-Hartman
` (416 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bard Liao, Andy Shevchenko,
Baoli.Zhang, Vinod Koul, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baoli.Zhang <baoli.zhang@linux.intel.com>
[ Upstream commit f772ff5a0e6758fd412803c09e03ba3bca5f5878 ]
The original implementation caused an out-of-bounds memory access
in the sdw_add_element_group_count for-loop when i == num.
for (i = 0; i <= num; i++) {
if (rate == group->rates[i] && lane == group->lanes[i])
...
To fix this error, the function now checks for existing rate/lane
entries in the group(a function parameter) using a for-loop before
adding them.
No functional changes apart from this fix.
Fixes: 9026118f20e2 ("soundwire: Add generic bandwidth allocation algorithm")
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Baoli.Zhang <baoli.zhang@linux.intel.com>
Link: https://patch.msgid.link/20260506055039.3751028-2-baoli.zhang@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../soundwire/generic_bandwidth_allocation.c | 31 +++++++++----------
1 file changed, 14 insertions(+), 17 deletions(-)
diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index b9316207c3ab2..45a2f80ed809a 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -199,28 +199,25 @@ static int sdw_add_element_group_count(struct sdw_group *group,
int num = group->count;
int i;
- for (i = 0; i <= num; i++) {
+ for (i = 0; i < num; i++) {
if (rate == group->rates[i])
- break;
-
- if (i != num)
- continue;
-
- if (group->count >= group->max_size) {
- unsigned int *rates;
+ return 0;
+ }
- group->max_size += 1;
- rates = krealloc(group->rates,
- (sizeof(int) * group->max_size),
- GFP_KERNEL);
- if (!rates)
- return -ENOMEM;
- group->rates = rates;
- }
+ if (group->count >= group->max_size) {
+ unsigned int *rates;
- group->rates[group->count++] = rate;
+ group->max_size += 1;
+ rates = krealloc(group->rates,
+ (sizeof(int) * group->max_size),
+ GFP_KERNEL);
+ if (!rates)
+ return -ENOMEM;
+ group->rates = rates;
}
+ group->rates[group->count++] = rate;
+
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 454/869] net: serialize netif_running() check in enqueue_to_backlog()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (452 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 453/869] soundwire: fix bug in sdw_add_element_group_count found by syzkaller Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 455/869] RDMA/irdma: Replace waitqueue and flag with completion Greg Kroah-Hartman
` (415 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+965506b59a2de0b6905c,
Eric Dumazet, Julian Anastasov, Kuniyuki Iwashima, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 46762cefe7f4e5bffc1eb467810a7bbb02e461d7 ]
Syzbot reported a KASAN slab-use-after-free in fib_rules_lookup().
The root cause is a race condition where packets can escape the backlog
flushing during device unregistration (e.g., during netns exit).
Commit e9e4dd3267d0 ("net: do not process device backlog during unregistration")
introduced a lockless netif_running() check in enqueue_to_backlog() to
prevent queuing packets to an unregistering device.
However, this creates a TOCTOU race window.
A lockless transmitter (like veth_xmit) can pass
the check before dev_close() clears IFF_UP. If the transmitter is then
delayed, flush_all_backlogs() can run and finish before the transmitter
grabs the backlog lock and queues the packet. The packet then escapes
the flush and triggers UAF later when processed.
Fix this by moving the netif_running() check inside the backlog lock.
This serializes the check with the flush work (which also grabs the lock).
We then either queue the packet before the flush runs (so it gets flushed),
or check netif_running() after the flush/close completes (so it gets dropped).
Fixes: e9e4dd3267d0 ("net: do not process device backlog during unregistration")
Reported-by: syzbot+965506b59a2de0b6905c@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/6a315824.b0403584.28d0ff.0000.GAE@google.com/T/#u
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Julian Anastasov <ja@ssi.bg>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260616141317.407791-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/core/dev.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index 388770b88b449..2c058f6a59159 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5041,10 +5041,6 @@ static int enqueue_to_backlog(struct sk_buff *skb, int cpu,
int max_backlog;
u32 tail;
- reason = SKB_DROP_REASON_DEV_READY;
- if (!netif_running(skb->dev))
- goto bad_dev;
-
reason = SKB_DROP_REASON_CPU_BACKLOG;
sd = &per_cpu(softnet_data, cpu);
@@ -5055,6 +5051,11 @@ static int enqueue_to_backlog(struct sk_buff *skb, int cpu,
backlog_lock_irq_save(sd, &flags);
qlen = skb_queue_len(&sd->input_pkt_queue);
if (qlen <= max_backlog && !skb_flow_limit(skb, qlen)) {
+ if (unlikely(!netif_running(skb->dev))) {
+ backlog_unlock_irq_restore(sd, &flags);
+ reason = SKB_DROP_REASON_DEV_READY;
+ goto bad_dev;
+ }
if (!qlen) {
/* Schedule NAPI for backlog device. We can use
* non atomic operation as we own the queue lock.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 455/869] RDMA/irdma: Replace waitqueue and flag with completion
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (453 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 454/869] net: serialize netif_running() check in enqueue_to_backlog() Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 456/869] RDMA/bnxt_re: Avoid repeated requests to allocate WC pages Greg Kroah-Hartman
` (414 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jacob Moroni, Jason Gunthorpe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jacob Moroni <jmoroni@google.com>
[ Upstream commit d9c8c45e6d2f438a3c8e643ae78b59454fa0fadd ]
The driver previously used a waitqueue along with an explicit
request_done flag, but without proper barriers around request_done.
An earlier patch by Gui-Dong Han <hanguidong02@gmail.com> attempted
to fix this by adding the missing memory barriers. Rather than
adding the barriers, this patch replaces the waitqueue+flag with
a completion, which is designed for this exact purpose.
Fixes: 44d9e52977a1 ("RDMA/irdma: Implement device initialization definitions")
Fixes: 915cc7ac0f8e ("RDMA/irdma: Add miscellaneous utility definitions")
Link: https://patch.msgid.link/r/20260616155601.1081448-1-jmoroni@google.com
Signed-off-by: Jacob Moroni <jmoroni@google.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/irdma/hw.c | 7 +++----
drivers/infiniband/hw/irdma/main.h | 3 +--
drivers/infiniband/hw/irdma/utils.c | 12 +++++-------
3 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/drivers/infiniband/hw/irdma/hw.c b/drivers/infiniband/hw/irdma/hw.c
index ad50b77282f8a..c1e5bcf6ab604 100644
--- a/drivers/infiniband/hw/irdma/hw.c
+++ b/drivers/infiniband/hw/irdma/hw.c
@@ -1001,9 +1001,9 @@ static int irdma_create_cqp(struct irdma_pci_f *rf)
INIT_LIST_HEAD(&cqp->cqp_avail_reqs);
INIT_LIST_HEAD(&cqp->cqp_pending_reqs);
- /* init the waitqueue of the cqp_requests and add them to the list */
+ /* init the completion of the cqp_requests and add them to the list */
for (i = 0; i < sqsize; i++) {
- init_waitqueue_head(&cqp->cqp_requests[i].waitq);
+ init_completion(&cqp->cqp_requests[i].comp);
list_add_tail(&cqp->cqp_requests[i].list, &cqp->cqp_avail_reqs);
}
init_waitqueue_head(&cqp->remove_wq);
@@ -2103,8 +2103,7 @@ void irdma_cqp_ce_handler(struct irdma_pci_f *rf, struct irdma_sc_cq *cq)
cqp_request->compl_info.error = info.error;
if (cqp_request->waiting) {
- WRITE_ONCE(cqp_request->request_done, true);
- wake_up(&cqp_request->waitq);
+ complete_all(&cqp_request->comp);
irdma_put_cqp_request(&rf->cqp, cqp_request);
} else {
if (cqp_request->callback_fcn)
diff --git a/drivers/infiniband/hw/irdma/main.h b/drivers/infiniband/hw/irdma/main.h
index e5dc43442dff7..47b95efd51cea 100644
--- a/drivers/infiniband/hw/irdma/main.h
+++ b/drivers/infiniband/hw/irdma/main.h
@@ -155,13 +155,12 @@ struct irdma_cqp_compl_info {
struct irdma_cqp_request {
struct cqp_cmds_info info;
- wait_queue_head_t waitq;
+ struct completion comp;
struct list_head list;
refcount_t refcnt;
void (*callback_fcn)(struct irdma_cqp_request *cqp_request);
void *param;
struct irdma_cqp_compl_info compl_info;
- bool request_done; /* READ/WRITE_ONCE macros operate on it */
bool waiting:1;
bool dynamic:1;
};
diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c
index 45c3f82887eff..1a73e1b740745 100644
--- a/drivers/infiniband/hw/irdma/utils.c
+++ b/drivers/infiniband/hw/irdma/utils.c
@@ -445,7 +445,7 @@ struct irdma_cqp_request *irdma_alloc_and_get_cqp_request(struct irdma_cqp *cqp,
if (cqp_request) {
cqp_request->dynamic = true;
if (wait)
- init_waitqueue_head(&cqp_request->waitq);
+ init_completion(&cqp_request->comp);
}
}
if (!cqp_request) {
@@ -482,7 +482,7 @@ void irdma_free_cqp_request(struct irdma_cqp *cqp,
if (cqp_request->dynamic) {
kfree(cqp_request);
} else {
- WRITE_ONCE(cqp_request->request_done, false);
+ reinit_completion(&cqp_request->comp);
cqp_request->callback_fcn = NULL;
cqp_request->waiting = false;
@@ -516,8 +516,7 @@ irdma_free_pending_cqp_request(struct irdma_cqp *cqp,
{
if (cqp_request->waiting) {
cqp_request->compl_info.error = true;
- WRITE_ONCE(cqp_request->request_done, true);
- wake_up(&cqp_request->waitq);
+ complete_all(&cqp_request->comp);
}
wait_event_timeout(cqp->remove_wq,
refcount_read(&cqp_request->refcnt) == 1, 1000);
@@ -571,9 +570,8 @@ static int irdma_wait_event(struct irdma_pci_f *rf,
cqp_timeout.compl_cqp_cmds = atomic64_read(&rf->sc_dev.cqp->completed_ops);
do {
irdma_cqp_ce_handler(rf, &rf->ccq.sc_cq);
- if (wait_event_timeout(cqp_request->waitq,
- READ_ONCE(cqp_request->request_done),
- msecs_to_jiffies(CQP_COMPL_WAIT_TIME_MS)))
+ if (wait_for_completion_timeout(&cqp_request->comp,
+ msecs_to_jiffies(CQP_COMPL_WAIT_TIME_MS)))
break;
irdma_check_cqp_progress(&cqp_timeout, &rf->sc_dev);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 456/869] RDMA/bnxt_re: Avoid repeated requests to allocate WC pages
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (454 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 455/869] RDMA/irdma: Replace waitqueue and flag with completion Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 457/869] RDMA/bnxt_re: Add a max slot check for SQ Greg Kroah-Hartman
` (413 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kalesh AP, Selvin Xavier,
Jason Gunthorpe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Selvin Xavier <selvin.xavier@broadcom.com>
[ Upstream commit 441baa79043431807115fd030d7d0bb14ed441a0 ]
Applications can request multiple WC pages for the same ucontext.
As of now, only 1 WC page per ucontext is supported. Add a lock to
avoid concurrent access and a check to fail repeated requests.
Also, if the mmap entry insert fails for the WC, free the Doorbell
page index mapped for the WC page.
Fixes: eee6268421a2 ("RDMA/bnxt_re: Move the UAPI methods to a dedicated file")
Fixes: 360da60d6c6e ("RDMA/bnxt_re: Enable low latency push")
Link: https://patch.msgid.link/r/20260615224751.232802-12-selvin.xavier@broadcom.com
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/bnxt_re/ib_verbs.c | 34 +++++++++++++++++++-----
drivers/infiniband/hw/bnxt_re/ib_verbs.h | 1 +
2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 467bdfea6c92c..339e9be2e8f24 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -4237,6 +4237,7 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata)
goto fail;
}
spin_lock_init(&uctx->sh_lock);
+ mutex_init(&uctx->wcdpi_lock);
resp.comp_mask = BNXT_RE_UCNTX_CMASK_HAVE_CCTX;
chip_met_rev_num = rdev->chip_ctx->chip_num;
@@ -4453,14 +4454,23 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle *
switch (alloc_type) {
case BNXT_RE_ALLOC_WC_PAGE:
- if (cctx->modes.db_push) {
+ if (cctx->modes.db_push) {
+ mutex_lock(&uctx->wcdpi_lock);
+ /* already allocated — one WC page per context */
+ if (uctx->wcdpi.dbr) {
+ mutex_unlock(&uctx->wcdpi_lock);
+ return -EEXIST;
+ }
if (bnxt_qplib_alloc_dpi(&rdev->qplib_res, &uctx->wcdpi,
- uctx, BNXT_QPLIB_DPI_TYPE_WC))
+ uctx, BNXT_QPLIB_DPI_TYPE_WC)) {
+ mutex_unlock(&uctx->wcdpi_lock);
return -ENOMEM;
+ }
length = PAGE_SIZE;
dpi = uctx->wcdpi.dpi;
addr = (u64)uctx->wcdpi.umdbr;
mmap_flag = BNXT_RE_MMAP_WC_DB;
+ mutex_unlock(&uctx->wcdpi_lock);
} else {
return -EINVAL;
}
@@ -4483,8 +4493,15 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle *
}
entry = bnxt_re_mmap_entry_insert(uctx, addr, mmap_flag, &mmap_offset);
- if (!entry)
+ if (!entry) {
+ if (mmap_flag == BNXT_RE_MMAP_WC_DB) {
+ mutex_lock(&uctx->wcdpi_lock);
+ bnxt_qplib_dealloc_dpi(&rdev->qplib_res, &uctx->wcdpi);
+ uctx->wcdpi.dbr = NULL;
+ mutex_unlock(&uctx->wcdpi_lock);
+ }
return -ENOMEM;
+ }
uobj->object = entry;
uverbs_finalize_uobj_create(attrs, BNXT_RE_ALLOC_PAGE_HANDLE);
@@ -4515,11 +4532,16 @@ static int alloc_page_obj_cleanup(struct ib_uobject *uobject,
switch (entry->mmap_flag) {
case BNXT_RE_MMAP_WC_DB:
- if (uctx && uctx->wcdpi.dbr) {
+ if (uctx) {
struct bnxt_re_dev *rdev = uctx->rdev;
- bnxt_qplib_dealloc_dpi(&rdev->qplib_res, &uctx->wcdpi);
- uctx->wcdpi.dbr = NULL;
+ mutex_lock(&uctx->wcdpi_lock);
+ if (uctx->wcdpi.dbr) {
+ bnxt_qplib_dealloc_dpi(&rdev->qplib_res,
+ &uctx->wcdpi);
+ uctx->wcdpi.dbr = NULL;
+ }
+ mutex_unlock(&uctx->wcdpi_lock);
}
break;
case BNXT_RE_MMAP_DBR_BAR:
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h
index 9cd8f770d1b27..b01b685ee70f6 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h
@@ -141,6 +141,7 @@ struct bnxt_re_ucontext {
struct bnxt_re_dev *rdev;
struct bnxt_qplib_dpi dpi;
struct bnxt_qplib_dpi wcdpi;
+ struct mutex wcdpi_lock; /* serialises WC DPI alloc/free */
void *shpg;
spinlock_t sh_lock; /* protect shpg */
struct rdma_user_mmap_entry *shpage_mmap;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 457/869] RDMA/bnxt_re: Add a max slot check for SQ
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (455 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 456/869] RDMA/bnxt_re: Avoid repeated requests to allocate WC pages Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 458/869] RDMA/bnxt_re: Free CQ toggle page after firmware teardown Greg Kroah-Hartman
` (412 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sriharsha Basavapatna, Selvin Xavier,
Jason Gunthorpe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Selvin Xavier <selvin.xavier@broadcom.com>
[ Upstream commit dc95931b7e1326dacae547874bf38c092e5960d8 ]
The variable WQE mode must be validated against
the maximum slots supported by HW. The max supported
value is 64K. Adding a max and min check and fail if user
supplied value is more than the max supported and zero.
Fixes: d8ea645d6984 ("RDMA/bnxt_re: Handle variable WQE support for user applications")
Link: https://patch.msgid.link/r/20260615224751.232802-10-selvin.xavier@broadcom.com
Reviewed-by: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/bnxt_re/ib_verbs.c | 3 +++
drivers/infiniband/hw/bnxt_re/qplib_sp.h | 1 +
2 files changed, 4 insertions(+)
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 339e9be2e8f24..86de1d9bca6b2 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -1402,6 +1402,9 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd,
}
qplqp->type = (u8)qptype;
qplqp->wqe_mode = bnxt_re_is_var_size_supported(rdev, uctx);
+ if (uctx && qplqp->wqe_mode == BNXT_QPLIB_WQE_MODE_VARIABLE &&
+ (!ureq->sq_slots || ureq->sq_slots > BNXT_RE_MAX_SQ_SLOTS))
+ return -EINVAL;
if (init_attr->qp_type == IB_QPT_RC) {
qplqp->max_rd_atomic = dev_attr->max_qp_rd_atom;
qplqp->max_dest_rd_atomic = dev_attr->max_qp_init_rd_atom;
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.h b/drivers/infiniband/hw/bnxt_re/qplib_sp.h
index fcfef5cbb38d4..92f3131a9a829 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.h
@@ -357,6 +357,7 @@ int bnxt_qplib_modify_cc(struct bnxt_qplib_res *res,
#define BNXT_VAR_MAX_SLOT_ALIGN 256
#define BNXT_VAR_MAX_SGE 13
#define BNXT_RE_MAX_RQ_WQES 65536
+#define BNXT_RE_MAX_SQ_SLOTS 65536
#define BNXT_STATIC_MAX_SGE 6
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 458/869] RDMA/bnxt_re: Free CQ toggle page after firmware teardown
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (456 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 457/869] RDMA/bnxt_re: Add a max slot check for SQ Greg Kroah-Hartman
@ 2026-10-17 15:54 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 459/869] RDMA/bnxt_re: Fix budget handling of notification queue Greg Kroah-Hartman
` (411 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:54 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Selvin Xavier, Jason Gunthorpe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Selvin Xavier <selvin.xavier@broadcom.com>
[ Upstream commit bb45e06f9914ca64ac95341a80a0c20bb8dd46a9 ]
Free the toggle page only after firmware teardown completes so that
an NQ interrupt arriving during bnxt_qplib_destroy_cq() won't write
the toggle value to an already-freed page. Move free_page() after
bnxt_qplib_destroy_cq.
Fixes: e275919d9669 ("RDMA/bnxt_re: Share a page to expose per CQ info with userspace")
Link: https://patch.msgid.link/r/20260615224751.232802-4-selvin.xavier@broadcom.com
Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/bnxt_re/ib_verbs.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 86de1d9bca6b2..324825ecf6b2c 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -2987,11 +2987,11 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
nq = cq->qplib_cq.nq;
cctx = rdev->chip_ctx;
- if (cctx->modes.toggle_bits & BNXT_QPLIB_CQ_TOGGLE_BIT) {
- free_page((unsigned long)cq->uctx_cq_page);
+ if (cctx->modes.toggle_bits & BNXT_QPLIB_CQ_TOGGLE_BIT)
hash_del(&cq->hash_entry);
- }
bnxt_qplib_destroy_cq(&rdev->qplib_res, &cq->qplib_cq);
+ if (cctx->modes.toggle_bits & BNXT_QPLIB_CQ_TOGGLE_BIT)
+ free_page((unsigned long)cq->uctx_cq_page);
ib_umem_release(cq->umem);
atomic_dec(&rdev->stats.res.cq_count);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 459/869] RDMA/bnxt_re: Fix budget handling of notification queue
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (457 preceding siblings ...)
2026-10-17 15:54 ` [PATCH 6.12 458/869] RDMA/bnxt_re: Free CQ toggle page after firmware teardown Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 460/869] RDMA/bnxt_re: Remove unusable nq variable Greg Kroah-Hartman
` (410 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kashyap Desai, Kalesh AP,
Jason Gunthorpe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kashyap Desai <kashyap.desai@broadcom.com>
[ Upstream commit 6b395d31146a3fae775823ea8570a37b922f6685 ]
The cited commit in Fixes tag introduced a bug which can cause hang
of completion queue processing because of notification queue budget
goes to zero.
Found while doing nfs over rdma mount and umount.
Below message is noticed because of the existing bug.
kernel: cm_destroy_id_wait_timeout: cm_id=00000000ff6c6cc6 timed out. state 11 -> 0, refcnt=1
Fix to handle this issue -
Driver will not change nq->budget upon create and destroy of cq and srq
rdma resources.
Fixes: cb97b377a135 ("RDMA/bnxt_re: Refurbish CQ to NQ hash calculation")
Link: https://patch.msgid.link/r/20250324040935.90182-1-kalesh-anakkur.purayil@broadcom.com
Signed-off-by: Kashyap Desai <kashyap.desai@broadcom.com>
Signed-off-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Stable-dep-of: 131e2918b9b0 ("RDMA/bnxt_re: Free SRQ toggle page after firmware teardown")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/bnxt_re/ib_verbs.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 324825ecf6b2c..7a17088186cb7 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -1733,8 +1733,6 @@ int bnxt_re_destroy_srq(struct ib_srq *ib_srq, struct ib_udata *udata)
bnxt_qplib_destroy_srq(&rdev->qplib_res, qplib_srq);
ib_umem_release(srq->umem);
atomic_dec(&rdev->stats.res.srq_count);
- if (nq)
- nq->budget--;
return 0;
}
@@ -1856,8 +1854,6 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq,
goto fail;
}
}
- if (nq)
- nq->budget++;
active_srqs = atomic_inc_return(&rdev->stats.res.srq_count);
if (active_srqs > rdev->stats.res.srq_watermark)
rdev->stats.res.srq_watermark = active_srqs;
@@ -2995,7 +2991,6 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
ib_umem_release(cq->umem);
atomic_dec(&rdev->stats.res.cq_count);
- nq->budget--;
kfree(cq->cql);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 460/869] RDMA/bnxt_re: Remove unusable nq variable
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (458 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 459/869] RDMA/bnxt_re: Fix budget handling of notification queue Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 461/869] RDMA/bnxt_re: Free SRQ toggle page after firmware teardown Greg Kroah-Hartman
` (409 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, kernel test robot, Leon Romanovsky,
Jason Gunthorpe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <leonro@nvidia.com>
[ Upstream commit ffc59e32c67e599cc473d6427a4aa584399d5b3c ]
Remove nq variable from bnxt_re_create_srq() and bnxt_re_destroy_srq()
as it generates the following compilation warnings:
>> drivers/infiniband/hw/bnxt_re/ib_verbs.c:1777:24: warning: variable
'nq' set but not used [-Wunused-but-set-variable]
1777 | struct bnxt_qplib_nq *nq = NULL;
| ^
drivers/infiniband/hw/bnxt_re/ib_verbs.c:1828:24: warning: variable
'nq' set but not used [-Wunused-but-set-variable]
1828 | struct bnxt_qplib_nq *nq = NULL;
| ^
2 warnings generated.
Fixes: 6b395d31146a ("RDMA/bnxt_re: Fix budget handling of notification queue")
Link: https://patch.msgid.link/r/8a4343e217d7d1c0a5a786b785c4ac57cb72a2a0.1744288299.git.leonro@nvidia.com
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202504091055.CzgXnk4C-lkp@intel.com/
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Stable-dep-of: 131e2918b9b0 ("RDMA/bnxt_re: Free SRQ toggle page after firmware teardown")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/bnxt_re/ib_verbs.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 7a17088186cb7..d2c3038aad69d 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -1722,10 +1722,7 @@ int bnxt_re_destroy_srq(struct ib_srq *ib_srq, struct ib_udata *udata)
ib_srq);
struct bnxt_re_dev *rdev = srq->rdev;
struct bnxt_qplib_srq *qplib_srq = &srq->qplib_srq;
- struct bnxt_qplib_nq *nq = NULL;
- if (qplib_srq->cq)
- nq = qplib_srq->cq->nq;
if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT) {
free_page((unsigned long)srq->uctx_srq_page);
hash_del(&srq->hash_entry);
@@ -1773,7 +1770,6 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq,
struct ib_udata *udata)
{
struct bnxt_qplib_dev_attr *dev_attr;
- struct bnxt_qplib_nq *nq = NULL;
struct bnxt_re_ucontext *uctx;
struct bnxt_re_dev *rdev;
struct bnxt_re_srq *srq;
@@ -1819,7 +1815,6 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq,
srq->qplib_srq.eventq_hw_ring_id = rdev->nqr->nq[0].ring_id;
srq->qplib_srq.sg_info.pgsize = PAGE_SIZE;
srq->qplib_srq.sg_info.pgshft = PAGE_SHIFT;
- nq = &rdev->nqr->nq[0];
if (udata) {
rc = bnxt_re_init_user_srq(rdev, pd, srq, udata);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 461/869] RDMA/bnxt_re: Free SRQ toggle page after firmware teardown
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (459 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 460/869] RDMA/bnxt_re: Remove unusable nq variable Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 462/869] RDMA/bnxt_re: Initialize dpi variable to zero Greg Kroah-Hartman
` (408 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Selvin Xavier, Jason Gunthorpe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Selvin Xavier <selvin.xavier@broadcom.com>
[ Upstream commit 131e2918b9b0529687e67e2e58047304027f095a ]
Free the toggle page only after firmware teardown completes so that
an NQ interrupt arriving during bnxt_qplib_destroy_srq() won't write
the toggle values to an already-freed page. Move free_page() after
bnxt_qplib_destroy_srq().
Fixes: 181028a0d84c ("RDMA/bnxt_re: Share a page to expose per SRQ info with userspace")
Link: https://patch.msgid.link/r/20260615224751.232802-3-selvin.xavier@broadcom.com
Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/bnxt_re/ib_verbs.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index d2c3038aad69d..4e3086e6340ee 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -1723,11 +1723,11 @@ int bnxt_re_destroy_srq(struct ib_srq *ib_srq, struct ib_udata *udata)
struct bnxt_re_dev *rdev = srq->rdev;
struct bnxt_qplib_srq *qplib_srq = &srq->qplib_srq;
- if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT) {
- free_page((unsigned long)srq->uctx_srq_page);
+ if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT)
hash_del(&srq->hash_entry);
- }
bnxt_qplib_destroy_srq(&rdev->qplib_res, qplib_srq);
+ if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT)
+ free_page((unsigned long)srq->uctx_srq_page);
ib_umem_release(srq->umem);
atomic_dec(&rdev->stats.res.srq_count);
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 462/869] RDMA/bnxt_re: Initialize dpi variable to zero
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (460 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 461/869] RDMA/bnxt_re: Free SRQ toggle page after firmware teardown Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 463/869] sockmap: Fix use-after-free in udp_bpf_recvmsg() Greg Kroah-Hartman
` (407 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Anantha Prabhu, Kalesh AP,
Selvin Xavier, Jason Gunthorpe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Selvin Xavier <selvin.xavier@broadcom.com>
[ Upstream commit 978b27d6ce538bb832ccd69e45802824e4301c4b ]
dpi is initialized only for BNXT_RE_ALLOC_WC_PAGE, but copied
for all the cases. So initialize the dpi to 0.
Fixes: eee6268421a2 ("RDMA/bnxt_re: Move the UAPI methods to a dedicated file")
Fixes: 360da60d6c6e ("RDMA/bnxt_re: Enable low latency push")
Link: https://patch.msgid.link/r/20260615224751.232802-2-selvin.xavier@broadcom.com
Reviewed-by: Anantha Prabhu <anantha.prabhu@broadcom.com>
Signed-off-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/bnxt_re/ib_verbs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 4e3086e6340ee..8231fd9b665ce 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -4429,8 +4429,8 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle *
struct bnxt_re_ucontext *uctx;
struct bnxt_re_dev *rdev;
u64 mmap_offset;
+ u32 dpi = 0;
u32 length;
- u32 dpi;
u64 addr;
int err;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 463/869] sockmap: Fix use-after-free in udp_bpf_recvmsg()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (461 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 462/869] RDMA/bnxt_re: Initialize dpi variable to zero Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 464/869] ALSA: seq: Clean up fifo locking with guard Greg Kroah-Hartman
` (406 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+9307c991a6d07ce6e6d8,
Jiayuan Chen, Jakub Sitnicki, Emil Tsalapatis, Kuniyuki Iwashima,
Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit c010995b29c8939c6aa69e3cb26f8dbee163d156 ]
syzbot reported use-after-free of struct sk_msg in sk_msg_recvmsg(). [0]
sk_msg_recvmsg() peeks sk_msg from psock->ingress_msg under a lock,
but its processing is lockless.
Thus, sk_msg_recvmsg() must be serialised by callers, otherwise
multiple threads could touch the same sk_msg.
For example, TCP uses lock_sock(), and AF_UNIX uses unix_sk(sk)->iolock.
Initially, udp_bpf_recvmsg() had used lock_sock(), but the cited
commit removed it.
Let's serialise sk_msg_recvmsg() with lock_sock() in udp_bpf_recvmsg().
Note that holding spin_lock_bh(&sk->sk_receive_queue.lock) is not
an option due to copy_page_to_iter() in sk_msg_recvmsg().
[0]:
BUG: KASAN: slab-use-after-free in sk_msg_recvmsg+0xb54/0xc30 net/core/skmsg.c:428
Read of size 4 at addr ffff88814cdcf000 by task syz.0.24/6020
CPU: 1 UID: 0 PID: 6020 Comm: syz.0.24 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Compute Engine/Google Compute Engine, BIOS Google 01/13/2026
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:378 [inline]
print_report+0xba/0x230 mm/kasan/report.c:482
kasan_report+0x117/0x150 mm/kasan/report.c:595
sk_msg_recvmsg+0xb54/0xc30 net/core/skmsg.c:428
udp_bpf_recvmsg+0x4bd/0xe00 net/ipv4/udp_bpf.c:84
inet_recvmsg+0x260/0x270 net/ipv4/af_inet.c:891
sock_recvmsg_nosec net/socket.c:1078 [inline]
sock_recvmsg+0x1a8/0x270 net/socket.c:1100
____sys_recvmsg+0x1e6/0x4a0 net/socket.c:2812
___sys_recvmsg+0x215/0x590 net/socket.c:2854
do_recvmmsg+0x334/0x800 net/socket.c:2949
__sys_recvmmsg net/socket.c:3023 [inline]
__do_sys_recvmmsg net/socket.c:3046 [inline]
__se_sys_recvmmsg net/socket.c:3039 [inline]
__x64_sys_recvmmsg+0x198/0x250 net/socket.c:3039
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fb319f9aeb9
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fb31ad97028 EFLAGS: 00000246 ORIG_RAX: 000000000000012b
RAX: ffffffffffffffda RBX: 00007fb31a216090 RCX: 00007fb319f9aeb9
RDX: 0000000000000001 RSI: 0000200000000400 RDI: 0000000000000004
RBP: 00007fb31a008c1f R08: 0000000000000000 R09: 0000000000000000
R10: 0000000040000021 R11: 0000000000000246 R12: 0000000000000000
R13: 00007fb31a216128 R14: 00007fb31a216090 R15: 00007ffe21dd0a98
</TASK>
Allocated by task 6019:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
__kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
kasan_kmalloc include/linux/kasan.h:263 [inline]
__kmalloc_cache_noprof+0x3d1/0x6e0 mm/slub.c:5780
kmalloc_noprof include/linux/slab.h:957 [inline]
kzalloc_noprof include/linux/slab.h:1094 [inline]
alloc_sk_msg net/core/skmsg.c:510 [inline]
sk_psock_skb_ingress_self+0x60/0x350 net/core/skmsg.c:612
sk_psock_verdict_apply net/core/skmsg.c:1038 [inline]
sk_psock_verdict_recv+0x7d9/0x8d0 net/core/skmsg.c:1236
udp_read_skb+0x73e/0x7e0 net/ipv4/udp.c:2045
sk_psock_verdict_data_ready+0x12d/0x550 net/core/skmsg.c:1257
__udp_enqueue_schedule_skb+0xc54/0x10b0 net/ipv4/udp.c:1789
__udp_queue_rcv_skb net/ipv4/udp.c:2346 [inline]
udp_queue_rcv_one_skb+0xac5/0x19c0 net/ipv4/udp.c:2475
__udp4_lib_mcast_deliver+0xc06/0xcf0 net/ipv4/udp.c:2585
__udp4_lib_rcv+0x10f6/0x2620 net/ipv4/udp.c:2724
ip_protocol_deliver_rcu+0x282/0x440 net/ipv4/ip_input.c:207
ip_local_deliver_finish+0x3bb/0x6f0 net/ipv4/ip_input.c:241
NF_HOOK+0x336/0x3c0 include/linux/netfilter.h:318
dst_input include/net/dst.h:474 [inline]
ip_sublist_rcv_finish+0x221/0x2a0 net/ipv4/ip_input.c:584
ip_list_rcv_finish net/ipv4/ip_input.c:628 [inline]
ip_sublist_rcv+0x5c6/0xa70 net/ipv4/ip_input.c:644
ip_list_rcv+0x3f1/0x450 net/ipv4/ip_input.c:678
__netif_receive_skb_list_ptype net/core/dev.c:6195 [inline]
__netif_receive_skb_list_core+0x7e5/0x810 net/core/dev.c:6242
__netif_receive_skb_list net/core/dev.c:6294 [inline]
netif_receive_skb_list_internal+0x995/0xcf0 net/core/dev.c:6385
netif_receive_skb_list+0x54/0x410 net/core/dev.c:6437
xdp_recv_frames net/bpf/test_run.c:269 [inline]
xdp_test_run_batch net/bpf/test_run.c:350 [inline]
bpf_test_run_xdp_live+0x1946/0x1cf0 net/bpf/test_run.c:379
bpf_prog_test_run_xdp+0x81c/0x1160 net/bpf/test_run.c:1396
bpf_prog_test_run+0x2c7/0x340 kernel/bpf/syscall.c:4703
__sys_bpf+0x5cb/0x920 kernel/bpf/syscall.c:6182
__do_sys_bpf kernel/bpf/syscall.c:6274 [inline]
__se_sys_bpf kernel/bpf/syscall.c:6272 [inline]
__x64_sys_bpf+0x7c/0x90 kernel/bpf/syscall.c:6272
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 6021:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:584
poison_slab_object mm/kasan/common.c:253 [inline]
__kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
kasan_slab_free include/linux/kasan.h:235 [inline]
slab_free_hook mm/slub.c:2540 [inline]
slab_free mm/slub.c:6674 [inline]
kfree+0x1be/0x650 mm/slub.c:6882
kfree_sk_msg include/linux/skmsg.h:385 [inline]
sk_msg_recvmsg+0xaa8/0xc30 net/core/skmsg.c:483
udp_bpf_recvmsg+0x4bd/0xe00 net/ipv4/udp_bpf.c:84
inet_recvmsg+0x260/0x270 net/ipv4/af_inet.c:891
sock_recvmsg_nosec net/socket.c:1078 [inline]
sock_recvmsg+0x1a8/0x270 net/socket.c:1100
____sys_recvmsg+0x1e6/0x4a0 net/socket.c:2812
___sys_recvmsg+0x215/0x590 net/socket.c:2854
do_recvmmsg+0x334/0x800 net/socket.c:2949
__sys_recvmmsg net/socket.c:3023 [inline]
__do_sys_recvmmsg net/socket.c:3046 [inline]
__se_sys_recvmmsg net/socket.c:3039 [inline]
__x64_sys_recvmmsg+0x198/0x250 net/socket.c:3039
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Fixes: 9f2470fbc4cb ("skmsg: Improve udp_bpf_recvmsg() accuracy")
Reported-by: syzbot+9307c991a6d07ce6e6d8@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/69922ac9.a70a0220.2c38d7.00e0.GAE@google.com/
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Link: https://lore.kernel.org/r/20260615021959.140010-5-jiayuan.chen@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv4/udp_bpf.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/ipv4/udp_bpf.c b/net/ipv4/udp_bpf.c
index 779a3a03762f1..b07774034a910 100644
--- a/net/ipv4/udp_bpf.c
+++ b/net/ipv4/udp_bpf.c
@@ -52,7 +52,9 @@ static int udp_msg_wait_data(struct sock *sk, struct sk_psock *psock,
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
ret = udp_msg_has_data(sk, psock);
if (!ret) {
+ release_sock(sk);
wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
+ lock_sock(sk);
ret = udp_msg_has_data(sk, psock);
}
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
@@ -81,6 +83,7 @@ static int udp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
goto out;
}
+ lock_sock(sk);
msg_bytes_ready:
copied = sk_msg_recvmsg(sk, psock, msg, len, flags);
if (!copied) {
@@ -92,11 +95,17 @@ static int udp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
if (data) {
if (psock_has_data(psock))
goto msg_bytes_ready;
+
+ release_sock(sk);
+
ret = sk_udp_recvmsg(sk, msg, len, flags, addr_len);
goto out;
}
copied = -EAGAIN;
}
+
+ release_sock(sk);
+
ret = copied;
out:
sk_psock_put(sk, psock);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 464/869] ALSA: seq: Clean up fifo locking with guard
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (462 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 463/869] sockmap: Fix use-after-free in udp_bpf_recvmsg() Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 465/869] ALSA: seq: avoid stale FIFO cells during resize Greg Kroah-Hartman
` (405 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Takashi Iwai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <tiwai@suse.de>
[ Upstream commit 9314e34e37292f2d3d43dcc8a7f54366b4c0811d ]
Yet more cleanup, now for seq_fifo.c about its refcount calls; the
manual refcount calls (either snd_use_lock_*() or snd_seq_fifo_lock())
are replaced with guard(snd_seq_fifo).
Only code refactoring, and no behavior change.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20250827080520.7544-8-tiwai@suse.de
Stable-dep-of: e546128291f8 ("ALSA: seq: avoid stale FIFO cells during resize")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/core/seq/seq_clientmgr.c | 3 +--
sound/core/seq/seq_fifo.c | 15 ++++-----------
sound/core/seq/seq_fifo.h | 1 +
3 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 35f099e02ca70..86316cf027aed 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -463,7 +463,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
cell = NULL;
err = 0;
- snd_seq_fifo_lock(fifo);
+ guard(snd_seq_fifo)(fifo);
if (IS_ENABLED(CONFIG_SND_SEQ_UMP) && client->midi_version > 0)
aligned_size = sizeof(struct snd_seq_ump_event);
@@ -522,7 +522,6 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
if (err == -EAGAIN && result > 0)
err = 0;
}
- snd_seq_fifo_unlock(fifo);
return (err < 0) ? err : result;
}
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index 3a10b081f129c..f23c6b7ae2403 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -106,12 +106,11 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
if (snd_BUG_ON(!f))
return -EINVAL;
- snd_use_lock_use(&f->use_lock);
+ guard(snd_seq_fifo)(f);
err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL, NULL); /* always non-blocking */
if (err < 0) {
if ((err == -ENOMEM) || (err == -EAGAIN))
atomic_inc(&f->overflow);
- snd_use_lock_free(&f->use_lock);
return err;
}
@@ -130,8 +129,6 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
if (waitqueue_active(&f->input_sleep))
wake_up(&f->input_sleep);
- snd_use_lock_free(&f->use_lock);
-
return 0; /* success */
}
@@ -263,14 +260,10 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
/* get the number of unused cells safely */
int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f)
{
- int cells;
-
if (!f)
return 0;
- snd_use_lock_use(&f->use_lock);
- scoped_guard(spinlock_irqsave, &f->lock)
- cells = snd_seq_unused_cells(f->pool);
- snd_use_lock_free(&f->use_lock);
- return cells;
+ guard(snd_seq_fifo)(f);
+ guard(spinlock_irqsave)(&f->lock);
+ return snd_seq_unused_cells(f->pool);
}
diff --git a/sound/core/seq/seq_fifo.h b/sound/core/seq/seq_fifo.h
index b56a7b897c9c3..4c9c49127746b 100644
--- a/sound/core/seq/seq_fifo.h
+++ b/sound/core/seq/seq_fifo.h
@@ -37,6 +37,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, struct snd_seq_event *event);
/* lock fifo from release */
#define snd_seq_fifo_lock(fifo) snd_use_lock_use(&(fifo)->use_lock)
#define snd_seq_fifo_unlock(fifo) snd_use_lock_free(&(fifo)->use_lock)
+DEFINE_GUARD(snd_seq_fifo, struct snd_seq_fifo *, snd_seq_fifo_lock(_T), snd_seq_fifo_unlock(_T))
/* get a cell from fifo - fifo should be locked */
int snd_seq_fifo_cell_out(struct snd_seq_fifo *f, struct snd_seq_event_cell **cellp, int nonblock);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 465/869] ALSA: seq: avoid stale FIFO cells during resize
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (463 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 464/869] ALSA: seq: Clean up fifo locking with guard Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 466/869] net: watchdog: fix refcount tracking races Greg Kroah-Hartman
` (404 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Cen Zhang, Takashi Iwai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <zzzccc427@gmail.com>
[ Upstream commit e546128291f8d688dcb931827e2efd2aa6c0734d ]
snd_seq_fifo_resize() still needs to publish the replacement pool
before it waits for FIFO users. A blocking snd_seq_read() holds
f->use_lock while it sleeps, so concurrent senders must be able to
queue to the new pool and wake that reader instead of failing against a
closing old pool.
However, snd_seq_fifo_event_in() duplicates an event before it takes
f->lock, and snd_seq_read() can dequeue a cell and later call
snd_seq_fifo_cell_putback() if copy_to_user() or
snd_seq_expand_var_event() fails. If resize swaps f->pool and detaches
oldhead in between, either path can relink an old-pool cell after the
snapshot. That stale cell sits outside the drained oldhead list, keeps
oldpool->counter elevated, and can leave snd_seq_pool_delete() waiting
for the retired pool to drain.
Keep the existing swap-before-wait ordering in snd_seq_fifo_resize(),
but reject stale cells before any FIFO relink. Revalidate event-in cells
under f->lock and retry them against the published replacement pool, and
free stale putback cells instead of linking them back into the FIFO.
The buggy scenario involves two paths, with each column showing the
order within that path:
resize path: relink path:
1. Allocate newpool. 1. Take f->use_lock.
2. Swap f->pool to newpool and 2. Duplicate or dequeue an old-pool
detach oldhead. cell before oldpool closes.
3. Mark oldpool closing and 3. Reach a later relink point after
wait for FIFO users. resize published newpool.
4. Free oldhead and delete 4. Relink the old-pool cell after
oldpool. resize detached oldhead.
5. Drop f->use_lock.
The reproducer reports a resize ioctl blocked in the expected pool
teardown path:
signal: resize iteration=98 target_pool=4 exceeded 250ms
(elapsed=251ms)
diagnostic: resize_tid=651 wchan=snd_seq_pool_done
diagnostic: resize_tid=651 stack=
snd_seq_pool_done+0x5b/0x140
snd_seq_pool_delete+0x7a/0x90
snd_seq_fifo_resize+0x193/0x1e0
snd_seq_ioctl_set_client_pool+0x214/0x260
snd_seq_ioctl+0x119/0x540
__x64_sys_ioctl+0xd1/0x120
do_syscall_64+0xbb/0x2f0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
A second run with larger pools hit the same target path:
signal: resize iteration=32 target_pool=64 exceeded 250ms
(elapsed=251ms)
diagnostic: resize_tid=663 wchan=snd_seq_pool_done
diagnostic: resize_tid=663 stack=
snd_seq_pool_done+0x5b/0x140
snd_seq_pool_delete+0x7a/0x90
snd_seq_fifo_resize+0x193/0x1e0
snd_seq_ioctl_set_client_pool+0x214/0x260
snd_seq_ioctl+0x119/0x540
__x64_sys_ioctl+0xd1/0x120
do_syscall_64+0xbb/0x2f0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Fixes: 2d7d54002e39 ("ALSA: seq: Fix race during FIFO resize")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Link: https://patch.msgid.link/20260614004801.3507773-2-zzzccc427@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/core/seq/seq_fifo.c | 52 ++++++++++++++++++++++++++++-----------
1 file changed, 37 insertions(+), 15 deletions(-)
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index f23c6b7ae2403..c3dfe04c3883d 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -101,13 +101,17 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
struct snd_seq_event *event)
{
struct snd_seq_event_cell *cell;
+ struct snd_seq_pool *pool;
+ bool linked;
int err;
if (snd_BUG_ON(!f))
return -EINVAL;
guard(snd_seq_fifo)(f);
- err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL, NULL); /* always non-blocking */
+retry:
+ pool = READ_ONCE(f->pool);
+ err = snd_seq_event_dup(pool, event, &cell, 1, NULL, NULL); /* always non-blocking */
if (err < 0) {
if ((err == -ENOMEM) || (err == -EAGAIN))
atomic_inc(&f->overflow);
@@ -115,14 +119,24 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
}
/* append new cells to fifo */
+ linked = false;
scoped_guard(spinlock_irqsave, &f->lock) {
- if (f->tail != NULL)
- f->tail->next = cell;
- f->tail = cell;
- if (f->head == NULL)
- f->head = cell;
- cell->next = NULL;
- f->cells++;
+ if (cell->pool == f->pool) {
+ if (f->tail)
+ f->tail->next = cell;
+ f->tail = cell;
+ if (!f->head)
+ f->head = cell;
+ cell->next = NULL;
+ f->cells++;
+ linked = true;
+ }
+ }
+
+ if (!linked) {
+ /* Retry against the replacement pool after resize publishes it. */
+ snd_seq_cell_free(cell);
+ goto retry;
}
/* wakeup client */
@@ -194,13 +208,21 @@ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f,
void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f,
struct snd_seq_event_cell *cell)
{
+ bool linked = false;
+
if (cell) {
- guard(spinlock_irqsave)(&f->lock);
- cell->next = f->head;
- f->head = cell;
- if (!f->tail)
- f->tail = cell;
- f->cells++;
+ scoped_guard(spinlock_irqsave, &f->lock) {
+ if (cell->pool == f->pool) {
+ cell->next = f->head;
+ f->head = cell;
+ if (!f->tail)
+ f->tail = cell;
+ f->cells++;
+ linked = true;
+ }
+ }
+ if (!linked)
+ snd_seq_cell_free(cell);
}
}
@@ -236,7 +258,7 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
oldpool = f->pool;
oldhead = f->head;
/* exchange pools */
- f->pool = newpool;
+ WRITE_ONCE(f->pool, newpool);
f->head = NULL;
f->tail = NULL;
f->cells = 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 466/869] net: watchdog: fix refcount tracking races
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (464 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 465/869] ALSA: seq: avoid stale FIFO cells during resize Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 467/869] bnxt: fix head underflow on XDP head-grow Greg Kroah-Hartman
` (403 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+381d82bbf0253710b35d,
syzbot+3479efbc2821cb2a79f2, Eric Dumazet, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 8eed5519e496b7a07f441a0f579cb228a33189f7 ]
Blamed commit converted the untracked dev_hold()/dev_put() calls
in the watchdog code to use the tracked dev_hold_track()/dev_put_track()
(which were later renamed/interfaced to netdev_hold() and netdev_put()).
By introducing dev->watchdog_dev_tracker to store the
reference tracking information without adding synchronization
between netdev_watchdog_up() and dev_watchdog(), it enabled the
race condition where this pointer could be overwritten or freed
concurrently, leading to the list corruption crash syzbot reported:
list_del corruption, ffff888114a18c00->next is NULL
kernel BUG at lib/list_debug.c:52 !
Oops: invalid opcode: 0000 [#1] SMP KASAN PTI
CPU: 1 UID: 0 PID: 91 Comm: kworker/u8:5 Not tainted syzkaller #0 PREEMPT(lazy)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/09/2026
Workqueue: events_unbound linkwatch_event
RIP: 0010:__list_del_entry_valid_or_report.cold+0x22/0x2a lib/list_debug.c:52
Call Trace:
<TASK>
__list_del_entry_valid include/linux/list.h:132 [inline]
__list_del_entry include/linux/list.h:246 [inline]
list_move_tail include/linux/list.h:341 [inline]
ref_tracker_free+0x1a7/0x6c0 lib/ref_tracker.c:329
netdev_tracker_free include/linux/netdevice.h:4491 [inline]
netdev_put include/linux/netdevice.h:4508 [inline]
netdev_put include/linux/netdevice.h:4504 [inline]
netdev_watchdog_down net/sched/sch_generic.c:600 [inline]
dev_deactivate_many+0x28c/0xfe0 net/sched/sch_generic.c:1363
dev_deactivate+0x109/0x1d0 net/sched/sch_generic.c:1397
linkwatch_do_dev net/core/link_watch.c:184 [inline]
linkwatch_do_dev+0xd3/0x120 net/core/link_watch.c:166
__linkwatch_run_queue+0x3a5/0x810 net/core/link_watch.c:240
linkwatch_event+0x8f/0xc0 net/core/link_watch.c:314
process_one_work+0xa0e/0x1980 kernel/workqueue.c:3314
process_scheduled_works kernel/workqueue.c:3397 [inline]
worker_thread+0x5ef/0xe50 kernel/workqueue.c:3478
kthread+0x370/0x450 kernel/kthread.c:436
ret_from_fork+0x69a/0xc80 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
This patch has three coordinated parts:
1) Add dev->watchdog_lock and dev->watchdog_ref_held to serialize watchdog operations.
2) Remove netdev_watchdog_up() call from netif_carrier_on():
This ensures netdev_watchdog_up() is only called from process/BH context
(via linkwatch workqueue dev_activate()), allowing us to use
spin_lock_bh() for synchronization.
3) Synchronize watchdog up and watchdog timer:
Protect netdev_watchdog_up() with tx_global_lock and watchdog_lock.
Only allocate a new tracker in netdev_watchdog_up() if one is
not already present.
In dev_watchdog(), ensure we don't release the tracker if the
timer was rescheduled either by dev_watchdog() itself or concurrently
by netdev_watchdog_up().
Fixes: f12bf6f3f942 ("net: watchdog: add net device refcount tracker")
Reported-by: syzbot+381d82bbf0253710b35d@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/6a26b751.c25708ab.1b19ef.0013.GAE@google.com/T/#u
Tested-by: syzbot+3479efbc2821cb2a79f2@syzkaller.appspotmail.com
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260611152737.2580480-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/netdevice.h | 4 ++++
net/core/dev.c | 3 ++-
net/sched/sch_generic.c | 48 ++++++++++++++++++++++++++++-----------
3 files changed, 41 insertions(+), 14 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0aa536df9cb59..58e2f366dfe4d 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1896,6 +1896,8 @@ enum netdev_reg_state {
* @qdisc_hash: qdisc hash table
* @watchdog_timeo: Represents the timeout that is used by
* the watchdog (see dev_watchdog())
+ * @watchdog_lock: protect watchdog_ref_held
+ * @watchdog_ref_held: True if the watchdog device ref is taken.
* @watchdog_timer: List of timers
*
* @proto_down_reason: reason a netdev interface is held down
@@ -2285,6 +2287,8 @@ struct net_device {
/* These may be needed for future network-power-down code. */
struct timer_list watchdog_timer;
int watchdog_timeo;
+ spinlock_t watchdog_lock;
+ bool watchdog_ref_held;
u32 proto_down_reason;
diff --git a/net/core/dev.c b/net/core/dev.c
index 2c058f6a59159..9888affc68df3 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -10479,7 +10479,8 @@ static int netif_alloc_netdev_queues(struct net_device *dev)
netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL);
spin_lock_init(&dev->tx_global_lock);
-
+ spin_lock_init(&dev->watchdog_lock);
+ dev->watchdog_ref_held = false;
return 0;
}
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 6a61bd0c081c6..7ec650ff9daae 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -542,28 +542,46 @@ static void dev_watchdog(struct timer_list *t)
dev->netdev_ops->ndo_tx_timeout(dev, i);
netif_unfreeze_queues(dev);
}
- if (!mod_timer(&dev->watchdog_timer,
- round_jiffies(oldest_start +
- dev->watchdog_timeo)))
- release = false;
+ spin_lock(&dev->watchdog_lock);
+ mod_timer(&dev->watchdog_timer,
+ round_jiffies(oldest_start +
+ dev->watchdog_timeo));
+ release = false;
+ spin_unlock(&dev->watchdog_lock);
}
}
spin_unlock(&dev->tx_global_lock);
- if (release)
+ spin_lock(&dev->watchdog_lock);
+ if (timer_pending(&dev->watchdog_timer))
+ release = false;
+ if (release && dev->watchdog_ref_held) {
netdev_put(dev, &dev->watchdog_dev_tracker);
+ dev->watchdog_ref_held = false;
+ }
+ spin_unlock(&dev->watchdog_lock);
}
void __netdev_watchdog_up(struct net_device *dev)
{
- if (dev->netdev_ops->ndo_tx_timeout) {
- if (dev->watchdog_timeo <= 0)
- dev->watchdog_timeo = 5*HZ;
- if (!mod_timer(&dev->watchdog_timer,
- round_jiffies(jiffies + dev->watchdog_timeo)))
+ if (!dev->netdev_ops->ndo_tx_timeout)
+ return;
+ if (dev->watchdog_timeo <= 0)
+ dev->watchdog_timeo = 5*HZ;
+ spin_lock_bh(&dev->tx_global_lock);
+
+ spin_lock(&dev->watchdog_lock);
+ if (!mod_timer(&dev->watchdog_timer,
+ round_jiffies(jiffies + dev->watchdog_timeo))) {
+ if (!dev->watchdog_ref_held) {
netdev_hold(dev, &dev->watchdog_dev_tracker,
GFP_ATOMIC);
+ dev->watchdog_ref_held = true;
+ }
}
+ spin_unlock(&dev->watchdog_lock);
+
+ spin_unlock_bh(&dev->tx_global_lock);
}
EXPORT_SYMBOL_GPL(__netdev_watchdog_up);
@@ -575,8 +593,14 @@ static void dev_watchdog_up(struct net_device *dev)
static void dev_watchdog_down(struct net_device *dev)
{
netif_tx_lock_bh(dev);
- if (del_timer(&dev->watchdog_timer))
+
+ spin_lock(&dev->watchdog_lock);
+ if (timer_delete(&dev->watchdog_timer)) {
netdev_put(dev, &dev->watchdog_dev_tracker);
+ dev->watchdog_ref_held = false;
+ }
+ spin_unlock(&dev->watchdog_lock);
+
netif_tx_unlock_bh(dev);
}
@@ -593,8 +617,6 @@ void netif_carrier_on(struct net_device *dev)
return;
atomic_inc(&dev->carrier_up_count);
linkwatch_fire_event(dev);
- if (netif_running(dev))
- __netdev_watchdog_up(dev);
}
}
EXPORT_SYMBOL(netif_carrier_on);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 467/869] bnxt: fix head underflow on XDP head-grow
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (465 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 466/869] net: watchdog: fix refcount tracking races Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 468/869] cxl/region: Block region delete during region creation Greg Kroah-Hartman
` (402 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Joe Damato, Michael Chan,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joe Damato <joe@dama.to>
[ Upstream commit e26657fe3b85c068b01f42bb0c602f242d643ba9 ]
The xdp.py test test_xdp_native_adjst_head_grow_data crashes when run on
a bnxt machine (and also crashes in NIPA).
It seems that the bug is an underflow in bnxt_rx_multi_page_skb, which
builds the skb head:
napi_build_skb(data_ptr - bp->rx_offset, rxr->rx_page_size);
The problem with this expression is that in page mode, rx_offset is:
bp->rx_offset = NET_IP_ALIGN + XDP_PACKET_HEADROOM;
Which evaluates (at least on x86_64) to 258.
The test test_xdp_native_adjst_head_grow_data tests a case where the
head is adjusted by -256.
When this test runs, data_ptr is shifted to frag_start + 2 (where
frag_start = page_address(page) + offset).
Then, bnxt_rx_multi_page_skb is invoked and the napi_build_skb
expression subtracts 258, landing at an address before frag_start. This
could be either the previous fragment or the previous physical page when
the offset is < 256 (e.g. if the fragment started at offset 0).
When the skb is freed, the page pool fragment reference is dropped on
either the wrong page or the wrong frag of the right page. In either
case, the corrupted reference count can lead to the page being
prematurely recycled while still in use. Once (incorrectly) recycled, it
can be handed out again and on driver teardown this would result in a
double free.
The commit under fixes updated this code to handle the case where the
native page size is >= 64k, but it unintentionally broke the head grow
case.
To fix this, add an offset field to struct bnxt_sw_rx_bd, mirroring the
existing offset field in struct bnxt_sw_rx_agg_bd. Populate it on
allocation and preserve it on reuse.
In bnxt_rx_multi_page_skb, use the newly added offset field to compute
the fragment start and pass that to napi_build_skb. Adjust the layout
with skb_reserve.
There are two cases, the non-adjustment case and the adjustment case.
In both cases, the skb is built at page_address(page) + offset to
account for the case where the native page size >= 64K and skb_reserve
is called with data_ptr - (page_address(page) + offset). That
difference equals bp->rx_offset when data_ptr was not moved, or
bp->rx_offset + xdp_adjust when XDP adjusted the head.
Re-running the failing test with this commit applied causes the test to
run successfully to completion.
The other rx_skb_func implementations don't have this issue.
Fixes: f6974b4c2d8e ("bnxt_en: Fix page pool logic for page size >= 64K")
Signed-off-by: Joe Damato <joe@dama.to>
Reviewed-by: Michael Chan <michael.chan@broadcom.com>
Link: https://patch.msgid.link/20260609204458.2237787-2-joe@dama.to
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 ++++++++--
drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 4749119180c4b..497799b089ce2 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -924,6 +924,7 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
mapping += bp->rx_dma_offset;
rx_buf->data = page;
rx_buf->data_ptr = page_address(page) + offset + bp->rx_offset;
+ rx_buf->offset = offset;
} else {
u8 *data = __bnxt_alloc_rx_frag(bp, &mapping, rxr, gfp);
@@ -932,6 +933,7 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
rx_buf->data = data;
rx_buf->data_ptr = data + bp->rx_offset;
+ rx_buf->offset = 0;
}
rx_buf->mapping = mapping;
@@ -953,6 +955,7 @@ void bnxt_reuse_rx_data(struct bnxt_rx_ring_info *rxr, u16 cons, void *data)
prod_rx_buf->data_ptr = cons_rx_buf->data_ptr;
prod_rx_buf->mapping = cons_rx_buf->mapping;
+ prod_rx_buf->offset = cons_rx_buf->offset;
prod_bd = &rxr->rx_desc_ring[RX_RING(bp, prod)][RX_IDX(prod)];
cons_bd = &rxr->rx_desc_ring[RX_RING(bp, cons)][RX_IDX(cons)];
@@ -1090,8 +1093,11 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp,
struct page *page = data;
u16 prod = rxr->rx_prod;
struct sk_buff *skb;
+ void *frag_start;
int err;
+ frag_start = page_address(page) + rxr->rx_buf_ring[cons].offset;
+
err = bnxt_alloc_rx_data(bp, rxr, prod, GFP_ATOMIC);
if (unlikely(err)) {
bnxt_reuse_rx_data(rxr, cons, data);
@@ -1100,13 +1106,13 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp,
dma_addr -= bp->rx_dma_offset;
dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, rxr->rx_page_size,
bp->rx_dir);
- skb = napi_build_skb(data_ptr - bp->rx_offset, rxr->rx_page_size);
+ skb = napi_build_skb(frag_start, rxr->rx_page_size);
if (!skb) {
page_pool_recycle_direct(rxr->page_pool, page);
return NULL;
}
skb_mark_for_recycle(skb);
- skb_reserve(skb, bp->rx_offset);
+ skb_reserve(skb, data_ptr - (u8 *)frag_start);
__skb_put(skb, len);
return skb;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index 105945aa3ffcc..1c094dd2ad25e 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -894,6 +894,7 @@ struct bnxt_sw_rx_bd {
void *data;
u8 *data_ptr;
dma_addr_t mapping;
+ unsigned int offset;
};
struct bnxt_sw_rx_agg_bd {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 468/869] cxl/region: Block region delete during region creation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (466 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 467/869] bnxt: fix head underflow on XDP head-grow Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 469/869] ixgbe: do not configure xps for XDP queues Greg Kroah-Hartman
` (401 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dan Williams, Alejandro Lucero,
Dave Jiang, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Williams <djbw@kernel.org>
[ Upstream commit d91feb88692e81b00cd22f0125cfcd04970b4a0b ]
Expand the range lock, rename it "regions_lock", to disable region deletion
in the critical period between construct_region() and attach_target(), as
well as the period between device_add() and registering the remove actions.
Otherwise, userspace can confuse the kernel. It can violate the assumption
the region stays registered through the completion of cxl_add_to_region().
It can violate the assumption that devm_add_action_or_reset() is working
with a live 'struct cxl_region'.
It is ok for the region to disappear outside of those windows as that
mirrors device hotplug flows where the proper locks are held.
Fixes: a32320b71f08 ("cxl/region: Add region autodiscovery")
Signed-off-by: Dan Williams <djbw@kernel.org>
Reviewed-by: Alejandro Lucero <alucerop@amd.com>
Tested-by: ALejandro Lucero <alucerop@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://patch.msgid.link/20260519210158.1499795-2-djbw@kernel.org
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/cxl/core/port.c | 2 +-
drivers/cxl/core/region.c | 23 ++++++++++++++++++++---
drivers/cxl/cxl.h | 4 ++--
3 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 6eb2e69361412..217a24a2f56e3 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -1825,7 +1825,7 @@ struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
return ERR_PTR(rc);
}
- mutex_init(&cxlrd->range_lock);
+ mutex_init(&cxlrd->regions_lock);
cxld = &cxlsd->cxld;
cxld->dev.type = &cxl_decoder_root_type;
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 009c0a262ee8d..00c9c60d9a246 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -2566,7 +2566,12 @@ static ssize_t create_pmem_region_store(struct device *dev,
if (rc != 1)
return -EINVAL;
+ rc = mutex_lock_interruptible(&cxlrd->regions_lock);
+ if (rc)
+ return rc;
+
cxlr = __create_region(cxlrd, CXL_DECODER_PMEM, id);
+ mutex_unlock(&cxlrd->regions_lock);
if (IS_ERR(cxlr))
return PTR_ERR(cxlr);
@@ -2586,7 +2591,12 @@ static ssize_t create_ram_region_store(struct device *dev,
if (rc != 1)
return -EINVAL;
+ rc = mutex_lock_interruptible(&cxlrd->regions_lock);
+ if (rc)
+ return rc;
+
cxlr = __create_region(cxlrd, CXL_DECODER_RAM, id);
+ mutex_unlock(&cxlrd->regions_lock);
if (IS_ERR(cxlr))
return PTR_ERR(cxlr);
@@ -2634,13 +2644,21 @@ static ssize_t delete_region_store(struct device *dev,
struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
struct cxl_port *port = to_cxl_port(dev->parent);
struct cxl_region *cxlr;
+ int rc;
+
+ rc = mutex_lock_interruptible(&cxlrd->regions_lock);
+ if (rc)
+ return rc;
cxlr = cxl_find_region_by_name(cxlrd, buf);
- if (IS_ERR(cxlr))
+ if (IS_ERR(cxlr)) {
+ mutex_unlock(&cxlrd->regions_lock);
return PTR_ERR(cxlr);
+ }
devm_release_action(port->uport_dev, unregister_region, cxlr);
put_device(&cxlr->dev);
+ mutex_unlock(&cxlrd->regions_lock);
return len;
}
@@ -3345,7 +3363,7 @@ int cxl_add_to_region(struct cxl_port *root, struct cxl_endpoint_decoder *cxled)
* Ensure that if multiple threads race to construct_region() for @hpa
* one does the construction and the others add to that.
*/
- mutex_lock(&cxlrd->range_lock);
+ guard(mutex)(&cxlrd->regions_lock);
region_dev = device_find_child(&cxlrd->cxlsd.cxld.dev, hpa,
match_region_by_range);
if (!region_dev) {
@@ -3353,7 +3371,6 @@ int cxl_add_to_region(struct cxl_port *root, struct cxl_endpoint_decoder *cxled)
region_dev = &cxlr->dev;
} else
cxlr = to_cxl_region(region_dev);
- mutex_unlock(&cxlrd->range_lock);
rc = PTR_ERR_OR_ZERO(cxlr);
if (rc)
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 490394c84aee3..6d726ca28935d 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -442,7 +442,7 @@ typedef u64 (*cxl_hpa_to_spa_fn)(struct cxl_root_decoder *cxlrd, u64 hpa);
* @region_id: region id for next region provisioning event
* @hpa_to_spa: translate CXL host-physical-address to Platform system-physical-address
* @platform_data: platform specific configuration data
- * @range_lock: sync region autodiscovery by address range
+ * @regions_lock: sync region discovery, construction, and deletion
* @qos_class: QoS performance class cookie
* @cxlsd: base cxl switch decoder
*/
@@ -451,7 +451,7 @@ struct cxl_root_decoder {
atomic_t region_id;
cxl_hpa_to_spa_fn hpa_to_spa;
void *platform_data;
- struct mutex range_lock;
+ struct mutex regions_lock;
int qos_class;
struct cxl_switch_decoder cxlsd;
};
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 469/869] ixgbe: do not configure xps for XDP queues
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (467 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 468/869] cxl/region: Block region delete during region creation Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 470/869] bpf: Reject sleepable BPF_LSM_CGROUP programs at load time Greg Kroah-Hartman
` (400 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alexander Lobakin,
Aleksandr Loktionov, Larysa Zaremba, Simon Horman, Patryk Holda,
Tony Nguyen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Larysa Zaremba <larysa.zaremba@intel.com>
[ Upstream commit 7bd4355272de34c2e90e34b72c5613736d03c32b ]
netif_set_xps_queue() should not be called for an XDP Tx queue, since such
queues are not netdev-exposed. On systems with number of CPUs >=64, on E610
adapter, netdev is configured with maximum number queue pairs being 63
(due to MSI-X assignment), but configuring XDP results in 64 XDP queues.
So, during XDP program load, when netif_set_xps_queue() is called for the
last XDP queue, we get a WARNING with a call trace and KASAN report
afterwards (if enabled).
[ 2012.699800] WARNING: net/core/dev.c:2854 at __netif_set_xps_queue+0x116a/0x1e40, CPU#36: xdpsock/103668
[...]
[ 2012.700029] RIP: 0010:__netif_set_xps_queue+0x116a/0x1e40
[ 2012.700035] Code: b6 34 06 48 89 f8 83 e0 07 83 c0 01 40 38 f0 7c 09 40 84 f6 0f 85 03 0a 00 00 0f b7 44 24 40 66 43 89 44 6a 18 e9 01 fb ff ff <0f> 0b e9 f2 ee ff ff 44 8b 44 24 44 45 85 c0 74 50 4d 85 e4 0f 84
[ 2012.700040] RSP: 0018:ffff8882369aeb28 EFLAGS: 00010246
[ 2012.700046] RAX: 0000000000000000 RBX: 000000000000003f RCX: 0000000000000000
[ 2012.700050] RDX: 1ffff1111da3d891 RSI: ffff888120e34250 RDI: ffff8888ed1ec488
[ 2012.700054] RBP: ffff888913281560 R08: 0000000000000000 R09: ffff8888ed1ec000
[ 2012.700058] R10: ffff8888a2e83180 R11: 0000000000000000 R12: 0000000000007fa8
[ 2012.700061] R13: 000000000000003f R14: ffff888120e34854 R15: ffff8889132817c8
[ 2012.700065] FS: 00007fc8ea9ff740(0000) GS:ffff88884cefe000(0000) knlGS:0000000000000000
[ 2012.700069] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 2012.700073] CR2: 00007f81c8000020 CR3: 00000002299f8006 CR4: 00000000007726f0
[ 2012.700077] PKRU: 55555554
[ 2012.700080] Call Trace:
[ 2012.700084] <TASK>
[ 2012.700087] ? ktime_get+0x61/0x150
[ 2012.700097] ? usleep_range_state+0x133/0x1b0
[ 2012.700108] ? __pfx_usleep_range_state+0x10/0x10
[ 2012.700114] netif_set_xps_queue+0x31/0x50
[ 2012.700119] ixgbe_configure_tx_ring+0x472/0x920 [ixgbe]
[...]
[ 2012.700486] ixgbe_xdp+0x38f/0x750 [ixgbe]
[...]
[ 2012.701094] BUG: KASAN: slab-out-of-bounds in __netif_set_xps_queue+0x1ac5/0x1e40
[ 2012.701100] Write of size 4 at addr ffff88888d43cff8 by task xdpsock/103668
Skip XPS configuration for XDP Tx queues.
Fixes: 33fdc82f0883 ("ixgbe: add support for XDP_TX action")
Reviewed-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Patryk Holda <patryk.holda@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 8b8404d8c9460..aef70cf119bb3 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -3543,7 +3543,8 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
}
/* initialize XPS */
- if (!test_and_set_bit(__IXGBE_TX_XPS_INIT_DONE, &ring->state)) {
+ if (!ring_is_xdp(ring) &&
+ !test_and_set_bit(__IXGBE_TX_XPS_INIT_DONE, &ring->state)) {
struct ixgbe_q_vector *q_vector = ring->q_vector;
if (q_vector)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 470/869] bpf: Reject sleepable BPF_LSM_CGROUP programs at load time
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (468 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 469/869] ixgbe: do not configure xps for XDP queues Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 471/869] ocfs2: validate fast symlink target during inode read Greg Kroah-Hartman
` (399 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Windsor, Yonghong Song,
Song Liu, Kumar Kartikeya Dwivedi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Windsor <dwindsor@gmail.com>
[ Upstream commit 5b038319be442c620f774e6fc9e9283deeca1c75 ]
The cgroup shim runs under rcu_read_lock_dont_migrate(), so we should
not attach any sleepable BPF programs there. Add support to the verifier
to explicitly reject attempts to load sleepable BPF programs destined
for LSM cgroup attachment.
Without this, we get the following splat from a BPF_LSM_CGROUP
program marked BPF_F_SLEEPABLE attached to file_open when it calls
bpf_get_dentry_xattr():
BUG: sleeping function called from invalid context at kernel/locking/rwsem.c:1567
in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 34317, name: load
preempt_count: 0, expected: 0
RCU nest depth: 2, expected: 0
Call Trace:
down_read+0x76/0x480
ext4_xattr_get+0x11f/0x700
__vfs_getxattr+0xf0/0x150
bpf_get_dentry_xattr+0xbb/0xf0
bpf_prog_e76a298dac9218c6_test_open+0x6a/0x85
__cgroup_bpf_run_lsm_current+0x326/0x840
bpf_trampoline_6442534646+0x62/0x14d
security_file_open+0x34/0x60
do_dentry_open+0x340/0x1260
vfs_open+0x7a/0x440
path_openat+0x1bac/0x30a0
libbpf provides a .s named section variant for every sleepable
program type except lsm_cgroup, reflecting that per-cgroup LSM programs
are intended to only run in a non-sleepable context.
The above splat was obtained by bypassing libbpf by using bpf(2)
directly.
Fixes: 69fd337a975c ("bpf: per-cgroup lsm flavor")
Signed-off-by: David Windsor <dwindsor@gmail.com>
Acked-by: Yonghong Song <yonghong.song@linux.dev>
Acked-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/bpf/20260605145707.608579-1-dwindsor@gmail.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5a1c8733f3222..03d5e7db3df76 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -22800,8 +22800,10 @@ static bool can_be_sleepable(struct bpf_prog *prog)
return false;
}
}
- return prog->type == BPF_PROG_TYPE_LSM ||
- prog->type == BPF_PROG_TYPE_KPROBE /* only for uprobes */ ||
+ if (prog->type == BPF_PROG_TYPE_LSM)
+ return prog->expected_attach_type != BPF_LSM_CGROUP;
+
+ return prog->type == BPF_PROG_TYPE_KPROBE /* only for uprobes */ ||
prog->type == BPF_PROG_TYPE_STRUCT_OPS;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 471/869] ocfs2: validate fast symlink target during inode read
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (469 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 470/869] bpf: Reject sleepable BPF_LSM_CGROUP programs at load time Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 472/869] wifi: ath12k: fix memory leak in ath12k_wifi7_dp_rx_h_verify_tkip_mic() Greg Kroah-Hartman
` (398 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Zhang Cen, Joseph Qi, Gui-Dong Han,
Mark Fasheh, Joel Becker, Junxiao Bi, Changwei Ge, Jun Piao,
Heming Zhao, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Cen <rollkingzzc@gmail.com>
[ Upstream commit e234973f286ed2e8961a24561ec91594ec3e3ff8 ]
ocfs2_validate_inode_block() already rejects several inconsistent
self-contained dinodes before they are exposed to the rest of the
filesystem. Fast symlinks need the same treatment.
A zero-cluster symlink is treated as a fast symlink and later read through
page_get_link() and ocfs2_fast_symlink_read_folio(). That path uses
strnlen() on the inline payload and then copies len + 1 bytes into the
folio. If a corrupt dinode stores an i_size that does not fit the inline
area or omits the terminating NUL at i_size, that copy reads past the end
of the inode block buffer.
Reject zero-cluster symlink dinodes whose i_size exceeds the inline
fast-symlink capacity or whose inline payload is not NUL-terminated
exactly at i_size when the inode block is validated. This keeps malformed
fast symlinks from reaching the read path.
Validation reproduced this kernel report:
KASAN use-after-free in ocfs2_fast_symlink_read_folio+0x12c/0x1f0
RIP: 0033:0x7f5c6d859aa7
Read of size 3905
Call trace:
dump_stack_lvl+0x66/0xa0 (?:?)
print_report+0xce/0x630 (?:?)
ocfs2_fast_symlink_read_folio+0x12c/0x1f0 (fs/ocfs2/inode.c:?)
srso_alias_return_thunk+0x5/0xfbef5 (?:?)
__virt_addr_valid+0x19f/0x330 (?:?)
kasan_report+0xe0/0x110 (?:?)
kasan_check_range+0x105/0x1b0 (?:?)
__asan_memcpy+0x23/0x60 (?:?)
filemap_read_folio+0x27/0xe0 (?:?)
filemap_read_folio+0x35/0xe0 (?:?)
do_read_cache_folio+0x138/0x230 (?:?)
__page_get_link+0x26/0x110 (?:?)
page_get_link+0x2e/0x70 (?:?)
vfs_readlink+0x15e/0x250 (?:?)
touch_atime+0x4d/0x370 (?:?)
do_readlinkat+0x186/0x200 (?:?)
do_user_addr_fault+0x65a/0x890 (?:?)
__x64_sys_readlink+0x46/0x60 (?:?)
do_syscall_64+0x115/0x6a0 (arch/x86/entry/syscall_64.c:87)
entry_SYSCALL_64_after_hwframe+0x77/0x7f (?:?)
Link: https://lore.kernel.org/20260528151230.361127-1-rollkingzzc@gmail.com
Fixes: ea022dfb3c2a ("ocfs: simplify symlink handling")
Assisted-by: Codex:gpt-5.5
Signed-off-by: Zhang Cen <rollkingzzc@gmail.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Gui-Dong Han <2045gemini@gmail.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/inode.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 4f7b03f34a4c0..dd486c74ab9d1 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -1585,6 +1585,29 @@ int ocfs2_validate_inode_block(struct super_block *sb,
goto bail;
}
+ if (S_ISLNK(le16_to_cpu(di->i_mode)) &&
+ !le32_to_cpu(di->i_clusters)) {
+ int max_inline = ocfs2_fast_symlink_chars(sb);
+ u64 i_size = le64_to_cpu(di->i_size);
+
+ if (i_size >= max_inline) {
+ rc = ocfs2_error(sb,
+ "Invalid dinode #%llu: fast symlink i_size %llu exceeds max %d\n",
+ (unsigned long long)bh->b_blocknr,
+ (unsigned long long)i_size,
+ max_inline - 1);
+ goto bail;
+ }
+
+ if (strnlen((char *)di->id2.i_symlink, i_size + 1) != i_size) {
+ rc = ocfs2_error(sb,
+ "Invalid dinode #%llu: fast symlink is not NUL-terminated at i_size %llu\n",
+ (unsigned long long)bh->b_blocknr,
+ (unsigned long long)i_size);
+ goto bail;
+ }
+ }
+
if (le32_to_cpu(di->i_flags) & OCFS2_CHAIN_FL) {
struct ocfs2_chain_list *cl = &di->id2.i_chain;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 472/869] wifi: ath12k: fix memory leak in ath12k_wifi7_dp_rx_h_verify_tkip_mic()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (470 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 471/869] ocfs2: validate fast symlink target during inode read Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 473/869] md: replace wait loop with wait_event() in md_handle_request() Greg Kroah-Hartman
` (397 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Miaoqing Pan, Tamizh Chelvam Raja,
Baochen Qiang, Jeff Johnson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Miaoqing Pan <miaoqing.pan@oss.qualcomm.com>
[ Upstream commit 98d4f92ab6a1af2ea2ab590d7e2801b203110981 ]
In ath12k_wifi7_dp_rx_h_verify_tkip_mic(), the call to
ath12k_dp_rx_check_nwifi_hdr_len_valid() may return false when the
NWIFI header length is invalid, causing the function to abort early with
-EINVAL.
When this happens, the error propagates to
ath12k_wifi7_dp_rx_h_defrag(), which clears first_frag by setting it
to NULL. As a result, the corresponding MSDU is no longer referenced
by the defragmentation path and is never freed.
This leads to a memory leak for the affected MSDU on this error path.
Proper cleanup is required to ensure the MSDU is released when header
validation fails during TKIP MIC verification.
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3
Fixes: 9a0dddfb30f1 ("wifi: ath12k: Fix invalid data access in ath12k_dp_rx_h_undecap_nwifi")
Signed-off-by: Miaoqing Pan <miaoqing.pan@oss.qualcomm.com>
Reviewed-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Link: https://patch.msgid.link/20260512021108.2031651-1-miaoqing.pan@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath12k/dp_rx.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index d1248b98573ef..7b4e01041df98 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -2905,8 +2905,10 @@ static int ath12k_dp_rx_h_verify_tkip_mic(struct ath12k *ar, struct ath12k_peer
RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
skb_pull(msdu, hal_rx_desc_sz);
- if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu)))
+ if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu))) {
+ dev_kfree_skb_any(msdu);
return -EINVAL;
+ }
ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs);
ath12k_dp_rx_h_undecap(ar, msdu, rx_desc,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 473/869] md: replace wait loop with wait_event() in md_handle_request()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (471 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 472/869] wifi: ath12k: fix memory leak in ath12k_wifi7_dp_rx_h_verify_tkip_mic() Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 474/869] md/raid1,raid10: fix deadlock in read error recovery path Greg Kroah-Hartman
` (396 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Abd-Alrhman Masalkhi, Yu Kuai,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
[ Upstream commit 8e8278ac702e2d5d44211b4b10599aa3b2cb0555 ]
The wait loop is equivalent to wait_event() and can be simplified by
usaing it for improving readability.
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
Link: https://lore.kernel.org/r/20260415140319.376578-2-abd.masalkhi@gmail.com
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
Stable-dep-of: ba976e350111 ("md/raid1,raid10: fix bio accounting for split md cloned bios")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/md.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 55632055196f0..424ee03f47429 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -381,20 +381,12 @@ bool md_handle_request(struct mddev *mddev, struct bio *bio)
{
check_suspended:
if (is_suspended(mddev, bio)) {
- DEFINE_WAIT(__wait);
/* Bail out if REQ_NOWAIT is set for the bio */
if (bio->bi_opf & REQ_NOWAIT) {
bio_wouldblock_error(bio);
return true;
}
- for (;;) {
- prepare_to_wait(&mddev->sb_wait, &__wait,
- TASK_UNINTERRUPTIBLE);
- if (!is_suspended(mddev, bio))
- break;
- schedule();
- }
- finish_wait(&mddev->sb_wait, &__wait);
+ wait_event(mddev->sb_wait, !is_suspended(mddev, bio));
}
if (!percpu_ref_tryget_live(&mddev->active_io))
goto check_suspended;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 474/869] md/raid1,raid10: fix deadlock in read error recovery path
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (472 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 473/869] md: replace wait loop with wait_event() in md_handle_request() Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 475/869] md/raid1,raid10: fix bio accounting for split md cloned bios Greg Kroah-Hartman
` (395 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Abd-Alrhman Masalkhi, Xiao Ni,
Yu Kuai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
[ Upstream commit 7b15c24f805339a585cfe7d72f446b7e88b9bcc0 ]
raid1d and raid10d may resubmit a split md cloned bio while handling
a read error. In this case, resubmitting the bio can lead to a deadlock
if the array is suspended before md_handle_request() acquires an
active_io reference via percpu_ref_tryget_live().
Since the cloned bio already holds an active_io reference,
trying to acquire another reference via percpu_ref_tryget_live()
can lead to a deadlock while the array is suspended.
Fix this by using percpu_ref_get() for md cloned bios.
Fixes: bb2a9acefaf9 ("md/raid1: switch to use md_account_bio() for io accounting")
Fixes: 820455238366 ("md/raid10: switch to use md_account_bio() for io accounting")
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
Reviewed-by: Xiao Ni <xiao@kernel.org>
Reviewed-by: Yu Kuai <yukuai@fygo.io>
Link: https://patch.msgid.link/20260501114652.590037-2-abd.masalkhi@gmail.com
Signed-off-by: Yu Kuai <yukuai@fygo.io>
Stable-dep-of: ba976e350111 ("md/raid1,raid10: fix bio accounting for split md cloned bios")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/md.c | 25 ++++++++++++++++---------
drivers/md/md.h | 5 +++++
2 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 424ee03f47429..db8df74fcf67a 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -380,17 +380,24 @@ static bool is_suspended(struct mddev *mddev, struct bio *bio)
bool md_handle_request(struct mddev *mddev, struct bio *bio)
{
check_suspended:
- if (is_suspended(mddev, bio)) {
- /* Bail out if REQ_NOWAIT is set for the bio */
- if (bio->bi_opf & REQ_NOWAIT) {
- bio_wouldblock_error(bio);
- return true;
+ if (unlikely(md_cloned_bio(mddev, bio))) {
+ /*
+ * This bio is an MD cloned bio and already holds an
+ * active_io reference, so percpu_ref_get() is safe here.
+ */
+ percpu_ref_get(&mddev->active_io);
+ } else {
+ if (is_suspended(mddev, bio)) {
+ /* Bail out if REQ_NOWAIT is set for the bio */
+ if (bio->bi_opf & REQ_NOWAIT) {
+ bio_wouldblock_error(bio);
+ return true;
+ }
+ wait_event(mddev->sb_wait, !is_suspended(mddev, bio));
}
- wait_event(mddev->sb_wait, !is_suspended(mddev, bio));
+ if (!percpu_ref_tryget_live(&mddev->active_io))
+ goto check_suspended;
}
- if (!percpu_ref_tryget_live(&mddev->active_io))
- goto check_suspended;
-
if (!mddev->pers->make_request(mddev, bio)) {
percpu_ref_put(&mddev->active_io);
if (!mddev->gendisk && mddev->pers->prepare_suspend)
diff --git a/drivers/md/md.h b/drivers/md/md.h
index bd5d95b1bac74..eba943cbd3b26 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -1001,6 +1001,11 @@ void mddev_update_io_opt(struct mddev *mddev, unsigned int nr_stripes);
extern const struct block_device_operations md_fops;
+static inline bool md_cloned_bio(struct mddev *mddev, struct bio *bio)
+{
+ return bio->bi_pool == &mddev->io_clone_set;
+}
+
/*
* MD devices can be used undeneath by DM, in which case ->gendisk is NULL.
*/
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 475/869] md/raid1,raid10: fix bio accounting for split md cloned bios
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (473 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 474/869] md/raid1,raid10: fix deadlock in read error recovery path Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 476/869] md/raid1,raid10: fix error-path detection with md_cloned_bio() Greg Kroah-Hartman
` (394 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Abd-Alrhman Masalkhi, Xiao Ni,
Yu Kuai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
[ Upstream commit ba976e3501111d11c550848b3b7341a73035f582 ]
Use md_cloned_bio() to control bio accounting instead of relying
on r1bio_existed in raid1 or the io_accounting flag in raid10.
The previous logic does not reliably reflect whether a bio is an
md cloned bio. When a failed bio is split and resubmitted via
bio_submit_split_bioset() on the error path, this can lead to either
double accounting for md cloned bios, or missing accounting for bios
returned from bio_submit_split_bioset()
Fix this by using md_cloned_bio() to detect md cloned bios and
skip accounting accordingly.
Fixes: bb2a9acefaf9 ("md/raid1: switch to use md_account_bio() for io accounting")
Fixes: 820455238366 ("md/raid10: switch to use md_account_bio() for io accounting")
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
Reviewed-by: Xiao Ni <xiao@kernel.org>
Link: https://patch.msgid.link/20260501114652.590037-4-abd.masalkhi@gmail.com
Signed-off-by: Yu Kuai <yukuai@fygo.io>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/raid1.c | 2 +-
drivers/md/raid10.c | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 91ecf50eba402..b365fd4595228 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1400,7 +1400,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
}
r1_bio->read_disk = rdisk;
- if (!r1bio_existed) {
+ if (likely(!md_cloned_bio(mddev, bio))) {
md_account_bio(mddev, &bio);
r1_bio->master_bio = bio;
}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index fc68e6b05ddfe..fe136080a3798 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1143,7 +1143,7 @@ static bool regular_request_wait(struct mddev *mddev, struct r10conf *conf,
}
static void raid10_read_request(struct mddev *mddev, struct bio *bio,
- struct r10bio *r10_bio, bool io_accounting)
+ struct r10bio *r10_bio)
{
struct r10conf *conf = mddev->private;
struct bio *read_bio;
@@ -1220,7 +1220,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
}
slot = r10_bio->read_slot;
- if (io_accounting) {
+ if (likely(!md_cloned_bio(mddev, bio))) {
md_account_bio(mddev, &bio);
r10_bio->master_bio = bio;
}
@@ -1551,7 +1551,7 @@ static bool __make_request(struct mddev *mddev, struct bio *bio, int sectors)
ret = true;
if (bio_data_dir(bio) == READ)
- raid10_read_request(mddev, bio, r10_bio, true);
+ raid10_read_request(mddev, bio, r10_bio);
else
ret = raid10_write_request(mddev, bio, r10_bio);
@@ -2889,7 +2889,7 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
rdev_dec_pending(rdev, mddev);
r10_bio->state = 0;
- raid10_read_request(mddev, r10_bio->master_bio, r10_bio, false);
+ raid10_read_request(mddev, r10_bio->master_bio, r10_bio);
/*
* allow_barrier after re-submit to ensure no sync io
* can be issued while regular io pending.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 476/869] md/raid1,raid10: fix error-path detection with md_cloned_bio()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (474 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 475/869] md/raid1,raid10: fix bio accounting for split md cloned bios Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 477/869] nvmet-tcp: check return value of nvmet_tcp_set_queue_sock Greg Kroah-Hartman
` (393 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Abd-Alrhman Masalkhi, Xiao Ni,
Yu Kuai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
[ Upstream commit 811545e0926d02a6a0b1a1258bb5544777c164d4 ]
Detect the error path using md_cloned_bio() instead of relying
on r1_bio in raid1 or r10_bio->read_slot in raid10, which may be
NULL or -1 after splitting and resubmitting a failed bio.
As a result, the error path may not be recognized and memory
allocations can incorrectly use GFP_NOIO instead of
(GFP_NOIO | __GFP_HIGH), which can lead to a deadlock under
memory pressure.
Fixes: 689389a06ce7 ("md/raid1: simplify handle_read_error().")
Fixes: 545250f24809 ("md/raid10: simplify handle_read_error()")
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
Reviewed-by: Xiao Ni <xiao@kernel.org>
Link: https://patch.msgid.link/20260501114652.590037-3-abd.masalkhi@gmail.com
Signed-off-by: Yu Kuai <yukuai@fygo.io>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/raid1.c | 13 ++++++++++---
drivers/md/raid10.c | 20 ++++++++++++++------
2 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index b365fd4595228..c1ed903fa9c03 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1322,11 +1322,18 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
bool r1bio_existed = !!r1_bio;
/*
- * If r1_bio is set, we are blocking the raid1d thread
- * so there is a tiny risk of deadlock. So ask for
+ * An md cloned bio indicates we are in the error path.
+ * This is more reliable than checking r1_bio, which might
+ * be NULL even in the error path if a failed bio was split.
+ */
+ bool err_path = md_cloned_bio(mddev, bio);
+
+ /*
+ * If we are in the error path, we are blocking the raid1d
+ * thread so there is a tiny risk of deadlock. So ask for
* emergency memory if needed.
*/
- gfp_t gfp = r1_bio ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
+ gfp_t gfp = err_path ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
/*
* Still need barrier for READ in case that whole
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index fe136080a3798..875759fa86cab 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1152,9 +1152,22 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
char b[BDEVNAME_SIZE];
int slot = r10_bio->read_slot;
struct md_rdev *err_rdev = NULL;
- gfp_t gfp = GFP_NOIO;
int error;
+ /*
+ * An md cloned bio indicates we are in the error path.
+ * This is more reliable than checking slot, which might
+ * be -1 even in the error path if a failed bio was split.
+ */
+ bool err_path = md_cloned_bio(mddev, bio);
+
+ /*
+ * If we are in the error path, we are blocking the raid10d
+ * thread so there is a tiny risk of deadlock. So ask for
+ * emergency memory if needed.
+ */
+ gfp_t gfp = err_path ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
+
if (slot >= 0 && r10_bio->devs[slot].rdev) {
/*
* This is an error retry, but we cannot
@@ -1164,11 +1177,6 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
* we lose the device name in error messages.
*/
int disk;
- /*
- * As we are blocking raid10, it is a little safer to
- * use __GFP_HIGH.
- */
- gfp = GFP_NOIO | __GFP_HIGH;
disk = r10_bio->devs[slot].devnum;
err_rdev = conf->mirrors[disk].rdev;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 477/869] nvmet-tcp: check return value of nvmet_tcp_set_queue_sock
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (475 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 476/869] md/raid1,raid10: fix error-path detection with md_cloned_bio() Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 478/869] ALSA: seq: oss: Fix UAF at handling events with embedded SysEx data Greg Kroah-Hartman
` (392 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Hannes Reinecke, Chaitanya Kulkarni,
Geliang Tang, Keith Busch, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geliang Tang <tanggeliang@kylinos.cn>
[ Upstream commit 7ef789703e2b91775dcb36b2efa46325be31a2a0 ]
The return value of nvmet_tcp_set_queue_sock() is currently ignored in
nvmet_tcp_tls_handshake_done(). If it fails (e.g., due to the socket
not being in TCP_ESTABLISHED state), the socket callbacks will not be
properly set, leading to queue and socket leakage.
Fix this by capturing the return value and calling
nvmet_tcp_schedule_release_queue() on failure to ensure proper cleanup.
Fixes: 675b453e0241 ("nvmet-tcp: enable TLS handshake upcall")
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/nvme/target/tcp.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index 5509737bb4cb9..fcb1a3dbff011 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -1906,10 +1906,12 @@ static void nvmet_tcp_tls_handshake_done(void *data, int status,
spin_unlock_bh(&queue->state_lock);
cancel_delayed_work_sync(&queue->tls_handshake_tmo_work);
+
+ if (!status)
+ status = nvmet_tcp_set_queue_sock(queue);
+
if (status)
nvmet_tcp_schedule_release_queue(queue);
- else
- nvmet_tcp_set_queue_sock(queue);
kref_put(&queue->kref, nvmet_tcp_release_queue);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 478/869] ALSA: seq: oss: Fix UAF at handling events with embedded SysEx data
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (476 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 477/869] nvmet-tcp: check return value of nvmet_tcp_set_queue_sock Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 479/869] OPP: Fix race between OPP addition and lookup Greg Kroah-Hartman
` (391 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Takashi Iwai, Sasha Levin, Zhang Cen
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <tiwai@suse.de>
[ Upstream commit 7c349b4f2a603202fb8c363bd2774a22ac2fddf3 ]
The OSS sequencer processes the input MIDI bytes into a sequencer
event to be dispatched later (in snd_seq_oss_midi_putc() called from
snd_seq_oss_process_event()). When it's a SysEx data, the event
record contains data.ext.ptr pointer to the original SysEx bytes, and
the referred data is copied into the pool afterwards at dispatching.
The problem is that, if the sequencer port gets closed concurrently
before the dispatch, the OSS sequencer core also releases the
resources (in snd_seq_oss_midi_check_exit_port()), while the pending
event may hold a stale pointer, eventually leading to a UAF at a later
dispatch.
Fortunately, there is already a refcounting mechanism (snd_use_lock_t)
for the OSS MIDI device access, and for addressing the issue above, we
just need to extend the refcount until the event gets dispatched.
This patch extends snd_seq_oss_process_event() to give back the
refcount object, which is in turn released after calling the sequencer
dispatcher with the given event in the caller side.
According to the original report, KASAN report as below:
KASAN slab-use-after-free in snd_seq_event_dup+0x40c/0x470
RIP: 0033:0x7f2cb66a6340
Read of size 6
Call trace:
dump_stack_lvl+0x73/0xb0 (?:?)
print_report+0xd1/0x650 (?:?)
srso_alias_return_thunk+0x5/0xfbef5 (?:?)
__virt_addr_valid+0x1a7/0x340 (?:?)
kasan_complete_mode_report_info+0x64/0x200 (?:?)
kasan_report+0xf7/0x130 (?:?)
snd_seq_event_dup+0x40c/0x470 (?:?)
kasan_check_range+0x10c/0x1c0 (?:?)
__asan_memcpy+0x27/0x70 (?:?)
snd_seq_event_dup+0x9/0x470 (?:?)
snd_seq_client_enqueue_event+0x139/0x240 (?:?)
_raw_spin_unlock_irqrestore+0x4b/0x60 (?:?)
snd_seq_kernel_client_enqueue+0x102/0x120 (?:?)
snd_seq_oss_write+0x416/0x4e0 (?:?)
apparmor_file_permission+0x20/0x30 (?:?)
odev_write+0x3b/0x60 (?:?)
vfs_write+0x1ce/0x850 (?:?)
lock_release+0xc8/0x2a0 (?:?)
__kasan_check_write+0x18/0x20 (?:?)
__mutex_unlock_slowpath+0x129/0x510 (?:?)
ksys_write+0xe1/0x180 (?:?)
mutex_unlock+0x16/0x20 (?:?)
odev_ioctl+0x65/0xc0 (?:?)
__x64_sys_write+0x46/0x60 (?:?)
x64_sys_call+0x7d/0x20d0 (?:?)
do_syscall_64+0xc1/0x360 (arch/x86/entry/syscall_64.c:87)
entry_SYSCALL_64_after_hwframe+0x77/0x7f (?:?)
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-and-tested-by: Zhang Cen <rollkingzzc@gmail.com>
Closes: https://lore.kernel.org/20260521233900.478153-1-rollkingzzc@gmail.com
Link: https://patch.msgid.link/20260526152843.617503-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/core/seq/oss/seq_oss_event.c | 6 ++++--
sound/core/seq/oss/seq_oss_event.h | 3 ++-
sound/core/seq/oss/seq_oss_ioctl.c | 5 ++++-
sound/core/seq/oss/seq_oss_midi.c | 6 +++++-
sound/core/seq/oss/seq_oss_midi.h | 2 +-
sound/core/seq/oss/seq_oss_rw.c | 5 ++++-
6 files changed, 20 insertions(+), 7 deletions(-)
diff --git a/sound/core/seq/oss/seq_oss_event.c b/sound/core/seq/oss/seq_oss_event.c
index 7b7c925dd3aa2..4699c084d018e 100644
--- a/sound/core/seq/oss/seq_oss_event.c
+++ b/sound/core/seq/oss/seq_oss_event.c
@@ -39,8 +39,10 @@ static int set_echo_event(struct seq_oss_devinfo *dp, union evrec *rec, struct s
*/
int
-snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
+snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q,
+ struct snd_seq_event *ev, snd_use_lock_t **lockp)
{
+ *lockp = NULL;
switch (q->s.code) {
case SEQ_EXTENDED:
return extended_event(dp, q, ev);
@@ -69,7 +71,7 @@ snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd
if (snd_seq_oss_midi_open(dp, q->s.dev, SNDRV_SEQ_OSS_FILE_WRITE))
break;
if (snd_seq_oss_midi_filemode(dp, q->s.dev) & SNDRV_SEQ_OSS_FILE_WRITE)
- return snd_seq_oss_midi_putc(dp, q->s.dev, q->s.parm1, ev);
+ return snd_seq_oss_midi_putc(dp, q->s.dev, q->s.parm1, ev, lockp);
break;
case SEQ_ECHO:
diff --git a/sound/core/seq/oss/seq_oss_event.h b/sound/core/seq/oss/seq_oss_event.h
index b4f723949a170..a4524e51d0e9d 100644
--- a/sound/core/seq/oss/seq_oss_event.h
+++ b/sound/core/seq/oss/seq_oss_event.h
@@ -91,7 +91,8 @@ union evrec {
#define ev_is_long(ev) ((ev)->s.code >= 128)
#define ev_length(ev) ((ev)->s.code >= 128 ? LONG_EVENT_SIZE : SHORT_EVENT_SIZE)
-int snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev);
+int snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q,
+ struct snd_seq_event *ev, snd_use_lock_t **lockp);
int snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *q);
int snd_seq_oss_event_input(struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop);
diff --git a/sound/core/seq/oss/seq_oss_ioctl.c b/sound/core/seq/oss/seq_oss_ioctl.c
index ccf682689ec95..ce7a69d52b308 100644
--- a/sound/core/seq/oss/seq_oss_ioctl.c
+++ b/sound/core/seq/oss/seq_oss_ioctl.c
@@ -45,14 +45,17 @@ static int snd_seq_oss_oob_user(struct seq_oss_devinfo *dp, void __user *arg)
{
unsigned char ev[8];
struct snd_seq_event tmpev;
+ snd_use_lock_t *lock = NULL;
if (copy_from_user(ev, arg, 8))
return -EFAULT;
memset(&tmpev, 0, sizeof(tmpev));
snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.client, dp->addr.port);
tmpev.time.tick = 0;
- if (! snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev)) {
+ if (!snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev, &lock)) {
snd_seq_oss_dispatch(dp, &tmpev, 0, 0);
+ if (lock)
+ snd_use_lock_free(lock);
}
return 0;
}
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
index f8e247d9e5c99..f1ec7f41dcfe1 100644
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -634,7 +634,8 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq
* non-zero : invalid - ignored
*/
int
-snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, struct snd_seq_event *ev)
+snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c,
+ struct snd_seq_event *ev, snd_use_lock_t **lockp)
{
struct seq_oss_midi *mdev;
@@ -643,6 +644,9 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru
return -ENODEV;
if (snd_midi_event_encode_byte(mdev->coder, c, ev)) {
snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port);
+ /* the caller must release this later */
+ *lockp = &mdev->use_lock;
+ snd_use_lock_use(*lockp);
snd_use_lock_free(&mdev->use_lock);
return 0;
}
diff --git a/sound/core/seq/oss/seq_oss_midi.h b/sound/core/seq/oss/seq_oss_midi.h
index bcc1683773dfb..4819d4170bf6d 100644
--- a/sound/core/seq/oss/seq_oss_midi.h
+++ b/sound/core/seq/oss/seq_oss_midi.h
@@ -26,7 +26,7 @@ void snd_seq_oss_midi_open_all(struct seq_oss_devinfo *dp, int file_mode);
int snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev);
void snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev);
int snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c,
- struct snd_seq_event *ev);
+ struct snd_seq_event *ev, snd_use_lock_t **lockp);
int snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private);
int snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev);
int snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf);
diff --git a/sound/core/seq/oss/seq_oss_rw.c b/sound/core/seq/oss/seq_oss_rw.c
index 45bb458597708..b7147ac78ee8b 100644
--- a/sound/core/seq/oss/seq_oss_rw.c
+++ b/sound/core/seq/oss/seq_oss_rw.c
@@ -154,6 +154,7 @@ insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
{
int rc = 0;
struct snd_seq_event event;
+ snd_use_lock_t *lock = NULL;
/* if this is a timing event, process the current time */
if (snd_seq_oss_process_timer_event(dp->timer, rec))
@@ -165,7 +166,7 @@ insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
event.type = SNDRV_SEQ_EVENT_NOTEOFF;
snd_seq_oss_fill_addr(dp, &event, dp->addr.client, dp->addr.port);
- if (snd_seq_oss_process_event(dp, rec, &event))
+ if (snd_seq_oss_process_event(dp, rec, &event, &lock))
return 0; /* invalid event - no need to insert queue */
event.time.tick = snd_seq_oss_timer_cur_tick(dp->timer);
@@ -174,6 +175,8 @@ insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
else
rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, opt,
!is_nonblock_mode(dp->file_mode));
+ if (lock)
+ snd_use_lock_free(lock);
return rc;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 479/869] OPP: Fix race between OPP addition and lookup
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (477 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 478/869] ALSA: seq: oss: Fix UAF at handling events with embedded SysEx data Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 480/869] wifi: ath11k: cancel SSR work items during PCI shutdown Greg Kroah-Hartman
` (390 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ling Xu, Di Shen, Viresh Kumar,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Di Shen <di.shen@unisoc.com>
[ Upstream commit f5e1cc9a284bff2510981643a5bca4bc4c21b81a ]
A race exists between dev_pm_opp_add_dynamic() and
dev_pm_opp_find_freq_exact():
CPU0 (add) CPU1 (lookup)
------------------------------- ------------------------------
_opp_add()
mutex_lock()
list_add(&new_opp->node, head)
mutex_unlock() _opp_table_find_key()
mutex_lock()
dev_pm_opp_get(opp)
kref_get()
mutex_unlock()
kref_init(&new_opp->kref)
dev_pm_opp_put()
kref_put_mutex()
The newly added OPP is inserted into the list before its kref is
initialized. A concurrent lookup can find this OPP and increment its
reference count while it is still uninitialized, leading to refcount
corruption and a potential premature free.
Fix this by initializing ->kref and ->opp_table before making the OPP
visible via list_add(). This ensures any concurrent lookup observes a
fully initialized object.
Fixes: 7034764a1e4a (PM / OPP: Add 'struct kref' to struct dev_pm_opp)
Co-developed-by: Ling Xu <ling_ling.xu@unisoc.com>
Signed-off-by: Ling Xu <ling_ling.xu@unisoc.com>
Signed-off-by: Di Shen <di.shen@unisoc.com>
[ Viresh: Updated commit log ]
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/opp/core.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index b5df41ce3afff..46baa5c36c0d4 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -2026,11 +2026,10 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
return ret;
}
- list_add(&new_opp->node, head);
- mutex_unlock(&opp_table->lock);
-
new_opp->opp_table = opp_table;
kref_init(&new_opp->kref);
+ list_add(&new_opp->node, head);
+ mutex_unlock(&opp_table->lock);
opp_debug_create_one(new_opp, opp_table);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 480/869] wifi: ath11k: cancel SSR work items during PCI shutdown
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (478 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 479/869] OPP: Fix race between OPP addition and lookup Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 481/869] drm/amd/display: Fix divide-by-zero in calculate_mcache_setting on zero viewport Greg Kroah-Hartman
` (389 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Wei Zhang, Rameshkumar Sundaram,
Baochen Qiang, Jeff Johnson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Zhang <wei.zhang@oss.qualcomm.com>
[ Upstream commit 8c79aac429b583301f387374ff37c59be671df87 ]
A reboot can crash the kernel if it overlaps with WLAN firmware crash
recovery (SSR). The crash is a NULL pointer dereference in the MHI teardown
path while freeing DMA-backed MHI contexts.
Simplified trace:
dma_free_attrs
mhi_deinit_dev_ctxt [mhi]
ath11k_pci_power_down [ath11k_pci]
ath11k_pci_shutdown [ath11k_pci]
device_shutdown
kernel_restart
On the host side, SSR is driven by the MHI RDDM callback, which queues
reset_work to perform device recovery. reset_work power-cycles the device
by calling ath11k_hif_power_down() followed by ath11k_hif_power_up(). The
power-down phase deinitializes MHI and frees DMA resources.
Shutdown/reboot runs fully asynchronously with this RDDM-driven SSR
recovery flow. As a result, the shutdown path
(ath11k_pci_shutdown() -> ath11k_pci_power_down()) can race with the SSR
recovery sequence.
Fix this by canceling SSR-related work items during PCI shutdown, marking
the device as unregistering, and serializing the RDDM callback path that
checks and queues reset_work. This ensures that no new SSR recovery work
can be queued once teardown has started, and that any in-flight recovery
work is fully synchronized before device power-down, preventing MHI
teardown and DMA resource freeing from running more than once.
Note: This issue only affects PCI/MHI-based devices. AHB-based ath11k
devices do not queue reset_work in normal SSR flows.
Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04866.5-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1
Fixes: 13da397f884d ("ath11k: add support for device recovery for QCA6390/WCN6855")
Fixes: 5edbb148bc57 ("wifi: ath11k: Add firmware coredump collection support")
Signed-off-by: Wei Zhang <wei.zhang@oss.qualcomm.com>
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Link: https://patch.msgid.link/20260404043050.3433754-1-wei.zhang@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath11k/mhi.c | 4 +++-
drivers/net/wireless/ath/ath11k/pci.c | 7 +++++++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c
index 9c2200cc0348b..593f24602fc45 100644
--- a/drivers/net/wireless/ath/ath11k/mhi.c
+++ b/drivers/net/wireless/ath/ath11k/mhi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/msi.h>
@@ -282,8 +282,10 @@ static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl,
break;
}
+ spin_lock_bh(&ab->base_lock);
if (!(test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags)))
queue_work(ab->workqueue_aux, &ab->reset_work);
+ spin_unlock_bh(&ab->base_lock);
break;
default:
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 6b0e52a6fb89b..18957d450080e 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -1023,6 +1023,13 @@ static void ath11k_pci_shutdown(struct pci_dev *pdev)
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
+
+ spin_lock_bh(&ab->base_lock);
+ set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
+ spin_unlock_bh(&ab->base_lock);
+
+ cancel_work_sync(&ab->reset_work);
+
ath11k_pci_power_down(ab);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 481/869] drm/amd/display: Fix divide-by-zero in calculate_mcache_setting on zero viewport
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (479 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 480/869] wifi: ath11k: cancel SSR work items during PCI shutdown Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 482/869] s390/ap: Move response_type struct into ap_msg struct Greg Kroah-Hartman
` (388 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sun peng (Leo) Li, Dillon Varone,
George Zhang, Fangzhi Zuo, Dan Wheeler, Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: George Zhang <george.zhang@amd.com>
[ Upstream commit f327e389c07cfc3a2f6ff54f6214e1a52d457edc ]
If a plane reaches calculate_mcache_setting with a zero-area viewport,
calculate_mcache_setting exits early with num_mcaches == 0 and
mvmpg_width/height == 0. This will cause a divide-by-zero panic and can
also cause an underflow on num_mcaches.
Fix this by changing calculate_mcache_setting to bool and adding guards
after each calculate_mcache_row_bytes call. If num_mcaches or
mvmpg_width/height is zero, return a false. Callers will propagate the
failure as a rejected mode, which prevents the panic.
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/5302
Reviewed-by: Sun peng (Leo) Li <sunpeng.li@amd.com>
Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: George Zhang <george.zhang@amd.com>
Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 29c0f7c655f47bcbd575ff75e58480df6ec3c9da)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../src/dml2_core/dml2_core_dcn4_calcs.c | 31 +++++++++++++++----
1 file changed, 25 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
index d18b60c9761bd..37dd05d917685 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
@@ -2449,7 +2449,7 @@ static void calculate_mcache_row_bytes(
DML2_ASSERT(*p->num_mcaches > 0);
}
-static void calculate_mcache_setting(
+static bool calculate_mcache_setting(
struct dml2_core_internal_scratch *scratch,
struct dml2_core_calcs_calculate_mcache_setting_params *p)
{
@@ -2473,7 +2473,7 @@ static void calculate_mcache_setting(
*p->lc_comb_mcache = 0;
if (!p->dcc_enable)
- return;
+ return true;
l->is_dual_plane = dml_is_420(p->source_format) || p->source_format == dml2_rgbe_alpha;
@@ -2509,7 +2509,14 @@ static void calculate_mcache_setting(
l->l_p.mvmpg_per_mcache_lb = &l->mvmpg_per_mcache_lb_l;
calculate_mcache_row_bytes(scratch, &l->l_p);
- dml2_assert(*p->num_mcaches_l > 0);
+ if (*p->num_mcaches_l == 0 ||
+ (p->surf_vert ? l->mvmpg_height_l : l->mvmpg_width_l) == 0) {
+ dml2_printf("DML::%s: degenerate luma viewport (num_mcaches_l=%u mvmpg_%s_l=%u) — mode not supported\n",
+ __func__, *p->num_mcaches_l,
+ p->surf_vert ? "height" : "width",
+ p->surf_vert ? l->mvmpg_height_l : l->mvmpg_width_l);
+ return false;
+ }
if (l->is_dual_plane) {
l->c_p.num_chans = p->num_chans;
@@ -2544,7 +2551,14 @@ static void calculate_mcache_setting(
l->c_p.mvmpg_per_mcache_lb = &l->mvmpg_per_mcache_lb_c;
calculate_mcache_row_bytes(scratch, &l->c_p);
- dml2_assert(*p->num_mcaches_c > 0);
+ if (*p->num_mcaches_c == 0 ||
+ (p->surf_vert ? l->mvmpg_height_c : l->mvmpg_width_c) == 0) {
+ dml2_printf("DML::%s: degenerate chroma viewport (num_mcaches_c=%u mvmpg_%s_c=%u) — mode not supported\n",
+ __func__, *p->num_mcaches_c,
+ p->surf_vert ? "height" : "width",
+ p->surf_vert ? l->mvmpg_height_c : l->mvmpg_width_c);
+ return false;
+ }
}
// Sharing for iMALL access
@@ -2652,6 +2666,7 @@ static void calculate_mcache_setting(
*p->mcache_shift_granularity_l = l->mvmpg_access_width_l;
*p->mcache_shift_granularity_c = l->mvmpg_access_width_c;
+ return true;
}
static void calculate_mall_bw_overhead_factor(
@@ -8481,7 +8496,10 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out
calculate_mcache_setting_params->mall_comb_mcache_c = &mode_lib->ms.mall_comb_mcache_c[k];
calculate_mcache_setting_params->lc_comb_mcache = &mode_lib->ms.lc_comb_mcache[k];
- calculate_mcache_setting(&mode_lib->scratch, calculate_mcache_setting_params);
+ if (!calculate_mcache_setting(&mode_lib->scratch, calculate_mcache_setting_params)) {
+ mode_lib->ms.support.ModeSupport = false;
+ return false;
+ }
}
calculate_mall_bw_overhead_factor(
@@ -10483,7 +10501,8 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex
calculate_mcache_setting_params->mall_comb_mcache_l = &mode_lib->mp.mall_comb_mcache_l[k];
calculate_mcache_setting_params->mall_comb_mcache_c = &mode_lib->mp.mall_comb_mcache_c[k];
calculate_mcache_setting_params->lc_comb_mcache = &mode_lib->mp.lc_comb_mcache[k];
- calculate_mcache_setting(&mode_lib->scratch, calculate_mcache_setting_params);
+ if (!calculate_mcache_setting(&mode_lib->scratch, calculate_mcache_setting_params))
+ return false;
}
calculate_mall_bw_overhead_factor(
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 482/869] s390/ap: Move response_type struct into ap_msg struct
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (480 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 481/869] drm/amd/display: Fix divide-by-zero in calculate_mcache_setting on zero viewport Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 483/869] s390/ap/zcrypt: Rework AP message buffer allocation Greg Kroah-Hartman
` (387 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Harald Freudenberger, Holger Dengler,
Heiko Carstens, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <freude@linux.ibm.com>
[ Upstream commit 43435495a0f4e3a08792835285901b01e6d5b6da ]
Move the very small response_type struct into struct ap_msg.
So there is no need to kmalloc this tiny struct with each
ap message preparation.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Link: https://lore.kernel.org/r/20250424133619.16495-2-freude@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Stable-dep-of: e935cd525af4 ("s390/zcrypt: Close speculative mem read possibility")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/s390/crypto/ap_bus.h | 8 ++-
drivers/s390/crypto/zcrypt_msgtype50.c | 16 ++----
drivers/s390/crypto/zcrypt_msgtype6.c | 74 +++++++++-----------------
3 files changed, 37 insertions(+), 61 deletions(-)
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 6111913c858c0..deef76c06f9a9 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -214,6 +214,11 @@ struct ap_queue {
typedef enum ap_sm_wait (ap_func_t)(struct ap_queue *queue);
+struct ap_response_type {
+ struct completion work;
+ int type;
+};
+
struct ap_message {
struct list_head list; /* Request queueing. */
unsigned long psmid; /* Message id. */
@@ -222,7 +227,7 @@ struct ap_message {
size_t bufsize; /* allocated msg buffer size */
u16 flags; /* Flags, see AP_MSG_FLAG_xxx */
int rc; /* Return code for this message */
- void *private; /* ap driver private pointer. */
+ struct ap_response_type response;
/* receive is called from tasklet context */
void (*receive)(struct ap_queue *, struct ap_message *,
struct ap_message *);
@@ -250,7 +255,6 @@ static inline void ap_init_message(struct ap_message *ap_msg)
static inline void ap_release_message(struct ap_message *ap_msg)
{
kfree_sensitive(ap_msg->msg);
- kfree_sensitive(ap_msg->private);
}
enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event);
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c
index adc65eddaa1e3..47c401f5409b3 100644
--- a/drivers/s390/crypto/zcrypt_msgtype50.c
+++ b/drivers/s390/crypto/zcrypt_msgtype50.c
@@ -438,7 +438,7 @@ static void zcrypt_msgtype50_receive(struct ap_queue *aq,
msg->len = sizeof(error_reply);
}
out:
- complete((struct completion *)msg->private);
+ complete(&msg->response.work);
}
static atomic_t zcrypt_step = ATOMIC_INIT(0);
@@ -454,7 +454,6 @@ static long zcrypt_msgtype50_modexpo(struct zcrypt_queue *zq,
struct ica_rsa_modexpo *mex,
struct ap_message *ap_msg)
{
- struct completion work;
int rc;
ap_msg->bufsize = MSGTYPE50_CRB3_MAX_MSG_SIZE;
@@ -464,15 +463,14 @@ static long zcrypt_msgtype50_modexpo(struct zcrypt_queue *zq,
ap_msg->receive = zcrypt_msgtype50_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
- ap_msg->private = &work;
rc = ICAMEX_msg_to_type50MEX_msg(zq, ap_msg, mex);
if (rc)
goto out;
- init_completion(&work);
+ init_completion(&ap_msg->response.work);
rc = ap_queue_message(zq->queue, ap_msg);
if (rc)
goto out;
- rc = wait_for_completion_interruptible(&work);
+ rc = wait_for_completion_interruptible(&ap_msg->response.work);
if (rc == 0) {
rc = ap_msg->rc;
if (rc == 0)
@@ -485,7 +483,6 @@ static long zcrypt_msgtype50_modexpo(struct zcrypt_queue *zq,
}
out:
- ap_msg->private = NULL;
if (rc)
pr_debug("send me cprb at dev=%02x.%04x rc=%d\n",
AP_QID_CARD(zq->queue->qid),
@@ -504,7 +501,6 @@ static long zcrypt_msgtype50_modexpo_crt(struct zcrypt_queue *zq,
struct ica_rsa_modexpo_crt *crt,
struct ap_message *ap_msg)
{
- struct completion work;
int rc;
ap_msg->bufsize = MSGTYPE50_CRB3_MAX_MSG_SIZE;
@@ -514,15 +510,14 @@ static long zcrypt_msgtype50_modexpo_crt(struct zcrypt_queue *zq,
ap_msg->receive = zcrypt_msgtype50_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
- ap_msg->private = &work;
rc = ICACRT_msg_to_type50CRT_msg(zq, ap_msg, crt);
if (rc)
goto out;
- init_completion(&work);
+ init_completion(&ap_msg->response.work);
rc = ap_queue_message(zq->queue, ap_msg);
if (rc)
goto out;
- rc = wait_for_completion_interruptible(&work);
+ rc = wait_for_completion_interruptible(&ap_msg->response.work);
if (rc == 0) {
rc = ap_msg->rc;
if (rc == 0)
@@ -535,7 +530,6 @@ static long zcrypt_msgtype50_modexpo_crt(struct zcrypt_queue *zq,
}
out:
- ap_msg->private = NULL;
if (rc)
pr_debug("send crt cprb at dev=%02x.%04x rc=%d\n",
AP_QID_CARD(zq->queue->qid),
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index b64c9d9fc6137..09ef91af1e2af 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -31,11 +31,6 @@
#define CEIL4(x) ((((x) + 3) / 4) * 4)
-struct response_type {
- struct completion work;
- int type;
-};
-
#define CEXXC_RESPONSE_TYPE_ICA 0
#define CEXXC_RESPONSE_TYPE_XCRB 1
#define CEXXC_RESPONSE_TYPE_EP11 2
@@ -856,7 +851,7 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq,
.type = TYPE82_RSP_CODE,
.reply_code = REP82_ERROR_MACHINE_FAILURE,
};
- struct response_type *resp_type = msg->private;
+ struct ap_response_type *resp_type = &msg->response;
struct type86x_reply *t86r;
int len;
@@ -920,7 +915,7 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq,
.type = TYPE82_RSP_CODE,
.reply_code = REP82_ERROR_MACHINE_FAILURE,
};
- struct response_type *resp_type = msg->private;
+ struct ap_response_type *resp_type = &msg->response;
struct type86_ep11_reply *t86r;
int len;
@@ -967,9 +962,7 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
struct ica_rsa_modexpo *mex,
struct ap_message *ap_msg)
{
- struct response_type resp_type = {
- .type = CEXXC_RESPONSE_TYPE_ICA,
- };
+ struct ap_response_type *resp_type = &ap_msg->response;
int rc;
ap_msg->msg = (void *)get_zeroed_page(GFP_KERNEL);
@@ -979,15 +972,15 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
- ap_msg->private = &resp_type;
rc = icamex_msg_to_type6mex_msgx(zq, ap_msg, mex);
if (rc)
goto out_free;
- init_completion(&resp_type.work);
+ resp_type->type = CEXXC_RESPONSE_TYPE_ICA;
+ init_completion(&resp_type->work);
rc = ap_queue_message(zq->queue, ap_msg);
if (rc)
goto out_free;
- rc = wait_for_completion_interruptible(&resp_type.work);
+ rc = wait_for_completion_interruptible(&resp_type->work);
if (rc == 0) {
rc = ap_msg->rc;
if (rc == 0)
@@ -1001,7 +994,6 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
out_free:
free_page((unsigned long)ap_msg->msg);
- ap_msg->private = NULL;
ap_msg->msg = NULL;
return rc;
}
@@ -1017,9 +1009,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
struct ica_rsa_modexpo_crt *crt,
struct ap_message *ap_msg)
{
- struct response_type resp_type = {
- .type = CEXXC_RESPONSE_TYPE_ICA,
- };
+ struct ap_response_type *resp_type = &ap_msg->response;
int rc;
ap_msg->msg = (void *)get_zeroed_page(GFP_KERNEL);
@@ -1029,15 +1019,15 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
- ap_msg->private = &resp_type;
rc = icacrt_msg_to_type6crt_msgx(zq, ap_msg, crt);
if (rc)
goto out_free;
- init_completion(&resp_type.work);
+ resp_type->type = CEXXC_RESPONSE_TYPE_ICA;
+ init_completion(&resp_type->work);
rc = ap_queue_message(zq->queue, ap_msg);
if (rc)
goto out_free;
- rc = wait_for_completion_interruptible(&resp_type.work);
+ rc = wait_for_completion_interruptible(&resp_type->work);
if (rc == 0) {
rc = ap_msg->rc;
if (rc == 0)
@@ -1051,7 +1041,6 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
out_free:
free_page((unsigned long)ap_msg->msg);
- ap_msg->private = NULL;
ap_msg->msg = NULL;
return rc;
}
@@ -1069,9 +1058,7 @@ int prep_cca_ap_msg(bool userspace, struct ica_xcRB *xcrb,
struct ap_message *ap_msg,
unsigned int *func_code, unsigned short **dom)
{
- struct response_type resp_type = {
- .type = CEXXC_RESPONSE_TYPE_XCRB,
- };
+ struct ap_response_type *resp_type = &ap_msg->response;
ap_msg->bufsize = atomic_read(&ap_max_msg_size);
ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
@@ -1080,9 +1067,7 @@ int prep_cca_ap_msg(bool userspace, struct ica_xcRB *xcrb,
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
- ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
- if (!ap_msg->private)
- return -ENOMEM;
+ resp_type->type = CEXXC_RESPONSE_TYPE_XCRB;
return xcrb_msg_to_type6cprb_msgx(userspace, ap_msg, xcrb, func_code, dom);
}
@@ -1097,7 +1082,7 @@ static long zcrypt_msgtype6_send_cprb(bool userspace, struct zcrypt_queue *zq,
struct ica_xcRB *xcrb,
struct ap_message *ap_msg)
{
- struct response_type *rtype = ap_msg->private;
+ struct ap_response_type *resp_type = &ap_msg->response;
struct {
struct type6_hdr hdr;
struct CPRBX cprbx;
@@ -1128,11 +1113,11 @@ static long zcrypt_msgtype6_send_cprb(bool userspace, struct zcrypt_queue *zq,
msg->hdr.fromcardlen1 -= delta;
}
- init_completion(&rtype->work);
+ init_completion(&resp_type->work);
rc = ap_queue_message(zq->queue, ap_msg);
if (rc)
goto out;
- rc = wait_for_completion_interruptible(&rtype->work);
+ rc = wait_for_completion_interruptible(&resp_type->work);
if (rc == 0) {
rc = ap_msg->rc;
if (rc == 0)
@@ -1166,9 +1151,7 @@ int prep_ep11_ap_msg(bool userspace, struct ep11_urb *xcrb,
struct ap_message *ap_msg,
unsigned int *func_code, unsigned int *domain)
{
- struct response_type resp_type = {
- .type = CEXXC_RESPONSE_TYPE_EP11,
- };
+ struct ap_response_type *resp_type = &ap_msg->response;
ap_msg->bufsize = atomic_read(&ap_max_msg_size);
ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
@@ -1177,9 +1160,7 @@ int prep_ep11_ap_msg(bool userspace, struct ep11_urb *xcrb,
ap_msg->receive = zcrypt_msgtype6_receive_ep11;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
- ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
- if (!ap_msg->private)
- return -ENOMEM;
+ resp_type->type = CEXXC_RESPONSE_TYPE_EP11;
return xcrb_msg_to_type6_ep11cprb_msgx(userspace, ap_msg, xcrb,
func_code, domain);
}
@@ -1197,7 +1178,7 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue *
{
int rc;
unsigned int lfmt;
- struct response_type *rtype = ap_msg->private;
+ struct ap_response_type *resp_type = &ap_msg->response;
struct {
struct type6_hdr hdr;
struct ep11_cprb cprbx;
@@ -1251,11 +1232,11 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue *
msg->hdr.fromcardlen1 = zq->reply.bufsize -
sizeof(struct type86_hdr) - sizeof(struct type86_fmt2_ext);
- init_completion(&rtype->work);
+ init_completion(&resp_type->work);
rc = ap_queue_message(zq->queue, ap_msg);
if (rc)
goto out;
- rc = wait_for_completion_interruptible(&rtype->work);
+ rc = wait_for_completion_interruptible(&resp_type->work);
if (rc == 0) {
rc = ap_msg->rc;
if (rc == 0)
@@ -1279,9 +1260,7 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue *
int prep_rng_ap_msg(struct ap_message *ap_msg, int *func_code,
unsigned int *domain)
{
- struct response_type resp_type = {
- .type = CEXXC_RESPONSE_TYPE_XCRB,
- };
+ struct ap_response_type *resp_type = &ap_msg->response;
ap_msg->bufsize = AP_DEFAULT_MAX_MSG_SIZE;
ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
@@ -1290,9 +1269,8 @@ int prep_rng_ap_msg(struct ap_message *ap_msg, int *func_code,
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
- ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
- if (!ap_msg->private)
- return -ENOMEM;
+
+ resp_type->type = CEXXC_RESPONSE_TYPE_XCRB;
rng_type6cprb_msgx(ap_msg, ZCRYPT_RNG_BUFFER_SIZE, domain);
@@ -1319,16 +1297,16 @@ static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq,
short int verb_length;
short int key_length;
} __packed * msg = ap_msg->msg;
- struct response_type *rtype = ap_msg->private;
+ struct ap_response_type *resp_type = &ap_msg->response;
int rc;
msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
- init_completion(&rtype->work);
+ init_completion(&resp_type->work);
rc = ap_queue_message(zq->queue, ap_msg);
if (rc)
goto out;
- rc = wait_for_completion_interruptible(&rtype->work);
+ rc = wait_for_completion_interruptible(&resp_type->work);
if (rc == 0) {
rc = ap_msg->rc;
if (rc == 0)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 483/869] s390/ap/zcrypt: Rework AP message buffer allocation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (481 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 482/869] s390/ap: Move response_type struct into ap_msg struct Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 484/869] s390/ap: Introduce ap message buffer pool Greg Kroah-Hartman
` (386 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Harald Freudenberger, Holger Dengler,
Heiko Carstens, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <freude@linux.ibm.com>
[ Upstream commit 57db62a130ce69e6f3a870cf1119d8f860391f97 ]
Slight rework on the way how AP message buffers are allocated.
Instead of having multiple places with kmalloc() calls all
the AP message buffers are now allocated and freed on exactly
one place: ap_init_apmsg() allocates the current AP bus max
limit of ap_max_msg_size (defaults to 12KB). The AP message
buffer is then freed in ap_release_apmsg().
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Link: https://lore.kernel.org/r/20250424133619.16495-3-freude@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Stable-dep-of: e935cd525af4 ("s390/zcrypt: Close speculative mem read possibility")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/s390/crypto/ap_bus.c | 26 +++++++++++++
drivers/s390/crypto/ap_bus.h | 21 +----------
drivers/s390/crypto/zcrypt_api.c | 51 +++++++++++++++-----------
drivers/s390/crypto/zcrypt_msgtype50.c | 20 ++++++----
drivers/s390/crypto/zcrypt_msgtype6.c | 35 +++++++++---------
5 files changed, 87 insertions(+), 66 deletions(-)
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index e7068016a9868..64fed5dbc80f3 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -546,6 +546,32 @@ static void ap_poll_thread_stop(void)
#define is_card_dev(x) ((x)->parent == ap_root_device)
#define is_queue_dev(x) ((x)->parent != ap_root_device)
+/*
+ * ap_init_apmsg() - Initialize ap_message.
+ */
+int ap_init_apmsg(struct ap_message *ap_msg)
+{
+ unsigned int maxmsgsize = atomic_read(&ap_max_msg_size);
+
+ memset(ap_msg, 0, sizeof(*ap_msg));
+ ap_msg->msg = kmalloc(maxmsgsize, GFP_KERNEL);
+ if (!ap_msg->msg)
+ return -ENOMEM;
+ ap_msg->bufsize = maxmsgsize;
+
+ return 0;
+}
+EXPORT_SYMBOL(ap_init_apmsg);
+
+/*
+ * ap_release_apmsg() - Release ap_message.
+ */
+void ap_release_apmsg(struct ap_message *ap_msg)
+{
+ kfree_sensitive(ap_msg->msg);
+}
+EXPORT_SYMBOL(ap_release_apmsg);
+
/**
* ap_bus_match()
* @dev: Pointer to device
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index deef76c06f9a9..8b7cdd58a4ca4 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -237,25 +237,8 @@ struct ap_message {
#define AP_MSG_FLAG_USAGE 0x0002 /* CCA, EP11: usage (no admin) msg */
#define AP_MSG_FLAG_ADMIN 0x0004 /* CCA, EP11: admin (=control) msg */
-/**
- * ap_init_message() - Initialize ap_message.
- * Initialize a message before using. Otherwise this might result in
- * unexpected behaviour.
- */
-static inline void ap_init_message(struct ap_message *ap_msg)
-{
- memset(ap_msg, 0, sizeof(*ap_msg));
-}
-
-/**
- * ap_release_message() - Release ap_message.
- * Releases all memory used internal within the ap_message struct
- * Currently this is the message and private field.
- */
-static inline void ap_release_message(struct ap_message *ap_msg)
-{
- kfree_sensitive(ap_msg->msg);
-}
+int ap_init_apmsg(struct ap_message *ap_msg);
+void ap_release_apmsg(struct ap_message *ap_msg);
enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event);
enum ap_sm_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_sm_event event);
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 6bfebc3ef0a76..543f1dfe1a105 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -642,16 +642,17 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms,
struct zcrypt_queue *zq, *pref_zq;
struct ap_message ap_msg;
unsigned int wgt = 0, pref_wgt = 0;
- unsigned int func_code;
- int cpen, qpen, qid = 0, rc = -ENODEV;
+ unsigned int func_code = 0;
+ int cpen, qpen, qid = 0, rc;
struct module *mod;
trace_s390_zcrypt_req(mex, TP_ICARSAMODEXPO);
- ap_init_message(&ap_msg);
+ rc = ap_init_apmsg(&ap_msg);
+ if (rc)
+ goto out;
if (mex->outputdatalength < mex->inputdatalength) {
- func_code = 0;
rc = -EINVAL;
goto out;
}
@@ -728,7 +729,7 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms,
spin_unlock(&zcrypt_list_lock);
out:
- ap_release_message(&ap_msg);
+ ap_release_apmsg(&ap_msg);
if (tr) {
tr->last_rc = rc;
tr->last_qid = qid;
@@ -746,16 +747,17 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
struct zcrypt_queue *zq, *pref_zq;
struct ap_message ap_msg;
unsigned int wgt = 0, pref_wgt = 0;
- unsigned int func_code;
- int cpen, qpen, qid = 0, rc = -ENODEV;
+ unsigned int func_code = 0;
+ int cpen, qpen, qid = 0, rc;
struct module *mod;
trace_s390_zcrypt_req(crt, TP_ICARSACRT);
- ap_init_message(&ap_msg);
+ rc = ap_init_apmsg(&ap_msg);
+ if (rc)
+ goto out;
if (crt->outputdatalength < crt->inputdatalength) {
- func_code = 0;
rc = -EINVAL;
goto out;
}
@@ -832,7 +834,7 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
spin_unlock(&zcrypt_list_lock);
out:
- ap_release_message(&ap_msg);
+ ap_release_apmsg(&ap_msg);
if (tr) {
tr->last_rc = rc;
tr->last_qid = qid;
@@ -850,15 +852,18 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
struct zcrypt_queue *zq, *pref_zq;
struct ap_message ap_msg;
unsigned int wgt = 0, pref_wgt = 0;
- unsigned int func_code;
+ unsigned int func_code = 0;
unsigned short *domain, tdom;
- int cpen, qpen, qid = 0, rc = -ENODEV;
+ int cpen, qpen, qid = 0, rc;
struct module *mod;
trace_s390_zcrypt_req(xcrb, TB_ZSECSENDCPRB);
xcrb->status = 0;
- ap_init_message(&ap_msg);
+
+ rc = ap_init_apmsg(&ap_msg);
+ if (rc)
+ goto out;
rc = prep_cca_ap_msg(userspace, xcrb, &ap_msg, &func_code, &domain);
if (rc)
@@ -962,7 +967,7 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
spin_unlock(&zcrypt_list_lock);
out:
- ap_release_message(&ap_msg);
+ ap_release_apmsg(&ap_msg);
if (tr) {
tr->last_rc = rc;
tr->last_qid = qid;
@@ -1033,14 +1038,16 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
struct ep11_target_dev *targets;
unsigned short target_num;
unsigned int wgt = 0, pref_wgt = 0;
- unsigned int func_code, domain;
+ unsigned int func_code = 0, domain;
struct ap_message ap_msg;
- int cpen, qpen, qid = 0, rc = -ENODEV;
+ int cpen, qpen, qid = 0, rc;
struct module *mod;
trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB);
- ap_init_message(&ap_msg);
+ rc = ap_init_apmsg(&ap_msg);
+ if (rc)
+ goto out;
target_num = (unsigned short)xcrb->targets_num;
@@ -1164,7 +1171,7 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
out_free:
kfree(targets);
out:
- ap_release_message(&ap_msg);
+ ap_release_apmsg(&ap_msg);
if (tr) {
tr->last_rc = rc;
tr->last_qid = qid;
@@ -1204,7 +1211,7 @@ static long zcrypt_rng(char *buffer)
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
unsigned int wgt = 0, pref_wgt = 0;
- unsigned int func_code;
+ unsigned int func_code = 0;
struct ap_message ap_msg;
unsigned int domain;
int qid = 0, rc = -ENODEV;
@@ -1212,7 +1219,9 @@ static long zcrypt_rng(char *buffer)
trace_s390_zcrypt_req(buffer, TP_HWRNGCPRB);
- ap_init_message(&ap_msg);
+ rc = ap_init_apmsg(&ap_msg);
+ if (rc)
+ goto out;
rc = prep_rng_ap_msg(&ap_msg, &func_code, &domain);
if (rc)
goto out;
@@ -1258,7 +1267,7 @@ static long zcrypt_rng(char *buffer)
spin_unlock(&zcrypt_list_lock);
out:
- ap_release_message(&ap_msg);
+ ap_release_apmsg(&ap_msg);
trace_s390_zcrypt_rep(buffer, func_code, rc,
AP_QID_CARD(qid), AP_QID_QUEUE(qid));
return rc;
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c
index 47c401f5409b3..fc0a2a053dc22 100644
--- a/drivers/s390/crypto/zcrypt_msgtype50.c
+++ b/drivers/s390/crypto/zcrypt_msgtype50.c
@@ -449,6 +449,10 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0);
* @zq: pointer to zcrypt_queue structure that identifies the
* CEXxA device to the request distributor
* @mex: pointer to the modexpo request buffer
+ * This function assumes that ap_msg has been initialized with
+ * ap_init_apmsg() and thus a valid buffer with the size of
+ * ap_msg->bufsize is available within ap_msg. Also the caller has
+ * to make sure ap_release_apmsg() is always called even on failure.
*/
static long zcrypt_msgtype50_modexpo(struct zcrypt_queue *zq,
struct ica_rsa_modexpo *mex,
@@ -456,10 +460,8 @@ static long zcrypt_msgtype50_modexpo(struct zcrypt_queue *zq,
{
int rc;
- ap_msg->bufsize = MSGTYPE50_CRB3_MAX_MSG_SIZE;
- ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
- if (!ap_msg->msg)
- return -ENOMEM;
+ if (ap_msg->bufsize < MSGTYPE50_CRB3_MAX_MSG_SIZE)
+ return -EMSGSIZE;
ap_msg->receive = zcrypt_msgtype50_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
@@ -496,6 +498,10 @@ static long zcrypt_msgtype50_modexpo(struct zcrypt_queue *zq,
* @zq: pointer to zcrypt_queue structure that identifies the
* CEXxA device to the request distributor
* @crt: pointer to the modexpoc_crt request buffer
+ * This function assumes that ap_msg has been initialized with
+ * ap_init_apmsg() and thus a valid buffer with the size of
+ * ap_msg->bufsize is available within ap_msg. Also the caller has
+ * to make sure ap_release_apmsg() is always called even on failure.
*/
static long zcrypt_msgtype50_modexpo_crt(struct zcrypt_queue *zq,
struct ica_rsa_modexpo_crt *crt,
@@ -503,10 +509,8 @@ static long zcrypt_msgtype50_modexpo_crt(struct zcrypt_queue *zq,
{
int rc;
- ap_msg->bufsize = MSGTYPE50_CRB3_MAX_MSG_SIZE;
- ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
- if (!ap_msg->msg)
- return -ENOMEM;
+ if (ap_msg->bufsize < MSGTYPE50_CRB3_MAX_MSG_SIZE)
+ return -EMSGSIZE;
ap_msg->receive = zcrypt_msgtype50_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index 09ef91af1e2af..9cefbb30960fd 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -1050,9 +1050,10 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
* Prepare a CCA AP msg: fetch the required data from userspace,
* prepare the AP msg, fill some info into the ap_message struct,
* extract some data from the CPRB and give back to the caller.
- * This function allocates memory and needs an ap_msg prepared
- * by the caller with ap_init_message(). Also the caller has to
- * make sure ap_release_message() is always called even on failure.
+ * This function assumes that ap_msg has been initialized with
+ * ap_init_apmsg() and thus a valid buffer with the size of
+ * ap_msg->bufsize is available within ap_msg. Also the caller has
+ * to make sure ap_release_apmsg() is always called even on failure.
*/
int prep_cca_ap_msg(bool userspace, struct ica_xcRB *xcrb,
struct ap_message *ap_msg,
@@ -1060,10 +1061,6 @@ int prep_cca_ap_msg(bool userspace, struct ica_xcRB *xcrb,
{
struct ap_response_type *resp_type = &ap_msg->response;
- ap_msg->bufsize = atomic_read(&ap_max_msg_size);
- ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
- if (!ap_msg->msg)
- return -ENOMEM;
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
@@ -1143,9 +1140,10 @@ static long zcrypt_msgtype6_send_cprb(bool userspace, struct zcrypt_queue *zq,
* Prepare an EP11 AP msg: fetch the required data from userspace,
* prepare the AP msg, fill some info into the ap_message struct,
* extract some data from the CPRB and give back to the caller.
- * This function allocates memory and needs an ap_msg prepared
- * by the caller with ap_init_message(). Also the caller has to
- * make sure ap_release_message() is always called even on failure.
+ * This function assumes that ap_msg has been initialized with
+ * ap_init_apmsg() and thus a valid buffer with the size of
+ * ap_msg->bufsize is available within ap_msg. Also the caller has
+ * to make sure ap_release_apmsg() is always called even on failure.
*/
int prep_ep11_ap_msg(bool userspace, struct ep11_urb *xcrb,
struct ap_message *ap_msg,
@@ -1153,10 +1151,6 @@ int prep_ep11_ap_msg(bool userspace, struct ep11_urb *xcrb,
{
struct ap_response_type *resp_type = &ap_msg->response;
- ap_msg->bufsize = atomic_read(&ap_max_msg_size);
- ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
- if (!ap_msg->msg)
- return -ENOMEM;
ap_msg->receive = zcrypt_msgtype6_receive_ep11;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
@@ -1257,15 +1251,20 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue *
return rc;
}
+/*
+ * Prepare a CEXXC get random request ap message.
+ * This function assumes that ap_msg has been initialized with
+ * ap_init_apmsg() and thus a valid buffer with the size of
+ * ap_max_msg_size is available within ap_msg. Also the caller has
+ * to make sure ap_release_apmsg() is always called even on failure.
+ */
int prep_rng_ap_msg(struct ap_message *ap_msg, int *func_code,
unsigned int *domain)
{
struct ap_response_type *resp_type = &ap_msg->response;
- ap_msg->bufsize = AP_DEFAULT_MAX_MSG_SIZE;
- ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
- if (!ap_msg->msg)
- return -ENOMEM;
+ if (ap_msg->bufsize < AP_DEFAULT_MAX_MSG_SIZE)
+ return -EMSGSIZE;
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 484/869] s390/ap: Introduce ap message buffer pool
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (482 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 483/869] s390/ap/zcrypt: Rework AP message buffer allocation Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 485/869] s390/ap/zcrypt: New xflag parameter Greg Kroah-Hartman
` (385 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Harald Freudenberger, Holger Dengler,
Heiko Carstens, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <freude@linux.ibm.com>
[ Upstream commit dcc160b3a090b1ffa0710ed72ae325be37298c0e ]
There is a need for a do-not-allocate-memory path through the AP bus
layer. The pkey layer may be triggered via the in-kernel interface
from a protected key crypto algorithm (namely PAES) to convert a
secure key into a protected key. This happens in a workqueue context,
so sleeping is allowed but memory allocations causing IO operations
are not permitted.
To accomplish this, an AP message memory pool with pre-allocated space
is established. When ap_init_apmsg() with use_mempool set to true is
called, instead of kmalloc() the ap message buffer is allocated from
the ap_msg_pool. This pool only holds a limited amount of buffers:
ap_msg_pool_min_items with the item size AP_DEFAULT_MAX_MSG_SIZE and
exactly one of these items (if available) is returned if
ap_init_apmsg() with the use_mempool arg set to true is called. When
this pool is exhausted and use_mempool is set true, ap_init_apmsg()
returns -ENOMEM without any attempt to allocate memory and the caller
has to deal with that.
Default values for this mempool of ap messages is:
* Each buffer is 12KB (that is the default AP bus size
and all the urgent messages should fit into this space).
* Minimum items held in the pool is 8. This value is adjustable
via module parameter ap.msgpool_min_items.
The zcrypt layer may use this flag to indicate to the ap bus that the
processing path for this message should not allocate memory but should
use pre-allocated memory buffer instead. This is to prevent deadlocks
with crypto and io for example with encrypted swap volumes.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Link: https://lore.kernel.org/r/20250424133619.16495-4-freude@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Stable-dep-of: e935cd525af4 ("s390/zcrypt: Close speculative mem read possibility")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/s390/crypto/ap_bus.c | 54 ++++++++++++++++++++++++++++++--
drivers/s390/crypto/ap_bus.h | 3 +-
drivers/s390/crypto/zcrypt_api.c | 10 +++---
3 files changed, 58 insertions(+), 9 deletions(-)
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 64fed5dbc80f3..4cd88c90c6a8c 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -40,6 +40,7 @@
#include <linux/module.h>
#include <asm/uv.h>
#include <asm/chsc.h>
+#include <linux/mempool.h>
#include "ap_bus.h"
#include "ap_debug.h"
@@ -101,6 +102,27 @@ static struct ap_config_info *const ap_qci_info_old = &qci[1];
*/
debug_info_t *ap_dbf_info;
+/*
+ * There is a need for a do-not-allocate-memory path through the AP bus
+ * layer. The pkey layer may be triggered via the in-kernel interface from
+ * a protected key crypto algorithm (namely PAES) to convert a secure key
+ * into a protected key. This happens in a workqueue context, so sleeping
+ * is allowed but memory allocations causing IO operations are not permitted.
+ * To accomplish this, an AP message memory pool with pre-allocated space
+ * is established. When ap_init_apmsg() with use_mempool set to true is
+ * called, instead of kmalloc() the ap message buffer is allocated from
+ * the ap_msg_pool. This pool only holds a limited amount of buffers:
+ * ap_msg_pool_min_items with the item size AP_DEFAULT_MAX_MSG_SIZE and
+ * exactly one of these items (if available) is returned if ap_init_apmsg()
+ * with the use_mempool arg set to true is called. When this pool is exhausted
+ * and use_mempool is set true, ap_init_apmsg() returns -ENOMEM without
+ * any attempt to allocate memory and the caller has to deal with that.
+ */
+static mempool_t *ap_msg_pool;
+static unsigned int ap_msg_pool_min_items = 8;
+module_param_named(msgpool_min_items, ap_msg_pool_min_items, uint, 0440);
+MODULE_PARM_DESC(msgpool_min_items, "AP message pool minimal items");
+
/*
* AP bus rescan related things.
*/
@@ -549,11 +571,22 @@ static void ap_poll_thread_stop(void)
/*
* ap_init_apmsg() - Initialize ap_message.
*/
-int ap_init_apmsg(struct ap_message *ap_msg)
+int ap_init_apmsg(struct ap_message *ap_msg, bool use_mempool)
{
- unsigned int maxmsgsize = atomic_read(&ap_max_msg_size);
+ unsigned int maxmsgsize;
memset(ap_msg, 0, sizeof(*ap_msg));
+
+ if (use_mempool) {
+ ap_msg->msg = mempool_alloc_preallocated(ap_msg_pool);
+ if (!ap_msg->msg)
+ return -ENOMEM;
+ ap_msg->bufsize = AP_DEFAULT_MAX_MSG_SIZE;
+ ap_msg->flags |= AP_MSG_FLAG_MEMPOOL;
+ return 0;
+ }
+
+ maxmsgsize = atomic_read(&ap_max_msg_size);
ap_msg->msg = kmalloc(maxmsgsize, GFP_KERNEL);
if (!ap_msg->msg)
return -ENOMEM;
@@ -568,7 +601,12 @@ EXPORT_SYMBOL(ap_init_apmsg);
*/
void ap_release_apmsg(struct ap_message *ap_msg)
{
- kfree_sensitive(ap_msg->msg);
+ if (ap_msg->flags & AP_MSG_FLAG_MEMPOOL) {
+ memzero_explicit(ap_msg->msg, ap_msg->bufsize);
+ mempool_free(ap_msg->msg, ap_msg_pool);
+ } else {
+ kfree_sensitive(ap_msg->msg);
+ }
}
EXPORT_SYMBOL(ap_release_apmsg);
@@ -2457,6 +2495,14 @@ static int __init ap_module_init(void)
/* init ap_queue hashtable */
hash_init(ap_queues);
+ /* create ap msg buffer memory pool */
+ ap_msg_pool = mempool_create_kmalloc_pool(ap_msg_pool_min_items,
+ AP_DEFAULT_MAX_MSG_SIZE);
+ if (!ap_msg_pool) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
/* set up the AP permissions (ioctls, ap and aq masks) */
ap_perms_init();
@@ -2503,6 +2549,7 @@ static int __init ap_module_init(void)
out_bus:
bus_unregister(&ap_bus_type);
out:
+ mempool_destroy(ap_msg_pool);
ap_debug_exit();
return rc;
}
@@ -2513,6 +2560,7 @@ static void __exit ap_module_exit(void)
ap_irq_exit();
root_device_unregister(ap_root_device);
bus_unregister(&ap_bus_type);
+ mempool_destroy(ap_msg_pool);
ap_debug_exit();
}
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 8b7cdd58a4ca4..675bc6959d578 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -236,8 +236,9 @@ struct ap_message {
#define AP_MSG_FLAG_SPECIAL 0x0001 /* flag msg as 'special' with NQAP */
#define AP_MSG_FLAG_USAGE 0x0002 /* CCA, EP11: usage (no admin) msg */
#define AP_MSG_FLAG_ADMIN 0x0004 /* CCA, EP11: admin (=control) msg */
+#define AP_MSG_FLAG_MEMPOOL 0x0008 /* ap msg buffer allocated via mempool */
-int ap_init_apmsg(struct ap_message *ap_msg);
+int ap_init_apmsg(struct ap_message *ap_msg, bool use_mempool);
void ap_release_apmsg(struct ap_message *ap_msg);
enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event);
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 543f1dfe1a105..11f9793282b27 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -648,7 +648,7 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms,
trace_s390_zcrypt_req(mex, TP_ICARSAMODEXPO);
- rc = ap_init_apmsg(&ap_msg);
+ rc = ap_init_apmsg(&ap_msg, false);
if (rc)
goto out;
@@ -753,7 +753,7 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
trace_s390_zcrypt_req(crt, TP_ICARSACRT);
- rc = ap_init_apmsg(&ap_msg);
+ rc = ap_init_apmsg(&ap_msg, false);
if (rc)
goto out;
@@ -861,7 +861,7 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
xcrb->status = 0;
- rc = ap_init_apmsg(&ap_msg);
+ rc = ap_init_apmsg(&ap_msg, false);
if (rc)
goto out;
@@ -1045,7 +1045,7 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB);
- rc = ap_init_apmsg(&ap_msg);
+ rc = ap_init_apmsg(&ap_msg, false);
if (rc)
goto out;
@@ -1219,7 +1219,7 @@ static long zcrypt_rng(char *buffer)
trace_s390_zcrypt_req(buffer, TP_HWRNGCPRB);
- rc = ap_init_apmsg(&ap_msg);
+ rc = ap_init_apmsg(&ap_msg, false);
if (rc)
goto out;
rc = prep_rng_ap_msg(&ap_msg, &func_code, &domain);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 485/869] s390/ap/zcrypt: New xflag parameter
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (483 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 484/869] s390/ap: Introduce ap message buffer pool Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 486/869] s390/zcrypt: Move inline function rng_type6cprb_msgx from header to code Greg Kroah-Hartman
` (384 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Harald Freudenberger, Holger Dengler,
Heiko Carstens, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <freude@linux.ibm.com>
[ Upstream commit 80c20b2c6dc09296f2cfb438a7b919a55f31237e ]
Introduce a new flag parameter for the both cprb send functions
zcrypt_send_cprb() and zcrypt_send_ep11_cprb(). This new
xflags parameter ("execution flags") shall be used to provide
execution hints and flags for this crypto request.
There are two flags implemented to be used with these functions:
* ZCRYPT_XFLAG_USERSPACE - indicates to the lower layers that
all the ptrs address userspace. So when construction the ap msg
copy_from_user() is to be used. If this flag is NOT set, the ptrs
address kernel memory and thus memcpy() is to be used.
* ZCRYPT_XFLAG_NOMEMALLOC - indicates that this task must not
allocate memory which may be allocated with io operations.
For the AP bus and zcrypt message layer this means:
* The ZCRYPT_XFLAG_USERSPACE is mapped to the already existing
bool variable "userspace" which is propagated to the zcrypt
proto implementations.
* The ZCRYPT_XFLAG_NOMEMALLOC results in setting the AP flag
AP_MSG_FLAG_MEMPOOL when the AP msg buffer is initialized.
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Link: https://lore.kernel.org/r/20250424133619.16495-6-freude@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Stable-dep-of: e935cd525af4 ("s390/zcrypt: Close speculative mem read possibility")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/s390/crypto/ap_bus.c | 6 ++--
drivers/s390/crypto/ap_bus.h | 2 +-
drivers/s390/crypto/zcrypt_api.c | 45 ++++++++++++++++-----------
drivers/s390/crypto/zcrypt_api.h | 11 +++++--
drivers/s390/crypto/zcrypt_ccamisc.c | 16 +++++-----
drivers/s390/crypto/zcrypt_ep11misc.c | 10 +++---
6 files changed, 52 insertions(+), 38 deletions(-)
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 4cd88c90c6a8c..5ed62f46b3648 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -571,18 +571,18 @@ static void ap_poll_thread_stop(void)
/*
* ap_init_apmsg() - Initialize ap_message.
*/
-int ap_init_apmsg(struct ap_message *ap_msg, bool use_mempool)
+int ap_init_apmsg(struct ap_message *ap_msg, u32 flags)
{
unsigned int maxmsgsize;
memset(ap_msg, 0, sizeof(*ap_msg));
+ ap_msg->flags = flags;
- if (use_mempool) {
+ if (flags & AP_MSG_FLAG_MEMPOOL) {
ap_msg->msg = mempool_alloc_preallocated(ap_msg_pool);
if (!ap_msg->msg)
return -ENOMEM;
ap_msg->bufsize = AP_DEFAULT_MAX_MSG_SIZE;
- ap_msg->flags |= AP_MSG_FLAG_MEMPOOL;
return 0;
}
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 675bc6959d578..4b7ffa840563c 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -238,7 +238,7 @@ struct ap_message {
#define AP_MSG_FLAG_ADMIN 0x0004 /* CCA, EP11: admin (=control) msg */
#define AP_MSG_FLAG_MEMPOOL 0x0008 /* ap msg buffer allocated via mempool */
-int ap_init_apmsg(struct ap_message *ap_msg, bool use_mempool);
+int ap_init_apmsg(struct ap_message *ap_msg, u32 flags);
void ap_release_apmsg(struct ap_message *ap_msg);
enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event);
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 11f9793282b27..217664f22714e 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -648,7 +648,7 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms,
trace_s390_zcrypt_req(mex, TP_ICARSAMODEXPO);
- rc = ap_init_apmsg(&ap_msg, false);
+ rc = ap_init_apmsg(&ap_msg, 0);
if (rc)
goto out;
@@ -753,7 +753,7 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
trace_s390_zcrypt_req(crt, TP_ICARSACRT);
- rc = ap_init_apmsg(&ap_msg, false);
+ rc = ap_init_apmsg(&ap_msg, 0);
if (rc)
goto out;
@@ -844,10 +844,11 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
return rc;
}
-static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
+static long _zcrypt_send_cprb(u32 xflags, struct ap_perms *perms,
struct zcrypt_track *tr,
struct ica_xcRB *xcrb)
{
+ bool userspace = xflags & ZCRYPT_XFLAG_USERSPACE;
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
struct ap_message ap_msg;
@@ -861,7 +862,8 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
xcrb->status = 0;
- rc = ap_init_apmsg(&ap_msg, false);
+ rc = ap_init_apmsg(&ap_msg, xflags & ZCRYPT_XFLAG_NOMEMALLOC ?
+ AP_MSG_FLAG_MEMPOOL : 0);
if (rc)
goto out;
@@ -977,7 +979,7 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
return rc;
}
-long zcrypt_send_cprb(struct ica_xcRB *xcrb)
+long zcrypt_send_cprb(struct ica_xcRB *xcrb, u32 xflags)
{
struct zcrypt_track tr;
int rc;
@@ -985,13 +987,13 @@ long zcrypt_send_cprb(struct ica_xcRB *xcrb)
memset(&tr, 0, sizeof(tr));
do {
- rc = _zcrypt_send_cprb(false, &ap_perms, &tr, xcrb);
+ rc = _zcrypt_send_cprb(xflags, &ap_perms, &tr, xcrb);
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
/* on ENODEV failure: retry once again after a requested rescan */
if (rc == -ENODEV && zcrypt_process_rescan())
do {
- rc = _zcrypt_send_cprb(false, &ap_perms, &tr, xcrb);
+ rc = _zcrypt_send_cprb(xflags, &ap_perms, &tr, xcrb);
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
rc = -EIO;
@@ -1029,10 +1031,11 @@ static bool is_desired_ep11_queue(unsigned int dev_qid,
return false;
}
-static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
+static long _zcrypt_send_ep11_cprb(u32 xflags, struct ap_perms *perms,
struct zcrypt_track *tr,
struct ep11_urb *xcrb)
{
+ bool userspace = xflags & ZCRYPT_XFLAG_USERSPACE;
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
struct ep11_target_dev *targets;
@@ -1045,7 +1048,8 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB);
- rc = ap_init_apmsg(&ap_msg, false);
+ rc = ap_init_apmsg(&ap_msg, xflags & ZCRYPT_XFLAG_NOMEMALLOC ?
+ AP_MSG_FLAG_MEMPOOL : 0);
if (rc)
goto out;
@@ -1181,7 +1185,7 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
return rc;
}
-long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
+long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb, u32 xflags)
{
struct zcrypt_track tr;
int rc;
@@ -1189,13 +1193,13 @@ long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
memset(&tr, 0, sizeof(tr));
do {
- rc = _zcrypt_send_ep11_cprb(false, &ap_perms, &tr, xcrb);
+ rc = _zcrypt_send_ep11_cprb(xflags, &ap_perms, &tr, xcrb);
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
/* on ENODEV failure: retry once again after a requested rescan */
if (rc == -ENODEV && zcrypt_process_rescan())
do {
- rc = _zcrypt_send_ep11_cprb(false, &ap_perms, &tr, xcrb);
+ rc = _zcrypt_send_ep11_cprb(xflags, &ap_perms, &tr, xcrb);
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
rc = -EIO;
@@ -1219,7 +1223,7 @@ static long zcrypt_rng(char *buffer)
trace_s390_zcrypt_req(buffer, TP_HWRNGCPRB);
- rc = ap_init_apmsg(&ap_msg, false);
+ rc = ap_init_apmsg(&ap_msg, 0);
if (rc)
goto out;
rc = prep_rng_ap_msg(&ap_msg, &func_code, &domain);
@@ -1532,6 +1536,7 @@ static int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg)
int rc;
struct ica_xcRB xcrb;
struct zcrypt_track tr;
+ u32 xflags = ZCRYPT_XFLAG_USERSPACE;
struct ica_xcRB __user *uxcrb = (void __user *)arg;
memset(&tr, 0, sizeof(tr));
@@ -1539,13 +1544,13 @@ static int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg)
return -EFAULT;
do {
- rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb);
+ rc = _zcrypt_send_cprb(xflags, perms, &tr, &xcrb);
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
/* on ENODEV failure: retry once again after a requested rescan */
if (rc == -ENODEV && zcrypt_process_rescan())
do {
- rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb);
+ rc = _zcrypt_send_cprb(xflags, perms, &tr, &xcrb);
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
rc = -EIO;
@@ -1562,6 +1567,7 @@ static int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg)
int rc;
struct ep11_urb xcrb;
struct zcrypt_track tr;
+ u32 xflags = ZCRYPT_XFLAG_USERSPACE;
struct ep11_urb __user *uxcrb = (void __user *)arg;
memset(&tr, 0, sizeof(tr));
@@ -1569,13 +1575,13 @@ static int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg)
return -EFAULT;
do {
- rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb);
+ rc = _zcrypt_send_ep11_cprb(xflags, perms, &tr, &xcrb);
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
/* on ENODEV failure: retry once again after a requested rescan */
if (rc == -ENODEV && zcrypt_process_rescan())
do {
- rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb);
+ rc = _zcrypt_send_ep11_cprb(xflags, perms, &tr, &xcrb);
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
rc = -EIO;
@@ -1836,6 +1842,7 @@ static long trans_xcrb32(struct ap_perms *perms, struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct compat_ica_xcrb __user *uxcrb32 = compat_ptr(arg);
+ u32 xflags = ZCRYPT_XFLAG_USERSPACE;
struct compat_ica_xcrb xcrb32;
struct zcrypt_track tr;
struct ica_xcRB xcrb64;
@@ -1865,13 +1872,13 @@ static long trans_xcrb32(struct ap_perms *perms, struct file *filp,
xcrb64.priority_window = xcrb32.priority_window;
xcrb64.status = xcrb32.status;
do {
- rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb64);
+ rc = _zcrypt_send_cprb(xflags, perms, &tr, &xcrb64);
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
/* on ENODEV failure: retry once again after a requested rescan */
if (rc == -ENODEV && zcrypt_process_rescan())
do {
- rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb64);
+ rc = _zcrypt_send_cprb(xflags, perms, &tr, &xcrb64);
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
rc = -EIO;
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
index 4ed481df57ca4..44f1583295451 100644
--- a/drivers/s390/crypto/zcrypt_api.h
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -76,6 +76,13 @@ struct zcrypt_track {
#define TRACK_AGAIN_CARD_WEIGHT_PENALTY 1000
#define TRACK_AGAIN_QUEUE_WEIGHT_PENALTY 10000
+/*
+ * xflags - to be used with zcrypt_send_cprb() and
+ * zcrypt_send_ep11_cprb() for the xflags parameter.
+ */
+#define ZCRYPT_XFLAG_USERSPACE 0x0001 /* data ptrs address userspace */
+#define ZCRYPT_XFLAG_NOMEMALLOC 0x0002 /* do not allocate memory via kmalloc */
+
struct zcrypt_ops {
long (*rsa_modexpo)(struct zcrypt_queue *, struct ica_rsa_modexpo *,
struct ap_message *);
@@ -161,8 +168,8 @@ void zcrypt_msgtype_unregister(struct zcrypt_ops *);
struct zcrypt_ops *zcrypt_msgtype(unsigned char *, int);
int zcrypt_api_init(void);
void zcrypt_api_exit(void);
-long zcrypt_send_cprb(struct ica_xcRB *xcRB);
-long zcrypt_send_ep11_cprb(struct ep11_urb *urb);
+long zcrypt_send_cprb(struct ica_xcRB *xcRB, u32 xflags);
+long zcrypt_send_ep11_cprb(struct ep11_urb *urb, u32 xflags);
void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus);
int zcrypt_device_status_ext(int card, int queue,
struct zcrypt_device_status_ext *devstatus);
diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c
index c84aa0bdfcae3..f46819cfa5f0f 100644
--- a/drivers/s390/crypto/zcrypt_ccamisc.c
+++ b/drivers/s390/crypto/zcrypt_ccamisc.c
@@ -415,7 +415,7 @@ int cca_genseckey(u16 cardnr, u16 domain,
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
- rc = zcrypt_send_cprb(&xcrb);
+ rc = zcrypt_send_cprb(&xcrb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, errno %d\n",
__func__, (int)cardnr, (int)domain, rc);
@@ -554,7 +554,7 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
- rc = zcrypt_send_cprb(&xcrb);
+ rc = zcrypt_send_cprb(&xcrb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
__func__, (int)cardnr, (int)domain, rc);
@@ -682,7 +682,7 @@ int cca_sec2protkey(u16 cardnr, u16 domain,
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
- rc = zcrypt_send_cprb(&xcrb);
+ rc = zcrypt_send_cprb(&xcrb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
__func__, (int)cardnr, (int)domain, rc);
@@ -911,7 +911,7 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
- rc = zcrypt_send_cprb(&xcrb);
+ rc = zcrypt_send_cprb(&xcrb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
__func__, (int)cardnr, (int)domain, rc);
@@ -1083,7 +1083,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
- rc = zcrypt_send_cprb(&xcrb);
+ rc = zcrypt_send_cprb(&xcrb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
__func__, (int)cardnr, (int)domain, rc);
@@ -1302,7 +1302,7 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
- rc = zcrypt_send_cprb(&xcrb);
+ rc = zcrypt_send_cprb(&xcrb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
__func__, (int)cardnr, (int)domain, rc);
@@ -1468,7 +1468,7 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
- rc = zcrypt_send_cprb(&xcrb);
+ rc = zcrypt_send_cprb(&xcrb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
__func__, (int)cardnr, (int)domain, rc);
@@ -1582,7 +1582,7 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain,
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
- rc = zcrypt_send_cprb(&xcrb);
+ rc = zcrypt_send_cprb(&xcrb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
__func__, (int)cardnr, (int)domain, rc);
diff --git a/drivers/s390/crypto/zcrypt_ep11misc.c b/drivers/s390/crypto/zcrypt_ep11misc.c
index cb7e6da43602d..b60e262bcaa38 100644
--- a/drivers/s390/crypto/zcrypt_ep11misc.c
+++ b/drivers/s390/crypto/zcrypt_ep11misc.c
@@ -636,7 +636,7 @@ static int ep11_query_info(u16 cardnr, u16 domain, u32 query_type,
req, sizeof(*req) + sizeof(*req_pl),
rep, sizeof(*rep) + sizeof(*rep_pl) + buflen);
- rc = zcrypt_send_ep11_cprb(urb);
+ rc = zcrypt_send_ep11_cprb(urb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
__func__, (int)cardnr, (int)domain, rc);
@@ -892,7 +892,7 @@ static int _ep11_genaeskey(u16 card, u16 domain,
req, sizeof(*req) + req_pl_size,
rep, sizeof(*rep) + sizeof(*rep_pl));
- rc = zcrypt_send_ep11_cprb(urb);
+ rc = zcrypt_send_ep11_cprb(urb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
__func__, (int)card, (int)domain, rc);
@@ -1049,7 +1049,7 @@ static int ep11_cryptsingle(u16 card, u16 domain,
req, sizeof(*req) + req_pl_size,
rep, sizeof(*rep) + rep_pl_size);
- rc = zcrypt_send_ep11_cprb(urb);
+ rc = zcrypt_send_ep11_cprb(urb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
__func__, (int)card, (int)domain, rc);
@@ -1212,7 +1212,7 @@ static int _ep11_unwrapkey(u16 card, u16 domain,
req, sizeof(*req) + req_pl_size,
rep, sizeof(*rep) + sizeof(*rep_pl));
- rc = zcrypt_send_ep11_cprb(urb);
+ rc = zcrypt_send_ep11_cprb(urb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
__func__, (int)card, (int)domain, rc);
@@ -1372,7 +1372,7 @@ static int _ep11_wrapkey(u16 card, u16 domain,
req, sizeof(*req) + req_pl_size,
rep, sizeof(*rep) + sizeof(*rep_pl));
- rc = zcrypt_send_ep11_cprb(urb);
+ rc = zcrypt_send_ep11_cprb(urb, 0);
if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
__func__, (int)card, (int)domain, rc);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 486/869] s390/zcrypt: Move inline function rng_type6cprb_msgx from header to code
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (484 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 485/869] s390/ap/zcrypt: New xflag parameter Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 487/869] s390/zcrypt: Rework domain processing within zcrypt device driver Greg Kroah-Hartman
` (383 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Holger Dengler, Anthony Krowiak,
Harald Freudenberger, Heiko Carstens, Vasily Gorbik, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <freude@linux.ibm.com>
[ Upstream commit 23a4757d6d699e602b358808359149d0e8be6db9 ]
Function rng_type6cprb_msgx() is only used once and thus no need
to provide it in header file any more. Move it at the place within
the code where it is used.
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Acked-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Stable-dep-of: e935cd525af4 ("s390/zcrypt: Close speculative mem read possibility")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/s390/crypto/zcrypt_msgtype6.c | 49 +++++++++++++++++++++++++++
drivers/s390/crypto/zcrypt_msgtype6.h | 49 ---------------------------
2 files changed, 49 insertions(+), 49 deletions(-)
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index 9cefbb30960fd..f6adb8ba3f95c 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -1251,6 +1251,55 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue *
return rc;
}
+/**
+ * Prepare a type6 CPRB message for random number generation
+ *
+ * @ap_dev: AP device pointer
+ * @ap_msg: pointer to AP message
+ */
+static inline void rng_type6cprb_msgx(struct ap_message *ap_msg,
+ unsigned int random_number_length,
+ unsigned int *domain)
+{
+ struct {
+ struct type6_hdr hdr;
+ struct CPRBX cprbx;
+ char function_code[2];
+ short int rule_length;
+ char rule[8];
+ short int verb_length;
+ short int key_length;
+ } __packed * msg = ap_msg->msg;
+ static struct type6_hdr static_type6_hdrX = {
+ .type = 0x06,
+ .offset1 = 0x00000058,
+ .agent_id = {'C', 'A'},
+ .function_code = {'R', 'L'},
+ .tocardlen1 = sizeof(*msg) - sizeof(msg->hdr),
+ .fromcardlen1 = sizeof(*msg) - sizeof(msg->hdr),
+ };
+ static struct CPRBX local_cprbx = {
+ .cprb_len = 0x00dc,
+ .cprb_ver_id = 0x02,
+ .func_id = {0x54, 0x32},
+ .req_parml = sizeof(*msg) - sizeof(msg->hdr) -
+ sizeof(msg->cprbx),
+ .rpl_msgbl = sizeof(*msg) - sizeof(msg->hdr),
+ };
+
+ msg->hdr = static_type6_hdrX;
+ msg->hdr.fromcardlen2 = random_number_length;
+ msg->cprbx = local_cprbx;
+ msg->cprbx.rpl_datal = random_number_length;
+ memcpy(msg->function_code, msg->hdr.function_code, 0x02);
+ msg->rule_length = 0x0a;
+ memcpy(msg->rule, "RANDOM ", 8);
+ msg->verb_length = 0x02;
+ msg->key_length = 0x02;
+ ap_msg->len = sizeof(*msg);
+ *domain = (unsigned short)msg->cprbx.domain;
+}
+
/*
* Prepare a CEXXC get random request ap message.
* This function assumes that ap_msg has been initialized with
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h
index 6f5ced8d6cdae..9f7510019bc45 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.h
+++ b/drivers/s390/crypto/zcrypt_msgtype6.h
@@ -110,55 +110,6 @@ int prep_rng_ap_msg(struct ap_message *ap_msg,
int speed_idx_cca(int);
int speed_idx_ep11(int);
-/**
- * Prepare a type6 CPRB message for random number generation
- *
- * @ap_dev: AP device pointer
- * @ap_msg: pointer to AP message
- */
-static inline void rng_type6cprb_msgx(struct ap_message *ap_msg,
- unsigned int random_number_length,
- unsigned int *domain)
-{
- struct {
- struct type6_hdr hdr;
- struct CPRBX cprbx;
- char function_code[2];
- short int rule_length;
- char rule[8];
- short int verb_length;
- short int key_length;
- } __packed * msg = ap_msg->msg;
- static struct type6_hdr static_type6_hdrX = {
- .type = 0x06,
- .offset1 = 0x00000058,
- .agent_id = {'C', 'A'},
- .function_code = {'R', 'L'},
- .tocardlen1 = sizeof(*msg) - sizeof(msg->hdr),
- .fromcardlen1 = sizeof(*msg) - sizeof(msg->hdr),
- };
- static struct CPRBX local_cprbx = {
- .cprb_len = 0x00dc,
- .cprb_ver_id = 0x02,
- .func_id = {0x54, 0x32},
- .req_parml = sizeof(*msg) - sizeof(msg->hdr) -
- sizeof(msg->cprbx),
- .rpl_msgbl = sizeof(*msg) - sizeof(msg->hdr),
- };
-
- msg->hdr = static_type6_hdrX;
- msg->hdr.fromcardlen2 = random_number_length;
- msg->cprbx = local_cprbx;
- msg->cprbx.rpl_datal = random_number_length;
- memcpy(msg->function_code, msg->hdr.function_code, 0x02);
- msg->rule_length = 0x0a;
- memcpy(msg->rule, "RANDOM ", 8);
- msg->verb_length = 0x02;
- msg->key_length = 0x02;
- ap_msg->len = sizeof(*msg);
- *domain = (unsigned short)msg->cprbx.domain;
-}
-
void zcrypt_msgtype6_init(void);
void zcrypt_msgtype6_exit(void);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 487/869] s390/zcrypt: Rework domain processing within zcrypt device driver
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (485 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 486/869] s390/zcrypt: Move inline function rng_type6cprb_msgx from header to code Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 488/869] s390/zcrypt: Close speculative mem read possibility Greg Kroah-Hartman
` (382 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Holger Dengler, Harald Freudenberger,
Heiko Carstens, Vasily Gorbik, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <freude@linux.ibm.com>
[ Upstream commit e2c6d91eb8b1533753755f07803e47eceed263d0 ]
Slight rework of the domain handling within the zcrypt dd:
Remove this curious construct to give a pointer to the
domain field within the CPRB struct to the zcrypt API and
later fill in the target domain via this pointer.
Now the domain is filled in with the send function when
the ready constructed AP message is about to be pushed
down into the software queue for AP queue processing.
So now the domain handling for CCA, EP11 and (internal) rng
CPRBs is the same. With this comes a slight reshuffle of the
code related to domain processing in the zcrypt API and the
message type 60 protocol implementation code.
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Acked-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Stable-dep-of: e935cd525af4 ("s390/zcrypt: Close speculative mem read possibility")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/s390/crypto/zcrypt_api.c | 36 +++++++++++----------------
drivers/s390/crypto/zcrypt_msgtype6.c | 22 ++++++++++------
drivers/s390/crypto/zcrypt_msgtype6.h | 2 +-
3 files changed, 29 insertions(+), 31 deletions(-)
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 217664f22714e..df1f9dc6a37ad 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -849,13 +849,12 @@ static long _zcrypt_send_cprb(u32 xflags, struct ap_perms *perms,
struct ica_xcRB *xcrb)
{
bool userspace = xflags & ZCRYPT_XFLAG_USERSPACE;
- struct zcrypt_card *zc, *pref_zc;
- struct zcrypt_queue *zq, *pref_zq;
- struct ap_message ap_msg;
+ unsigned int domain, func_code = 0;
unsigned int wgt = 0, pref_wgt = 0;
- unsigned int func_code = 0;
- unsigned short *domain, tdom;
+ struct zcrypt_queue *zq, *pref_zq;
+ struct zcrypt_card *zc, *pref_zc;
int cpen, qpen, qid = 0, rc;
+ struct ap_message ap_msg;
struct module *mod;
trace_s390_zcrypt_req(xcrb, TB_ZSECSENDCPRB);
@@ -873,10 +872,9 @@ static long _zcrypt_send_cprb(u32 xflags, struct ap_perms *perms,
print_hex_dump_debug("ccareq: ", DUMP_PREFIX_ADDRESS, 16, 1,
ap_msg.msg, ap_msg.len, false);
- tdom = *domain;
- if (perms != &ap_perms && tdom < AP_DOMAINS) {
+ if (perms != &ap_perms && domain < AP_DOMAINS) {
if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
- if (!test_bit_inv(tdom, perms->adm)) {
+ if (!test_bit_inv(domain, perms->adm)) {
rc = -ENODEV;
goto out;
}
@@ -889,10 +887,10 @@ static long _zcrypt_send_cprb(u32 xflags, struct ap_perms *perms,
* If a valid target domain is set and this domain is NOT a usage
* domain but a control only domain, autoselect target domain.
*/
- if (tdom < AP_DOMAINS &&
- !ap_test_config_usage_domain(tdom) &&
- ap_test_config_ctrl_domain(tdom))
- tdom = AUTOSEL_DOM;
+ if (domain < AP_DOMAINS &&
+ !ap_test_config_usage_domain(domain) &&
+ ap_test_config_ctrl_domain(domain))
+ domain = AUTOSEL_DOM;
pref_zc = NULL;
pref_zq = NULL;
@@ -924,8 +922,8 @@ static long _zcrypt_send_cprb(u32 xflags, struct ap_perms *perms,
/* check for device usable and eligible */
if (!zq->online || !zq->ops->send_cprb ||
!ap_queue_usable(zq->queue) ||
- (tdom != AUTOSEL_DOM &&
- tdom != AP_QID_QUEUE(zq->queue->qid)))
+ (domain != AUTOSEL_DOM &&
+ domain != AP_QID_QUEUE(zq->queue->qid)))
continue;
/* check if device node has admission for this queue */
if (!zcrypt_check_queue(perms,
@@ -948,16 +946,11 @@ static long _zcrypt_send_cprb(u32 xflags, struct ap_perms *perms,
if (!pref_zq) {
pr_debug("no match for address %02x.%04x => ENODEV\n",
- xcrb->user_defined, *domain);
+ xcrb->user_defined, domain);
rc = -ENODEV;
goto out;
}
- /* in case of auto select, provide the correct domain */
- qid = pref_zq->queue->qid;
- if (*domain == AUTOSEL_DOM)
- *domain = AP_QID_QUEUE(qid);
-
rc = pref_zq->ops->send_cprb(userspace, pref_zq, xcrb, &ap_msg);
if (!rc) {
print_hex_dump_debug("ccarpl: ", DUMP_PREFIX_ADDRESS, 16, 1,
@@ -1217,7 +1210,6 @@ static long zcrypt_rng(char *buffer)
unsigned int wgt = 0, pref_wgt = 0;
unsigned int func_code = 0;
struct ap_message ap_msg;
- unsigned int domain;
int qid = 0, rc = -ENODEV;
struct module *mod;
@@ -1226,7 +1218,7 @@ static long zcrypt_rng(char *buffer)
rc = ap_init_apmsg(&ap_msg, 0);
if (rc)
goto out;
- rc = prep_rng_ap_msg(&ap_msg, &func_code, &domain);
+ rc = prep_rng_ap_msg(&ap_msg, &func_code, NULL);
if (rc)
goto out;
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index f6adb8ba3f95c..352d5c15f7dcc 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -329,7 +329,7 @@ struct type86_fmt2_msg {
static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg,
struct ica_xcRB *xcrb,
unsigned int *fcode,
- unsigned short **dom)
+ unsigned int *domain)
{
static struct type6_hdr static_type6_hdrX = {
.type = 0x06,
@@ -413,7 +413,8 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg,
sizeof(msg->hdr.function_code));
*fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1];
- *dom = (unsigned short *)&msg->cprbx.domain;
+ if (domain)
+ *domain = msg->cprbx.domain;
/* check subfunction, US and AU need special flag with NQAP */
if (memcmp(function_code, "US", 2) == 0 ||
@@ -530,7 +531,8 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap
else
ap_msg->flags |= AP_MSG_FLAG_USAGE;
- *domain = msg->cprbx.target_id;
+ if (domain)
+ *domain = msg->cprbx.target_id;
return 0;
}
@@ -1057,7 +1059,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
*/
int prep_cca_ap_msg(bool userspace, struct ica_xcRB *xcrb,
struct ap_message *ap_msg,
- unsigned int *func_code, unsigned short **dom)
+ unsigned int *func_code, unsigned int *domain)
{
struct ap_response_type *resp_type = &ap_msg->response;
@@ -1065,7 +1067,8 @@ int prep_cca_ap_msg(bool userspace, struct ica_xcRB *xcrb,
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
resp_type->type = CEXXC_RESPONSE_TYPE_XCRB;
- return xcrb_msg_to_type6cprb_msgx(userspace, ap_msg, xcrb, func_code, dom);
+ return xcrb_msg_to_type6cprb_msgx(userspace, ap_msg,
+ xcrb, func_code, domain);
}
/*
@@ -1110,6 +1113,9 @@ static long zcrypt_msgtype6_send_cprb(bool userspace, struct zcrypt_queue *zq,
msg->hdr.fromcardlen1 -= delta;
}
+ /* update domain field within the CPRB struct */
+ msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
+
init_completion(&resp_type->work);
rc = ap_queue_message(zq->queue, ap_msg);
if (rc)
@@ -1215,8 +1221,7 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue *
lfmt = 1; /* length format #1 */
}
payload_hdr = (struct pld_hdr *)((&msg->pld_lenfmt) + lfmt);
- payload_hdr->dom_val = (unsigned int)
- AP_QID_QUEUE(zq->queue->qid);
+ payload_hdr->dom_val = AP_QID_QUEUE(zq->queue->qid);
}
/*
@@ -1297,7 +1302,8 @@ static inline void rng_type6cprb_msgx(struct ap_message *ap_msg,
msg->verb_length = 0x02;
msg->key_length = 0x02;
ap_msg->len = sizeof(*msg);
- *domain = (unsigned short)msg->cprbx.domain;
+ if (domain)
+ *domain = msg->cprbx.domain;
}
/*
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h
index 9f7510019bc45..9cbe6e2b2d33c 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.h
+++ b/drivers/s390/crypto/zcrypt_msgtype6.h
@@ -96,7 +96,7 @@ struct type86_fmt2_ext {
int prep_cca_ap_msg(bool userspace, struct ica_xcRB *xcrb,
struct ap_message *ap_msg,
- unsigned int *fc, unsigned short **dom);
+ unsigned int *fc, unsigned int *dom);
int prep_ep11_ap_msg(bool userspace, struct ep11_urb *xcrb,
struct ap_message *ap_msg,
unsigned int *fc, unsigned int *dom);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 488/869] s390/zcrypt: Close speculative mem read possibility
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (486 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 487/869] s390/zcrypt: Rework domain processing within zcrypt device driver Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 489/869] afs: Fix UAF when sending a message Greg Kroah-Hartman
` (381 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Borntraeger, Finn Callies,
Harald Freudenberger, Vasily Gorbik, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <freude@linux.ibm.com>
[ Upstream commit e935cd525af4c6ed2e2c6404aa27ca19c7f39ddb ]
The domain value is extracted from a given CCA or EP11 ioctl struct
when a CPRB is about to be sent. Thus this is a user controlled value.
Under some special conditions (custom device node used, administrative
load) this value is used as an array index after bounds checking, but
without speculation barrier.
Add the missing array_index_nospec() call to prevent speculative
execution where this domain value is used.
Fixes: cfd68b33094e ("s390/zcrypt: Filter admin CPRBs on custom devices")
Cc: stable@vger.kernel.org
Reported-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/s390/crypto/zcrypt_api.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index df1f9dc6a37ad..0ded84744b1ee 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -874,6 +874,7 @@ static long _zcrypt_send_cprb(u32 xflags, struct ap_perms *perms,
if (perms != &ap_perms && domain < AP_DOMAINS) {
if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
+ domain = array_index_nospec(domain, AP_DOMAINS);
if (!test_bit_inv(domain, perms->adm)) {
rc = -ENODEV;
goto out;
@@ -1077,6 +1078,7 @@ static long _zcrypt_send_ep11_cprb(u32 xflags, struct ap_perms *perms,
if (perms != &ap_perms && domain < AP_DOMAINS) {
if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
+ domain = array_index_nospec(domain, AP_DOMAINS);
if (!test_bit_inv(domain, perms->adm)) {
rc = -ENODEV;
goto out_free;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 489/869] afs: Fix UAF when sending a message
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (487 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 488/869] s390/zcrypt: Close speculative mem read possibility Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 490/869] dibs: fix use-after-free of dmb_node in loopback attach/detach/unregister Greg Kroah-Hartman
` (380 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Marc Dionne, David Howells,
Jeffrey Altman, linux-afs, stable, Christian Brauner (Amutable),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit 4af1ec68d54b3871155914d584fb10669c41a861 ]
In afs_make_call(), there's a race with async call reception and
destruction. If a call is dispatched that doesn't have call->write_iter
set (used to specify the data content for FS.StoreData), then the first
rxrpc_kernel_send_data() will not set MSG_MORE in the msghdr.
Once rxrpc_send_data() queues the last request packet, the response could
come in at any time and cause the call to be completed and put. However,
afs_make_call() will look at the call again to see it ->write_iter should
be handled - something it's only allowed to do if it has its own ref on the
call. Whilst this is the case for synchronous calls, it isn't true for
async calls such as FS.FetchData.
There's also a potential UAF in afs_make_call() in the event that an
asynchronous call is being sent, but the call fails in some way (e.g. it
gets aborted from the server). The problem there is that afs_make_call()
tries to abort a call if the rxrpc send fails, but the asynchronous
notification from rxrpc may have caused the afs_call to be torn down.
generic/650 plays games with randomly taking CPUs offline, and can
interject a significant delay such that the call is deallocated before
afs_make_call() gets to check call->write_iter - and a UAF ensues (caught
by KASAN).
BUG: KASAN: slab-use-after-free in afs_make_call+0x1c90/0x2210 [kafs]
Read of size 8 at addr ffff888035e050e8 by task fsstress/1409
Fix this by making afs_make_op_call() give the op->call its own ref rather
than transferring the caller's ref to it and then dropping the ref when
afs_make_call() returns.
This also means that the afs_make_call() func never loses its ref on the
call now.
Fixes: eddf51f2bb2c ("afs: Make {Y,}FS.FetchData an asynchronous operation")
Fixes: e49c7b2f6de7 ("afs: Build an abstraction around an "operation" concept")
Link: https://sashiko.dev/#/patchset/20260702144919.172295-1-dhowells%40redhat.com
Reported-by: Marc Dionne <marc.dionne@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260723113452.566619-4-dhowells@redhat.com
cc: Jeffrey Altman <jaltman@auristor.com>
cc: linux-afs@lists.infradead.org
cc: stable@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/afs/internal.h | 4 +++-
fs/afs/rxrpc.c | 4 ++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index beaedbb3a01ce..a1090863ea465 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -1336,6 +1336,7 @@ extern int __net_init afs_open_socket(struct afs_net *);
extern void __net_exit afs_close_socket(struct afs_net *);
extern void afs_charge_preallocation(struct work_struct *);
extern void afs_put_call(struct afs_call *);
+extern struct afs_call *afs_get_call(struct afs_call *call, enum afs_call_trace why);
void afs_deferred_put_call(struct afs_call *call);
void afs_make_call(struct afs_call *call, gfp_t gfp);
void afs_wait_for_call_to_complete(struct afs_call *call);
@@ -1362,7 +1363,7 @@ static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *c
{
struct afs_addr_list *alist = op->estate->addresses;
- op->call = call;
+ op->call = afs_get_call(call, afs_call_trace_get);
op->type = call->type;
call->op = op;
call->key = op->key;
@@ -1370,6 +1371,7 @@ static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *c
call->peer = rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer);
call->service_id = op->server->service_id;
afs_make_call(call, gfp);
+ afs_put_call(call);
}
static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index c35c2332c5b72..12bafd03fd59a 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -247,8 +247,8 @@ void afs_deferred_put_call(struct afs_call *call)
schedule_work(&call->free_work);
}
-static struct afs_call *afs_get_call(struct afs_call *call,
- enum afs_call_trace why)
+struct afs_call *afs_get_call(struct afs_call *call,
+ enum afs_call_trace why)
{
int r;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 490/869] dibs: fix use-after-free of dmb_node in loopback attach/detach/unregister
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (488 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 489/869] afs: Fix UAF when sending a message Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 491/869] iommu/iommufd: Fix IOPF group ownership UAF Greg Kroah-Hartman
` (379 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rahul Chandelkar, Hidayath Khan,
Alexandra Winter, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hidayath Khan <hidayath@linux.ibm.com>
[ Upstream commit a10ea943356b9d70c5616a0a06f6fa97cfdaccb1 ]
dibs_lo_attach_dmb(), dibs_lo_detach_dmb() and dibs_lo_unregister_dmb()
look up the dmb_node under dmb_ht_lock, drop the lock and only then
operate on the node's refcount. Nothing keeps the node alive across
that window: __dibs_lo_unregister_dmb() removes the node from the hash
table under the write lock and immediately frees it.
A concurrent final put can therefore free the node between the lookup
and the refcount operation:
CPU0 (attach) CPU1 (owner unregisters)
read_lock_bh(&dmb_ht_lock)
find dmb_node (refcnt == 1)
read_unlock_bh(&dmb_ht_lock)
refcount_dec_and_test() 1 -> 0
write_lock_bh(&dmb_ht_lock)
hash_del(&dmb_node->list)
write_unlock_bh(&dmb_ht_lock)
kfree(dmb_node)
refcount_inc_not_zero(&dmb_node->refcnt) <-- use-after-free
The same window exists for the refcount_dec_and_test() calls in the
detach and unregister paths.
Close the race structurally by making hash table membership and the
refcount transitions atomic with respect to each other:
- Perform the final refcount_dec_and_test() and hash_del() in a single
dmb_ht_lock write-side critical section, in both the unregister and
the detach path. Freeing the node still happens after the lock is
dropped, which is safe because a node whose refcount reached zero has
left the hash table and can no longer be found.
- This establishes the invariant that any node found in the hash table
holds at least one reference, and that the final reference can only
be dropped under the write lock. dibs_lo_attach_dmb() can thus take
its reference with a plain refcount_inc() while still holding the
read lock; refcount_inc_not_zero() is no longer needed.
__dibs_lo_unregister_dmb() no longer touches the hash table and is
renamed to dibs_lo_free_dmb() accordingly.
Note: commit cc21191b584c ("dibs: Move data path to dibs layer") moved
the code to its current location; the race was introduced earlier by
commit c3a910f2380f ("net/smc: implement DMB-merged operations of
loopback-ism").
Tested SMC-D via ISM and dibs loopback.
Cc: stable@vger.kernel.org
Fixes: c3a910f2380f ("net/smc: implement DMB-merged operations of loopback-ism")
Reported-by: Rahul Chandelkar <rc@rexion.ai>
Signed-off-by: Hidayath Khan <hidayath@linux.ibm.com>
Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
Link: https://patch.msgid.link/20260727093530.968834-1-hidayath@linux.ibm.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/smc/smc_loopback.c | 45 +++++++++++++++++++++---------------------
1 file changed, 22 insertions(+), 23 deletions(-)
diff --git a/net/smc/smc_loopback.c b/net/smc/smc_loopback.c
index 0bf9e4075f033..cb72ff920578a 100644
--- a/net/smc/smc_loopback.c
+++ b/net/smc/smc_loopback.c
@@ -117,14 +117,9 @@ static int smc_lo_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
return rc;
}
-static void __smc_lo_unregister_dmb(struct smc_lo_dev *ldev,
- struct smc_lo_dmb_node *dmb_node)
+static void smc_lo_free_dmb(struct smc_lo_dev *ldev,
+ struct smc_lo_dmb_node *dmb_node)
{
- /* remove dmb from hash table */
- write_lock_bh(&ldev->dmb_ht_lock);
- hash_del(&dmb_node->list);
- write_unlock_bh(&ldev->dmb_ht_lock);
-
clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
folio_put(virt_to_folio(dmb_node->cpu_addr));
kfree(dmb_node);
@@ -137,9 +132,10 @@ static int smc_lo_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
{
struct smc_lo_dmb_node *dmb_node = NULL, *tmp_node;
struct smc_lo_dev *ldev = smcd->priv;
+ bool last;
/* find dmb from hash table */
- read_lock_bh(&ldev->dmb_ht_lock);
+ write_lock_bh(&ldev->dmb_ht_lock);
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
if (tmp_node->token == dmb->dmb_tok) {
dmb_node = tmp_node;
@@ -147,13 +143,16 @@ static int smc_lo_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
}
}
if (!dmb_node) {
- read_unlock_bh(&ldev->dmb_ht_lock);
+ write_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
}
- read_unlock_bh(&ldev->dmb_ht_lock);
+ last = refcount_dec_and_test(&dmb_node->refcnt);
+ if (last)
+ hash_del(&dmb_node->list);
+ write_unlock_bh(&ldev->dmb_ht_lock);
- if (refcount_dec_and_test(&dmb_node->refcnt))
- __smc_lo_unregister_dmb(ldev, dmb_node);
+ if (last)
+ smc_lo_free_dmb(ldev, dmb_node);
return 0;
}
@@ -179,14 +178,9 @@ static int smc_lo_attach_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
read_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
}
+ refcount_inc(&dmb_node->refcnt);
read_unlock_bh(&ldev->dmb_ht_lock);
- if (!refcount_inc_not_zero(&dmb_node->refcnt))
- /* the dmb is being unregistered, but has
- * not been removed from the hash table.
- */
- return -EINVAL;
-
/* provide dmb information */
dmb->sba_idx = dmb_node->sba_idx;
dmb->dmb_tok = dmb_node->token;
@@ -200,9 +194,10 @@ static int smc_lo_detach_dmb(struct smcd_dev *smcd, u64 token)
{
struct smc_lo_dmb_node *dmb_node = NULL, *tmp_node;
struct smc_lo_dev *ldev = smcd->priv;
+ bool last;
/* find dmb_node according to dmb->dmb_tok */
- read_lock_bh(&ldev->dmb_ht_lock);
+ write_lock_bh(&ldev->dmb_ht_lock);
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, token) {
if (tmp_node->token == token) {
dmb_node = tmp_node;
@@ -210,13 +205,17 @@ static int smc_lo_detach_dmb(struct smcd_dev *smcd, u64 token)
}
}
if (!dmb_node) {
- read_unlock_bh(&ldev->dmb_ht_lock);
+ write_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
}
- read_unlock_bh(&ldev->dmb_ht_lock);
+ last = refcount_dec_and_test(&dmb_node->refcnt);
+ if (last)
+ hash_del(&dmb_node->list);
+ write_unlock_bh(&ldev->dmb_ht_lock);
+
+ if (last)
+ smc_lo_free_dmb(ldev, dmb_node);
- if (refcount_dec_and_test(&dmb_node->refcnt))
- __smc_lo_unregister_dmb(ldev, dmb_node);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 491/869] iommu/iommufd: Fix IOPF group ownership UAF
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (489 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 490/869] dibs: fix use-after-free of dmb_node in loopback attach/detach/unregister Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 492/869] octeontx2-af: Block VFs from clobbering special CGX PKIND state Greg Kroah-Hartman
` (378 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Peiyang He, Kevin Tian,
Jason Gunthorpe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peiyang He <peiyang_he@smail.nju.edu.cn>
[ Upstream commit 738e6f32e61d80b554e37015ecb7bc620b88001c ]
iopf_group_alloc() links each last-page IOPF group into the generic IOPF
pending list before invoking the domain fault handler.
iommufd_fault_iopf_handler() also queued an accepted group in the
IOMMUFD deliver list without removing it from the generic pending list.
When detach or HWPT replacement drops the device's IOPF reference count
to zero, an IOMMU driver may call iopf_queue_remove_device(). That
function responds to and frees groups through the generic pending list
without removing the same groups from IOMMUFD's deliver list or response
xarray. A later read, response, or cleanup can then access the freed
group and cause a UAF.
Fix this by dequeuing an accepted group from the generic pending list
before IOMMUFD queues it for userspace response.
Make iopf_group_response() send a response regardless of pending-list
membership, so the dequeued group can still be completed by IOMMUFD.
Link: https://patch.msgid.link/r/3CFD314D0FE4D7EC+20260720085017.3998878-2-peiyang_he@smail.nju.edu.cn
Closes: https://lore.kernel.org/all/B4F28798E2E784CA+d29f723c-b2b5-4b67-8d1c-4f7b9b0b27cb@smail.nju.edu.cn/
Fixes: 34765cbc679c ("iommufd: Associate fault object with iommufd_hw_pgtable")
Cc: stable@vger.kernel.org
Tested-by: Peiyang He <peiyang_he@smail.nju.edu.cn>
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Peiyang He <peiyang_he@smail.nju.edu.cn>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/iommu/io-pgfault.c | 24 +++++++++++++++++++-----
drivers/iommu/iommufd/fault.c | 2 ++
include/linux/iommu.h | 5 +++++
3 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
index 8b5926c1452ed..afe977235d72f 100644
--- a/drivers/iommu/io-pgfault.c
+++ b/drivers/iommu/io-pgfault.c
@@ -332,16 +332,30 @@ void iopf_group_response(struct iopf_group *group,
.code = status,
};
- /* Only send response if there is a fault report pending */
mutex_lock(&fault_param->lock);
- if (!list_empty(&group->pending_node)) {
- ops->page_response(dev, &group->last_fault, &resp);
- list_del_init(&group->pending_node);
- }
+ ops->page_response(dev, &group->last_fault, &resp);
+ list_del_init(&group->pending_node);
mutex_unlock(&fault_param->lock);
}
EXPORT_SYMBOL_GPL(iopf_group_response);
+/**
+ * iopf_group_dequeue - Dequeue a page fault group from the pending list
+ * @group: the group to dequeue
+ *
+ * The fault handler is responsible for responding to the group after
+ * this function returns.
+ */
+void iopf_group_dequeue(struct iopf_group *group)
+{
+ struct iommu_fault_param *fault_param = group->fault_param;
+
+ mutex_lock(&fault_param->lock);
+ list_del_init(&group->pending_node);
+ mutex_unlock(&fault_param->lock);
+}
+EXPORT_SYMBOL_GPL(iopf_group_dequeue);
+
/**
* iopf_queue_discard_partial - Remove all pending partial fault
* @queue: the queue whose partial faults need to be discarded
diff --git a/drivers/iommu/iommufd/fault.c b/drivers/iommu/iommufd/fault.c
index 74e3c93bce6ea..bdaecb6e1f7a3 100644
--- a/drivers/iommu/iommufd/fault.c
+++ b/drivers/iommu/iommufd/fault.c
@@ -454,6 +454,8 @@ int iommufd_fault_iopf_handler(struct iopf_group *group)
hwpt = group->attach_handle->domain->fault_data;
fault = hwpt->fault;
+ iopf_group_dequeue(group);
+
spin_lock(&fault->lock);
list_add_tail(&group->node, &fault->deliver);
spin_unlock(&fault->lock);
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index dc7ceb9406eda..929b9d0d90cde 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -1566,6 +1566,7 @@ void iopf_free_group(struct iopf_group *group);
int iommu_report_device_fault(struct device *dev, struct iopf_fault *evt);
void iopf_group_response(struct iopf_group *group,
enum iommu_page_response_code status);
+void iopf_group_dequeue(struct iopf_group *group);
#else
static inline int
iopf_queue_add_device(struct iopf_queue *queue, struct device *dev)
@@ -1611,5 +1612,9 @@ static inline void iopf_group_response(struct iopf_group *group,
enum iommu_page_response_code status)
{
}
+
+static inline void iopf_group_dequeue(struct iopf_group *group)
+{
+}
#endif /* CONFIG_IOMMU_IOPF */
#endif /* __LINUX_IOMMU_H */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 492/869] octeontx2-af: Block VFs from clobbering special CGX PKIND state
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (490 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 491/869] iommu/iommufd: Fix IOPF group ownership UAF Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 493/869] Bluetooth: hci_sync: hold conn in hci_connect_pa_sync() callback Greg Kroah-Hartman
` (377 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Geetha sowjanya, Hariprasad Kelam,
Ratheesh Kannoth, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hariprasad Kelam <hkelam@marvell.com>
[ Upstream commit 3bd438a58e910db5dc369aa25dfed1fc95f1b596 ]
PF and VF NIX LFs that share a CGX LMAC reuse the same hardware PKIND
programming. When HiGig2 or EDSA parsing is enabled, a VF NIX LF alloc must
not reset the LMAC RX PKIND or default TX parse config over the PF setup.
Add cgx_get_pkind() and rvu_cgx_is_pkind_config_permitted() so VFs skip
cgx_set_pkind(), rvu_npc_set_pkind(), and NIX_AF_LFX_TX_PARSE_CFG updates
when the LMAC is using NPC_RX_HIGIG_PKIND or NPC_RX_EDSA_PKIND.
Fixes: 94d942c5fb97 ("octeontx2-af: Config pkind for CGX mapped PFs")
Cc: Geetha sowjanya <gakula@marvell.com>
Signed-off-by: Hariprasad Kelam <hkelam@marvell.com>
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
Link: https://patch.msgid.link/20260722081229.1653619-1-rkannoth@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../net/ethernet/marvell/octeontx2/af/cgx.c | 12 +++
.../net/ethernet/marvell/octeontx2/af/cgx.h | 1 +
.../net/ethernet/marvell/octeontx2/af/rvu.h | 2 +
.../ethernet/marvell/octeontx2/af/rvu_cgx.c | 79 +++++++++++++++++++
.../ethernet/marvell/octeontx2/af/rvu_nix.c | 22 +++++-
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 29 ++++---
6 files changed, 131 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
index d415d5dbc1104..b62ed53032784 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
@@ -518,6 +518,18 @@ int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind)
return 0;
}
+int cgx_get_pkind(void *cgxd, u8 lmac_id, int *pkind)
+{
+ struct cgx *cgx = cgxd;
+
+ if (!is_lmac_valid(cgx, lmac_id))
+ return -ENODEV;
+
+ *pkind = cgx_read(cgx, lmac_id, cgx->mac_ops->rxid_map_offset);
+ *pkind = *pkind & 0x3F;
+ return 0;
+}
+
static u8 cgx_get_lmac_type(void *cgxd, int lmac_id)
{
struct cgx *cgx = cgxd;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
index 1cf12e5c7da87..e8f010ecb2849 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
@@ -141,6 +141,7 @@ int cgx_get_cgxid(void *cgxd);
int cgx_get_lmac_cnt(void *cgxd);
void *cgx_get_pdata(int cgx_id);
int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind);
+int cgx_get_pkind(void *cgxd, u8 lmac_id, int *pkind);
int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id);
int cgx_lmac_evh_unregister(void *cgxd, int lmac_id);
int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index 34b2a16e88446..88cf7978e0d79 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -989,6 +989,8 @@ void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
int blkaddr, u16 src, struct mcam_entry *entry,
u8 *intf, u8 *ena);
bool is_cgx_config_permitted(struct rvu *rvu, u16 pcifunc);
+bool rvu_cgx_check_permission_and_set_pkind(struct rvu *rvu, u16 pcifunc, int pkind);
+bool rvu_cgx_is_pkind_config_permitted(struct rvu *rvu, u16 pcifunc);
bool is_mac_feature_supported(struct rvu *rvu, int pf, int feature);
u32 rvu_cgx_get_fifolen(struct rvu *rvu);
void *rvu_first_cgx_pdata(struct rvu *rvu);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
index d0215f5e9a067..c227eb7ad5e8c 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
@@ -1351,3 +1351,82 @@ void rvu_mac_reset(struct rvu *rvu, u16 pcifunc)
if (mac_ops->mac_reset(cgxd, lmac, !is_vf(pcifunc)))
dev_err(rvu->dev, "Failed to reset MAC\n");
}
+
+/* Do not allow CGX-mapped VFs to overwrite PKIND when special parse kinds
+ * (HiGig, EDSA, etc.) are in use on the shared LMAC. VFs must not program
+ * NPC_TX_DEF_PKIND on NIX_AF_LFX_TX_PARSE_CFG in that case: the PF owns
+ * parse mode and no separate NPC_TX_HIGIG_PKIND is installed on the VF LF.
+ * TX-parse callers skip the write when denied; rvu_lf_reset() clears each LF
+ * before alloc so the next permitted owner programs NPC_TX_DEF_PKIND.
+ */
+bool rvu_cgx_is_pkind_config_permitted(struct rvu *rvu, u16 pcifunc)
+{
+ int pf, err, rxpkind;
+ u8 cgx_id, lmac_id;
+ void *cgxd;
+
+ pf = rvu_get_pf(pcifunc);
+
+ if (!(pcifunc & RVU_PFVF_FUNC_MASK))
+ return true;
+
+ if (!is_pf_cgxmapped(rvu, pf))
+ return true;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ cgxd = rvu_cgx_pdata(cgx_id, rvu);
+ err = cgx_get_pkind(cgxd, lmac_id, &rxpkind);
+ if (err)
+ return false;
+
+ switch (rxpkind) {
+ case NPC_RX_HIGIG_PKIND:
+ case NPC_RX_EDSA_PKIND:
+ return false;
+ default:
+ return true;
+ }
+}
+
+/* Do not allow CGX-mapped VFs to overwrite PKIND when special parse kinds
+ * (HiGig, EDSA, etc.) are in use on the shared LMAC.
+ */
+bool rvu_cgx_check_permission_and_set_pkind(struct rvu *rvu, u16 pcifunc, int pkind)
+{
+ int pf, err, rxpkind;
+ u8 cgx_id, lmac_id;
+ struct cgx *cgxd;
+
+ pf = rvu_get_pf(pcifunc);
+
+ if (!is_pf_cgxmapped(rvu, pf))
+ return false;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ cgxd = rvu_cgx_pdata(cgx_id, rvu);
+
+ mutex_lock(&cgxd->lock);
+ if (!is_vf(pcifunc))
+ goto set;
+
+ err = cgx_get_pkind(cgxd, lmac_id, &rxpkind);
+ if (err)
+ goto err;
+
+ switch (rxpkind) {
+ case NPC_RX_HIGIG_PKIND:
+ case NPC_RX_EDSA_PKIND:
+ goto err;
+ default:
+ break;
+ }
+
+set:
+ cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id, pkind);
+ mutex_unlock(&cgxd->lock);
+ return true;
+
+err:
+ mutex_unlock(&cgxd->lock);
+ return false;
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 74be2012ec04e..e9bcfc730f450 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -358,8 +358,8 @@ static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf,
pfvf->tx_chan_cnt = 1;
rsp->tx_link = cgx_id * hw->lmac_per_cgx + lmac_id;
- cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id, pkind);
- rvu_npc_set_pkind(rvu, pkind, pfvf);
+ if (rvu_cgx_check_permission_and_set_pkind(rvu, pcifunc, pkind))
+ rvu_npc_set_pkind(rvu, pkind, pfvf);
break;
case NIX_INTF_TYPE_LBK:
@@ -1444,11 +1444,13 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
struct nix_lf_alloc_req *req,
struct nix_lf_alloc_rsp *rsp)
{
- int nixlf, qints, hwctx_size, intf, err, rc = 0;
+ int nixlf, qints, hwctx_size, intf, err, rc = 0, pf;
struct rvu_hwinfo *hw = rvu->hw;
u16 pcifunc = req->hdr.pcifunc;
+ u8 cgx_id = 0, lmac_id = 0;
struct rvu_block *block;
struct rvu_pfvf *pfvf;
+ struct cgx *cgxd;
u64 cfg, ctx_cfg;
int blkaddr;
@@ -1616,8 +1618,20 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_CFG(nixlf), req->rx_cfg);
/* Configure pkind for TX parse config */
+
+ pf = rvu_get_pf(pcifunc);
cfg = NPC_TX_DEF_PKIND;
- rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
+
+ if (is_pf_cgxmapped(rvu, pf) && is_vf(pcifunc)) {
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ cgxd = rvu_cgx_pdata(cgx_id, rvu);
+ mutex_lock(&cgxd->lock);
+ if (rvu_cgx_is_pkind_config_permitted(rvu, pcifunc))
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
+ mutex_unlock(&cgxd->lock);
+ } else {
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
+ }
intf = is_lbk_vf(rvu, pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX;
if (is_sdp_pfvf(pcifunc))
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index 5c5376eace100..ba233b075744a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -16,6 +16,7 @@
#include "cgx.h"
#include "npc_profile.h"
#include "rvu_npc_hash.h"
+#include "lmac_common.h"
#define RSVD_MCAM_ENTRIES_PER_PF 3 /* Broadcast, Promisc and AllMulticast */
#define RSVD_MCAM_ENTRIES_PER_NIXLF 1 /* Ucast for LFs */
@@ -3330,10 +3331,11 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
{
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
- int blkaddr, nixlf, rc, intf_mode;
int pf = rvu_get_pf(pcifunc);
+ int blkaddr, nixlf, rc, intf_mode;
+ u8 cgx_id = 0, lmac_id = 0;
u64 rxpkind, txpkind;
- u8 cgx_id, lmac_id;
+ struct cgx *cgxd;
/* use default pkind to disable edsa/higig */
rxpkind = rvu_npc_get_pkind(rvu, pf);
@@ -3357,12 +3359,8 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
/* rx pkind set req valid only for cgx mapped PFs */
if (!is_cgx_config_permitted(rvu, pcifunc))
return 0;
- rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
-
- rc = cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id,
- rxpkind);
- if (rc)
- return rc;
+ if (!rvu_cgx_check_permission_and_set_pkind(rvu, pcifunc, rxpkind))
+ return -EINVAL;
}
if (dir & PKIND_TX) {
@@ -3371,8 +3369,19 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
if (rc)
return rc;
- rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf),
- txpkind);
+ if (is_pf_cgxmapped(rvu, pf) && is_vf(pcifunc)) {
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id,
+ &lmac_id);
+ cgxd = rvu_cgx_pdata(cgx_id, rvu);
+ mutex_lock(&cgxd->lock);
+ if (rvu_cgx_is_pkind_config_permitted(rvu, pcifunc))
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf),
+ txpkind);
+ mutex_unlock(&cgxd->lock);
+ } else {
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf),
+ txpkind);
+ }
}
pfvf->intf_mode = intf_mode;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 493/869] Bluetooth: hci_sync: hold conn in hci_connect_pa_sync() callback
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (491 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 492/869] octeontx2-af: Block VFs from clobbering special CGX PKIND state Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 494/869] Bluetooth: hci_sync: hold conn in hci_connect_big_sync() callback Greg Kroah-Hartman
` (376 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pauli Virtanen,
Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <pav@iki.fi>
[ Upstream commit 44fc74069d8988f2825246f9401218e29de2c0ab ]
There is theoretical UAF if the conn is freed while the hci_sync task is
running.
Hold refcount to avoid that.
Fixes: 6d0417e4e1cf ("Bluetooth: hci_conn: Fix not setting conn_timeout for Broadcast Receiver")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/hci_sync.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 3e3706231458d..2d28a649f33b0 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -7317,7 +7317,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err);
if (err == -ECANCELED)
- return;
+ goto done;
hci_dev_lock(hdev);
@@ -7341,6 +7341,8 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
unlock:
hci_dev_unlock(hdev);
+done:
+ hci_conn_put(conn);
}
static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data)
@@ -7430,8 +7432,11 @@ int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
int err;
- err = hci_cmd_sync_queue_once(hdev, hci_le_pa_create_sync, conn,
+ err = hci_cmd_sync_queue_once(hdev, hci_le_pa_create_sync,
+ hci_conn_get(conn),
create_pa_complete);
+ if (err)
+ hci_conn_put(conn);
return (err == -EEXIST) ? 0 : err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 494/869] Bluetooth: hci_sync: hold conn in hci_connect_big_sync() callback
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (492 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 493/869] Bluetooth: hci_sync: hold conn in hci_connect_pa_sync() callback Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 495/869] Bluetooth: ISO: hold sk properly in iso_conn_ready Greg Kroah-Hartman
` (375 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pauli Virtanen,
Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <pav@iki.fi>
[ Upstream commit 56e78b670356caab0b607e8aad4cf819a1909d07 ]
There is theoretical UAF if the conn is freed while the hci_sync task is
running.
Hold refcount to avoid that. Handle NULL hcon, return 0 + do nothing to
match the previous behavior.
Fixes: 024421cf3992 ("Bluetooth: hci_conn: Fix not setting timeout for BIG Create Sync")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/hci_sync.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 2d28a649f33b0..92ef7d88f8e3c 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -7447,10 +7447,12 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err);
if (err == -ECANCELED)
- return;
+ goto done;
- if (hci_conn_valid(hdev, conn))
- clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
+ clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
+
+done:
+ hci_conn_put(conn);
}
static int hci_le_big_create_sync(struct hci_dev *hdev, void *data)
@@ -7502,7 +7504,13 @@ int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
int err;
- err = hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync, conn,
+ if (!conn)
+ return 0;
+
+ err = hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync,
+ hci_conn_get(conn),
create_big_complete);
+ if (err)
+ hci_conn_put(conn);
return (err == -EEXIST) ? 0 : err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 495/869] Bluetooth: ISO: hold sk properly in iso_conn_ready
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (493 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 494/869] Bluetooth: hci_sync: hold conn in hci_connect_big_sync() callback Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 496/869] Bluetooth: ISO: lock sk in iso_connect_ind Greg Kroah-Hartman
` (374 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pauli Virtanen,
Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <pav@iki.fi>
[ Upstream commit 0d255e63fcf3f13a570d7ac11678fa1164ac015c ]
sk deref in iso_conn_ready must be done either under conn->lock, or
holding a refcount, to avoid concurrent close. conn->sk is currently
accessed without either:
[Task 1] [Task 2]
iso_sock_release
iso_conn_ready
sk = conn->sk
lock_sock(sk)
conn->sk = NULL
lock_sock(sk)
release_sock(sk)
iso_sock_kill(sk)
UAF on sk deref
Fix possible UAF by holding sk refcount in iso_conn_ready(). Also
recheck after lock_sock that the socket is still valid. Adjust locking
so conn->sk is cleared only under lock_sock.
Fixes: 27c24fda62b60 ("Bluetooth: switch to lock_sock in SCO")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/iso.c | 30 +++++++++++++++++++++---------
1 file changed, 21 insertions(+), 9 deletions(-)
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index 5b930d0e5a04c..89e59cdafd571 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -1980,23 +1980,17 @@ static void iso_sock_ready(struct sock *sk)
{
BT_DBG("sk %p", sk);
- if (!sk)
- return;
-
- lock_sock(sk);
+ lockdep_assert(lockdep_sock_is_held(sk));
switch (sk->sk_state) {
case BT_DISCONN:
case BT_CLOSED:
- release_sock(sk);
return;
}
iso_sock_clear_timer(sk);
sk->sk_state = BT_CONNECTED;
sk->sk_state_change(sk);
-
- release_sock(sk);
}
static bool iso_match_big(struct sock *sk, void *data)
@@ -2014,7 +2008,7 @@ static bool iso_match_pa_sync_flag(struct sock *sk, void *data)
static void iso_conn_ready(struct iso_conn *conn)
{
struct sock *parent = NULL;
- struct sock *sk = conn->sk;
+ struct sock *sk;
struct hci_ev_le_big_sync_estabilished *ev = NULL;
struct hci_ev_le_pa_sync_established *ev2 = NULL;
struct hci_ev_le_per_adv_report *ev3 = NULL;
@@ -2022,8 +2016,26 @@ static void iso_conn_ready(struct iso_conn *conn)
BT_DBG("conn %p", conn);
+ iso_conn_lock(conn);
+ sk = iso_sock_hold(conn);
+ iso_conn_unlock(conn);
+
if (sk) {
- iso_sock_ready(conn->sk);
+ lock_sock(sk);
+
+ /* conn->sk may have become NULL if racing with sk close, but
+ * due to held hdev->lock, it can't become different sk.
+ */
+ if (!conn->sk) {
+ release_sock(sk);
+ sock_put(sk);
+ return;
+ }
+
+ iso_sock_ready(sk);
+
+ release_sock(sk);
+ sock_put(sk);
} else {
hcon = conn->hcon;
if (!hcon)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 496/869] Bluetooth: ISO: lock sk in iso_connect_ind
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (494 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 495/869] Bluetooth: ISO: hold sk properly in iso_conn_ready Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 497/869] netfs: Fix folio_queue ENOMEM in writeback by adding a mempool Greg Kroah-Hartman
` (373 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pauli Virtanen,
Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <pav@iki.fi>
[ Upstream commit 4311fd6f429065a8ba208660360a895627a00cf3 ]
Accessing iso_pi(sk)->conn requires lock_sock, which is not taken in the
"ev3" part of iso_connect_ind. It may also be NULL if socket has
transitioned away from the LISTEN/CONNECT states before locking.
Fix by adding lock/release. Recheck hcon is valid after lock acquire
where needed.
Fixes: 168d9bf9c7f0 ("Bluetooth: ISO: Reassemble PA data for bcast sink")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/iso.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index 89e59cdafd571..eafa22468e5f0 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -2293,9 +2293,11 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
if (!sk)
goto done;
- hcon = iso_pi(sk)->conn->hcon;
+ lock_sock(sk);
+
+ hcon = iso_pi(sk)->conn ? iso_pi(sk)->conn->hcon : NULL;
if (!hcon)
- goto done;
+ goto release3;
if (ev3->data_status == LE_PA_DATA_TRUNCATED) {
/* The controller was unable to retrieve PA data. */
@@ -2303,12 +2305,12 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
HCI_MAX_PER_AD_TOT_LEN);
hcon->le_per_adv_data_len = 0;
hcon->le_per_adv_data_offset = 0;
- goto done;
+ goto release3;
}
if (hcon->le_per_adv_data_offset + ev3->length >
HCI_MAX_PER_AD_TOT_LEN)
- goto done;
+ goto release3;
memcpy(hcon->le_per_adv_data + hcon->le_per_adv_data_offset,
ev3->data, ev3->length);
@@ -2327,7 +2329,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
&base_len);
if (!base || base_len > BASE_MAX_LENGTH)
- goto done;
+ goto release3;
lock_sock(sk);
memcpy(iso_pi(sk)->base, base, base_len);
@@ -2339,6 +2341,9 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
*/
hcon->le_per_adv_data_len = 0;
}
+
+release3:
+ release_sock(sk);
} else {
sk = iso_get_sock(&hdev->bdaddr, BDADDR_ANY,
BT_LISTEN, NULL, NULL);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 497/869] netfs: Fix folio_queue ENOMEM in writeback by adding a mempool
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (495 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 496/869] Bluetooth: ISO: lock sk in iso_connect_ind Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 498/869] net/sched: cls_u32: validate offshift to prevent shift-out-of-bounds Greg Kroah-Hartman
` (372 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+0da43efa72f88bd3a8af,
David Howells, Paulo Alcantara, Yun Zhou, Matthew Wilcox,
Christoph Hellwig, netfs, linux-fsdevel,
Christian Brauner (Amutable), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit 1d78d56c43ef3768183e8370e7367b162700e049 ]
Fix the handling of folio_queue allocation failure in writeback by adding a
mempool and passing in gfp_t flags to the rolling buffer functions that
allocate memory, using the mempool if gfp != GFP_KERNEL.
This is then extended upwards and the gfp to be used for a request is stored
in the netfs_io_request struct and is then used for both requests and
subrequests, eliminating the sleeping loops there.
The failure caused:
folio != NULL
WARNING: fs/netfs/write_issue.c:603 at netfs_writepages+0x883/0xa10 fs/netfs/write_issue.c:603, CPU#3: syz.0.17/5919
Fixes: cd0277ed0c18 ("netfs: Use new folio_queue data type and iterator instead of xarray iter")
Reported-by: syzbot+0da43efa72f88bd3a8af@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=0da43efa72f88bd3a8af
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260727130716.1099906-5-dhowells@redhat.com
Tested-by: syzbot+0da43efa72f88bd3a8af@syzkaller.appspotmail.com
cc: Paulo Alcantara <pc@manguebit.org>
cc: Yun Zhou <yun.zhou@windriver.com>
cc: Matthew Wilcox <willy@infradead.org>
cc: Christoph Hellwig <hch@infradead.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/netfs/buffered_read.c | 6 +++---
fs/netfs/internal.h | 1 +
fs/netfs/main.c | 7 +++++++
fs/netfs/objects.c | 31 ++++++++++++++++++-------------
fs/netfs/read_pgpriv2.c | 2 +-
fs/netfs/rolling_buffer.c | 22 +++++++++++++---------
fs/netfs/write_issue.c | 8 ++++----
include/linux/netfs.h | 1 +
include/linux/rolling_buffer.h | 6 +++---
9 files changed, 51 insertions(+), 33 deletions(-)
diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c
index 1228cabbfde3a..23235e62f33ec 100644
--- a/fs/netfs/buffered_read.c
+++ b/fs/netfs/buffered_read.c
@@ -351,7 +351,7 @@ void netfs_readahead(struct readahead_control *ractl)
rreq->ractl = ractl;
rreq->submitted = rreq->start;
- if (rolling_buffer_init(&rreq->buffer, rreq->debug_id, ITER_DEST) < 0)
+ if (rolling_buffer_init(&rreq->buffer, rreq->debug_id, ITER_DEST, rreq->gfp) < 0)
goto cleanup_free;
netfs_read_to_pagecache(rreq);
@@ -372,10 +372,10 @@ static int netfs_create_singular_buffer(struct netfs_io_request *rreq, struct fo
{
ssize_t added;
- if (rolling_buffer_init(&rreq->buffer, rreq->debug_id, ITER_DEST) < 0)
+ if (rolling_buffer_init(&rreq->buffer, rreq->debug_id, ITER_DEST, rreq->gfp) < 0)
return -ENOMEM;
- added = rolling_buffer_append(&rreq->buffer, folio, rollbuf_flags);
+ added = rolling_buffer_append(&rreq->buffer, folio, rollbuf_flags, rreq->gfp);
if (added < 0)
return added;
rreq->submitted = rreq->start + added;
diff --git a/fs/netfs/internal.h b/fs/netfs/internal.h
index 7256277edacb8..b8b78c9be293d 100644
--- a/fs/netfs/internal.h
+++ b/fs/netfs/internal.h
@@ -34,6 +34,7 @@ extern struct list_head netfs_io_requests;
extern spinlock_t netfs_proc_lock;
extern mempool_t netfs_request_pool;
extern mempool_t netfs_subrequest_pool;
+extern mempool_t netfs_folioq_pool;
#ifdef CONFIG_PROC_FS
static inline void netfs_proc_add_rreq(struct netfs_io_request *rreq)
diff --git a/fs/netfs/main.c b/fs/netfs/main.c
index 3a8433e802cc2..98ff6d2e62ec3 100644
--- a/fs/netfs/main.c
+++ b/fs/netfs/main.c
@@ -28,6 +28,7 @@ static struct kmem_cache *netfs_request_slab;
static struct kmem_cache *netfs_subrequest_slab;
mempool_t netfs_request_pool;
mempool_t netfs_subrequest_pool;
+mempool_t netfs_folioq_pool;
#ifdef CONFIG_PROC_FS
LIST_HEAD(netfs_io_requests);
@@ -105,6 +106,9 @@ static int __init netfs_init(void)
{
int ret = -ENOMEM;
+ if (mempool_init_kmalloc_pool(&netfs_folioq_pool, 100, sizeof(struct folio_queue)) < 0)
+ goto error_folioq_pool;
+
netfs_request_slab = kmem_cache_create("netfs_request",
sizeof(struct netfs_io_request), 0,
SLAB_HWCACHE_ALIGN | SLAB_ACCOUNT,
@@ -157,6 +161,8 @@ static int __init netfs_init(void)
error_reqpool:
kmem_cache_destroy(netfs_request_slab);
error_req:
+ mempool_exit(&netfs_folioq_pool);
+error_folioq_pool:
return ret;
}
fs_initcall(netfs_init);
@@ -169,5 +175,6 @@ static void __exit netfs_exit(void)
kmem_cache_destroy(netfs_subrequest_slab);
mempool_exit(&netfs_request_pool);
kmem_cache_destroy(netfs_request_slab);
+ mempool_exit(&netfs_folioq_pool);
}
module_exit(netfs_exit);
diff --git a/fs/netfs/objects.c b/fs/netfs/objects.c
index 8c98b70eb3a4f..788bdaf7332f9 100644
--- a/fs/netfs/objects.c
+++ b/fs/netfs/objects.c
@@ -7,7 +7,6 @@
#include <linux/slab.h>
#include <linux/mempool.h>
-#include <linux/delay.h>
#include "internal.h"
/*
@@ -24,16 +23,22 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
struct netfs_io_request *rreq;
mempool_t *mempool = ctx->ops->request_pool ?: &netfs_request_pool;
struct kmem_cache *cache = mempool->pool_data;
+ gfp_t gfp = GFP_KERNEL;
int ret;
- for (;;) {
- rreq = mempool_alloc(mempool, GFP_KERNEL);
- if (rreq)
- break;
- msleep(10);
+ /* Writeback is part of memory reclaim and must not fail due to ENOMEM. */
+ if (origin == NETFS_WRITEBACK) {
+ gfp = GFP_NOFS; /* Allows use of mempools. */
+
+ rreq = mempool_alloc(mempool, gfp);
+ } else {
+ rreq = mempool->alloc(gfp, mempool->pool_data);
+ if (!rreq)
+ return ERR_PTR(-ENOMEM);
}
memset(rreq, 0, kmem_cache_size(cache));
+ rreq->gfp = gfp;
rreq->start = start;
rreq->len = len;
rreq->origin = origin;
@@ -182,13 +187,13 @@ struct netfs_io_subrequest *netfs_alloc_subrequest(struct netfs_io_request *rreq
mempool_t *mempool = rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool;
struct kmem_cache *cache = mempool->pool_data;
- for (;;) {
- subreq = mempool_alloc(rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool,
- GFP_KERNEL);
- if (subreq)
- break;
- msleep(10);
- }
+ /* The write-side callers don't handle failure, so only reads may fail. */
+ if (rreq->gfp == GFP_KERNEL && rreq->origin <= NETFS_DIO_READ)
+ subreq = mempool->alloc(rreq->gfp, mempool->pool_data);
+ else
+ subreq = mempool_alloc(mempool, rreq->gfp);
+ if (!subreq)
+ return NULL;
memset(subreq, 0, kmem_cache_size(cache));
diff --git a/fs/netfs/read_pgpriv2.c b/fs/netfs/read_pgpriv2.c
index 838f92eed1c23..d29d5ca594588 100644
--- a/fs/netfs/read_pgpriv2.c
+++ b/fs/netfs/read_pgpriv2.c
@@ -95,7 +95,7 @@ static int netfs_pgpriv2_copy_folio(struct netfs_io_request *wreq, struct folio
trace_netfs_folio(folio, netfs_folio_trace_store_copy);
/* Attach the folio to the rolling buffer. */
- if (rolling_buffer_append(&wreq->buffer, folio, 0) < 0)
+ if (rolling_buffer_append(&wreq->buffer, folio, 0, wreq->gfp) < 0)
return -ENOMEM;
cache->submit_extendable_to = fsize;
diff --git a/fs/netfs/rolling_buffer.c b/fs/netfs/rolling_buffer.c
index 75d97af14b4ab..7c768ca5ff592 100644
--- a/fs/netfs/rolling_buffer.c
+++ b/fs/netfs/rolling_buffer.c
@@ -6,6 +6,7 @@
*/
#include <linux/bitops.h>
+#include <linux/mempool.h>
#include <linux/pagemap.h>
#include <linux/rolling_buffer.h>
#include <linux/slab.h>
@@ -27,7 +28,10 @@ struct folio_queue *netfs_folioq_alloc(unsigned int rreq_id, gfp_t gfp,
{
struct folio_queue *fq;
- fq = kmalloc(sizeof(*fq), gfp);
+ if (gfp == GFP_KERNEL)
+ fq = netfs_folioq_pool.alloc(gfp, netfs_folioq_pool.pool_data);
+ else
+ fq = mempool_alloc(&netfs_folioq_pool, gfp);
if (fq) {
netfs_stat(&netfs_n_folioq);
folioq_init(fq, rreq_id);
@@ -50,7 +54,7 @@ void netfs_folioq_free(struct folio_queue *folioq,
{
trace_netfs_folioq(folioq, trace);
netfs_stat_d(&netfs_n_folioq);
- kfree(folioq);
+ mempool_free(folioq, &netfs_folioq_pool);
}
EXPORT_SYMBOL(netfs_folioq_free);
@@ -60,11 +64,11 @@ EXPORT_SYMBOL(netfs_folioq_free);
* consumer.
*/
int rolling_buffer_init(struct rolling_buffer *roll, unsigned int rreq_id,
- unsigned int direction)
+ unsigned int direction, gfp_t gfp)
{
struct folio_queue *fq;
- fq = netfs_folioq_alloc(rreq_id, GFP_NOFS, netfs_trace_folioq_rollbuf_init);
+ fq = netfs_folioq_alloc(rreq_id, gfp, netfs_trace_folioq_rollbuf_init);
if (!fq)
return -ENOMEM;
@@ -77,14 +81,14 @@ int rolling_buffer_init(struct rolling_buffer *roll, unsigned int rreq_id,
/*
* Add another folio_queue to a rolling buffer if there's no space left.
*/
-int rolling_buffer_make_space(struct rolling_buffer *roll)
+int rolling_buffer_make_space(struct rolling_buffer *roll, gfp_t gfp)
{
struct folio_queue *fq, *head = roll->head;
if (!folioq_full(head))
return 0;
- fq = netfs_folioq_alloc(head->rreq_id, GFP_NOFS, netfs_trace_folioq_make_space);
+ fq = netfs_folioq_alloc(head->rreq_id, gfp, netfs_trace_folioq_make_space);
if (!fq)
return -ENOMEM;
fq->prev = head;
@@ -122,7 +126,7 @@ ssize_t rolling_buffer_load_from_ra(struct rolling_buffer *roll,
int nr, ix, to;
ssize_t size = 0;
- if (rolling_buffer_make_space(roll) < 0)
+ if (rolling_buffer_make_space(roll, GFP_KERNEL) < 0)
return -ENOMEM;
fq = roll->head;
@@ -157,12 +161,12 @@ ssize_t rolling_buffer_load_from_ra(struct rolling_buffer *roll,
* Append a folio to the rolling buffer.
*/
ssize_t rolling_buffer_append(struct rolling_buffer *roll, struct folio *folio,
- unsigned int flags)
+ unsigned int flags, gfp_t gfp)
{
ssize_t size = folio_size(folio);
int slot;
- if (rolling_buffer_make_space(roll) < 0)
+ if (rolling_buffer_make_space(roll, gfp) < 0)
return -ENOMEM;
slot = folioq_append(roll->head, folio);
diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c
index 8143f84e60b4b..4242cfc683d7c 100644
--- a/fs/netfs/write_issue.c
+++ b/fs/netfs/write_issue.c
@@ -107,7 +107,7 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping,
ictx = netfs_inode(wreq->inode);
if (is_buffered)
fscache_begin_write_operation(&wreq->cache_resources, netfs_i_cookie(ictx));
- if (rolling_buffer_init(&wreq->buffer, wreq->debug_id, ITER_SOURCE) < 0)
+ if (rolling_buffer_init(&wreq->buffer, wreq->debug_id, ITER_SOURCE, wreq->gfp) < 0)
goto nomem;
wreq->cleaned_to = wreq->start;
@@ -167,7 +167,7 @@ static void netfs_prepare_write(struct netfs_io_request *wreq,
*/
if (iov_iter_is_folioq(wreq_iter) &&
wreq_iter->folioq_slot >= folioq_nr_slots(wreq_iter->folioq))
- rolling_buffer_make_space(&wreq->buffer);
+ rolling_buffer_make_space(&wreq->buffer, wreq->gfp);
subreq = netfs_alloc_subrequest(wreq);
subreq->source = stream->source;
@@ -330,7 +330,7 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
_enter("");
- if (rolling_buffer_make_space(&wreq->buffer) < 0)
+ if (rolling_buffer_make_space(&wreq->buffer, wreq->gfp) < 0)
return -ENOMEM;
/* netfs_perform_write() may shift i_size around the page or from out
@@ -432,7 +432,7 @@ static int netfs_write_folio(struct netfs_io_request *wreq,
}
/* Attach the folio to the rolling buffer. */
- rolling_buffer_append(&wreq->buffer, folio, 0);
+ rolling_buffer_append(&wreq->buffer, folio, 0, wreq->gfp);
/* Move the submission point forward to allow for write-streaming data
* not starting at the front of the page. We don't do write-streaming
diff --git a/include/linux/netfs.h b/include/linux/netfs.h
index ff208bbe6c5a6..cab466964141f 100644
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -246,6 +246,7 @@ struct netfs_io_request {
void *netfs_priv; /* Private data for the netfs */
void *netfs_priv2; /* Private data for the netfs */
struct bio_vec *direct_bv; /* DIO buffer list (when handling iovec-iter) */
+ gfp_t gfp; /* GFP flags to use */
unsigned int direct_bv_count; /* Number of elements in direct_bv[] */
unsigned int debug_id;
unsigned int rsize; /* Maximum read size (0 for none) */
diff --git a/include/linux/rolling_buffer.h b/include/linux/rolling_buffer.h
index ac15b1ffdd831..9e5dad29669cf 100644
--- a/include/linux/rolling_buffer.h
+++ b/include/linux/rolling_buffer.h
@@ -43,13 +43,13 @@ struct rolling_buffer_snapshot {
#define ROLLBUF_MARK_2 BIT(1)
int rolling_buffer_init(struct rolling_buffer *roll, unsigned int rreq_id,
- unsigned int direction);
-int rolling_buffer_make_space(struct rolling_buffer *roll);
+ unsigned int direction, gfp_t gfp);
+int rolling_buffer_make_space(struct rolling_buffer *roll, gfp_t gfp);
ssize_t rolling_buffer_load_from_ra(struct rolling_buffer *roll,
struct readahead_control *ractl,
struct folio_batch *put_batch);
ssize_t rolling_buffer_append(struct rolling_buffer *roll, struct folio *folio,
- unsigned int flags);
+ unsigned int flags, gfp_t gfp);
struct folio_queue *rolling_buffer_delete_spent(struct rolling_buffer *roll);
void rolling_buffer_clear(struct rolling_buffer *roll);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 498/869] net/sched: cls_u32: validate offshift to prevent shift-out-of-bounds
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (496 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 497/869] netfs: Fix folio_queue ENOMEM in writeback by adding a mempool Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 499/869] xsk: drain continuation descs after overflow in xsk_build_skb() Greg Kroah-Hartman
` (371 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, AutonomousCodeSecurity,
Cen Zhang (Microsoft), Jamal Hadi Salim, Victor Nogueira,
Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang (Microsoft) <blbllhy@gmail.com>
[ Upstream commit aef96eead2860cbfa371e4471d4f04412213b958 ]
u32_change() copies the user-provided tc_u32_sel.offshift (unsigned char,
0-255) into the kernel knode object without bounds validation. When a
packet later hits u32_classify() with TC_U32_VAROFFSET set, it evaluates
`ntohs(offmask & *data) >> offshift` where the left operand is a 16-bit
value promoted to a 32-bit int. Any offshift >= 32 is undefined behavior
per C11 6.5.7p3, triggerable by an unprivileged user via user/network
namespaces.
UBSAN: shift-out-of-bounds in net/sched/cls_u32.c:236:43
shift exponent 32 is too large for 32-bit type int
Fix this by rejecting offshift >= 16 during filter creation in
u32_change().
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: AutonomousCodeSecurity@microsoft.com
Link: https://lore.kernel.org/all/20260720034514.23053-1-blbllhy@gmail.com
Signed-off-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Tested-by: Jamal Hadi Salim <jhs@mojatatu.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Link: https://patch.msgid.link/20260723044955.89471-1-blbllhy@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sched/cls_u32.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index e5e5533f866dc..ea021dc39fea3 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -1132,6 +1132,13 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
goto erridr;
}
+ if (s->offshift >= 16) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "offshift must be less than 16");
+ err = -EINVAL;
+ goto erridr;
+ }
+
n = kzalloc(struct_size(n, sel.keys, s->nkeys), GFP_KERNEL);
if (n == NULL) {
err = -ENOBUFS;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 499/869] xsk: drain continuation descs after overflow in xsk_build_skb()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (497 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 498/869] net/sched: cls_u32: validate offshift to prevent shift-out-of-bounds Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 500/869] xsk: provide sufficient space in pool->tx_descs Greg Kroah-Hartman
` (370 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jason Xing, Maciej Fijalkowski,
Stanislav Fomichev, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason Xing <kernelxing@tencent.com>
[ Upstream commit bd44a6dcd4248883de90f5dad53ae80066e27096 ]
Fix generic xmit path multi-buffer logic when packets are either too big
(count of descriptors exceed MAX_SKB_FRAGS) or an invalid descriptor is
included in fragmented packet. Introduce xdp_sock::drain_cont and act
upon this flag - when it is set, keep on consuming descriptors from
AF_XDP Tx ring and put them directly onto Cq. Previously these
descriptors were silently lost and could never be reached again.
Fixes: cf24f5a5feea ("xsk: add support for AF_XDP multi-buffer on Tx path")
Closes: https://lore.kernel.org/all/20260425041726.85FB3C2BCB2@smtp.kernel.org/
Reviewed-by: Jason Xing <kernelxing@tencent.com>
Co-developed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com> # wrapped cq addr submission onto routine
Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Signed-off-by: Jason Xing <kernelxing@tencent.com>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20260719135609.147823-3-maciej.fijalkowski@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 72f2b4516faf ("xsk: reclaim invalid Tx descriptors in ZC batch path")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/xdp_sock.h | 1 +
net/xdp/xsk.c | 53 +++++++++++++++++++++++++++++++++++++++---
2 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h
index 98491d774d826..02a0896f8525c 100644
--- a/include/net/xdp_sock.h
+++ b/include/net/xdp_sock.h
@@ -80,6 +80,7 @@ struct xdp_sock {
* call of __xsk_generic_xmit().
*/
struct sk_buff *skb;
+ bool drain_cont;
struct list_head map_list;
/* Protects map_list */
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index 36170e10deda4..7054f5fd7f03e 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -600,6 +600,28 @@ static void xsk_cq_cancel_locked(struct xdp_sock *xs, u32 n)
spin_unlock_irqrestore(&xs->pool->cq_lock, flags);
}
+static int xsk_cq_submit_addr_single_locked(struct xsk_buff_pool *pool,
+ struct xdp_desc *desc)
+{
+ struct xsk_queue *cq = pool->cq;
+ unsigned long flags;
+ int err = -EAGAIN;
+
+ spin_lock_irqsave(&pool->cq_lock, flags);
+ /* Addresses are written at reserve time and publishing is positional,
+ * so the entry can only be published if no earlier Tx is still in
+ * flight in front of it. The caller retries later otherwise.
+ */
+ if (cq->cached_prod == READ_ONCE(cq->ring->producer)) {
+ err = xskq_prod_reserve_addr(cq, desc->addr);
+ if (!err)
+ xskq_prod_submit_n(cq, 1);
+ }
+ spin_unlock_irqrestore(&pool->cq_lock, flags);
+
+ return err;
+}
+
static u32 xsk_get_num_desc(struct sk_buff *skb)
{
return skb ? (long)skb_shinfo(skb)->destructor_arg : 0;
@@ -822,12 +844,13 @@ static int __xsk_generic_xmit(struct sock *sk)
{
struct xdp_sock *xs = xdp_sk(sk);
u32 max_batch = TX_BATCH_SIZE;
- bool sent_frame = false;
struct xdp_desc desc;
struct sk_buff *skb;
+ u32 cached_cons;
int err = 0;
mutex_lock(&xs->mutex);
+ cached_cons = xs->tx->cached_cons;
/* Since we dropped the RCU read lock, the socket state might have changed. */
if (unlikely(!xsk_is_bound(xs))) {
@@ -844,6 +867,17 @@ static int __xsk_generic_xmit(struct sock *sk)
goto out;
}
+ if (unlikely(xs->drain_cont)) {
+ if (xsk_cq_submit_addr_single_locked(xs->pool, &desc)) {
+ err = -EAGAIN;
+ goto out;
+ }
+ xs->tx->invalid_descs++;
+ xskq_cons_release(xs->tx);
+ xs->drain_cont = xp_mb_desc(&desc);
+ continue;
+ }
+
/* This is the backpressure mechanism for the Tx path.
* Reserve space in the completion queue and only proceed
* if there is space in it. This avoids having to implement
@@ -857,6 +891,8 @@ static int __xsk_generic_xmit(struct sock *sk)
err = PTR_ERR(skb);
if (err != -EOVERFLOW)
goto out;
+ if (xp_mb_desc(&desc))
+ xs->drain_cont = true;
err = 0;
continue;
}
@@ -885,18 +921,29 @@ static int __xsk_generic_xmit(struct sock *sk)
goto out;
}
- sent_frame = true;
xs->skb = NULL;
}
if (xskq_has_descs(xs->tx)) {
+ bool drain = xs->skb || xs->drain_cont || xp_mb_desc(&desc);
+
if (xs->skb)
xsk_drop_skb(xs->skb);
+
+ err = xsk_cq_submit_addr_single_locked(xs->pool, &desc);
+ if (err) {
+ xs->tx->invalid_descs--;
+ xs->drain_cont = drain;
+ err = -EAGAIN;
+ goto out;
+ }
+
xskq_cons_release(xs->tx);
+ xs->drain_cont = xp_mb_desc(&desc);
}
out:
- if (sent_frame)
+ if (xs->tx->cached_cons != cached_cons)
if (xsk_tx_writeable(xs))
sk->sk_write_space(sk);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 500/869] xsk: provide sufficient space in pool->tx_descs
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (498 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 499/869] xsk: drain continuation descs after overflow in xsk_build_skb() Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 501/869] xsk: reclaim invalid Tx descriptors in ZC batch path Greg Kroah-Hartman
` (369 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jason Xing, Maciej Fijalkowski,
Stanislav Fomichev, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
[ Upstream commit 08c9a8e794b4694c100dafcb80e069e29ad81b64 ]
The temporary Tx descriptor array in an XSK buffer pool is currently
sized from the Tx ring of the socket that creates the pool.
This is insufficient for shared-UMEM Tx. A later socket may have a
larger Tx ring and submit a valid multi-buffer packet containing more
descriptors than the first socket's ring, while still remaining within
the device's xdp_zc_max_segs limit.
A packet-framed batch parser bounded by the temporary array cannot reach
the end-of-packet descriptor in that case. It leaves the packet on the
Tx ring and encounters the same packet on every subsequent attempt,
stalling Tx processing for that socket.
Size the temporary descriptor array to the larger of the first Tx ring
and the device's xdp_zc_max_segs capability. This keeps the array large
enough to inspect one maximum-sized valid packet. Larger shared Tx rings
do not require further resizing, as they can be processed over multiple
batches.
Following commit will actually address the data path side.
Fixes: d5581966040f ("xsk: support ZC Tx multi-buffer in batch API")
Reviewed-by: Jason Xing <kernelxing@tencent.com>
Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20260719135609.147823-4-maciej.fijalkowski@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 72f2b4516faf ("xsk: reclaim invalid Tx descriptors in ZC batch path")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/xsk_buff_pool.h | 6 ++++--
net/xdp/xsk.c | 10 +++++++---
net/xdp/xsk_buff_pool.c | 13 ++++++++-----
3 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/include/net/xsk_buff_pool.h b/include/net/xsk_buff_pool.h
index 42e9058d85687..85e07a5a314b5 100644
--- a/include/net/xsk_buff_pool.h
+++ b/include/net/xsk_buff_pool.h
@@ -101,12 +101,14 @@ struct xsk_buff_pool {
/* AF_XDP core. */
struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs,
- struct xdp_umem *umem);
+ struct xdp_umem *umem,
+ u32 max_segs);
int xp_assign_dev(struct xsk_buff_pool *pool, struct net_device *dev,
u16 queue_id, u16 flags);
int xp_assign_dev_shared(struct xsk_buff_pool *pool, struct xdp_sock *umem_xs,
struct net_device *dev, u16 queue_id);
-int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs);
+int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs,
+ u32 max_segs);
void xp_destroy(struct xsk_buff_pool *pool);
void xp_get_pool(struct xsk_buff_pool *pool);
bool xp_put_pool(struct xsk_buff_pool *pool);
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index 7054f5fd7f03e..3442941285ec4 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -1317,7 +1317,8 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
* and/or device.
*/
xs->pool = xp_create_and_assign_umem(xs,
- umem_xs->umem);
+ umem_xs->umem,
+ dev->xdp_zc_max_segs);
if (!xs->pool) {
err = -ENOMEM;
sockfd_put(sock);
@@ -1349,7 +1350,8 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
* utilizes
*/
if (xs->tx && !xs->pool->tx_descs) {
- err = xp_alloc_tx_descs(xs->pool, xs);
+ err = xp_alloc_tx_descs(xs->pool, xs,
+ dev->xdp_zc_max_segs);
if (err) {
xp_put_pool(xs->pool);
xs->pool = NULL;
@@ -1367,7 +1369,9 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
goto out_unlock;
} else {
/* This xsk has its own umem. */
- xs->pool = xp_create_and_assign_umem(xs, xs->umem);
+ xs->pool = xp_create_and_assign_umem(xs, xs->umem,
+ dev->xdp_zc_max_segs);
+
if (!xs->pool) {
err = -ENOMEM;
goto out_unlock;
diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c
index a22cedd280cbb..dba014f72dc22 100644
--- a/net/xdp/xsk_buff_pool.c
+++ b/net/xdp/xsk_buff_pool.c
@@ -44,10 +44,12 @@ void xp_destroy(struct xsk_buff_pool *pool)
kvfree(pool);
}
-int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs)
+int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs,
+ u32 max_segs)
{
- pool->tx_descs = kvcalloc(xs->tx->nentries, sizeof(*pool->tx_descs),
- GFP_KERNEL);
+ u32 nentries = max(xs->tx->nentries, max_segs);
+
+ pool->tx_descs = kvcalloc(nentries, sizeof(*pool->tx_descs), GFP_KERNEL);
if (!pool->tx_descs)
return -ENOMEM;
@@ -55,7 +57,8 @@ int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs)
}
struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs,
- struct xdp_umem *umem)
+ struct xdp_umem *umem,
+ u32 max_segs)
{
bool unaligned = umem->flags & XDP_UMEM_UNALIGNED_CHUNK_FLAG;
struct xsk_buff_pool *pool;
@@ -72,7 +75,7 @@ struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs,
goto out;
if (xs->tx)
- if (xp_alloc_tx_descs(pool, xs))
+ if (xp_alloc_tx_descs(pool, xs, max_segs))
goto out;
pool->chunk_mask = ~((u64)umem->chunk_size - 1);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 501/869] xsk: reclaim invalid Tx descriptors in ZC batch path
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (499 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 500/869] xsk: provide sufficient space in pool->tx_descs Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 502/869] btrfs: skip global block reserve accounting for rescue mounts Greg Kroah-Hartman
` (368 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jason Xing, Maciej Fijalkowski,
Stanislav Fomichev, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
[ Upstream commit 72f2b4516faf55d4dfac2414649d3cffa5fd2c5e ]
The zero-copy Tx batch parser stops when it encounters an invalid
descriptor. If this happens after one or more continuation descriptors,
the Tx consumer can be advanced past fragments that are neither submitted
to the driver nor returned to userspace through the completion ring.
A similar problem occurs when a packet exceeds xdp_zc_max_segs. The
descriptors consumed up to the limit are released without completion, and
the remaining continuation descriptors can subsequently be interpreted
as the beginning of another packet.
Parse Tx batches in packet units and distinguish descriptors belonging to
complete valid packets from descriptors consumed while draining an
invalid or oversized packet. Return the former to the driver and append
the latter to the CQ address area so userspace can reclaim their UMEM
frames.
Treat a standalone invalid descriptor as a one-descriptor reclaim-only
packet. Advancing the Tx-ring consumer releases the ring slot, but does
not by itself return ownership of the referenced UMEM frame to userspace.
Once draining starts, continue until the packet's end-of-packet
descriptor is consumed. Preserve the drain state on the socket when EOP
has not yet been supplied, so draining can continue during a later call.
Leave incomplete but otherwise valid packets on the Tx ring.
Shared-UMEM pools using multi-buffer Tx also need packet-framed parsing.
Walk their Tx sockets one packet at a time, preserving the existing
per-socket fairness scheme, instead of using the legacy one-descriptor
fallback. Keep that fallback for shared pools that do not use
multi-buffer Tx. Since the drain state is maintained per socket and both
the singular and shared paths can resume an interrupted drain, changing
the socket list from singular to shared requires no special bind-time
transition.
CQ entries are positional, and drivers may complete only part of the Tx
work returned by xsk_tx_peek_release_desc_batch(). Therefore, reclaim-only
entries cannot be published immediately when earlier driver-visible
descriptors are still outstanding.
Track the number of driver-visible CQ entries preceding the reclaim
entries. Let xsk_tx_completed() publish partial hardware Tx completions,
and publish the reclaim entries only after every earlier Tx descriptor
has completed. Complete a reclaim-only batch immediately when there is no
driver-visible work in front of it, and prevent another Tx batch from
being appended while reclaim entries remain pending.
Also cap batch processing by the size of the pool's temporary descriptor
array, as Tx rings belonging to sockets sharing a UMEM may have different
sizes.
This ensures that every invalid Tx descriptor consumed by the ZC batch
path is either submitted to the driver as part of a valid packet or
returned to userspace without violating CQ completion ordering.
Reviewed-by: Jason Xing <kernelxing@tencent.com>
Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Fixes: cf24f5a5feea ("xsk: add support for AF_XDP multi-buffer on Tx path")
Link: https://patch.msgid.link/20260719135609.147823-5-maciej.fijalkowski@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
Documentation/networking/af_xdp.rst | 54 ++++----
include/net/xsk_buff_pool.h | 3 +
net/xdp/xsk.c | 188 +++++++++++++++++++++++++---
net/xdp/xsk_buff_pool.c | 1 +
net/xdp/xsk_queue.h | 65 +++++++---
5 files changed, 249 insertions(+), 62 deletions(-)
diff --git a/Documentation/networking/af_xdp.rst b/Documentation/networking/af_xdp.rst
index dceeb0d763aa2..e2c5ec61c2bd9 100644
--- a/Documentation/networking/af_xdp.rst
+++ b/Documentation/networking/af_xdp.rst
@@ -43,12 +43,13 @@ UMEM also has two rings: the FILL ring and the COMPLETION ring. The
FILL ring is used by the application to send down addr for the kernel
to fill in with RX packet data. References to these frames will then
appear in the RX ring once each packet has been received. The
-COMPLETION ring, on the other hand, contains frame addr that the
-kernel has transmitted completely and can now be used again by user
-space, for either TX or RX. Thus, the frame addrs appearing in the
-COMPLETION ring are addrs that were previously transmitted using the
-TX ring. In summary, the RX and FILL rings are used for the RX path
-and the TX and COMPLETION rings are used for the TX path.
+COMPLETION ring, on the other hand, contains frame addresses from Tx
+descriptors that the kernel has finished processing and that can now be
+used again by user space, for either Tx or Rx. This includes frames whose
+transmission has completed as well as frames referenced by invalid Tx
+descriptors rejected by the kernel. A completion therefore returns
+ownership of a frame to user space, but does not by itself guarantee that
+the packet was successfully transmitted.
The socket is then finally bound with a bind() call to a device and a
specific queue id on that device, and it is not until bind is
@@ -169,14 +170,15 @@ chunks mode, then the incoming addr will be left untouched.
UMEM Completion Ring
~~~~~~~~~~~~~~~~~~~~
-The COMPLETION Ring is used transfer ownership of UMEM frames from
+The COMPLETION Ring is used to transfer ownership of UMEM frames from
kernel-space to user-space. Just like the FILL ring, UMEM indices are
-used.
-
-Frames passed from the kernel to user-space are frames that has been
-sent (TX ring) and can be used by user-space again.
-
-The user application consumes UMEM addrs from this ring.
+used. Frames passed from the kernel to user-space are frames referenced
+by Tx descriptors that the kernel has finished processing and can be
+used by user-space again. This includes both frames whose transmission
+has completed and frames referenced by invalid Tx descriptors that were
+rejected and reclaimed by the kernel. A completion entry does not
+guarantee successful packet transmission. The user application consumes
+UMEM addrs from this ring.
RX Ring
@@ -499,21 +501,25 @@ will be treated as an invalid descriptor.
These are the semantics for producing packets onto AF_XDP Tx ring
consisting of multiple frames:
-* When an invalid descriptor is found, all the other
- descriptors/frames of this packet are marked as invalid and not
- completed. The next descriptor is treated as the start of a new
- packet, even if this was not the intent (because we cannot guess
- the intent). As before, if your program is producing invalid
- descriptors you have a bug that must be fixed.
+* When an invalid descriptor is found, the complete packet is treated as
+ invalid. The kernel consumes descriptors through the descriptor marking
+ the end of the packet and returns all their frame addresses through the
+ COMPLETION ring. A standalone invalid descriptor is treated as a
+ one-descriptor invalid packet. The descriptor following the end of the
+ invalid packet is treated as the start of a new packet. As before, if
+ your program is producing invalid descriptors you have a bug that must
+ be fixed. Rejected descriptors are reported in the ``tx_invalid_descs``
+ statistic.
* Zero length descriptors are treated as invalid descriptors.
* For copy mode, the maximum supported number of frames in a packet is
- equal to CONFIG_MAX_SKB_FRAGS + 1. If it is exceeded, all
- descriptors accumulated so far are dropped and treated as
- invalid. To produce an application that will work on any system
- regardless of this config setting, limit the number of frags to 18,
- as the minimum value of the config is 17.
+ equal to CONFIG_MAX_SKB_FRAGS + 1. If it is exceeded, all descriptors
+ through the end of the oversized packet are consumed, treated as invalid,
+ and their frame addresses are returned through the COMPLETION ring. To
+ produce an application that will work on any system regardless of this
+ config setting, limit the number of frags to 18, as the minimum value of
+ the config is 17.
* For zero-copy mode, the limit is up to what the NIC HW
supports. Usually at least five on the NICs we have checked. We
diff --git a/include/net/xsk_buff_pool.h b/include/net/xsk_buff_pool.h
index 85e07a5a314b5..4fce4bd826b9c 100644
--- a/include/net/xsk_buff_pool.h
+++ b/include/net/xsk_buff_pool.h
@@ -78,6 +78,9 @@ struct xsk_buff_pool {
u32 chunk_size;
u32 chunk_shift;
u32 frame_len;
+ u32 tx_descs_nentries;
+ u32 reclaim_descs;
+ u32 tx_zc_pending_descs;
u8 tx_metadata_len; /* inherited from umem */
u8 cached_need_wakeup;
bool uses_need_wakeup;
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index 3442941285ec4..8dd43f06d6ed1 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -440,6 +440,23 @@ void __xsk_map_flush(struct list_head *flush_list)
void xsk_tx_completed(struct xsk_buff_pool *pool, u32 nb_entries)
{
+ u32 reclaim_descs = READ_ONCE(pool->reclaim_descs);
+
+ if (unlikely(reclaim_descs)) {
+ u32 pending_descs = READ_ONCE(pool->tx_zc_pending_descs);
+
+ if (nb_entries < pending_descs) {
+ WRITE_ONCE(pool->tx_zc_pending_descs,
+ pending_descs - nb_entries);
+ xskq_prod_submit_n(pool->cq, nb_entries);
+ return;
+ }
+
+ WRITE_ONCE(pool->tx_zc_pending_descs, 0);
+ nb_entries += reclaim_descs;
+ WRITE_ONCE(pool->reclaim_descs, 0);
+ }
+
xskq_prod_submit_n(pool->cq, nb_entries);
}
EXPORT_SYMBOL(xsk_tx_completed);
@@ -518,24 +535,158 @@ static u32 xsk_tx_peek_release_fallback(struct xsk_buff_pool *pool, u32 max_entr
return nb_pkts;
}
+static void xsk_tx_commit_batch(struct xsk_buff_pool *pool,
+ struct xsk_tx_batch *batch)
+{
+ u32 nb_descs = xsk_tx_batch_cq_descs(batch);
+ u32 cq_cached_prod;
+
+ if (!nb_descs)
+ return;
+
+ cq_cached_prod = pool->cq->cached_prod;
+ xskq_prod_write_addr_batch(pool->cq, pool->tx_descs, nb_descs);
+
+ if (unlikely(batch->reclaim_descs)) {
+ u32 cq_pending_descs;
+
+ /* CQ is positional. Descriptors already written but not
+ * submitted must complete before any reclaim-only descriptors
+ * appended below.
+ */
+ cq_pending_descs = cq_cached_prod -
+ READ_ONCE(pool->cq->ring->producer);
+
+ WRITE_ONCE(pool->tx_zc_pending_descs,
+ batch->tx_descs + cq_pending_descs);
+ WRITE_ONCE(pool->reclaim_descs, batch->reclaim_descs);
+ if (unlikely(!pool->tx_zc_pending_descs))
+ xsk_tx_completed(pool, 0);
+ }
+}
+
+static struct xsk_tx_batch
+__xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, struct xdp_sock *xs,
+ struct xdp_desc *descs, u32 max_descs)
+{
+ struct xsk_tx_batch batch = {};
+ u32 entries;
+
+ entries = xskq_cons_nb_entries(xs->tx, max_descs);
+ if (!entries)
+ return batch;
+
+ batch = xskq_cons_read_desc_batch(xs, pool, descs, max_descs);
+ if (!xsk_tx_batch_cq_descs(&batch)) {
+ xs->tx->queue_empty_descs++;
+ } else {
+ __xskq_cons_release(xs->tx);
+ xs->sk.sk_write_space(&xs->sk);
+ }
+ return batch;
+}
+
+static struct xsk_tx_batch
+xsk_tx_peek_release_shared_desc_batch(struct xsk_buff_pool *pool, u32 max_descs)
+{
+ u32 cq_descs_before, cq_descs_after;
+ struct xsk_tx_batch sum_batch = {};
+ bool budget_exhausted;
+ u32 per_socket_budget;
+ struct xdp_sock *xs;
+
+ /* The fairness quota must allow one maximum-sized valid packet. */
+ per_socket_budget = max_t(u32, MAX_PER_SOCKET_BUDGET,
+ pool->netdev->xdp_zc_max_segs);
+
+again:
+ budget_exhausted = false;
+ cq_descs_before = xsk_tx_batch_cq_descs(&sum_batch);
+ list_for_each_entry_rcu(xs, &pool->xsk_tx_list, tx_list) {
+ u32 budget, budget_left, offset, remaining, used;
+ struct xsk_tx_batch curr_batch;
+
+ /* Once reclaim-only descriptors have been appended to the CQ
+ * address area, do not append driver-visible Tx descriptors
+ * from another socket after them. xsk_tx_completed() relies on
+ * all driver-visible descriptors preceding all reclaim-only
+ * descriptors in CQ order.
+ */
+ if (sum_batch.reclaim_descs)
+ break;
+
+ /* be gentle when playing with pool->tx_descs */
+ offset = xsk_tx_batch_cq_descs(&sum_batch);
+ if (offset >= max_descs)
+ break;
+
+ if (xs->tx_budget_spent >= per_socket_budget) {
+ if (xskq_cons_nb_entries(xs->tx, 1))
+ budget_exhausted = true;
+ continue;
+ }
+
+ budget_left = per_socket_budget - xs->tx_budget_spent;
+ remaining = max_descs - offset;
+ budget = min(remaining, budget_left);
+
+ curr_batch = __xsk_tx_peek_release_desc_batch(pool, xs,
+ pool->tx_descs + offset,
+ budget);
+ used = xsk_tx_batch_cq_descs(&curr_batch);
+ if (!used) {
+ if (curr_batch.budget_limited && budget_left < remaining)
+ budget_exhausted = true;
+ continue;
+ }
+
+ xs->tx_budget_spent += used;
+ sum_batch.tx_descs += curr_batch.tx_descs;
+ sum_batch.reclaim_descs = curr_batch.reclaim_descs;
+ }
+
+ cq_descs_after = xsk_tx_batch_cq_descs(&sum_batch);
+
+ if (sum_batch.reclaim_descs || cq_descs_after >= max_descs)
+ return sum_batch;
+
+ /* Continue filling the batch while this pass made progress */
+ if (cq_descs_before != cq_descs_after)
+ goto again;
+
+ if (!budget_exhausted)
+ return sum_batch;
+
+ list_for_each_entry_rcu(xs, &pool->xsk_tx_list, tx_list)
+ xs->tx_budget_spent = 0;
+ goto again;
+}
+
u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 nb_pkts)
{
+ struct xsk_tx_batch batch = {};
struct xdp_sock *xs;
+ bool umem_shared;
rcu_read_lock();
- if (!list_is_singular(&pool->xsk_tx_list)) {
- /* Fallback to the non-batched version */
- rcu_read_unlock();
- return xsk_tx_peek_release_fallback(pool, nb_pkts);
- }
+ if (unlikely(READ_ONCE(pool->reclaim_descs)))
+ goto out;
- xs = list_first_or_null_rcu(&pool->xsk_tx_list, struct xdp_sock, tx_list);
- if (!xs) {
- nb_pkts = 0;
+ xs = list_first_or_null_rcu(&pool->xsk_tx_list, struct xdp_sock,
+ tx_list);
+ if (!xs)
goto out;
- }
- nb_pkts = xskq_cons_nb_entries(xs->tx, nb_pkts);
+ nb_pkts = min(nb_pkts, pool->tx_descs_nentries);
+ if (!nb_pkts)
+ goto out;
+
+ umem_shared = !list_is_singular(&pool->xsk_tx_list);
+
+ if (umem_shared && !(pool->umem->flags & XDP_UMEM_SG_FLAG)) {
+ rcu_read_unlock();
+ return xsk_tx_peek_release_fallback(pool, nb_pkts);
+ }
/* This is the backpressure mechanism for the Tx path. Try to
* reserve space in the completion queue for all packets, but
@@ -547,19 +698,16 @@ u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 nb_pkts)
if (!nb_pkts)
goto out;
- nb_pkts = xskq_cons_read_desc_batch(xs->tx, pool, nb_pkts);
- if (!nb_pkts) {
- xs->tx->queue_empty_descs++;
- goto out;
- }
-
- __xskq_cons_release(xs->tx);
- xskq_prod_write_addr_batch(pool->cq, pool->tx_descs, nb_pkts);
- xs->sk.sk_write_space(&xs->sk);
+ batch = umem_shared ?
+ xsk_tx_peek_release_shared_desc_batch(pool, nb_pkts) :
+ __xsk_tx_peek_release_desc_batch(pool, xs,
+ pool->tx_descs,
+ nb_pkts);
+ xsk_tx_commit_batch(pool, &batch);
out:
rcu_read_unlock();
- return nb_pkts;
+ return batch.tx_descs;
}
EXPORT_SYMBOL(xsk_tx_peek_release_desc_batch);
diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c
index dba014f72dc22..925e0e62491d9 100644
--- a/net/xdp/xsk_buff_pool.c
+++ b/net/xdp/xsk_buff_pool.c
@@ -53,6 +53,7 @@ int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs,
if (!pool->tx_descs)
return -ENOMEM;
+ pool->tx_descs_nentries = nentries;
return 0;
}
diff --git a/net/xdp/xsk_queue.h b/net/xdp/xsk_queue.h
index 2ec64c185f8f7..43d4de9afcf90 100644
--- a/net/xdp/xsk_queue.h
+++ b/net/xdp/xsk_queue.h
@@ -53,6 +53,17 @@ struct parsed_desc {
u32 valid;
};
+struct xsk_tx_batch {
+ u32 tx_descs;
+ u32 reclaim_descs;
+ bool budget_limited;
+};
+
+static inline u32 xsk_tx_batch_cq_descs(const struct xsk_tx_batch *batch)
+{
+ return batch->tx_descs + batch->reclaim_descs;
+}
+
/* The structure of the shared state of the rings are a simple
* circular buffer, as outlined in
* Documentation/core-api/circular-buffers.rst. For the Rx and
@@ -258,17 +269,18 @@ static inline void parse_desc(struct xsk_queue *q, struct xsk_buff_pool *pool,
parsed->mb = xp_mb_desc(desc);
}
-static inline
-u32 xskq_cons_read_desc_batch(struct xsk_queue *q, struct xsk_buff_pool *pool,
- u32 max)
+static inline struct xsk_tx_batch
+xskq_cons_read_desc_batch(struct xdp_sock *xs, struct xsk_buff_pool *pool,
+ struct xdp_desc *descs, u32 max)
{
- u32 cached_cons = q->cached_cons, nb_entries = 0;
- struct xdp_desc *descs = pool->tx_descs;
- u32 total_descs = 0, nr_frags = 0;
+ bool drain = READ_ONCE(xs->drain_cont);
+ u32 cached_cons, nb_entries = 0;
+ struct xsk_tx_batch batch = {};
+ struct xsk_queue *q = xs->tx;
+ u32 nr_frags = 0;
+
+ cached_cons = q->cached_cons;
- /* track first entry, if stumble upon *any* invalid descriptor, rewind
- * current packet that consists of frags and stop the processing
- */
while (cached_cons != q->cached_prod && nb_entries < max) {
struct xdp_rxtx_ring *ring = (struct xdp_rxtx_ring *)q->ring;
u32 idx = cached_cons & q->ring_mask;
@@ -278,25 +290,42 @@ u32 xskq_cons_read_desc_batch(struct xsk_queue *q, struct xsk_buff_pool *pool,
cached_cons++;
parse_desc(q, pool, &descs[nb_entries], &parsed);
if (unlikely(!parsed.valid))
- break;
+ drain = true;
+
+ nr_frags++;
+ nb_entries++;
if (likely(!parsed.mb)) {
- total_descs += (nr_frags + 1);
- nr_frags = 0;
- } else {
- nr_frags++;
- if (nr_frags == pool->netdev->xdp_zc_max_segs) {
+ if (unlikely(drain)) {
+ batch.reclaim_descs = nr_frags;
+ WRITE_ONCE(xs->drain_cont, false);
nr_frags = 0;
break;
}
+
+ batch.tx_descs += nr_frags;
+ nr_frags = 0;
+ continue;
+ }
+
+ if (nr_frags == pool->netdev->xdp_zc_max_segs)
+ drain = true;
+ }
+
+ if (nr_frags) {
+ if (drain) {
+ batch.reclaim_descs = nr_frags;
+ WRITE_ONCE(xs->drain_cont, true);
+ } else {
+ if (nb_entries == max)
+ batch.budget_limited = true;
+ cached_cons -= nr_frags;
}
- nb_entries++;
}
- cached_cons -= nr_frags;
/* Release valid plus any invalid entries */
xskq_cons_release_n(q, cached_cons - q->cached_cons);
- return total_descs;
+ return batch;
}
/* Functions for consumers */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 502/869] btrfs: skip global block reserve accounting for rescue mounts
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (500 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 501/869] xsk: reclaim invalid Tx descriptors in ZC batch path Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 503/869] mm/page_table_check: skip special zero mappings Greg Kroah-Hartman
` (367 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Qu Wenruo, Dongjiang Zhu,
David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dongjiang Zhu <zhudongjiang@fnnas.com>
[ Upstream commit 51a0e8399858621442807a26057bcd1cd3ced046 ]
[BUG]
Mounting with rescue=ibadroots after corrupting the block group tree
root triggers a NULL pointer dereference:
BUG: kernel NULL pointer dereference, address: 0000000000000100
RIP: 0010:btrfs_update_global_block_rsv+0x9d/0x1c0 [btrfs]
Call Trace:
fill_dummy_bgs+0xd4/0x120 [btrfs]
open_ctree+0xc6e/0x1ca0 [btrfs]
btrfs_get_tree+0x50d/0xa40 [btrfs]
The same crash occurs with a corrupted raid stripe tree root, via
btrfs_read_block_groups() instead of fill_dummy_bgs().
[CAUSE]
With rescue=ibadroots, btrfs_read_roots() allows the mount to continue
when either root cannot be read, leaving the corresponding root pointer
NULL while its on-disk feature bit remains set.
btrfs_update_global_block_rsv() then dereferences the missing root based
on the feature bit alone.
[FIX]
Rescue mounts are fully read-only and cannot start transactions, so the
global reserve is never consumed. Under btrfs_is_full_ro(), mark the
reserve as full and return before performing the accounting.
And since we need to check if the fs is mount fully RO, export
fs_is_full_ro() as btrfs_is_full_ro(), and move it to fs.h.
Fixes: 8dbfc14fc736 ("btrfs: account block group tree when calculating global reserve size")
Fixes: 515020900d44 ("btrfs: read raid stripe tree from disk")
Suggested-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Dongjiang Zhu <zhudongjiang@fnnas.com>
[ Squash the fs_is_full_ro() export commit into this one. ]
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/block-rsv.c | 19 +++++++++++++++++--
fs/btrfs/disk-io.c | 11 +----------
fs/btrfs/fs.h | 9 +++++++++
3 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c
index a578bd3b32bb0..f111500a2c46e 100644
--- a/fs/btrfs/block-rsv.c
+++ b/fs/btrfs/block-rsv.c
@@ -326,10 +326,25 @@ void btrfs_block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv,
void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)
{
struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
- struct btrfs_space_info *sinfo = block_rsv->space_info;
+ struct btrfs_space_info *sinfo;
struct btrfs_root *root, *tmp;
- u64 num_bytes = btrfs_root_used(&fs_info->tree_root->root_item);
unsigned int min_items = 1;
+ u64 num_bytes;
+
+ /*
+ * A full read-only mount (rescue options) cannot start transactions,
+ * so the global reserve is never consumed. Mark it as full and skip
+ * the accounting.
+ */
+ if (btrfs_is_full_ro(fs_info)) {
+ spin_lock(&block_rsv->lock);
+ block_rsv->full = true;
+ spin_unlock(&block_rsv->lock);
+ return;
+ }
+
+ sinfo = block_rsv->space_info;
+ num_bytes = btrfs_root_used(&fs_info->tree_root->root_item);
/*
* The global block rsv is based on the size of the extent tree, the
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 2c98dd8c126e8..74af70897bcb0 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3169,15 +3169,6 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
return 0;
}
-static bool fs_is_full_ro(const struct btrfs_fs_info *fs_info)
-{
- if (!sb_rdonly(fs_info->sb))
- return false;
- if (unlikely(fs_info->mount_opt & BTRFS_MOUNT_FULL_RO_MASK))
- return true;
- return false;
-}
-
int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_devices)
{
u32 sectorsize;
@@ -3287,7 +3278,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
WRITE_ONCE(fs_info->fs_error, -EUCLEAN);
/* If the fs has any rescue options, no transaction is allowed. */
- if (fs_is_full_ro(fs_info))
+ if (btrfs_is_full_ro(fs_info))
WRITE_ONCE(fs_info->fs_error, -EROFS);
/* Set up fs_info before parsing mount options */
diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h
index 90b104dd38c23..de10a95707c85 100644
--- a/fs/btrfs/fs.h
+++ b/fs/btrfs/fs.h
@@ -1044,6 +1044,15 @@ void __btrfs_clear_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag,
#define btrfs_test_opt(fs_info, opt) ((fs_info)->mount_opt & \
BTRFS_MOUNT_##opt)
+static inline bool btrfs_is_full_ro(const struct btrfs_fs_info *fs_info)
+{
+ if (!sb_rdonly(fs_info->sb))
+ return false;
+ if (unlikely(fs_info->mount_opt & BTRFS_MOUNT_FULL_RO_MASK))
+ return true;
+ return false;
+}
+
static inline int btrfs_fs_closing(const struct btrfs_fs_info *fs_info)
{
/* Do it this way so we only ever do one test_bit in the normal case. */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 503/869] mm/page_table_check: skip special zero mappings
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (501 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 502/869] btrfs: skip global block reserve accounting for rescue mounts Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 504/869] eventfs: Use children field for rcu head and add memory barriers Greg Kroah-Hartman
` (366 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Zhiling Zou, Ren Wei, Vega,
Pasha Tatashin, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <zhilinz@nebusec.ai>
[ Upstream commit 8db4bab826ccc9ec10fa41736a48031cd338d392 ]
page_table_check_set() and page_table_check_clear() account mappings based
on PageAnon(). Shared zero-page PTEs and huge zero PMDs are special
mappings, but page_table_check can still account them as file-backed
pages.
An unprivileged process can populate enough zero mappings to overflow
file_map_count and hit the existing BUG_ON(). The PTE path can do this
with the shared zero page, and the PMD path can do the same with huge zero
mappings.
Skip special zero mappings in the user page-table accounting paths. Keep
the PTE-side pte_special() check, and identify huge zero PMDs from the
mapped folio instead of pmd_special(). That covers architectures where
pmd_special() is a no-op without adding huge_zero_pfn checks to the
generic counter helpers.
Link: https://lore.kernel.org/cover.1784717203.git.zhilinz@nebusec.ai
Link: https://lore.kernel.org/e94478e4fb7912fb7e8ebebed5ce85d00dc9a69d.1784717203.git.zhilinz@nebusec.ai
Fixes: df4e817b7108 ("mm: page table check")
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
Signed-off-by: Ren Wei <enjou1224z@gmail.com>
Reported-by: Vega <vega@nebusec.ai>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>
Assisted-by: Codex:gpt-5.4
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/page_table_check.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/mm/page_table_check.c b/mm/page_table_check.c
index ee52927e9e66b..2efa910eef23e 100644
--- a/mm/page_table_check.c
+++ b/mm/page_table_check.c
@@ -165,18 +165,29 @@ void __page_table_check_pte_clear(struct mm_struct *mm, pte_t pte)
if (&init_mm == mm)
return;
- if (pte_user_accessible_page(pte)) {
+ if (pte_user_accessible_page(pte) && !pte_special(pte)) {
page_table_check_clear(pte_pfn(pte), PAGE_SIZE >> PAGE_SHIFT);
}
}
EXPORT_SYMBOL(__page_table_check_pte_clear);
+static inline bool page_table_check_huge_zero_pmd(pmd_t pmd)
+{
+ unsigned long pfn = pmd_pfn(pmd);
+
+ if (!pfn_valid(pfn))
+ return false;
+
+ return is_huge_zero_folio(page_folio(pfn_to_page(pfn)));
+}
+
void __page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd)
{
if (&init_mm == mm)
return;
- if (pmd_user_accessible_page(pmd)) {
+ if (pmd_user_accessible_page(pmd) &&
+ !page_table_check_huge_zero_pmd(pmd)) {
page_table_check_clear(pmd_pfn(pmd), PMD_SIZE >> PAGE_SHIFT);
}
}
@@ -221,7 +232,7 @@ void __page_table_check_ptes_set(struct mm_struct *mm, pte_t *ptep, pte_t pte,
for (i = 0; i < nr; i++)
__page_table_check_pte_clear(mm, ptep_get(ptep + i));
- if (pte_user_accessible_page(pte))
+ if (pte_user_accessible_page(pte) && !pte_special(pte))
page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
}
EXPORT_SYMBOL(__page_table_check_ptes_set);
@@ -246,7 +257,8 @@ void __page_table_check_pmd_set(struct mm_struct *mm, pmd_t *pmdp, pmd_t pmd)
page_table_check_pmd_flags(pmd);
__page_table_check_pmd_clear(mm, *pmdp);
- if (pmd_user_accessible_page(pmd)) {
+ if (pmd_user_accessible_page(pmd) &&
+ !page_table_check_huge_zero_pmd(pmd)) {
page_table_check_set(pmd_pfn(pmd), PMD_SIZE >> PAGE_SHIFT,
pmd_write(pmd));
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 504/869] eventfs: Use children field for rcu head and add memory barriers
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (502 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 503/869] mm/page_table_check: skip special zero mappings Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 505/869] selftests: tls: add rekey tests Greg Kroah-Hartman
` (365 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Masami Hiramatsu (Google),
Steven Rostedt, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <rostedt@goodmis.org>
[ Upstream commit f0ece16ffca7384787b692431961ce202907acf5 ]
When an eventfs inode is freed, it sets ei->is_freed and then uses its
ei->list to add it to the srcu link list as the list field is a union with
the rcu list head. As the ei->list is used to iterate over an SRCU
protected list without taking the eventfs_mutex, there's nothing stopping
the iteration over that list to see the ei->rcu instead of the ei->list
and it will read a corrupt target.
To fix this, change the union of the rcu list head with the children list.
On freeing the eventfs inode, set the is_free and execute a smp_wmb()
before adding the eventfs inode to the SRCU list.
On iteration of the ei->children list, at the start, execute a smp_rmb()
and then read the is_freed of the ei to see if the children list is still
valid. If is_freed is set, then the ei_child read is not valid and the
loop should exit immediately.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260808094215.4252430d@robin
Fixes: 704f960dbee2f ("eventfs: Read ei->entries before ei->children in eventfs_iterate()")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260806022719.375354-1-shuangpeng.kernel%40gmail.com
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/tracefs/event_inode.c | 24 ++++++++++++++++++++++++
fs/tracefs/internal.h | 4 ++--
2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c
index a7b082a665bd1..abb0ea57601b6 100644
--- a/fs/tracefs/event_inode.c
+++ b/fs/tracefs/event_inode.c
@@ -124,7 +124,17 @@ static inline void put_ei(struct eventfs_inode *ei)
static inline void free_ei(struct eventfs_inode *ei)
{
if (ei) {
+ /* The ei should have no children if it is being freed. */
+ WARN_ON_ONCE(!list_empty(&ei->children));
ei->is_freed = 1;
+ /*
+ * The SRCU iteration has a smp_rmb() to make sure it
+ * sees a child (that may have already been freed)
+ * before it reads is_free. If is_free is set, it must
+ * not use the child it acquired from ei->children, as
+ * the list may be used for SRCU.
+ */
+ smp_wmb();
put_ei(ei);
}
}
@@ -649,6 +659,20 @@ static int eventfs_iterate(struct file *file, struct dir_context *ctx)
list_for_each_entry_srcu(ei_child, &ei->children, list,
srcu_read_lock_held(&eventfs_srcu)) {
+ /*
+ * If the ei is being freed, then the ei->children may be
+ * being used as the rcu list, which means the next element
+ * may be garbage. The ei->is_free is set before switching
+ * the ei->children over to ei->rcu. The read memory barrier
+ * here makes sure the ei_child is read before is_free is
+ * updated.
+ *
+ * Matches the smp_wmb() in free_ei()
+ */
+ smp_rmb();
+ if (ei->is_freed)
+ return -EINVAL;
+
if (c > 0) {
c--;
continue;
diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h
index a4a7f8431affb..c61481d04c8ee 100644
--- a/fs/tracefs/internal.h
+++ b/fs/tracefs/internal.h
@@ -46,11 +46,11 @@ struct eventfs_attr {
* @ino: The saved inode number
*/
struct eventfs_inode {
+ struct list_head list;
union {
- struct list_head list;
+ struct list_head children;
struct rcu_head rcu;
};
- struct list_head children;
const struct eventfs_entry *entries;
const char *name;
struct eventfs_attr *entry_attrs;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 505/869] selftests: tls: add rekey tests
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (503 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 504/869] eventfs: Use children field for rcu head and add memory barriers Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 506/869] tls: rx: restore msg_iter before TLS 1.3 optimistic retry Greg Kroah-Hartman
` (364 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sabrina Dubroca, David S. Miller,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sabrina Dubroca <sd@queasysnail.net>
[ Upstream commit 555f0edb9ff043196655a5b7cc65f67dfd05b530 ]
Test the kernel's ability to:
- update the key (but not the version or cipher), only for TLS1.3
- pause decryption after receiving a KeyUpdate message, until a new
RX key has been provided
- reflect the pause/non-readable socket in poll()
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Stable-dep-of: 1c8629651cb5 ("tls: rx: restore msg_iter before TLS 1.3 optimistic retry")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
tools/testing/selftests/net/tls.c | 458 ++++++++++++++++++++++++++++++
1 file changed, 458 insertions(+)
diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c
index f27a12d2a2c99..1264a20c1a04e 100644
--- a/tools/testing/selftests/net/tls.c
+++ b/tools/testing/selftests/net/tls.c
@@ -1649,6 +1649,464 @@ TEST_F(tls, recv_efault)
EXPECT_EQ(memcmp(rec2, recv_mem + 9, ret - 9), 0);
}
+#define TLS_RECORD_TYPE_HANDSHAKE 0x16
+/* key_update, length 1, update_not_requested */
+static const char key_update_msg[] = "\x18\x00\x00\x01\x00";
+static void tls_send_keyupdate(struct __test_metadata *_metadata, int fd)
+{
+ size_t len = sizeof(key_update_msg);
+
+ EXPECT_EQ(tls_send_cmsg(fd, TLS_RECORD_TYPE_HANDSHAKE,
+ (char *)key_update_msg, len, 0),
+ len);
+}
+
+static void tls_recv_keyupdate(struct __test_metadata *_metadata, int fd, int flags)
+{
+ char buf[100];
+
+ EXPECT_EQ(tls_recv_cmsg(_metadata, fd, TLS_RECORD_TYPE_HANDSHAKE, buf, sizeof(buf), flags),
+ sizeof(key_update_msg));
+ EXPECT_EQ(memcmp(buf, key_update_msg, sizeof(key_update_msg)), 0);
+}
+
+/* set the key to 0 then 1 for RX, immediately to 1 for TX */
+TEST_F(tls_basic, rekey_rx)
+{
+ struct tls_crypto_info_keys tls12_0, tls12_1;
+ char const *test_str = "test_message";
+ int send_len = strlen(test_str) + 1;
+ char buf[20];
+ int ret;
+
+ if (self->notls)
+ return;
+
+ tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
+ &tls12_0, 0);
+ tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
+ &tls12_1, 1);
+
+ ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_1, tls12_1.len);
+ ASSERT_EQ(ret, 0);
+
+ ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_0, tls12_0.len);
+ ASSERT_EQ(ret, 0);
+
+ ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_1, tls12_1.len);
+ EXPECT_EQ(ret, 0);
+
+ EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+ EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
+ EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
+}
+
+/* set the key to 0 then 1 for TX, immediately to 1 for RX */
+TEST_F(tls_basic, rekey_tx)
+{
+ struct tls_crypto_info_keys tls12_0, tls12_1;
+ char const *test_str = "test_message";
+ int send_len = strlen(test_str) + 1;
+ char buf[20];
+ int ret;
+
+ if (self->notls)
+ return;
+
+ tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
+ &tls12_0, 0);
+ tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
+ &tls12_1, 1);
+
+ ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_0, tls12_0.len);
+ ASSERT_EQ(ret, 0);
+
+ ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_1, tls12_1.len);
+ ASSERT_EQ(ret, 0);
+
+ ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_1, tls12_1.len);
+ EXPECT_EQ(ret, 0);
+
+ EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+ EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
+ EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
+}
+
+TEST_F(tls, rekey)
+{
+ char const *test_str_1 = "test_message_before_rekey";
+ char const *test_str_2 = "test_message_after_rekey";
+ struct tls_crypto_info_keys tls12;
+ int send_len;
+ char buf[100];
+
+ if (variant->tls_version != TLS_1_3_VERSION)
+ return;
+
+ /* initial send/recv */
+ send_len = strlen(test_str_1) + 1;
+ EXPECT_EQ(send(self->fd, test_str_1, send_len, 0), send_len);
+ EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
+ EXPECT_EQ(memcmp(buf, test_str_1, send_len), 0);
+
+ /* update TX key */
+ tls_send_keyupdate(_metadata, self->fd);
+ tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
+
+ /* send after rekey */
+ send_len = strlen(test_str_2) + 1;
+ EXPECT_EQ(send(self->fd, test_str_2, send_len, 0), send_len);
+
+ /* can't receive the KeyUpdate without a control message */
+ EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1);
+
+ /* get KeyUpdate */
+ tls_recv_keyupdate(_metadata, self->cfd, 0);
+
+ /* recv blocking -> -EKEYEXPIRED */
+ EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), 0), -1);
+ EXPECT_EQ(errno, EKEYEXPIRED);
+
+ /* recv non-blocking -> -EKEYEXPIRED */
+ EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_DONTWAIT), -1);
+ EXPECT_EQ(errno, EKEYEXPIRED);
+
+ /* update RX key */
+ EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
+
+ /* recv after rekey */
+ EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
+ EXPECT_EQ(memcmp(buf, test_str_2, send_len), 0);
+}
+
+TEST_F(tls, rekey_fail)
+{
+ char const *test_str_1 = "test_message_before_rekey";
+ char const *test_str_2 = "test_message_after_rekey";
+ struct tls_crypto_info_keys tls12;
+ int send_len;
+ char buf[100];
+
+ /* initial send/recv */
+ send_len = strlen(test_str_1) + 1;
+ EXPECT_EQ(send(self->fd, test_str_1, send_len, 0), send_len);
+ EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
+ EXPECT_EQ(memcmp(buf, test_str_1, send_len), 0);
+
+ /* update TX key */
+ tls_send_keyupdate(_metadata, self->fd);
+
+ if (variant->tls_version != TLS_1_3_VERSION) {
+ /* just check that rekey is not supported and return */
+ tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), -1);
+ EXPECT_EQ(errno, EBUSY);
+ return;
+ }
+
+ /* successful update */
+ tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
+
+ /* invalid update: change of version */
+ tls_crypto_info_init(TLS_1_2_VERSION, variant->cipher_type, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), -1);
+ EXPECT_EQ(errno, EINVAL);
+
+ /* invalid update (RX socket): change of version */
+ tls_crypto_info_init(TLS_1_2_VERSION, variant->cipher_type, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), -1);
+ EXPECT_EQ(errno, EINVAL);
+
+ /* invalid update: change of cipher */
+ if (variant->cipher_type == TLS_CIPHER_AES_GCM_256)
+ tls_crypto_info_init(variant->tls_version, TLS_CIPHER_CHACHA20_POLY1305, &tls12, 1);
+ else
+ tls_crypto_info_init(variant->tls_version, TLS_CIPHER_AES_GCM_256, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), -1);
+ EXPECT_EQ(errno, EINVAL);
+
+ /* send after rekey, the invalid updates shouldn't have an effect */
+ send_len = strlen(test_str_2) + 1;
+ EXPECT_EQ(send(self->fd, test_str_2, send_len, 0), send_len);
+
+ /* can't receive the KeyUpdate without a control message */
+ EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1);
+
+ /* get KeyUpdate */
+ tls_recv_keyupdate(_metadata, self->cfd, 0);
+
+ /* recv blocking -> -EKEYEXPIRED */
+ EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), 0), -1);
+ EXPECT_EQ(errno, EKEYEXPIRED);
+
+ /* recv non-blocking -> -EKEYEXPIRED */
+ EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_DONTWAIT), -1);
+ EXPECT_EQ(errno, EKEYEXPIRED);
+
+ /* update RX key */
+ tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
+
+ /* recv after rekey */
+ EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
+ EXPECT_EQ(memcmp(buf, test_str_2, send_len), 0);
+}
+
+TEST_F(tls, rekey_peek)
+{
+ char const *test_str_1 = "test_message_before_rekey";
+ struct tls_crypto_info_keys tls12;
+ int send_len;
+ char buf[100];
+
+ if (variant->tls_version != TLS_1_3_VERSION)
+ return;
+
+ send_len = strlen(test_str_1) + 1;
+ EXPECT_EQ(send(self->fd, test_str_1, send_len, 0), send_len);
+
+ /* update TX key */
+ tls_send_keyupdate(_metadata, self->fd);
+ tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
+
+ EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_PEEK), send_len);
+ EXPECT_EQ(memcmp(buf, test_str_1, send_len), 0);
+
+ EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
+ EXPECT_EQ(memcmp(buf, test_str_1, send_len), 0);
+
+ /* can't receive the KeyUpdate without a control message */
+ EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_PEEK), -1);
+
+ /* peek KeyUpdate */
+ tls_recv_keyupdate(_metadata, self->cfd, MSG_PEEK);
+
+ /* get KeyUpdate */
+ tls_recv_keyupdate(_metadata, self->cfd, 0);
+
+ /* update RX key */
+ EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
+}
+
+TEST_F(tls, splice_rekey)
+{
+ int send_len = TLS_PAYLOAD_MAX_LEN / 2;
+ char mem_send[TLS_PAYLOAD_MAX_LEN];
+ char mem_recv[TLS_PAYLOAD_MAX_LEN];
+ struct tls_crypto_info_keys tls12;
+ int p[2];
+
+ if (variant->tls_version != TLS_1_3_VERSION)
+ return;
+
+ memrnd(mem_send, sizeof(mem_send));
+
+ ASSERT_GE(pipe(p), 0);
+ EXPECT_EQ(send(self->fd, mem_send, send_len, 0), send_len);
+
+ /* update TX key */
+ tls_send_keyupdate(_metadata, self->fd);
+ tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
+
+ EXPECT_EQ(send(self->fd, mem_send, send_len, 0), send_len);
+
+ EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), send_len);
+ EXPECT_EQ(read(p[0], mem_recv, send_len), send_len);
+ EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
+
+ /* can't splice the KeyUpdate */
+ EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), -1);
+ EXPECT_EQ(errno, EINVAL);
+
+ /* peek KeyUpdate */
+ tls_recv_keyupdate(_metadata, self->cfd, MSG_PEEK);
+
+ /* get KeyUpdate */
+ tls_recv_keyupdate(_metadata, self->cfd, 0);
+
+ /* can't splice before updating the key */
+ EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), -1);
+ EXPECT_EQ(errno, EKEYEXPIRED);
+
+ /* update RX key */
+ EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
+
+ EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), send_len);
+ EXPECT_EQ(read(p[0], mem_recv, send_len), send_len);
+ EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
+}
+
+TEST_F(tls, rekey_peek_splice)
+{
+ char const *test_str_1 = "test_message_before_rekey";
+ struct tls_crypto_info_keys tls12;
+ int send_len;
+ char buf[100];
+ char mem_recv[TLS_PAYLOAD_MAX_LEN];
+ int p[2];
+
+ if (variant->tls_version != TLS_1_3_VERSION)
+ return;
+
+ ASSERT_GE(pipe(p), 0);
+
+ send_len = strlen(test_str_1) + 1;
+ EXPECT_EQ(send(self->fd, test_str_1, send_len, 0), send_len);
+
+ /* update TX key */
+ tls_send_keyupdate(_metadata, self->fd);
+ tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
+
+ EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_PEEK), send_len);
+ EXPECT_EQ(memcmp(buf, test_str_1, send_len), 0);
+
+ EXPECT_EQ(splice(self->cfd, NULL, p[1], NULL, TLS_PAYLOAD_MAX_LEN, 0), send_len);
+ EXPECT_EQ(read(p[0], mem_recv, send_len), send_len);
+ EXPECT_EQ(memcmp(mem_recv, test_str_1, send_len), 0);
+}
+
+TEST_F(tls, rekey_getsockopt)
+{
+ struct tls_crypto_info_keys tls12;
+ struct tls_crypto_info_keys tls12_get;
+ socklen_t len;
+
+ tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 0);
+
+ len = tls12.len;
+ EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_get, &len), 0);
+ EXPECT_EQ(len, tls12.len);
+ EXPECT_EQ(memcmp(&tls12_get, &tls12, tls12.len), 0);
+
+ len = tls12.len;
+ EXPECT_EQ(getsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_get, &len), 0);
+ EXPECT_EQ(len, tls12.len);
+ EXPECT_EQ(memcmp(&tls12_get, &tls12, tls12.len), 0);
+
+ if (variant->tls_version != TLS_1_3_VERSION)
+ return;
+
+ tls_send_keyupdate(_metadata, self->fd);
+ tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
+
+ tls_recv_keyupdate(_metadata, self->cfd, 0);
+ EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
+
+ len = tls12.len;
+ EXPECT_EQ(getsockopt(self->fd, SOL_TLS, TLS_TX, &tls12_get, &len), 0);
+ EXPECT_EQ(len, tls12.len);
+ EXPECT_EQ(memcmp(&tls12_get, &tls12, tls12.len), 0);
+
+ len = tls12.len;
+ EXPECT_EQ(getsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12_get, &len), 0);
+ EXPECT_EQ(len, tls12.len);
+ EXPECT_EQ(memcmp(&tls12_get, &tls12, tls12.len), 0);
+}
+
+TEST_F(tls, rekey_poll_pending)
+{
+ char const *test_str = "test_message_after_rekey";
+ struct tls_crypto_info_keys tls12;
+ struct pollfd pfd = { };
+ int send_len;
+ int ret;
+
+ if (variant->tls_version != TLS_1_3_VERSION)
+ return;
+
+ /* update TX key */
+ tls_send_keyupdate(_metadata, self->fd);
+ tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
+
+ /* get KeyUpdate */
+ tls_recv_keyupdate(_metadata, self->cfd, 0);
+
+ /* send immediately after rekey */
+ send_len = strlen(test_str) + 1;
+ EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+
+ /* key hasn't been updated, expect cfd to be non-readable */
+ pfd.fd = self->cfd;
+ pfd.events = POLLIN;
+ EXPECT_EQ(poll(&pfd, 1, 0), 0);
+
+ ret = fork();
+ ASSERT_GE(ret, 0);
+
+ if (ret) {
+ int pid2, status;
+
+ /* wait before installing the new key */
+ sleep(1);
+
+ /* update RX key while poll() is sleeping */
+ EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
+
+ pid2 = wait(&status);
+ EXPECT_EQ(pid2, ret);
+ EXPECT_EQ(status, 0);
+ } else {
+ pfd.fd = self->cfd;
+ pfd.events = POLLIN;
+ EXPECT_EQ(poll(&pfd, 1, 5000), 1);
+
+ exit(!__test_passed(_metadata));
+ }
+}
+
+TEST_F(tls, rekey_poll_delay)
+{
+ char const *test_str = "test_message_after_rekey";
+ struct tls_crypto_info_keys tls12;
+ struct pollfd pfd = { };
+ int send_len;
+ int ret;
+
+ if (variant->tls_version != TLS_1_3_VERSION)
+ return;
+
+ /* update TX key */
+ tls_send_keyupdate(_metadata, self->fd);
+ tls_crypto_info_init(variant->tls_version, variant->cipher_type, &tls12, 1);
+ EXPECT_EQ(setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, tls12.len), 0);
+
+ /* get KeyUpdate */
+ tls_recv_keyupdate(_metadata, self->cfd, 0);
+
+ ret = fork();
+ ASSERT_GE(ret, 0);
+
+ if (ret) {
+ int pid2, status;
+
+ /* wait before installing the new key */
+ sleep(1);
+
+ /* update RX key while poll() is sleeping */
+ EXPECT_EQ(setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len), 0);
+
+ sleep(1);
+ send_len = strlen(test_str) + 1;
+ EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+
+ pid2 = wait(&status);
+ EXPECT_EQ(pid2, ret);
+ EXPECT_EQ(status, 0);
+ } else {
+ pfd.fd = self->cfd;
+ pfd.events = POLLIN;
+ EXPECT_EQ(poll(&pfd, 1, 5000), 1);
+ exit(!__test_passed(_metadata));
+ }
+}
+
FIXTURE(tls_err)
{
int fd, cfd;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 506/869] tls: rx: restore msg_iter before TLS 1.3 optimistic retry
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (504 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 505/869] selftests: tls: add rekey tests Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 507/869] watchdog: at91sam9_wdt: prevent timer rearm during teardown Greg Kroah-Hartman
` (363 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jérémy Jean,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
[ Upstream commit 1c8629651cb54f7b51db8fc0b1a9944e4a4b0f5e ]
tls_decrypt_sg() advances msg->msg_iter when it maps user pages for
the optimistic TLS 1.3 zero-copy path. If the decrypted record turns
out not to be unpadded application data, tls_decrypt_sw() retries into
a kernel skb, but leaves the iterator advanced.
The subsequent copy from the skb then writes decrypted bytes again at
a later point in the caller iovecs while recvmsg() reports only the
post-retry length. A TLS peer can trigger this after the receiver
enables TLS_RX_EXPECT_NO_PAD.
Revert the iterator by the number of bytes consumed by the optimistic
mapping before retrying without zero-copy.
Add a selftest which sends a TLS 1.3 control record with
TLS_RX_EXPECT_NO_PAD enabled and verifies that recvmsg() does not
overwrite later iovecs beyond the returned length.
Fixes: ce61327ce989 ("tls: rx: support optimistic decrypt to user buffer with TLS 1.3")
Cc: stable@vger.kernel.org
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
Link: https://patch.msgid.link/20260804125528.2139928-1-Jeremy.Jean@oss.cyber.gouv.fr
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/tls/tls_sw.c | 2 ++
tools/testing/selftests/net/tls.c | 57 +++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+)
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index 323ac8b1ad0c8..dad093a3a793d 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -1753,6 +1753,8 @@ tls_decrypt_sw(struct sock *sk, struct tls_context *tls_ctx,
/* If opportunistic TLS 1.3 ZC failed retry without ZC */
if (unlikely(darg->zc && prot->version == TLS_1_3_VERSION &&
darg->tail != TLS_RECORD_TYPE_DATA)) {
+ iov_iter_revert(&msg->msg_iter, strp_msg(darg->skb)->full_len -
+ prot->overhead_size);
darg->zc = false;
if (!darg->tail)
TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSRXNOPADVIOL);
diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c
index 1264a20c1a04e..9388e77a1b21a 100644
--- a/tools/testing/selftests/net/tls.c
+++ b/tools/testing/selftests/net/tls.c
@@ -1650,6 +1650,63 @@ TEST_F(tls, recv_efault)
}
#define TLS_RECORD_TYPE_HANDSHAKE 0x16
+
+TEST_F(tls_basic, recvmsg_nopad_retry_iov)
+{
+ char payload[32];
+ char first_iov[sizeof(payload)];
+ char later_iov[sizeof(payload) * 2];
+ char expected_later_iov[sizeof(later_iov)];
+ char cbuf[CMSG_SPACE(sizeof(char))];
+ struct tls_crypto_info_keys tls13;
+ struct iovec iov[] = {
+ { .iov_base = first_iov, .iov_len = sizeof(first_iov) },
+ { .iov_base = later_iov, .iov_len = sizeof(later_iov) },
+ };
+ struct msghdr msg = {
+ .msg_iov = iov,
+ .msg_iovlen = ARRAY_SIZE(iov),
+ .msg_control = cbuf,
+ .msg_controllen = sizeof(cbuf),
+ };
+ int one = 1;
+ int ret;
+ int i;
+
+ if (self->notls)
+ SKIP(return, "no TLS support");
+
+ tls_crypto_info_init(TLS_1_3_VERSION, TLS_CIPHER_AES_GCM_128,
+ &tls13, 0);
+
+ ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls13, tls13.len);
+ ASSERT_EQ(ret, 0);
+
+ ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls13, tls13.len);
+ ASSERT_EQ(ret, 0);
+
+ ret = setsockopt(self->cfd, SOL_TLS, TLS_RX_EXPECT_NO_PAD,
+ &one, sizeof(one));
+ ASSERT_EQ(ret, 0);
+
+ for (i = 0; i < sizeof(payload); i++)
+ payload[i] = 0x40 + i;
+ memset(first_iov, 0xa5, sizeof(first_iov));
+ memset(later_iov, 0x5a, sizeof(later_iov));
+ memset(expected_later_iov, 0x5a, sizeof(expected_later_iov));
+
+ /* A control record forces optimistic TLS 1.3 RX to retry. */
+ ret = tls_send_cmsg(self->fd, TLS_RECORD_TYPE_HANDSHAKE,
+ payload, sizeof(payload), 0);
+ ASSERT_EQ(ret, sizeof(payload));
+
+ ret = recvmsg(self->cfd, &msg, 0);
+ ASSERT_EQ(ret, sizeof(payload));
+ EXPECT_EQ(memcmp(first_iov, payload, sizeof(payload)), 0);
+ EXPECT_EQ(memcmp(later_iov, expected_later_iov,
+ sizeof(later_iov)), 0);
+}
+
/* key_update, length 1, update_not_requested */
static const char key_update_msg[] = "\x18\x00\x00\x01\x00";
static void tls_send_keyupdate(struct __test_metadata *_metadata, int fd)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 507/869] watchdog: at91sam9_wdt: prevent timer rearm during teardown
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (505 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 506/869] tls: rx: restore msg_iter before TLS 1.3 optimistic retry Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 508/869] s390/ism: Fix UAF of sba and ieq during ism_dev_exit() Greg Kroah-Hartman
` (362 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Hongyan Xu, Guenter Roeck,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongyan Xu <getshell@seu.edu.cn>
[ Upstream commit 8444d66aa6b6e7fe0a26fa1a00a11cb4d0523783 ]
at91_ping() rearms the watchdog timer from its callback. timer_delete()
neither waits for a running callback nor prevents it from rearming the
timer, so probe failure or driver removal can leave the timer accessing the
devm-allocated at91wdt after it has been freed.
Use timer_shutdown_sync() on both teardown paths. It waits for a running
callback and rejects any attempt by the callback to rearm the timer.
Fixes: 5161b31dc39a ("watchdog: at91sam9_wdt: better watchdog support")
Signed-off-by: Hongyan Xu <getshell@seu.edu.cn>
Link: https://lore.kernel.org/r/20260806060613.1830-1-getshell@seu.edu.cn
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/watchdog/at91sam9_wdt.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 2c6474cb858b7..fe14f00662c56 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -242,7 +242,7 @@ static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt)
return 0;
out_stop_timer:
- del_timer(&wdt->timer);
+ timer_shutdown_sync(&wdt->timer);
return err;
}
@@ -378,7 +378,7 @@ static void at91wdt_remove(struct platform_device *pdev)
watchdog_unregister_device(&wdt->wdd);
pr_warn("I quit now, hardware will probably reboot!\n");
- del_timer(&wdt->timer);
+ timer_shutdown_sync(&wdt->timer);
}
#if defined(CONFIG_OF)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 508/869] s390/ism: Fix UAF of sba and ieq during ism_dev_exit()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (506 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 507/869] watchdog: at91sam9_wdt: prevent timer rearm during teardown Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 509/869] netfilter: nf_flow_table: drop existing skb dst before skb_dst_set_noref() Greg Kroah-Hartman
` (361 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alexandra Winter, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexandra Winter <wintera@linux.ibm.com>
[ Upstream commit b1896543ce59c4258625a35cf41e23a9a1f80ea2 ]
A ism interrupt handler can be active in parallel with ism_dev_exit(),
accessing freed data structures.
No new interrupts will be generated after unregister_ieq(). Drain ongoing
interrupt handlers by free_irq(), before freeing ism data structures.
Fixes: 684b89bc39ce ("s390/ism: add device driver for internal shared memory")
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Link: https://patch.msgid.link/20260805131043.954639-1-wintera@linux.ibm.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/s390/net/ism_drv.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index f2264cf6f40d8..c728095fc5059 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -244,13 +244,16 @@ static int unregister_sba(struct ism_dev *ism)
if (ret && ret != ISM_ERROR)
return -EIO;
+ return 0;
+}
+
+static void ism_free_sba(struct ism_dev *ism)
+{
dma_free_coherent(&ism->pdev->dev, PAGE_SIZE,
ism->sba, ism->sba_dma_addr);
ism->sba = NULL;
ism->sba_dma_addr = 0;
-
- return 0;
}
static int unregister_ieq(struct ism_dev *ism)
@@ -264,13 +267,16 @@ static int unregister_ieq(struct ism_dev *ism)
if (ret && ret != ISM_ERROR)
return -EIO;
+ return 0;
+}
+
+static void ism_free_ieq(struct ism_dev *ism)
+{
dma_free_coherent(&ism->pdev->dev, PAGE_SIZE,
ism->ieq, ism->ieq_dma_addr);
ism->ieq = NULL;
ism->ieq_dma_addr = 0;
-
- return 0;
}
static int ism_read_local_gid(struct ism_dev *ism)
@@ -580,8 +586,10 @@ static int ism_dev_init(struct ism_dev *ism)
unreg_ieq:
unregister_ieq(ism);
+ ism_free_ieq(ism);
unreg_sba:
unregister_sba(ism);
+ ism_free_sba(ism);
free_irq:
free_irq(pci_irq_vector(pdev, 0), ism);
free_client_arr:
@@ -678,9 +686,13 @@ static void ism_dev_exit(struct ism_dev *ism)
if (ism_v2_capable)
ism_del_vlan_id(ism, ISM_RESERVED_VLANID);
+ /* ism will only generate new IRQs while ieq & sba are registered */
unregister_ieq(ism);
unregister_sba(ism);
+ /* drain ongoing irpt handlers */
free_irq(pci_irq_vector(pdev, 0), ism);
+ ism_free_ieq(ism);
+ ism_free_sba(ism);
kfree(ism->sba_client_arr);
pci_free_irq_vectors(pdev);
list_del_init(&ism->list);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 509/869] netfilter: nf_flow_table: drop existing skb dst before skb_dst_set_noref()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (507 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 508/869] s390/ism: Fix UAF of sba and ieq during ism_dev_exit() Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 510/869] bnxt_en: Disable EOP for TPA on all chips to prevent data corruption Greg Kroah-Hartman
` (360 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+76d4e3a055aec3b007ec,
Eric Dumazet, Pablo Neira Ayuso, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 8aecf0bbcc72605592134c917c222207d8f63ab0 ]
Incoming skbs passing through netfilter flowtable offload hooks (or XFRM
offload path) might already carry a ref-counted dst_entry assigned during
earlier RX or routing steps.
Calling skb_dst_set_noref() when skb already holds a ref-counted dst
overwrites skb->_skb_refdst, leaking the previous dst_entry reference
count and triggering a DEBUG_NET_WARN_ON_ONCE assertion in
skb_dst_check_unset():
WARNING: at skb_dst_check_unset include/linux/skbuff.h:1170
WARNING: at skb_dst_set_noref include/linux/skbuff.h:1234
WARNING: at nf_flow_offload_ip_hook+0xf6c/0x2b60 net/netfilter/nf_flow_table_ip.c:864
Drop any existing dst_entry reference with skb_dst_drop(skb) before
setting the non-referenced flowtable destination.
Fixes: 2a79fd3908ac ("netfilter: nf_flow_table: attach dst to skbs")
Reported-by: syzbot+76d4e3a055aec3b007ec@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/6a71b141.9511d2ce.1fc5b9.033b.GAE@google.com/T/#u
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
Link: https://patch.msgid.link/20260804093328.1831847-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/netfilter/nf_flow_table_ip.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 98edcaa37b38d..e9d960a1180b8 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -268,6 +268,7 @@ static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
struct dst_entry *dst)
{
skb_orphan(skb);
+ skb_dst_drop(skb);
skb_dst_set_noref(skb, dst);
dst_output(state->net, state->sk, skb);
return NF_STOLEN;
@@ -453,6 +454,7 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
outdev = rt->dst.dev;
skb->dev = outdev;
nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
+ skb_dst_drop(skb);
skb_dst_set_noref(skb, &rt->dst);
neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb);
ret = NF_STOLEN;
@@ -748,6 +750,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
outdev = rt->dst.dev;
skb->dev = outdev;
nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
+ skb_dst_drop(skb);
skb_dst_set_noref(skb, &rt->dst);
neigh_xmit(NEIGH_ND_TABLE, outdev, nexthop, skb);
ret = NF_STOLEN;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 510/869] bnxt_en: Disable EOP for TPA on all chips to prevent data corruption
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (508 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 509/869] netfilter: nf_flow_table: drop existing skb dst before skb_dst_set_noref() Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 511/869] hwmon: (pmbus) Fix type confusion in notification logic Greg Kroah-Hartman
` (359 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pavan Chebbi, Kalesh AP,
Michael Chan, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Chan <michael.chan@broadcom.com>
[ Upstream commit c3faf548a00f4c17100cc9204746975fa46a73b9 ]
EOP (End of frame padding) on the AGG ring may cause overlapping of
zero padding at the end of one segment with the next segment's data.
If Relaxed Ordering (RO) is enabled, the zero padding may overwrite
valid data in the next segment and corrupt the data. Older chips
(P5 and older) do not automatically disable RO when EOP is enabled.
On some ARM systems, data corruption was reported on 57508 (P5)
chips with RO enabled.
Always disable EOP on all chips on the AGG rings when TPA is enabled
to fix the data corruption.
Fixes: bfcd8d791ec1 ("bnxt_en: Add fast path logic for TPA on 57500 chips.")
Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Link: https://patch.msgid.link/20260731190937.807270-5-michael.chan@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 497799b089ce2..dc2bc7a2de0e3 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -4311,11 +4311,14 @@ static void bnxt_init_one_rx_agg_ring_rxbd(struct bnxt *bp,
type = ((u32)rxr->rx_page_size << RX_BD_LEN_SHIFT) |
RX_BD_TYPE_RX_AGG_BD;
- /* On P7, setting EOP will cause the chip to disable
- * Relaxed Ordering (RO) for TPA data. Disable EOP for
- * potentially higher performance with RO.
+ /* Disable EOP if TPA is enabled to prevent overlapping zero
+ * padding with the next segment's data. On P7_PLUS, EOP will
+ * automatically disable Relaxed Ordering (RO) to prevent
+ * potential data corruption (and may degrade performance). On
+ * older chips, RO will not be automatically disabled and may
+ * cause corruption.
*/
- if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
+ if (!(bp->flags & BNXT_FLAG_TPA))
type |= RX_BD_FLAGS_AGG_EOP;
bnxt_init_rxbd_pages(ring, type);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 511/869] hwmon: (pmbus) Fix type confusion in notification logic
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (509 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 510/869] bnxt_en: Disable EOP for TPA on all chips to prevent data corruption Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 512/869] vhost_iotlb: bound map allocation in add_range Greg Kroah-Hartman
` (358 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vincent Jardin, Guenter Roeck,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <linux@roeck-us.net>
[ Upstream commit 59bd68ab05a8f9c9a60b6ec44682084184803ff4 ]
Sashiko reports:
At the start of the loop in pmbus_notify(), the code unconditionally casts
every attribute to a struct sensor_device_attribute:
drivers/hwmon/pmbus/pmbus_core.c:pmbus_notify() {
for (i = 0; i < data->num_attributes; i++) {
struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int index = attr->index;
...
}
However, data->group.attrs can contain other types like struct
pmbus_samples_reg or struct pmbus_sensor, which only embed a base
struct device_attribute.
If da is a struct pmbus_samples_reg, dev_attr is the last member. Casting
it to struct sensor_device_attribute and reading the index field appears
to access memory past the end of the allocation, which might trigger a
slab-out-of-bounds read.
Additionally, if da is a struct pmbus_sensor, casting it causes the index
field to overlap with the page, phase, and reg fields. Could this produce
a garbage mask on little-endian systems that spuriously matches the target
reg, page, and flags during an alert?
Fix the problem by using struct sensor_device_attr in struct pmbus_sensor
and struct pmbus_label. Since those attributes never trigger a
notification, set the value of attr->index to -1 for them. Use this value
to distinguish from boolean attributes which _can_ trigger a notification
and use the index field to encode mask, page, and register values.
Fixes: f469bde9afd1 ("hwmon: (pmbus/core) Notify hwmon events")
Cc: Vincent Jardin <vjardin@free.fr>
Tested-by: Vincent Jardin <vjardin@free.fr>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hwmon/pmbus/pmbus_core.c | 61 +++++++++++++++++++-------------
1 file changed, 37 insertions(+), 24 deletions(-)
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 5061717389dbd..ea79cff0e8d0d 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -35,7 +35,7 @@
struct pmbus_sensor {
struct pmbus_sensor *next;
char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */
- struct device_attribute attribute;
+ struct sensor_device_attribute attribute;
u8 page; /* page number */
u8 phase; /* phase number, 0xff for all phases */
u16 reg; /* register */
@@ -58,7 +58,7 @@ struct pmbus_boolean {
struct pmbus_label {
char name[PMBUS_NAME_SIZE]; /* sysfs label name */
- struct device_attribute attribute;
+ struct sensor_device_attribute attribute;
char label[PMBUS_NAME_SIZE]; /* label */
};
#define to_pmbus_label(_attr) \
@@ -1238,7 +1238,8 @@ static ssize_t pmbus_show_sensor(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev->parent);
- struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pmbus_sensor *sensor = to_pmbus_sensor(attr);
struct pmbus_data *data = i2c_get_clientdata(client);
ssize_t ret;
@@ -1258,7 +1259,8 @@ static ssize_t pmbus_set_sensor(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev->parent);
struct pmbus_data *data = i2c_get_clientdata(client);
- struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pmbus_sensor *sensor = to_pmbus_sensor(attr);
ssize_t rv = count;
s64 val;
int ret;
@@ -1281,7 +1283,8 @@ static ssize_t pmbus_set_sensor(struct device *dev,
static ssize_t pmbus_show_label(struct device *dev,
struct device_attribute *da, char *buf)
{
- struct pmbus_label *label = to_pmbus_label(da);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct pmbus_label *label = to_pmbus_label(attr);
return sysfs_emit(buf, "%s\n", label->label);
}
@@ -1434,8 +1437,8 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
bool update, bool readonly,
bool writeonly, bool convert)
{
+ struct sensor_device_attribute *a;
struct pmbus_sensor *sensor;
- struct device_attribute *a;
sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor)
@@ -1459,12 +1462,11 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
sensor->update = update;
sensor->convert = convert;
sensor->data = -ENODATA;
- pmbus_dev_attr_init(a, sensor->name,
- readonly ? 0444 : 0644,
- writeonly ? pmbus_show_zero : pmbus_show_sensor,
- pmbus_set_sensor);
+ pmbus_attr_init(a, sensor->name, readonly ? 0444 : 0644,
+ writeonly ? pmbus_show_zero : pmbus_show_sensor,
+ pmbus_set_sensor, -1);
- if (pmbus_add_attribute(data, &a->attr))
+ if (pmbus_add_attribute(data, &a->dev_attr.attr))
return NULL;
sensor->next = data->sensors;
@@ -1481,8 +1483,8 @@ static int pmbus_add_label(struct pmbus_data *data,
const char *name, int seq,
const char *lstring, int index, int phase)
{
+ struct sensor_device_attribute *a;
struct pmbus_label *label;
- struct device_attribute *a;
label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL);
if (!label)
@@ -1507,8 +1509,8 @@ static int pmbus_add_label(struct pmbus_data *data,
lstring, index, phase);
}
- pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL);
- return pmbus_add_attribute(data, &a->attr);
+ pmbus_attr_init(a, label->name, 0444, pmbus_show_label, NULL, -1);
+ return pmbus_add_attribute(data, &a->dev_attr.attr);
}
/*
@@ -2396,7 +2398,7 @@ struct pmbus_samples_attr {
struct pmbus_samples_reg {
int page;
struct pmbus_samples_attr *attr;
- struct device_attribute dev_attr;
+ struct sensor_device_attribute attribute;
};
static struct pmbus_samples_attr pmbus_samples_registers[] = {
@@ -2418,14 +2420,15 @@ static struct pmbus_samples_attr pmbus_samples_registers[] = {
}
};
-#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr)
+#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, attribute)
static ssize_t pmbus_show_samples(struct device *dev,
struct device_attribute *devattr, char *buf)
{
int val;
struct i2c_client *client = to_i2c_client(dev->parent);
- struct pmbus_samples_reg *reg = to_samples_reg(devattr);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pmbus_samples_reg *reg = to_samples_reg(attr);
struct pmbus_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
@@ -2444,7 +2447,8 @@ static ssize_t pmbus_set_samples(struct device *dev,
int ret;
long val;
struct i2c_client *client = to_i2c_client(dev->parent);
- struct pmbus_samples_reg *reg = to_samples_reg(devattr);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pmbus_samples_reg *reg = to_samples_reg(attr);
struct pmbus_data *data = i2c_get_clientdata(client);
if (kstrtol(buf, 0, &val) < 0)
@@ -2460,6 +2464,7 @@ static ssize_t pmbus_set_samples(struct device *dev,
static int pmbus_add_samples_attr(struct pmbus_data *data, int page,
struct pmbus_samples_attr *attr)
{
+ struct sensor_device_attribute *a;
struct pmbus_samples_reg *reg;
reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL);
@@ -2469,10 +2474,12 @@ static int pmbus_add_samples_attr(struct pmbus_data *data, int page,
reg->attr = attr;
reg->page = page;
- pmbus_dev_attr_init(®->dev_attr, attr->name, 0644,
- pmbus_show_samples, pmbus_set_samples);
+ a = ®->attribute;
+
+ pmbus_attr_init(a, attr->name, 0644,
+ pmbus_show_samples, pmbus_set_samples, -1);
- return pmbus_add_attribute(data, ®->dev_attr.attr);
+ return pmbus_add_attribute(data, &a->dev_attr.attr);
}
static int pmbus_add_samples_attributes(struct i2c_client *client,
@@ -2941,9 +2948,15 @@ static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int index = attr->index;
- u16 smask = pb_index_to_mask(index);
- u8 spage = pb_index_to_page(index);
- u16 sreg = pb_index_to_reg(index);
+ u16 smask, sreg;
+ u8 spage;
+
+ if (index == -1)
+ continue;
+
+ smask = pb_index_to_mask(index);
+ spage = pb_index_to_page(index);
+ sreg = pb_index_to_reg(index);
if (reg == sreg && page == spage && (smask & flags)) {
dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 512/869] vhost_iotlb: bound map allocation in add_range
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (510 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 511/869] hwmon: (pmbus) Fix type confusion in notification logic Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 513/869] bpf: Fix netns reference imbalance in conntrack kfuncs Greg Kroah-Hartman
` (357 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Linfeng Sun ,
Michael S. Tsirkin, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linfeng Sun <linfeng.sun.dev@gamil.com>
[ Upstream commit 1ed35ac7f3fe2b4396bdd29ac3a7f0ebc0829e94 ]
vhost_iotlb_add_range_ctx() only retires an old entry when the table
has a non-zero limit, has exactly reached that limit and has
VHOST_IOTLB_FLAG_RETIRE set. Non-retiring tables can keep allocating
entries after reaching their configured limit.
Existing vhost devices allocate their IOTLB with max_iotlb_entries from
vhost.c, which defaults to 2048 and is tunable by module parameter. Use
the caller-provided limit at the allocation point instead of adding a
separate default in the common IOTLB helper, and reject non-positive
values in vhost paths that can report an error.
Other vhost IOTLB users should not create zero-limit tables when entries
can be populated from userspace or guest-controlled requests. Add
caller-side max_iotlb_entries parameters for mlx5 vDPA, VDUSE and
vhost-vDPA. Reject non-positive VDUSE and vhost-vDPA values, and require
at least two entries for vdpa_sim and mlx5 vDPA paths that install
full-range mappings, since those mappings are split into two IOTLB
entries.
Handle full-range mappings in the common helper by checking that the
IOTLB can hold both split entries before inserting the first half. This
avoids returning an error after leaving a half mapping behind.
When the table is full, keep the existing retire behavior for retiring
tables and return -ENOSPC for non-retiring tables. Reuse the retired map
node instead of freeing it and allocating a replacement, so a stream of
IOTLB updates cannot keep forcing GFP_ATOMIC allocations after the table
has reached its limit. If a zero-limit IOTLB still reaches the common
helper, treat it as a configuration error and return -EINVAL.
I found this bug myself, though the patch was written with AI assistance.
Fixes: 0bbe30668d89 ("vhost: factor out IOTLB")
Assisted-by: OpenAI-Codex:GPT-5
Signed-off-by: Linfeng Sun <linfeng.sun.dev@gamil.com>
Message-ID: <AMYAtgAiKmgYcSQT5ukl-4qq.3.1781960405943.Hmail.241270009@hdu.edu.cn>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/vdpa/mlx5/core/mlx5_vdpa.h | 2 ++
drivers/vdpa/mlx5/core/mr.c | 5 ++-
drivers/vdpa/mlx5/core/resources.c | 11 ++++++-
drivers/vdpa/vdpa_sim/vdpa_sim.c | 10 ++++--
drivers/vdpa/vdpa_user/iova_domain.c | 11 ++++++-
drivers/vhost/iotlb.c | 47 +++++++++++++++++++---------
drivers/vhost/vdpa.c | 9 +++++-
drivers/vhost/vhost.c | 8 +++++
8 files changed, 82 insertions(+), 21 deletions(-)
diff --git a/drivers/vdpa/mlx5/core/mlx5_vdpa.h b/drivers/vdpa/mlx5/core/mlx5_vdpa.h
index 2cedf7e2dbc49..42f2f44b383c7 100644
--- a/drivers/vdpa/mlx5/core/mlx5_vdpa.h
+++ b/drivers/vdpa/mlx5/core/mlx5_vdpa.h
@@ -11,6 +11,8 @@
#define MLX5V_ETH_HARD_MTU (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
+extern int mlx5_vdpa_max_iotlb_entries;
+
struct mlx5_vdpa_direct_mr {
u64 start;
u64 end;
diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c
index 25e2c234bcef2..a5b5feb74f26f 100644
--- a/drivers/vdpa/mlx5/core/mr.c
+++ b/drivers/vdpa/mlx5/core/mr.c
@@ -778,6 +778,9 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
{
int err;
+ if (mlx5_vdpa_max_iotlb_entries < 2)
+ return -EINVAL;
+
if (iotlb)
err = create_user_mr(mvdev, mr, iotlb);
else
@@ -786,7 +789,7 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
if (err)
return err;
- mr->iotlb = vhost_iotlb_alloc(0, 0);
+ mr->iotlb = vhost_iotlb_alloc(mlx5_vdpa_max_iotlb_entries, 0);
if (!mr->iotlb) {
err = -ENOMEM;
goto err_mr;
diff --git a/drivers/vdpa/mlx5/core/resources.c b/drivers/vdpa/mlx5/core/resources.c
index aeae31d0cefae..28a4d7a35bf4e 100644
--- a/drivers/vdpa/mlx5/core/resources.c
+++ b/drivers/vdpa/mlx5/core/resources.c
@@ -3,8 +3,14 @@
#include <linux/iova.h>
#include <linux/mlx5/driver.h>
+#include <linux/moduleparam.h>
#include "mlx5_vdpa.h"
+int mlx5_vdpa_max_iotlb_entries = 2048;
+module_param_named(max_iotlb_entries, mlx5_vdpa_max_iotlb_entries, int, 0444);
+MODULE_PARM_DESC(max_iotlb_entries,
+ "Maximum number of iotlb entries. (default: 2048)");
+
static int alloc_pd(struct mlx5_vdpa_dev *dev, u32 *pdn, u16 uid)
{
struct mlx5_core_dev *mdev = dev->mdev;
@@ -229,7 +235,10 @@ int mlx5_vdpa_destroy_mkey(struct mlx5_vdpa_dev *mvdev, u32 mkey)
static int init_ctrl_vq(struct mlx5_vdpa_dev *mvdev)
{
- mvdev->cvq.iotlb = vhost_iotlb_alloc(0, 0);
+ if (mlx5_vdpa_max_iotlb_entries < 2)
+ return -EINVAL;
+
+ mvdev->cvq.iotlb = vhost_iotlb_alloc(mlx5_vdpa_max_iotlb_entries, 0);
if (!mvdev->cvq.iotlb)
return -ENOMEM;
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c
index 825690c6fed19..3bcec8c1e2ab3 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c
@@ -34,7 +34,7 @@ MODULE_PARM_DESC(batch_mapping, "Batched mapping 1 -Enable; 0 - Disable");
static int max_iotlb_entries = 2048;
module_param(max_iotlb_entries, int, 0444);
MODULE_PARM_DESC(max_iotlb_entries,
- "Maximum number of iotlb entries for each address space. 0 means unlimited. (default: 2048)");
+ "Maximum number of iotlb entries for each address space. (default: 2048)");
static bool use_va = true;
module_param(use_va, bool, 0444);
@@ -201,6 +201,8 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
if (!dev_attr->alloc_size)
return ERR_PTR(-EINVAL);
+ if (max_iotlb_entries < 2)
+ return ERR_PTR(-EINVAL);
if (config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) {
if (config->device_features &
@@ -266,8 +268,10 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
for (i = 0; i < vdpasim->dev_attr.nas; i++) {
vhost_iotlb_init(&vdpasim->iommu[i], max_iotlb_entries, 0);
- vhost_iotlb_add_range(&vdpasim->iommu[i], 0, ULONG_MAX, 0,
- VHOST_MAP_RW);
+ ret = vhost_iotlb_add_range(&vdpasim->iommu[i], 0, ULONG_MAX,
+ 0, VHOST_MAP_RW);
+ if (ret)
+ goto err_iommu;
vdpasim->iommu_pt[i] = true;
}
diff --git a/drivers/vdpa/vdpa_user/iova_domain.c b/drivers/vdpa/vdpa_user/iova_domain.c
index ec743bed361c1..e8b837df328f0 100644
--- a/drivers/vdpa/vdpa_user/iova_domain.c
+++ b/drivers/vdpa/vdpa_user/iova_domain.c
@@ -12,11 +12,17 @@
#include <linux/file.h>
#include <linux/anon_inodes.h>
#include <linux/highmem.h>
+#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
#include <linux/vdpa.h>
#include "iova_domain.h"
+static int max_iotlb_entries = 2048;
+module_param(max_iotlb_entries, int, 0444);
+MODULE_PARM_DESC(max_iotlb_entries,
+ "Maximum number of iotlb entries. (default: 2048)");
+
static int vduse_iotlb_add_range(struct vduse_iova_domain *domain,
u64 start, u64 last,
u64 addr, unsigned int perm,
@@ -622,11 +628,14 @@ vduse_domain_create(unsigned long iova_limit, size_t bounce_size)
if (iova_limit <= bounce_size)
return NULL;
+ if (max_iotlb_entries <= 0)
+ return NULL;
+
domain = kzalloc(sizeof(*domain), GFP_KERNEL);
if (!domain)
return NULL;
- domain->iotlb = vhost_iotlb_alloc(0, 0);
+ domain->iotlb = vhost_iotlb_alloc(max_iotlb_entries, 0);
if (!domain->iotlb)
goto err_iotlb;
diff --git a/drivers/vhost/iotlb.c b/drivers/vhost/iotlb.c
index ea61330a34310..a6228dd249316 100644
--- a/drivers/vhost/iotlb.c
+++ b/drivers/vhost/iotlb.c
@@ -20,6 +20,14 @@ INTERVAL_TREE_DEFINE(struct vhost_iotlb_map,
rb, __u64, __subtree_last,
START, LAST, static inline, vhost_iotlb_itree);
+static void vhost_iotlb_map_unlink(struct vhost_iotlb *iotlb,
+ struct vhost_iotlb_map *map)
+{
+ vhost_iotlb_itree_remove(map, &iotlb->root);
+ list_del(&map->link);
+ iotlb->nmaps--;
+}
+
/**
* vhost_iotlb_map_free - remove a map node and free it
* @iotlb: the IOTLB
@@ -28,10 +36,8 @@ INTERVAL_TREE_DEFINE(struct vhost_iotlb_map,
void vhost_iotlb_map_free(struct vhost_iotlb *iotlb,
struct vhost_iotlb_map *map)
{
- vhost_iotlb_itree_remove(map, &iotlb->root);
- list_del(&map->link);
+ vhost_iotlb_map_unlink(iotlb, map);
kfree(map);
- iotlb->nmaps--;
}
EXPORT_SYMBOL_GPL(vhost_iotlb_map_free);
@@ -57,14 +63,25 @@ int vhost_iotlb_add_range_ctx(struct vhost_iotlb *iotlb,
if (last < start)
return -EFAULT;
+ if (!iotlb->limit)
+ return -EINVAL;
+
/* If the range being mapped is [0, ULONG_MAX], split it into two entries
* otherwise its size would overflow u64.
*/
if (start == 0 && last == ULONG_MAX) {
u64 mid = last / 2;
- int err = vhost_iotlb_add_range_ctx(iotlb, start, mid, addr,
- perm, opaque);
+ int err;
+
+ if (iotlb->limit < 2)
+ return -ENOSPC;
+ if (!(iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) &&
+ iotlb->nmaps > iotlb->limit - 2)
+ return -ENOSPC;
+
+ err = vhost_iotlb_add_range_ctx(iotlb, start, mid, addr,
+ perm, opaque);
if (err)
return err;
@@ -72,17 +89,19 @@ int vhost_iotlb_add_range_ctx(struct vhost_iotlb *iotlb,
start = mid + 1;
}
- if (iotlb->limit &&
- iotlb->nmaps == iotlb->limit &&
- iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) {
- map = list_first_entry(&iotlb->list, typeof(*map), link);
- vhost_iotlb_map_free(iotlb, map);
+ if (iotlb->nmaps >= iotlb->limit) {
+ if (iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) {
+ map = list_first_entry(&iotlb->list, typeof(*map), link);
+ vhost_iotlb_map_unlink(iotlb, map);
+ } else {
+ return -ENOSPC;
+ }
+ } else {
+ map = kmalloc(sizeof(*map), GFP_ATOMIC);
+ if (!map)
+ return -ENOMEM;
}
- map = kmalloc(sizeof(*map), GFP_ATOMIC);
- if (!map)
- return -ENOMEM;
-
map->start = start;
map->size = last - start + 1;
map->last = last;
diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
index 789bd8da55052..a940718745def 100644
--- a/drivers/vhost/vdpa.c
+++ b/drivers/vhost/vdpa.c
@@ -34,6 +34,11 @@ enum {
#define VHOST_VDPA_DEV_MAX (1U << MINORBITS)
+static int max_iotlb_entries = 2048;
+module_param(max_iotlb_entries, int, 0444);
+MODULE_PARM_DESC(max_iotlb_entries,
+ "Maximum number of iotlb entries. (default: 2048)");
+
#define VHOST_VDPA_IOTLB_BUCKETS 16
struct vhost_vdpa_as {
@@ -112,12 +117,14 @@ static struct vhost_vdpa_as *vhost_vdpa_alloc_as(struct vhost_vdpa *v, u32 asid)
if (asid >= v->vdpa->nas)
return NULL;
+ if (max_iotlb_entries <= 0)
+ return NULL;
as = kmalloc(sizeof(*as), GFP_KERNEL);
if (!as)
return NULL;
- vhost_iotlb_init(&as->iotlb, 0, 0);
+ vhost_iotlb_init(&as->iotlb, max_iotlb_entries, 0);
as->id = asid;
hlist_add_head(&as->hash_link, head);
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index f966fc094f126..22119ec7fd9b7 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -1135,6 +1135,9 @@ EXPORT_SYMBOL_GPL(vhost_dev_set_owner);
static struct vhost_iotlb *iotlb_alloc(void)
{
+ if (max_iotlb_entries <= 0)
+ return NULL;
+
return vhost_iotlb_alloc(max_iotlb_entries,
VHOST_IOTLB_FLAG_RETIRE);
}
@@ -1979,6 +1982,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
return -EOPNOTSUPP;
if (mem.nregions > max_mem_regions)
return -E2BIG;
+ if (max_iotlb_entries <= 0)
+ return -EINVAL;
newmem = kvzalloc(struct_size(newmem, regions, mem.nregions),
GFP_KERNEL);
if (!newmem)
@@ -2281,6 +2286,9 @@ int vhost_init_device_iotlb(struct vhost_dev *d)
struct vhost_iotlb *niotlb, *oiotlb;
int i;
+ if (max_iotlb_entries <= 0)
+ return -EINVAL;
+
niotlb = iotlb_alloc();
if (!niotlb)
return -ENOMEM;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 513/869] bpf: Fix netns reference imbalance in conntrack kfuncs
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (511 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 512/869] vhost_iotlb: bound map allocation in add_range Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 514/869] btrfs: lzo: reject inline extents without valid headers Greg Kroah-Hartman
` (356 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Chengfeng Ye, Emil Tsalapatis,
Kumar Kartikeya Dwivedi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <nicoyip.dev@gmail.com>
[ Upstream commit fdeba03fea78407a8c52faa99177c9f7f29f90eb ]
The opts argument of the BPF conntrack kfuncs can point to a shared
map value. __bpf_nf_ct_lookup() and __bpf_nf_ct_alloc_entry() read
opts->netns_id separately when acquiring and releasing the network
namespace reference.
The reference imbalance can occur as follows:
CPU 0 CPU 1
read opts->netns_id (-1)
skip get_net_ns_by_id()
write opts->netns_id (id)
read opts->netns_id (id)
put_net(net) /* no matching get */
The reverse transition leaks the reference. Repeating the unmatched put
can destroy a live namespace and crash later users.
The kernel reported:
Oops: general protection fault, probably for non-canonical address
KASAN: null-ptr-deref in range [0x00000000000000e8-0x00000000000000ef]
RIP: 0010:bpf_prog_test_run_xdp+0x52c/0x1700
Call Trace:
__sys_bpf+0x1662/0x50c0
__x64_sys_bpf+0x73/0xb0
do_syscall_64+0xf9/0x540
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Kernel panic - not syncing: Fatal exception
Snapshot every input field of opts with READ_ONCE() before validating or
using it. The netns_id snapshot keeps the namespace get/put pair
balanced, while the other snapshots keep the remaining options from
changing partway through an invocation. The individual reads can still
observe an inconsistent combination during a concurrent update, but each
selected field value remains stable for that invocation.
Fixes: aed8ee7feb44 ("net: netfilter: Deduplicate code in bpf_{xdp,skb}_ct_lookup")
Fixes: d7e79c97c00c ("net: netfilter: Add kfuncs to allocate and insert CT")
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Link: https://lore.kernel.org/bpf/20260731160921.3245840-1-nicoyip.dev@gmail.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/netfilter/nf_conntrack_bpf.c | 72 +++++++++++++++++++++-----------
1 file changed, 48 insertions(+), 24 deletions(-)
diff --git a/net/netfilter/nf_conntrack_bpf.c b/net/netfilter/nf_conntrack_bpf.c
index c91a935a01706..c3f1d5dcba2c6 100644
--- a/net/netfilter/nf_conntrack_bpf.c
+++ b/net/netfilter/nf_conntrack_bpf.c
@@ -121,44 +121,56 @@ __bpf_nf_ct_alloc_entry(struct net *net, struct bpf_sock_tuple *bpf_tuple,
struct nf_conntrack_tuple otuple, rtuple;
struct nf_conntrack_zone ct_zone;
struct nf_conn *ct;
+ u8 ct_zone_dir = 0;
+ u16 ct_zone_id;
+ s32 netns_id;
+ u8 l4proto;
int err;
if (!opts || !bpf_tuple)
return ERR_PTR(-EINVAL);
if (!(opts_len == NF_BPF_CT_OPTS_SZ || opts_len == 12))
return ERR_PTR(-EINVAL);
+
+ netns_id = READ_ONCE(opts->netns_id);
+ l4proto = READ_ONCE(opts->l4proto);
+ ct_zone_id = READ_ONCE(opts->ct_zone_id);
if (opts_len == NF_BPF_CT_OPTS_SZ) {
- if (opts->reserved[0] || opts->reserved[1] || opts->reserved[2])
+ ct_zone_dir = READ_ONCE(opts->ct_zone_dir);
+ if (READ_ONCE(opts->reserved[0]) ||
+ READ_ONCE(opts->reserved[1]) ||
+ READ_ONCE(opts->reserved[2]))
return ERR_PTR(-EINVAL);
} else {
- if (opts->ct_zone_id)
+ if (ct_zone_id)
return ERR_PTR(-EINVAL);
}
- if (unlikely(opts->netns_id < BPF_F_CURRENT_NETNS))
+ if (unlikely(netns_id < BPF_F_CURRENT_NETNS))
return ERR_PTR(-EINVAL);
- err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,
+ err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, l4proto,
IP_CT_DIR_ORIGINAL, &otuple);
if (err < 0)
return ERR_PTR(err);
- err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,
+ err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, l4proto,
IP_CT_DIR_REPLY, &rtuple);
if (err < 0)
return ERR_PTR(err);
- if (opts->netns_id >= 0) {
- net = get_net_ns_by_id(net, opts->netns_id);
+ if (netns_id >= 0) {
+ net = get_net_ns_by_id(net, netns_id);
if (unlikely(!net))
return ERR_PTR(-ENONET);
}
if (opts_len == NF_BPF_CT_OPTS_SZ) {
- if (opts->ct_zone_dir == 0)
- opts->ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
- nf_ct_zone_init(&ct_zone,
- opts->ct_zone_id, opts->ct_zone_dir, 0);
+ if (ct_zone_dir == 0) {
+ ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
+ opts->ct_zone_dir = ct_zone_dir;
+ }
+ nf_ct_zone_init(&ct_zone, ct_zone_id, ct_zone_dir, 0);
} else {
ct_zone = nf_ct_zone_dflt;
}
@@ -172,7 +184,7 @@ __bpf_nf_ct_alloc_entry(struct net *net, struct bpf_sock_tuple *bpf_tuple,
__nf_ct_set_timeout(ct, timeout * HZ);
out:
- if (opts->netns_id >= 0)
+ if (netns_id >= 0)
put_net(net);
return ct;
@@ -187,46 +199,58 @@ static struct nf_conn *__bpf_nf_ct_lookup(struct net *net,
struct nf_conntrack_tuple tuple;
struct nf_conntrack_zone ct_zone;
struct nf_conn *ct;
+ u8 ct_zone_dir = 0;
+ u16 ct_zone_id;
+ s32 netns_id;
+ u8 l4proto;
int err;
if (!opts || !bpf_tuple)
return ERR_PTR(-EINVAL);
if (!(opts_len == NF_BPF_CT_OPTS_SZ || opts_len == 12))
return ERR_PTR(-EINVAL);
+
+ netns_id = READ_ONCE(opts->netns_id);
+ l4proto = READ_ONCE(opts->l4proto);
+ ct_zone_id = READ_ONCE(opts->ct_zone_id);
if (opts_len == NF_BPF_CT_OPTS_SZ) {
- if (opts->reserved[0] || opts->reserved[1] || opts->reserved[2])
+ ct_zone_dir = READ_ONCE(opts->ct_zone_dir);
+ if (READ_ONCE(opts->reserved[0]) ||
+ READ_ONCE(opts->reserved[1]) ||
+ READ_ONCE(opts->reserved[2]))
return ERR_PTR(-EINVAL);
} else {
- if (opts->ct_zone_id)
+ if (ct_zone_id)
return ERR_PTR(-EINVAL);
}
- if (unlikely(opts->l4proto != IPPROTO_TCP && opts->l4proto != IPPROTO_UDP))
+ if (unlikely(l4proto != IPPROTO_TCP && l4proto != IPPROTO_UDP))
return ERR_PTR(-EPROTO);
- if (unlikely(opts->netns_id < BPF_F_CURRENT_NETNS))
+ if (unlikely(netns_id < BPF_F_CURRENT_NETNS))
return ERR_PTR(-EINVAL);
- err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, opts->l4proto,
+ err = bpf_nf_ct_tuple_parse(bpf_tuple, tuple_len, l4proto,
IP_CT_DIR_ORIGINAL, &tuple);
if (err < 0)
return ERR_PTR(err);
- if (opts->netns_id >= 0) {
- net = get_net_ns_by_id(net, opts->netns_id);
+ if (netns_id >= 0) {
+ net = get_net_ns_by_id(net, netns_id);
if (unlikely(!net))
return ERR_PTR(-ENONET);
}
if (opts_len == NF_BPF_CT_OPTS_SZ) {
- if (opts->ct_zone_dir == 0)
- opts->ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
- nf_ct_zone_init(&ct_zone,
- opts->ct_zone_id, opts->ct_zone_dir, 0);
+ if (ct_zone_dir == 0) {
+ ct_zone_dir = NF_CT_DEFAULT_ZONE_DIR;
+ opts->ct_zone_dir = ct_zone_dir;
+ }
+ nf_ct_zone_init(&ct_zone, ct_zone_id, ct_zone_dir, 0);
} else {
ct_zone = nf_ct_zone_dflt;
}
hash = nf_conntrack_find_get(net, &ct_zone, &tuple);
- if (opts->netns_id >= 0)
+ if (netns_id >= 0)
put_net(net);
if (!hash)
return ERR_PTR(-ENOENT);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 514/869] btrfs: lzo: reject inline extents without valid headers
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (512 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 513/869] bpf: Fix netns reference imbalance in conntrack kfuncs Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 515/869] xfs: handle NULL b_addr in xfs_buf_free Greg Kroah-Hartman
` (355 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Lee, Qu Wenruo, David Sterba,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Lee <david.lee@trailofbits.com>
[ Upstream commit 0fa78ef637deb5dbe341582f88553a4bce496de0 ]
[BUG]
For a crafted btrfs image, the following KASAN can be triggered when
reading an inline lzo compressed file extent:
BUG: KASAN: slab-out-of-bounds in lzo_decompress+0x57d/0x700
Read of size 4 at addr ffff888006f2e644 by task btrfs_lzo_inlin/77
Call Trace:
<TASK>
dump_stack_lvl+0x5b/0x70
print_report+0xd1/0x610
kasan_report+0xe0/0x110
__asan_report_load_n_noabort+0x13/0x20
lzo_decompress+0x57d/0x700
btrfs_decompress+0x140/0x1c0
uncompress_inline+0x147/0x1b0
btrfs_get_extent+0xb23/0x10a0
btrfs_do_readpage.constprop.0+0x538/0x1ac0
btrfs_readahead+0x32f/0x5f0
read_pages+0x16f/0x850
page_cache_ra_unbounded+0x296/0x490
do_page_cache_ra+0xd9/0x130
page_cache_sync_ra+0x3ee/0x6f0
filemap_get_pages+0x306/0x15c0
filemap_read+0x329/0xd00
btrfs_file_read_iter+0x1f8/0x2b0
vfs_read+0x4ef/0x720
ksys_read+0xf8/0x1d0
__x64_sys_read+0x71/0xb0
x64_sys_call+0x1ab0/0x1b70
do_syscall_64+0x61/0x470
entry_SYSCALL_64_after_hwframe+0x4b/0x53
</TASK>
[CAUSE]
For an inline lzo compressed file extent, there should always be one lzo
header, recording the total length of the compressed data, followed by
one segment header, recording the compressed lzo payload.
But if a crafted inline lzo compressed file extent contains only an lzo
header, without the segment header or payload, lzo_decompress() will
still try to read the segment header, causing a read beyond the item
boundary.
Furthermore if the inline lzo compressed file extent is the first item
of the leaf, it will be at the extent buffer boundary. The above
out-of-boundary read will go beyond the extent buffer boundary,
triggering the above KASAN report.
[FIX]
Validate the total length of the inlined lzo compressed file extent, to
make sure there is at least one LZO header and one segment header, and a
non-zero payload.
Fixes: a6fa6fae40ec ("btrfs: Add lzo compression support")
Assisted-by: Codex:gpt-5.5
Signed-off-by: David Lee <david.lee@trailofbits.com>
[ Rework the commit message to remove slop ]
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/lzo.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c
index 72856f6775f7f..0d136da8b6be1 100644
--- a/fs/btrfs/lzo.c
+++ b/fs/btrfs/lzo.c
@@ -449,7 +449,7 @@ int lzo_decompress(struct list_head *ws, const u8 *data_in,
size_t max_segment_len = WORKSPACE_BUF_LENGTH;
int ret = 0;
- if (srclen < LZO_LEN || srclen > max_segment_len + LZO_LEN * 2)
+ if (srclen <= LZO_LEN * 2 || srclen > max_segment_len + LZO_LEN * 2)
return -EUCLEAN;
in_len = read_compress_length(data_in);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 515/869] xfs: handle NULL b_addr in xfs_buf_free
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (513 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 514/869] btrfs: lzo: reject inline extents without valid headers Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 516/869] soc: aspeed: lpc-snoop: Fix usercopy overflow in snoop_file_read Greg Kroah-Hartman
` (354 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+94c22d92f72f5a235b7d,
Yun Zhou, Christoph Hellwig, Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yun Zhou <yun.zhou@windriver.com>
[ Upstream commit d852729c5f4f830fbe7413df032e29459b3daf83 ]
When xfs_buf_alloc_backing_mem() fails, xfs_buf_free() is called with
bp->b_addr still NULL. The code falls through to the folio_put path
which calls virt_to_folio(NULL), dereferencing an invalid address and
causing a kernel crash.
Call Trace:
xfs_buf_free+0x25f/0x510
xfs_buf_alloc+0xc98/0x19b0
xfs_buf_find_insert+0x55/0x14d0
xfs_buf_get_map+0x122b/0x17c0
xfbtree_init_leaf_block+0x11c/0x4a0
xfbtree_init+0x1bb/0x460
xrep_rmap_setup_scan+0x100/0x1f0
xrep_rmapbt+0x41/0xc0
Fix this by skipping folio_put() when bp->b_addr is NULL.
Fixes: 5076a6040ca1 ("xfs: support in-memory buffer cache targets")
Reported-by: syzbot+94c22d92f72f5a235b7d@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=94c22d92f72f5a235b7d
Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/xfs_buf.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 52e3535411b27..571cf82566722 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -319,12 +319,14 @@ xfs_buf_free(
ASSERT(list_empty(&bp->b_lru));
- if (xfs_buftarg_is_mem(bp->b_target))
- xmbuf_unmap_page(bp);
- else if (bp->b_flags & _XBF_PAGES)
+ if (xfs_buftarg_is_mem(bp->b_target)) {
+ if (bp->b_addr)
+ xmbuf_unmap_page(bp);
+ } else if (bp->b_flags & _XBF_PAGES) {
xfs_buf_free_pages(bp);
- else if (bp->b_flags & _XBF_KMEM)
+ } else if (bp->b_flags & _XBF_KMEM) {
kfree(bp->b_addr);
+ }
call_rcu(&bp->b_rcu, xfs_buf_free_callback);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 516/869] soc: aspeed: lpc-snoop: Fix usercopy overflow in snoop_file_read
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (514 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 515/869] xfs: handle NULL b_addr in xfs_buf_free Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 517/869] gpio: pca953x: fix pca953x_irq_bus_sync_unlock regmap lock Greg Kroah-Hartman
` (353 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Karthikeyan KS, Andrew Jeffery,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karthikeyan KS <karthiproffesional@gmail.com>
[ Upstream commit 1acef6d85bfd98bd9dfe1f08bffa397a4dda8a6f ]
put_fifo_with_discard() acts as both producer and consumer on the kfifo:
it calls kfifo_skip() (advances out) and kfifo_put() (advances in) from
the IRQ handler without synchronizing with snoop_file_read(), which also
consumes via kfifo_to_user(). On SMP systems this concurrent access can
leave (in - out) larger than the ring buffer, so __kfifo_to_user()'s clamp
to (in - out) is ineffective and kfifo_copy_to_user() can attempt a
copy_to_user() past the kmalloc-2k backing store:
usercopy: Kernel memory exposure attempt detected from SLUB object
'kmalloc-2k' (offset 0, size 2049)!
kernel BUG at mm/usercopy.c!
Call trace:
usercopy_abort
__check_heap_object
__check_object_size
kfifo_copy_to_user
__kfifo_to_user
snoop_file_read
vfs_read
Serialize kfifo access with a per-channel spinlock shared between the
IRQ handler (producer) and the file reader (consumer). Annotate @fifo
with __guarded_by(&lock) and opt the driver into context analysis so the
compiler enforces that all fifo access holds the lock.
Fixes: 3772e5da4454 ("drivers/misc: Aspeed LPC snoop output using misc chardev")
Signed-off-by: Karthikeyan KS <karthiproffesional@gmail.com>
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/soc/aspeed/aspeed-lpc-snoop.c | 31 ++++++++++++++++++++-------
1 file changed, 23 insertions(+), 8 deletions(-)
diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c
index fc3a2c41cc107..35f58eb0f134c 100644
--- a/drivers/soc/aspeed/aspeed-lpc-snoop.c
+++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c
@@ -11,6 +11,7 @@
*/
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
@@ -59,6 +60,7 @@ struct aspeed_lpc_snoop_model_data {
struct aspeed_lpc_snoop_channel {
bool enabled;
+ spinlock_t lock;
struct kfifo fifo;
wait_queue_head_t wq;
struct miscdevice miscdev;
@@ -82,6 +84,7 @@ static ssize_t snoop_file_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file);
+ u8 *buf __free(kfree) = NULL;
unsigned int copied;
int ret = 0;
@@ -93,9 +96,16 @@ static ssize_t snoop_file_read(struct file *file, char __user *buffer,
if (ret == -ERESTARTSYS)
return -EINTR;
}
- ret = kfifo_to_user(&chan->fifo, buffer, count, &copied);
- if (ret)
- return ret;
+
+ count = min_t(size_t, count, SNOOP_FIFO_SIZE);
+
+ buf = kmalloc(count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ copied = kfifo_out_spinlocked(&chan->fifo, buf, count, &chan->lock);
+ if (copied && copy_to_user(buffer, buf, copied))
+ return -EFAULT;
return copied;
}
@@ -119,11 +129,13 @@ static const struct file_operations snoop_fops = {
/* Save a byte to a FIFO and discard the oldest byte if FIFO is full */
static void put_fifo_with_discard(struct aspeed_lpc_snoop_channel *chan, u8 val)
{
- if (!kfifo_initialized(&chan->fifo))
- return;
- if (kfifo_is_full(&chan->fifo))
- kfifo_skip(&chan->fifo);
- kfifo_put(&chan->fifo, val);
+ scoped_guard(spinlock, &chan->lock) {
+ if (!kfifo_initialized(&chan->fifo))
+ return;
+ if (kfifo_is_full(&chan->fifo))
+ kfifo_skip(&chan->fifo);
+ kfifo_put(&chan->fifo, val);
+ }
wake_up_interruptible(&chan->wq);
}
@@ -292,6 +304,9 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev)
if (!lpc_snoop)
return -ENOMEM;
+ spin_lock_init(&lpc_snoop->chan[0].lock);
+ spin_lock_init(&lpc_snoop->chan[1].lock);
+
np = pdev->dev.parent->of_node;
if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") &&
!of_device_is_compatible(np, "aspeed,ast2500-lpc-v2") &&
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 517/869] gpio: pca953x: fix pca953x_irq_bus_sync_unlock regmap lock
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (515 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 516/869] soc: aspeed: lpc-snoop: Fix usercopy overflow in snoop_file_read Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 518/869] firewire: ohci: fix NULL pointer dereference in ar_context_release Greg Kroah-Hartman
` (352 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Mark Tomlinson, Bartosz Golaszewski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Tomlinson <mark.tomlinson@alliedtelesis.co.nz>
[ Upstream commit 9dc325327babe7f159e84cbe9380a45342da0585 ]
Locking is disabled in the regmap config as this driver uses its own
lock. This means that all calls to regmap functions (read or write) must
hold the i2c_lock. The function pca953x_irq_bus_sync_unlock() did not do
this, and it was therefore possible that multiple threads could cause an
incorrect register to be read/written.
A previous patch partly fixed this, but only protected the write to the
interrupt mask register, and not the read from the direction register.
Fixes: bfc6444b57dc ("gpio: pca953x: fix pca953x_irq_bus_sync_unlock race")
Cc: stable@vger.kernel.org
Signed-off-by: Mark Tomlinson <mark.tomlinson@alliedtelesis.co.nz>
Link: https://patch.msgid.link/20260709045116.2304246-1-mark.tomlinson@alliedtelesis.co.nz
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpio/gpio-pca953x.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index ad9280472bdd5..1c7ae71dfe555 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -525,15 +525,23 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *
return 0;
}
-static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
+static int pca953x_gpio_direction_input_unlocked(struct gpio_chip *gc,
+ unsigned int off)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
u8 bit = BIT(off % BANK_SZ);
+ return regmap_write_bits(chip->regmap, dirreg, bit, bit);
+}
+
+static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned int off)
+{
+ struct pca953x_chip *chip = gpiochip_get_data(gc);
+
guard(mutex)(&chip->i2c_lock);
- return regmap_write_bits(chip->regmap, dirreg, bit, bit);
+ return pca953x_gpio_direction_input_unlocked(gc, off);
}
static int pca953x_gpio_direction_output(struct gpio_chip *gc,
@@ -759,9 +767,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
DECLARE_BITMAP(reg_direction, MAX_LINE);
int level;
- if (chip->driver_data & PCA_PCAL) {
- guard(mutex)(&chip->i2c_lock);
+ guard(mutex)(&chip->i2c_lock);
+ if (chip->driver_data & PCA_PCAL) {
/* Enable latch on interrupt-enabled inputs */
pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
@@ -782,7 +790,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
/* Look for any newly setup interrupt */
for_each_set_bit(level, irq_mask, gc->ngpio)
- pca953x_gpio_direction_input(&chip->gpio_chip, level);
+ pca953x_gpio_direction_input_unlocked(&chip->gpio_chip, level);
mutex_unlock(&chip->irq_lock);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 518/869] firewire: ohci: fix NULL pointer dereference in ar_context_release
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (516 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 517/869] gpio: pca953x: fix pca953x_irq_bus_sync_unlock regmap lock Greg Kroah-Hartman
@ 2026-10-17 15:55 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 519/869] ipvs: revalidate ihl to prevent out-of-bounds access Greg Kroah-Hartman
` (351 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:55 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+d30aad27833a559defab,
Aleksandr Nogikh, Takashi Sakamoto, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Nogikh <nogikh@google.com>
[ Upstream commit 42d217add8d80d6e7d9f58f80d11ea9b07ea113e ]
During the error handling path of the driver's probe function, a NULL
pointer dereference can occur in ar_context_release().
When pci_probe() fails early (e.g., if pcim_enable_device() or MMIO mapping
fails), the devres cleanup mechanism invokes release_ohci(). This function
unconditionally calls ar_context_release() to clean up the asynchronous
receive contexts. However, if ar_context_init() was not yet called,
ctx->ohci remains NULL (as the fw_ohci structure is zero-initialized by
devres_alloc()).
ar_context_release() immediately dereferences ctx->ohci to get the dev
pointer before checking if the context was actually initialized, leading to
a crash:
Oops: general protection fault, probably for non-canonical address
0xdffffc0000000001: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
RIP: 0010:ar_context_release+0x3f/0x380 drivers/firewire/ohci.c:543
Call Trace:
release_ohci+0x3f/0x60 drivers/firewire/ohci.c:3567
release_nodes drivers/base/devres.c:546 [inline]
devres_release_all+0x1a8/0x260 drivers/base/devres.c:576
device_unbind_cleanup drivers/base/dd.c:597 [inline]
really_probe+0x451/0xae0 drivers/base/dd.c:772
To fix this, move the assignment of the dev pointer after the !ctx->buffer
check. If ctx->buffer is NULL, it indicates that the context was never
successfully initialized and there is nothing to release, safely avoiding
the dereference of the uninitialized ctx->ohci pointer.
Fixes: 5716e58aecdd ("firewire: ohci: release buffer for AR req/resp contexts when managed resource is released")
Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: syzbot+d30aad27833a559defab@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d30aad27833a559defab
Link: https://syzkaller.appspot.com/ai_job?id=10a18617-7893-42dd-bf1c-cd49e19e95d9
Signed-off-by: Aleksandr Nogikh <nogikh@google.com>
Link: https://lore.kernel.org/r/90c5db71-dd1f-4d46-b9d3-2f1046cbd5ea@mail.kernel.org
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/firewire/ohci.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 90fcab1f65bcd..4dca78f859f63 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -753,12 +753,14 @@ static void ar_context_link_page(struct ar_context *ctx, unsigned int index)
static void ar_context_release(struct ar_context *ctx)
{
- struct device *dev = ctx->ohci->card.device;
+ struct device *dev;
unsigned int i;
if (!ctx->buffer)
return;
+ dev = ctx->ohci->card.device;
+
vunmap(ctx->buffer);
for (i = 0; i < AR_BUFFERS; i++) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 519/869] ipvs: revalidate ihl to prevent out-of-bounds access
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (517 preceding siblings ...)
2026-10-17 15:55 ` [PATCH 6.12 518/869] firewire: ohci: fix NULL pointer dereference in ar_context_release Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 520/869] sctp: validate cookie AUTH state before use Greg Kroah-Hartman
` (350 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Julian Anastasov, Pablo Neira Ayuso,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Julian Anastasov <ja@ssi.bg>
[ Upstream commit d93660df4dd1d116f608ada4a29a80a5d6f0a6ed ]
While the outer IP header is already pulled into the skb head,
we must be careful and revalidate the embedded headers after
reading them from the skb frags to prevent out-of-bounds
access.
One such place reported by Sashiko is ip_vs_nat_icmp() where
local process can change the ihl field and after
skb_ensure_writable() we can see larger value which is a
problem for the ip_send_check(cih) calls.
Add check to drop the packet if the ihl field is changed.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Link: https://sashiko.dev/#/patchset/20260730183506.87473-1-ja%40ssi.bg
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/ip_vs.h | 2 +-
net/netfilter/ipvs/ip_vs_core.c | 11 +++++++++--
net/netfilter/ipvs/ip_vs_xmit.c | 3 ++-
3 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 35f012f620150..d2bfc9f67082c 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -1713,7 +1713,7 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)
return fwd;
}
-void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+bool ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_conn *cp, int dir, unsigned int toff,
bool has_ports, struct ip_vs_iphdr *ciph);
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 4e30a903f4bdc..401159a660750 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -745,7 +745,7 @@ static int ip_vs_route_me_harder(struct netns_ipvs *ipvs, int af,
* Packet has been made sufficiently writable in caller
* - inout: 1=in->out, 0=out->in
*/
-void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
+bool ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_conn *cp, int inout, unsigned int toff,
bool has_ports, struct ip_vs_iphdr *ciph)
{
@@ -753,6 +753,11 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct icmphdr *icmph = (struct icmphdr *)(skb->data + toff);
struct iphdr *cih = (struct iphdr *)(icmph + 1);
+ /* Before now we may used ihl from skb frag, revalidate it after
+ * copying it into skb head to prevent out-of-bounds access
+ */
+ if (cih->ihl * 4 != ciph->len - ciph->off)
+ return false;
if (inout) {
iph->saddr = cp->vaddr.ip;
ip_send_check(iph);
@@ -786,6 +791,7 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
else
IP_VS_DBG_PKT(11, AF_INET, pp, skb, ciph->off,
"Forwarding altered incoming ICMP");
+ return true;
}
#ifdef CONFIG_IP_VS_IPV6
@@ -877,7 +883,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
ip_vs_nat_icmp_v6(skb, pp, cp, 1, toff, has_ports, ciph);
else
#endif
- ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports, ciph);
+ if (!ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports, ciph))
+ goto out;
if (ip_vs_route_me_harder(cp->ipvs, af, skb, hooknum))
goto out;
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 240378e37741a..e0c2820be57ee 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -1577,7 +1577,8 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
if (skb_cow(skb, rt->dst.dev->hard_header_len))
goto tx_error;
- ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports, ciph);
+ if (!ip_vs_nat_icmp(skb, pp, cp, 0, toff, has_ports, ciph))
+ goto tx_error;
/* Another hack: avoid icmp_send in ip_fragment */
skb->ignore_df = 1;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 520/869] sctp: validate cookie AUTH state before use
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (518 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 519/869] ipvs: revalidate ihl to prevent out-of-bounds access Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 521/869] scsi: core: pair EH runtime PM get and put Greg Kroah-Hartman
` (349 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jérémy Jean, Xin Long,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
[ Upstream commit 3dbb44d88b1e94dd31fe43588af7437b34b44d56 ]
When cookie authentication is disabled, COOKIE_ECHO restores fixed-size
AUTH fields directly from peer-controlled cookie bytes. A forged RANDOM
length, HMAC list, or CHUNKS list can then reach association consumers
with lengths or identifiers that were never validated against the local
backing arrays.
A forged RANDOM length can cause out-of-bounds reads during key-vector
construction. A forged HMAC identifier also caused a 32-byte write past
a zero-length AUTH chunk, providing a primitive for a local privilege
escalation chain.
Validate the cookie's RANDOM, HMACS, and CHUNKS parameters at the cookie
trust boundary before copying them into the association. Reject invalid
types, malformed lengths, unsupported HMAC identifiers, HMAC lists
without SHA1, and forbidden chunk ids.
Fixes: bbd0d59809f9 ("[SCTP]: Implement the receive and verification of AUTH chunk")
Fixes: 1f485649f529 ("[SCTP]: Implement SCTP-AUTH internals")
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
Acked-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/20260804200042.2412009-1-Jeremy.Jean@oss.cyber.gouv.fr
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/sctp/auth.h | 3 ++
net/sctp/auth.c | 76 ++++++++++++++++++++++++++++++++++++++++
net/sctp/sm_make_chunk.c | 3 ++
3 files changed, 82 insertions(+)
diff --git a/include/net/sctp/auth.h b/include/net/sctp/auth.h
index d4b3b2dcd15b7..8fcc8bb1439cf 100644
--- a/include/net/sctp/auth.h
+++ b/include/net/sctp/auth.h
@@ -23,6 +23,7 @@ struct sctp_association;
struct sctp_authkey;
struct sctp_hmacalgo;
struct crypto_shash;
+struct sctp_cookie;
/*
* Define a generic struct that will hold all the info
@@ -81,6 +82,8 @@ int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp);
void sctp_auth_destroy_hmacs(struct crypto_shash *auth_hmacs[]);
struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id);
struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc);
+bool sctp_auth_verify_cookie_params(const struct sctp_endpoint *ep,
+ const struct sctp_cookie *cookie);
void sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc,
struct sctp_hmac_algo_param *hmacs);
int sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc,
diff --git a/net/sctp/auth.c b/net/sctp/auth.c
index 8320764b16b92..1a722ae146a26 100644
--- a/net/sctp/auth.c
+++ b/net/sctp/auth.c
@@ -376,6 +376,82 @@ int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep,
return -ENOMEM;
}
+static bool sctp_auth_chunk_id_forbidden(__u8 chunk_id)
+{
+ switch (chunk_id) {
+ case SCTP_CID_INIT:
+ case SCTP_CID_INIT_ACK:
+ case SCTP_CID_SHUTDOWN_COMPLETE:
+ case SCTP_CID_AUTH:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Verify AUTH parameters copied from a state cookie before they are restored
+ * into an association. When cookie authentication is disabled these fields
+ * are peer-controlled, so they must satisfy the same constraints as locally
+ * generated AUTH parameters.
+ */
+bool sctp_auth_verify_cookie_params(const struct sctp_endpoint *ep,
+ const struct sctp_cookie *cookie)
+{
+ const struct sctp_paramhdr *random;
+ const struct sctp_hmac_algo_param *hmacs;
+ const struct sctp_chunks_param *chunks;
+ u16 hmacs_len, chunks_len;
+ u16 n_hmacs, n_chunks, i;
+ bool has_sha1 = false;
+
+ if (sctp_sk(ep->base.sk)->hmac || !ep->auth_enable)
+ return true;
+
+ random = (const struct sctp_paramhdr *)cookie->auth_random;
+ if (random->type != SCTP_PARAM_RANDOM ||
+ ntohs(random->length) != sizeof(*random) + SCTP_AUTH_RANDOM_LENGTH)
+ return false;
+
+ hmacs = (const struct sctp_hmac_algo_param *)cookie->auth_hmacs;
+ hmacs_len = ntohs(hmacs->param_hdr.length);
+ if (hmacs->param_hdr.type != SCTP_PARAM_HMAC_ALGO ||
+ hmacs_len < sizeof(struct sctp_paramhdr) +
+ sizeof(hmacs->hmac_ids[0]) ||
+ hmacs_len > sizeof(cookie->auth_hmacs) ||
+ (hmacs_len - sizeof(struct sctp_paramhdr)) %
+ sizeof(hmacs->hmac_ids[0]))
+ return false;
+
+ n_hmacs = (hmacs_len - sizeof(struct sctp_paramhdr)) /
+ sizeof(hmacs->hmac_ids[0]);
+ for (i = 0; i < n_hmacs; i++) {
+ u16 hmac_id = ntohs(hmacs->hmac_ids[i]);
+
+ if (hmac_id > SCTP_AUTH_HMAC_ID_MAX ||
+ !sctp_hmac_list[hmac_id].hmac_name)
+ return false;
+ if (hmac_id == SCTP_AUTH_HMAC_ID_SHA1)
+ has_sha1 = true;
+ }
+ if (!has_sha1)
+ return false;
+
+ chunks = (const struct sctp_chunks_param *)cookie->auth_chunks;
+ chunks_len = ntohs(chunks->param_hdr.length);
+ if (chunks->param_hdr.type != SCTP_PARAM_CHUNKS ||
+ chunks_len < sizeof(struct sctp_paramhdr) ||
+ chunks_len > sizeof(cookie->auth_chunks))
+ return false;
+
+ n_chunks = chunks_len - sizeof(struct sctp_paramhdr);
+ for (i = 0; i < n_chunks; i++) {
+ if (sctp_auth_chunk_id_forbidden(chunks->chunks[i]))
+ return false;
+ }
+
+ return true;
+}
+
/* Public interface to create the association shared key.
* See code above for the algorithm.
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 34692cadea982..1bbc041c06440 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1883,6 +1883,9 @@ struct sctp_association *sctp_unpack_cookie(
/* Set up our peer's port number. */
retval->peer.port = ntohs(chunk->sctp_hdr->source);
+ if (!sctp_auth_verify_cookie_params(ep, bear_cookie))
+ goto malformed;
+
/* Populate the association from the cookie. */
memcpy(&retval->c, bear_cookie, sizeof(*bear_cookie));
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 521/869] scsi: core: pair EH runtime PM get and put
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (519 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 520/869] sctp: validate cookie AUTH state before use Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 522/869] ASoC: SOF: Relocate and rework functionality for PCM stream freeing Greg Kroah-Hartman
` (348 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Hongjie Fang, Bart Van Assche,
Peter Wang, Martin K. Petersen (Oracle), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongjie Fang <hongjiefang@asrmicro.com>
[ Upstream commit 872f486259ae0bc6b73ca4735a15d013241f73e9 ]
shost->eh_noresume is currently consulted twice in one error handling
iteration: once before scsi_autopm_get_host() and once again before
scsi_autopm_put_host().
That is racy when a PM-triggered error path flips shost->eh_noresume
while the SCSI EH thread is still running.
The problem flow looks like this:
PM path
ufshcd_set_dev_pwr_mode()
shost->eh_noresume = 1
ufshcd_execute_start_stop <-- trigger EH
...
shost->eh_noresume = 0
EH path
scsi_error_handler()
if (!shost->eh_noresume)
scsi_autopm_get_host() <-- skipped
...
if (!shost->eh_noresume)
scsi_autopm_put_host() <-- executed later
In that case one EH iteration can skip autoresume on entry and still
drop a runtime PM reference on exit. That leaves an unmatched runtime PM
put and can trigger a runtime PM usage count underflow.
Fix this by making eh_noresume a regular bool so it can be accessed with
READ_ONCE() and WRITE_ONCE(). Snapshot it once per EH iteration and use
that snapshot for both runtime PM get and put decisions.
Fixes: ae0751ffc77e ("[SCSI] add flag to skip the runtime PM calls on the host")
Signed-off-by: Hongjie Fang <hongjiefang@asrmicro.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
Link: https://patch.msgid.link/20260729111614.2407559-1-hongjiefang@asrmicro.com
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/scsi/scsi_error.c | 6 ++++--
drivers/ufs/core/ufshcd.c | 4 ++--
include/scsi/scsi_host.h | 7 ++++---
3 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 3ecdcb21040c9..94b873ec73449 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -2338,6 +2338,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)
int scsi_error_handler(void *data)
{
struct Scsi_Host *shost = data;
+ bool eh_noresume;
/*
* We use TASK_INTERRUPTIBLE so that the thread is not
@@ -2379,7 +2380,8 @@ int scsi_error_handler(void *data)
* what we need to do to get it up and online again (if we can).
* If we fail, we end up taking the thing offline.
*/
- if (!shost->eh_noresume && scsi_autopm_get_host(shost) != 0) {
+ eh_noresume = READ_ONCE(shost->eh_noresume);
+ if (!eh_noresume && scsi_autopm_get_host(shost) != 0) {
SCSI_LOG_ERROR_RECOVERY(1,
shost_printk(KERN_ERR, shost,
"scsi_eh_%d: unable to autoresume\n",
@@ -2403,7 +2405,7 @@ int scsi_error_handler(void *data)
* which are still online.
*/
scsi_restart_operations(shost);
- if (!shost->eh_noresume)
+ if (!eh_noresume)
scsi_autopm_put_host(shost);
}
__set_current_state(TASK_RUNNING);
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 44c84090496d6..81297a429cfe6 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -9561,7 +9561,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
* we are functional while we are here, skip host resume in error
* handling context.
*/
- hba->host->eh_noresume = 1;
+ WRITE_ONCE(hba->host->eh_noresume, 1);
/*
* Current function would be generally called from the power management
@@ -9583,7 +9583,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
}
scsi_device_put(sdp);
- hba->host->eh_noresume = 0;
+ WRITE_ONCE(hba->host->eh_noresume, 0);
return ret;
}
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 990747f803fef..28ab13c6ac619 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -633,6 +633,10 @@ struct Scsi_Host {
*/
unsigned nr_hw_queues;
unsigned nr_maps;
+
+ /* Don't resume host in EH */
+ bool eh_noresume;
+
unsigned active_mode:2;
/*
@@ -654,9 +658,6 @@ struct Scsi_Host {
/* Asynchronous scan in progress */
unsigned async_scan:1;
- /* Don't resume host in EH */
- unsigned eh_noresume:1;
-
/* The controller does not support WRITE SAME */
unsigned no_write_same:1;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 522/869] ASoC: SOF: Relocate and rework functionality for PCM stream freeing
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (520 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 521/869] scsi: core: pair EH runtime PM get and put Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 523/869] ASoC: SOF: pcm: Move period/buffer configuration print after platform open Greg Kroah-Hartman
` (347 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Peter Ujfalusi, Liam Girdwood,
Bard Liao, Ranjani Sridharan, Mark Brown, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
[ Upstream commit 169ec0a541aac8afb215ab591b0fd53276686014 ]
Move the sof_pcm_stream_free() from sof-audio.c to pcm.c as static function
and add wrapper to free all active stream, which is going to be used in
ipc3/4 topology code (removes duplicated code).
With this change most of the PCM stream related code is located in one
source file for easier lookup and simplified flow.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://patch.msgid.link/20250206092828.7569-2-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Stable-dep-of: 17661c67b206 ("ASoC: SOF: ipc4-pcm: Continue the pipeline trigger in case of IPC timeout")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/soc/sof/ipc3-topology.c | 20 ++-------
sound/soc/sof/ipc4-topology.c | 18 +-------
sound/soc/sof/pcm.c | 78 +++++++++++++++++++++++++++++++++++
sound/soc/sof/sof-audio.c | 49 ----------------------
sound/soc/sof/sof-audio.h | 3 +-
5 files changed, 84 insertions(+), 84 deletions(-)
diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c
index 19bbae725d838..f449362a2905a 100644
--- a/sound/soc/sof/ipc3-topology.c
+++ b/sound/soc/sof/ipc3-topology.c
@@ -2386,28 +2386,16 @@ static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify)
static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev)
{
struct snd_sof_widget *swidget;
- struct snd_sof_pcm *spcm;
- int dir, ret;
+ int ret;
/*
* free all PCMs and their associated DAPM widgets if their connected DAPM widget
* list is not NULL. This should only be true for paused streams at this point.
* This is equivalent to the handling of FE DAI suspend trigger for running streams.
*/
- list_for_each_entry(spcm, &sdev->pcm_list, list) {
- for_each_pcm_streams(dir) {
- struct snd_pcm_substream *substream = spcm->stream[dir].substream;
-
- if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
- continue;
-
- if (spcm->stream[dir].list) {
- ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
- if (ret < 0)
- return ret;
- }
- }
- }
+ ret = sof_pcm_free_all_streams(sdev);
+ if (ret)
+ return ret;
/*
* free any left over DAI widgets. This is equivalent to the handling of suspend trigger
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index fabd364d33168..6af0cc154f3d7 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -3345,9 +3345,6 @@ static int sof_ipc4_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai *
static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
{
- struct snd_sof_pcm *spcm;
- int dir, ret;
-
/*
* This function is called during system suspend, we need to make sure
* that all streams have been freed up.
@@ -3359,21 +3356,8 @@ static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
*
* This will also make sure that paused streams handled correctly.
*/
- list_for_each_entry(spcm, &sdev->pcm_list, list) {
- for_each_pcm_streams(dir) {
- struct snd_pcm_substream *substream = spcm->stream[dir].substream;
-
- if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
- continue;
- if (spcm->stream[dir].list) {
- ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
- if (ret < 0)
- return ret;
- }
- }
- }
- return 0;
+ return sof_pcm_free_all_streams(sdev);
}
static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index c5c6353f18cee..61bd690b29fa5 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -191,6 +191,84 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
return 0;
}
+static int sof_pcm_stream_free(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ struct snd_sof_pcm *spcm, int dir,
+ bool free_widget_list)
+{
+ const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
+ int ret;
+ int err = 0;
+
+ if (spcm->prepared[substream->stream]) {
+ /* stop DMA first if needed */
+ if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
+ snd_sof_pcm_platform_trigger(sdev, substream,
+ SNDRV_PCM_TRIGGER_STOP);
+
+ /* free PCM in the DSP */
+ if (pcm_ops && pcm_ops->hw_free) {
+ ret = pcm_ops->hw_free(sdev->component, substream);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: pcm_ops hw_free failed %d\n",
+ __func__, ret);
+ err = ret;
+ }
+ }
+
+ spcm->prepared[substream->stream] = false;
+ spcm->pending_stop[substream->stream] = false;
+ }
+
+ /* reset the DMA */
+ ret = snd_sof_pcm_platform_hw_free(sdev, substream);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: platform hw free failed %d\n",
+ __func__, ret);
+ if (!err)
+ err = ret;
+ }
+
+ /* free widget list */
+ if (free_widget_list) {
+ ret = sof_widget_list_free(sdev, spcm, dir);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: sof_widget_list_free failed %d\n",
+ __func__, ret);
+ if (!err)
+ err = ret;
+ }
+ }
+
+ return err;
+}
+
+int sof_pcm_free_all_streams(struct snd_sof_dev *sdev)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_sof_pcm *spcm;
+ int dir, ret;
+
+ list_for_each_entry(spcm, &sdev->pcm_list, list) {
+ for_each_pcm_streams(dir) {
+ substream = spcm->stream[dir].substream;
+
+ if (!substream || !substream->runtime ||
+ spcm->stream[dir].suspend_ignored)
+ continue;
+
+ if (spcm->stream[dir].list) {
+ ret = sof_pcm_stream_free(sdev, substream, spcm,
+ dir, true);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
static int sof_pcm_hw_free(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index f0a4e146d7981..ef7d2f4b31c81 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -828,55 +828,6 @@ bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev)
return false;
}
-int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
- struct snd_sof_pcm *spcm, int dir, bool free_widget_list)
-{
- const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
- int ret;
- int err = 0;
-
- if (spcm->prepared[substream->stream]) {
- /* stop DMA first if needed */
- if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
- snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP);
-
- /* free PCM in the DSP */
- if (pcm_ops && pcm_ops->hw_free) {
- ret = pcm_ops->hw_free(sdev->component, substream);
- if (ret < 0) {
- dev_err(sdev->dev, "%s: pcm_ops hw_free failed %d\n",
- __func__, ret);
- err = ret;
- }
- }
-
- spcm->prepared[substream->stream] = false;
- spcm->pending_stop[substream->stream] = false;
- }
-
- /* reset the DMA */
- ret = snd_sof_pcm_platform_hw_free(sdev, substream);
- if (ret < 0) {
- dev_err(sdev->dev, "%s: platform hw free failed %d\n",
- __func__, ret);
- if (!err)
- err = ret;
- }
-
- /* free widget list */
- if (free_widget_list) {
- ret = sof_widget_list_free(sdev, spcm, dir);
- if (ret < 0) {
- dev_err(sdev->dev, "%s: sof_widget_list_free failed %d\n",
- __func__, ret);
- if (!err)
- err = ret;
- }
- }
-
- return err;
-}
-
/*
* Generic object lookup APIs.
*/
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 01b819dd84984..6d652a202f698 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -648,8 +648,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir);
int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, struct snd_sof_dev *sdev,
struct snd_sof_pcm *spcm);
-int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
- struct snd_sof_pcm *spcm, int dir, bool free_widget_list);
+int sof_pcm_free_all_streams(struct snd_sof_dev *sdev);
int get_token_u32(void *elem, void *object, u32 offset);
int get_token_u16(void *elem, void *object, u32 offset);
int get_token_comp_format(void *elem, void *object, u32 offset);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 523/869] ASoC: SOF: pcm: Move period/buffer configuration print after platform open
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (521 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 522/869] ASoC: SOF: Relocate and rework functionality for PCM stream freeing Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 524/869] ASoC: SOF: pcm: Add snd_sof_pcm specific wrappers for dev_dbg() and dev_err() Greg Kroah-Hartman
` (346 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Peter Ujfalusi, Liam Girdwood,
Bard Liao, Ranjani Sridharan, Mark Brown, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
[ Upstream commit 4d2ea16576c8aa1437048cf436bff85653f139fe ]
The platform specific pcm_open call via snd_sof_pcm_platform_open() can
modify the initial buffer configuration via constraints.
Move the prints as last step in the sof_pcm_open() function to reflect the
final setup.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://patch.msgid.link/20250206092828.7569-3-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Stable-dep-of: 17661c67b206 ("ASoC: SOF: ipc4-pcm: Continue the pipeline trigger in case of IPC timeout")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/soc/sof/pcm.c | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index 61bd690b29fa5..cba6d0b67999e 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -536,15 +536,6 @@ static int sof_pcm_open(struct snd_soc_component *component,
*/
runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max);
- dev_dbg(component->dev, "period min %zd max %zd bytes\n",
- runtime->hw.period_bytes_min,
- runtime->hw.period_bytes_max);
- dev_dbg(component->dev, "period count %d max %d\n",
- runtime->hw.periods_min,
- runtime->hw.periods_max);
- dev_dbg(component->dev, "buffer max %zd bytes\n",
- runtime->hw.buffer_bytes_max);
-
/* set wait time - TODO: come from topology */
substream->wait_time = 500;
@@ -554,10 +545,21 @@ static int sof_pcm_open(struct snd_soc_component *component,
spcm->prepared[substream->stream] = false;
ret = snd_sof_pcm_platform_open(sdev, substream);
- if (ret < 0)
+ if (ret < 0) {
dev_err(component->dev, "error: pcm open failed %d\n", ret);
+ return ret;
+ }
- return ret;
+ dev_dbg(component->dev, "period bytes min %zd, max %zd\n",
+ runtime->hw.period_bytes_min,
+ runtime->hw.period_bytes_max);
+ dev_dbg(component->dev, "period count min %d, max %d\n",
+ runtime->hw.periods_min,
+ runtime->hw.periods_max);
+ dev_dbg(component->dev, "buffer bytes max %zd\n",
+ runtime->hw.buffer_bytes_max);
+
+ return 0;
}
static int sof_pcm_close(struct snd_soc_component *component,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 524/869] ASoC: SOF: pcm: Add snd_sof_pcm specific wrappers for dev_dbg() and dev_err()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (522 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 523/869] ASoC: SOF: pcm: Move period/buffer configuration print after platform open Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 525/869] ASoC: SOF: ipc4-pcm: Continue the pipeline trigger in case of IPC timeout Greg Kroah-Hartman
` (345 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Peter Ujfalusi, Liam Girdwood,
Bard Liao, Ranjani Sridharan, Mark Brown, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
[ Upstream commit 860693187c597645b28a421d8acb26428b8afd3f ]
Introduce spcm_dbg() and spcm_err() macros to provide consistent printing
for debug and error messages which includes usable information in the
print's prefix.
Update the prints in pcm.c, ipc3-pcm.c and ipc4-pcm.c to take advantage of
the features provided by the macros.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://patch.msgid.link/20250206092828.7569-4-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Stable-dep-of: 17661c67b206 ("ASoC: SOF: ipc4-pcm: Continue the pipeline trigger in case of IPC timeout")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/soc/sof/ipc3-pcm.c | 13 +++---
sound/soc/sof/ipc4-pcm.c | 16 ++++---
sound/soc/sof/pcm.c | 95 +++++++++++++++++----------------------
sound/soc/sof/sof-audio.h | 14 ++++++
4 files changed, 72 insertions(+), 66 deletions(-)
diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c
index 1c1b8f5953674..90ef5d99f626a 100644
--- a/sound/soc/sof/ipc3-pcm.c
+++ b/sound/soc/sof/ipc3-pcm.c
@@ -117,22 +117,23 @@ static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component,
if (platform_params->cont_update_posn)
pcm.params.cont_update_posn = 1;
- dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag);
+ spcm_dbg(spcm, substream->stream, "stream_tag %d\n",
+ pcm.params.stream_tag);
/* send hw_params IPC to the DSP */
ret = sof_ipc_tx_message(sdev->ipc, &pcm, sizeof(pcm),
&ipc_params_reply, sizeof(ipc_params_reply));
if (ret < 0) {
- dev_err(component->dev, "HW params ipc failed for stream %d\n",
- pcm.params.stream_tag);
+ spcm_err(spcm, substream->stream,
+ "STREAM_PCM_PARAMS ipc failed for stream_tag %d\n",
+ pcm.params.stream_tag);
return ret;
}
ret = snd_sof_set_stream_data_offset(sdev, &spcm->stream[substream->stream],
ipc_params_reply.posn_offset);
if (ret < 0) {
- dev_err(component->dev, "%s: invalid stream data offset for PCM %d\n",
- __func__, spcm->pcm.pcm_id);
+ spcm_err(spcm, substream->stream, "invalid stream data offset\n");
return ret;
}
@@ -171,7 +172,7 @@ static int sof_ipc3_pcm_trigger(struct snd_soc_component *component,
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
break;
default:
- dev_err(component->dev, "Unhandled trigger cmd %d\n", cmd);
+ spcm_err(spcm, substream->stream, "Unhandled trigger cmd %d\n", cmd);
return -EINVAL;
}
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index 5e877dc921b1e..dd521ea0b16a4 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -324,7 +324,7 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
set_fifo_size = false;
break;
default:
- dev_err(sdev->dev, "Unexpected state %d", state);
+ spcm_err(spcm, direction, "Unexpected pipeline state %d\n", state);
return -EINVAL;
}
@@ -344,8 +344,8 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
if (!pipeline->use_chain_dma) {
- dev_err(sdev->dev,
- "All pipelines in chained DMA stream should have use_chain_dma attribute set.");
+ spcm_err(spcm, direction,
+ "All pipelines in chained DMA path should have use_chain_dma attribute set.");
return -EINVAL;
}
@@ -400,12 +400,12 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
int ret;
int i;
- dev_dbg(sdev->dev, "trigger cmd: %d state: %d\n", cmd, state);
-
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
+ spcm_dbg(spcm, substream->stream, "cmd: %d, state: %d\n", cmd, state);
+
pipeline_list = &spcm->stream[substream->stream].pipeline_list;
/* nothing to trigger if the list is empty */
@@ -500,7 +500,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
*/
ret = sof_ipc4_set_multi_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, trigger_list);
if (ret < 0) {
- dev_err(sdev->dev, "failed to pause all pipelines\n");
+ spcm_err(spcm, substream->stream, "failed to pause all pipelines\n");
goto free;
}
@@ -529,7 +529,9 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
/* else set the RUNNING/RESET state in the DSP */
ret = sof_ipc4_set_multi_pipeline_state(sdev, state, trigger_list);
if (ret < 0) {
- dev_err(sdev->dev, "failed to set final state %d for all pipelines\n", state);
+ spcm_err(spcm, substream->stream,
+ "failed to set final state %d for all pipelines\n",
+ state);
/*
* workaround: if the firmware is crashed while setting the
* pipelines to reset state we must ignore the error code and
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index cba6d0b67999e..d584a72e6f52f 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -99,8 +99,8 @@ sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_run
ret = snd_soc_dapm_dai_get_connected_widgets(dai, dir, &list,
dpcm_end_walk_at_be);
if (ret < 0) {
- dev_err(sdev->dev, "error: dai %s has no valid %s path\n", dai->name,
- snd_pcm_direction_name(dir));
+ spcm_err(spcm, dir, "dai %s has no valid %s path\n",
+ dai->name, snd_pcm_direction_name(dir));
return ret;
}
@@ -108,8 +108,7 @@ sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_run
ret = sof_widget_list_setup(sdev, spcm, params, platform_params, dir);
if (ret < 0) {
- dev_err(sdev->dev, "error: failed widget list set up for pcm %d dir %d\n",
- spcm->pcm.pcm_id, dir);
+ spcm_err(spcm, dir, "Widget list set up failed\n");
spcm->stream[dir].list = NULL;
snd_soc_dapm_dai_free_widgets(&list);
return ret;
@@ -139,6 +138,8 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
+ spcm_dbg(spcm, substream->stream, "Entry: hw_params\n");
+
/*
* Handle repeated calls to hw_params() without free_pcm() in
* between. At least ALSA OSS emulation depends on this.
@@ -151,12 +152,9 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
spcm->prepared[substream->stream] = false;
}
- dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n",
- spcm->pcm.pcm_id, substream->stream);
-
ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, &platform_params);
if (ret < 0) {
- dev_err(component->dev, "platform hw params failed\n");
+ spcm_err(spcm, substream->stream, "platform hw params failed\n");
return ret;
}
@@ -210,8 +208,8 @@ static int sof_pcm_stream_free(struct snd_sof_dev *sdev,
if (pcm_ops && pcm_ops->hw_free) {
ret = pcm_ops->hw_free(sdev->component, substream);
if (ret < 0) {
- dev_err(sdev->dev, "%s: pcm_ops hw_free failed %d\n",
- __func__, ret);
+ spcm_err(spcm, substream->stream,
+ "pcm_ops->hw_free failed %d\n", ret);
err = ret;
}
}
@@ -223,8 +221,8 @@ static int sof_pcm_stream_free(struct snd_sof_dev *sdev,
/* reset the DMA */
ret = snd_sof_pcm_platform_hw_free(sdev, substream);
if (ret < 0) {
- dev_err(sdev->dev, "%s: platform hw free failed %d\n",
- __func__, ret);
+ spcm_err(spcm, substream->stream,
+ "platform hw free failed %d\n", ret);
if (!err)
err = ret;
}
@@ -233,8 +231,8 @@ static int sof_pcm_stream_free(struct snd_sof_dev *sdev,
if (free_widget_list) {
ret = sof_widget_list_free(sdev, spcm, dir);
if (ret < 0) {
- dev_err(sdev->dev, "%s: sof_widget_list_free failed %d\n",
- __func__, ret);
+ spcm_err(spcm, substream->stream,
+ "sof_widget_list_free failed %d\n", ret);
if (!err)
err = ret;
}
@@ -285,8 +283,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
- dev_dbg(component->dev, "pcm: free stream %d dir %d\n",
- spcm->pcm.pcm_id, substream->stream);
+ spcm_dbg(spcm, substream->stream, "Entry: hw_free\n");
ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true);
@@ -311,6 +308,8 @@ static int sof_pcm_prepare(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
+ spcm_dbg(spcm, substream->stream, "Entry: prepare\n");
+
if (spcm->prepared[substream->stream]) {
if (!spcm->pending_stop[substream->stream])
return 0;
@@ -324,15 +323,12 @@ static int sof_pcm_prepare(struct snd_soc_component *component,
return ret;
}
- dev_dbg(component->dev, "pcm: prepare stream %d dir %d\n",
- spcm->pcm.pcm_id, substream->stream);
-
/* set hw_params */
ret = sof_pcm_hw_params(component,
substream, &spcm->params[substream->stream]);
if (ret < 0) {
- dev_err(component->dev,
- "error: set pcm hw_params after resume\n");
+ spcm_err(spcm, substream->stream,
+ "failed to set hw_params after resume\n");
return ret;
}
@@ -362,8 +358,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
- dev_dbg(component->dev, "pcm: trigger stream %d dir %d cmd %d\n",
- spcm->pcm.pcm_id, substream->stream, cmd);
+ spcm_dbg(spcm, substream->stream, "Entry: trigger (cmd: %d)\n", cmd);
spcm->pending_stop[substream->stream] = false;
@@ -412,7 +407,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
reset_hw_params = true;
break;
default:
- dev_err(component->dev, "Unhandled trigger cmd %d\n", cmd);
+ spcm_err(spcm, substream->stream, "Unhandled trigger cmd %d\n", cmd);
return -EINVAL;
}
@@ -514,9 +509,7 @@ static int sof_pcm_open(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
- dev_dbg(component->dev, "pcm: open stream %d dir %d\n",
- spcm->pcm.pcm_id, substream->stream);
-
+ spcm_dbg(spcm, substream->stream, "Entry: open\n");
caps = &spcm->pcm.caps[substream->stream];
@@ -546,18 +539,16 @@ static int sof_pcm_open(struct snd_soc_component *component,
ret = snd_sof_pcm_platform_open(sdev, substream);
if (ret < 0) {
- dev_err(component->dev, "error: pcm open failed %d\n", ret);
+ spcm_err(spcm, substream->stream,
+ "platform pcm open failed %d\n", ret);
return ret;
}
- dev_dbg(component->dev, "period bytes min %zd, max %zd\n",
- runtime->hw.period_bytes_min,
- runtime->hw.period_bytes_max);
- dev_dbg(component->dev, "period count min %d, max %d\n",
- runtime->hw.periods_min,
- runtime->hw.periods_max);
- dev_dbg(component->dev, "buffer bytes max %zd\n",
- runtime->hw.buffer_bytes_max);
+ spcm_dbg(spcm, substream->stream, "period bytes min %zd, max %zd\n",
+ runtime->hw.period_bytes_min, runtime->hw.period_bytes_max);
+ spcm_dbg(spcm, substream->stream, "period count min %d, max %d\n",
+ runtime->hw.periods_min, runtime->hw.periods_max);
+ spcm_dbg(spcm, substream->stream, "buffer bytes max %zd\n", runtime->hw.buffer_bytes_max);
return 0;
}
@@ -578,13 +569,12 @@ static int sof_pcm_close(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
- dev_dbg(component->dev, "pcm: close stream %d dir %d\n",
- spcm->pcm.pcm_id, substream->stream);
+ spcm_dbg(spcm, substream->stream, "Entry: close\n");
err = snd_sof_pcm_platform_close(sdev, substream);
if (err < 0) {
- dev_err(component->dev, "error: pcm close failed %d\n",
- err);
+ spcm_err(spcm, substream->stream,
+ "platform pcm close failed %d\n", err);
/*
* keep going, no point in preventing the close
* from happening
@@ -618,7 +608,8 @@ static int sof_pcm_new(struct snd_soc_component *component,
return 0;
}
- dev_dbg(component->dev, "creating new PCM %s\n", spcm->pcm.pcm_name);
+ dev_dbg(spcm->scomp->dev, "pcm%u (%s): Entry: pcm_construct\n",
+ spcm->pcm.pcm_id, spcm->pcm.pcm_name);
/* do we need to pre-allocate playback audio buffer pages */
if (!spcm->pcm.playback)
@@ -626,16 +617,15 @@ static int sof_pcm_new(struct snd_soc_component *component,
caps = &spcm->pcm.caps[stream];
- /* pre-allocate playback audio buffer pages */
- dev_dbg(component->dev,
- "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n",
- caps->name, caps->buffer_size_min, caps->buffer_size_max);
-
if (!pcm->streams[stream].substream) {
- dev_err(component->dev, "error: NULL playback substream!\n");
+ spcm_err(spcm, stream, "NULL playback substream!\n");
return -EINVAL;
}
+ /* pre-allocate playback audio buffer pages */
+ spcm_dbg(spcm, stream, "allocate %s playback DMA buffer size 0x%x max 0x%x\n",
+ caps->name, caps->buffer_size_min, caps->buffer_size_max);
+
snd_pcm_set_managed_buffer(pcm->streams[stream].substream,
SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
0, le32_to_cpu(caps->buffer_size_max));
@@ -648,16 +638,15 @@ static int sof_pcm_new(struct snd_soc_component *component,
caps = &spcm->pcm.caps[stream];
- /* pre-allocate capture audio buffer pages */
- dev_dbg(component->dev,
- "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n",
- caps->name, caps->buffer_size_min, caps->buffer_size_max);
-
if (!pcm->streams[stream].substream) {
- dev_err(component->dev, "error: NULL capture substream!\n");
+ spcm_err(spcm, stream, "NULL capture substream!\n");
return -EINVAL;
}
+ /* pre-allocate capture audio buffer pages */
+ spcm_dbg(spcm, stream, "allocate %s capture DMA buffer size 0x%x max 0x%x\n",
+ caps->name, caps->buffer_size_min, caps->buffer_size_max);
+
snd_pcm_set_managed_buffer(pcm->streams[stream].substream,
SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
0, le32_to_cpu(caps->buffer_size_max));
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 6d652a202f698..a0b1bfcc093a8 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -616,6 +616,20 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp,
void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream);
void snd_sof_pcm_init_elapsed_work(struct work_struct *work);
+/*
+ * snd_sof_pcm specific wrappers for dev_dbg() and dev_err() to provide
+ * consistent and useful prints.
+ */
+#define spcm_dbg(__spcm, __dir, __fmt, ...) \
+ dev_dbg((__spcm)->scomp->dev, "pcm%u (%s), dir %d: " __fmt, \
+ (__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \
+ ##__VA_ARGS__)
+
+#define spcm_err(__spcm, __dir, __fmt, ...) \
+ dev_err((__spcm)->scomp->dev, "%s: pcm%u (%s), dir %d: " __fmt, \
+ __func__, (__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \
+ ##__VA_ARGS__)
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS)
void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream);
void snd_sof_compr_init_elapsed_work(struct work_struct *work);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 525/869] ASoC: SOF: ipc4-pcm: Continue the pipeline trigger in case of IPC timeout
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (523 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 524/869] ASoC: SOF: pcm: Add snd_sof_pcm specific wrappers for dev_dbg() and dev_err() Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 526/869] tracing/probes: Remove WARN_ON_ONCE from parse_btf_arg Greg Kroah-Hartman
` (344 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Peter Ujfalusi, Kai Vehmanen,
Mark Brown, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
[ Upstream commit 17661c67b206612cb3ba65d5ae726cd2015d0a53 ]
Ignore IPC errors for pipeline state change if the firmware state is
crashed or the IPC has timed out.
If the firmware has crashed the kernel still needs to go through the state
changes to reset its internal to be able to correctly work the next time
the DSP is booted up.
The case with IPC timeout is a bit more problematic, but it has been
rootcaused to be the result of system scheduling blockage and the firmware
did actually received and handled the message, but the reply handling got
blocked by issues outside of the SOF stack.
So far the best way to handle this is to continue with setting the state.
Fixes: c40aad7c81e5 ("ASoC: SOF: ipc4-pcm: Workaround for crashed firmware on system suspend")
Cc: stable@vger.kernel.org
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://patch.msgid.link/20260730112343.26687-1-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/soc/sof/ipc4-pcm.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index dd521ea0b16a4..79b4aed4d26cd 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -501,7 +501,19 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
ret = sof_ipc4_set_multi_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, trigger_list);
if (ret < 0) {
spcm_err(spcm, substream->stream, "failed to pause all pipelines\n");
- goto free;
+ /*
+ * workaround: if the firmware is crashed or the IPC timed out
+ * while setting the pipeline state we must ignore the error
+ * code and proceed to set adjust the local pipeline states.
+ *
+ * If the firmware is crashed we will not send IPC messages
+ * and we are going to see errors printed, but the state of the
+ * widgets will be correct for the next boot.
+ */
+ if (sdev->fw_state != SOF_FW_CRASHED && ret != -ETIMEDOUT)
+ goto free;
+
+ ret = 0;
}
/* update PAUSED state for all pipelines just triggered */
@@ -533,14 +545,15 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
"failed to set final state %d for all pipelines\n",
state);
/*
- * workaround: if the firmware is crashed while setting the
- * pipelines to reset state we must ignore the error code and
- * reset it to 0.
- * Since the firmware is crashed we will not send IPC messages
+ * workaround: if the firmware is crashed or the IPC timed out
+ * while setting the pipeline state we must ignore the error
+ * code and proceed to set adjust the local pipeline states.
+ *
+ * If the firmware is crashed we will not send IPC messages
* and we are going to see errors printed, but the state of the
* widgets will be correct for the next boot.
*/
- if (sdev->fw_state != SOF_FW_CRASHED || state != SOF_IPC4_PIPE_RESET)
+ if (sdev->fw_state != SOF_FW_CRASHED && ret != -ETIMEDOUT)
goto free;
ret = 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 526/869] tracing/probes: Remove WARN_ON_ONCE from parse_btf_arg
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (524 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 525/869] ASoC: SOF: ipc4-pcm: Continue the pipeline trigger in case of IPC timeout Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 527/869] net: ibm: emac: use devm_platform_ioremap_resource Greg Kroah-Hartman
` (343 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Masami Hiramatsu (Google),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
[ Upstream commit 251a8fe1b9aedccd298b77bc28426d564c5a923f ]
Sashiko found that user can cause this WARN_ON_ONCE() easily
with adding a kprobe event based on a raw address with BTF
parameter.
Since this is not an unexpected condition, remove the
WARN_ON_ONCE().
Link: https://lore.kernel.org/all/178177265367.2059927.13789953014706792126.stgit@mhiramat.tok.corp.google.com/
Link: https://sashiko.dev/#/patchset/178165816303.269421.7302603996990753309.stgit%40devnote2
Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: b576e09701c7 ("tracing/probes: Support function parameters if BTF is available")
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/trace/trace_probe.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 9c6ca26ffb927..95201c0daa8f0 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -622,7 +622,7 @@ static int parse_btf_arg(char *varname,
int i, is_ptr, ret;
u32 tid;
- if (WARN_ON_ONCE(!ctx->funcname))
+ if (!ctx->funcname)
return -EINVAL;
is_ptr = split_next_field(varname, &field, ctx);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 527/869] net: ibm: emac: use devm_platform_ioremap_resource
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (525 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 526/869] tracing/probes: Remove WARN_ON_ONCE from parse_btf_arg Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 528/869] net: ibm: emac: use platform_get_irq Greg Kroah-Hartman
` (342 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rosen Penev, Simon Horman,
Shannon Nelson, Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <rosenp@gmail.com>
[ Upstream commit c9bf90863df5fc8bae9513ce9bfcc260fad2ea0e ]
No need to have a struct resource. Gets rid of the TODO.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Shannon Nelson <shannon.nelson@amd.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: f623d38fe6c4 ("net: emac: Fix NULL pointer dereference in emac_probe")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/ibm/emac/core.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index a7aef2fb668d2..99be3cc32e915 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -3049,12 +3049,10 @@ static int emac_probe(struct platform_device *ofdev)
ndev->irq = dev->emac_irq;
- /* Map EMAC regs */
- // TODO : platform_get_resource() and devm_ioremap_resource()
- dev->emacp = devm_of_iomap(&ofdev->dev, np, 0, NULL);
- if (!dev->emacp) {
+ dev->emacp = devm_platform_ioremap_resource(ofdev, 0);
+ if (IS_ERR(dev->emacp)) {
dev_err(&ofdev->dev, "can't map device registers");
- err = -ENOMEM;
+ err = PTR_ERR(dev->emacp);
goto err_gone;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 528/869] net: ibm: emac: use platform_get_irq
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (526 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 527/869] net: ibm: emac: use devm_platform_ioremap_resource Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 529/869] net: emac: Fix NULL pointer dereference in emac_probe Greg Kroah-Hartman
` (341 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rosen Penev, Simon Horman,
Shannon Nelson, Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <rosenp@gmail.com>
[ Upstream commit a598f66d9169312e7eaab8cc7b8f175866e68997 ]
No need for irq_of_parse_and_map since we have platform_device.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Shannon Nelson <shannon.nelson@amd.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: f623d38fe6c4 ("net: emac: Fix NULL pointer dereference in emac_probe")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/ibm/emac/core.c | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 99be3cc32e915..7999d0b8caaeb 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -3030,15 +3030,8 @@ static int emac_probe(struct platform_device *ofdev)
if (err)
goto err_gone;
- /* Get interrupts. EMAC irq is mandatory */
- dev->emac_irq = irq_of_parse_and_map(np, 0);
- if (!dev->emac_irq) {
- printk(KERN_ERR "%pOF: Can't map main interrupt\n", np);
- err = -ENODEV;
- goto err_gone;
- }
-
/* Setup error IRQ handler */
+ dev->emac_irq = platform_get_irq(ofdev, 0);
err = devm_request_irq(&ofdev->dev, dev->emac_irq, emac_irq, 0, "EMAC",
dev);
if (err) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 529/869] net: emac: Fix NULL pointer dereference in emac_probe
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (527 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 528/869] net: ibm: emac: use platform_get_irq Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 530/869] ieee802154: Avoid calling WARN_ON() on -ENOMEM in cfg802154_switch_netns() Greg Kroah-Hartman
` (340 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rosen Penev, Andrew Lunn,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <rosenp@gmail.com>
[ Upstream commit f623d38fe6c4e8c40b23f42cc6fe6963fa49997b ]
Move devm_request_irq() after devm_platform_ioremap_resource() so that
dev->emacp is mapped before the interrupt handler can fire. An early
interrupt hitting emac_irq() would dereference the NULL dev->emacp and
crash.
Also remove redundant error message. devm_platform_ioremap_resource()
already returns an error message with dev_err_probe().
Fixes: dcc34ef7c834 ("net: ibm: emac: manage emac_irq with devm")
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20260618023405.415644-1-rosenp@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/ibm/emac/core.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 7999d0b8caaeb..e88117add9129 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -3030,6 +3030,12 @@ static int emac_probe(struct platform_device *ofdev)
if (err)
goto err_gone;
+ dev->emacp = devm_platform_ioremap_resource(ofdev, 0);
+ if (IS_ERR(dev->emacp)) {
+ err = PTR_ERR(dev->emacp);
+ goto err_gone;
+ }
+
/* Setup error IRQ handler */
dev->emac_irq = platform_get_irq(ofdev, 0);
err = devm_request_irq(&ofdev->dev, dev->emac_irq, emac_irq, 0, "EMAC",
@@ -3042,13 +3048,6 @@ static int emac_probe(struct platform_device *ofdev)
ndev->irq = dev->emac_irq;
- dev->emacp = devm_platform_ioremap_resource(ofdev, 0);
- if (IS_ERR(dev->emacp)) {
- dev_err(&ofdev->dev, "can't map device registers");
- err = PTR_ERR(dev->emacp);
- goto err_gone;
- }
-
/* Wait for dependent devices */
err = emac_wait_deps(dev);
if (err)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 530/869] ieee802154: Avoid calling WARN_ON() on -ENOMEM in cfg802154_switch_netns()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (528 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 529/869] net: emac: Fix NULL pointer dereference in emac_probe Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 531/869] coresight: ete: Always save state on power down Greg Kroah-Hartman
` (339 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+e0bd4e4815a910c0daa8,
Kuniyuki Iwashima, Miquel Raynal, Ivan Abramov, Stefan Schmidt,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Abramov <i.abramov@mt-integration.ru>
[ Upstream commit 0569f67ed6a7af838e2141da93c68e6b6013f483 ]
It's pointless to call WARN_ON() in case of an allocation failure in
dev_change_net_namespace() and device_rename(), since it only leads to
useless splats caused by deliberate fault injections, so avoid it.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
Fixes: 66e5c2672cd1 ("ieee802154: add netns support")
Reported-by: syzbot+e0bd4e4815a910c0daa8@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/000000000000f4a1b7061f9421de@google.com/#t
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Ivan Abramov <i.abramov@mt-integration.ru>
Link: https://lore.kernel.org/20250403101935.991385-3-i.abramov@mt-integration.ru
Signed-off-by: Stefan Schmidt <stefan@datenfreihafen.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ieee802154/core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
index 4a4379c828b90..9b807f78a3105 100644
--- a/net/ieee802154/core.c
+++ b/net/ieee802154/core.c
@@ -245,7 +245,7 @@ int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
wpan_dev->netdev->netns_local = false;
err = dev_change_net_namespace(wpan_dev->netdev, net,
"wpan%d");
- WARN_ON(err);
+ WARN_ON(err && err != -ENOMEM);
wpan_dev->netdev->netns_local = true;
}
@@ -255,7 +255,7 @@ int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
wpan_phy_net_set(&rdev->wpan_phy, net);
err = device_rename(&rdev->wpan_phy.dev, dev_name(&rdev->wpan_phy.dev));
- WARN_ON(err);
+ WARN_ON(err && err != -ENOMEM);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 531/869] coresight: ete: Always save state on power down
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (529 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 530/869] ieee802154: Avoid calling WARN_ON() on -ENOMEM in cfg802154_switch_netns() Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 532/869] ALSA: seq: oss: Serialize readq reset state with q->lock Greg Kroah-Hartman
` (338 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, James Clark, Leo Yan,
Suzuki K Poulose, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <james.clark@linaro.org>
[ Upstream commit 2ab4645fe4206c142a5f1491e191c906279686cf ]
System register ETMs and ETE are unlikely to be preserved on CPU power
down. The ETE DT binding also never documented
"arm,coresight-loses-context-with-cpu" so nobody would have legitimately
been able to use that binding to fix it and ACPI has no such binding at
all.
Fix it by hard coding the setting for sysreg ETMs (ETE is always sysreg)
or ACPI boots. Use a local variable when setting up save_state so that
it's immune to concurrent probing when devices have different
configurations which is an issue with modifying the global.
This fixes the following error when using Coresight with ACPI on the FVP
which supports CPU PM:
coresight ete0: External agent took claim tag
WARNING: drivers/hwtracing/coresight/coresight-core.c:248 at coresight_disclaim_device_unlocked+0xe0/0xe8, CPU#0: perf/117
Fixes: 35e1c9163e02 ("coresight: ete: Add support for ETE tracing")
Signed-off-by: James Clark <james.clark@linaro.org>
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20260505-james-cs-ete-pm_save_enable-v3-1-485d21dd79b8@linaro.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../coresight/coresight-etm4x-core.c | 44 ++++++++++++++-----
1 file changed, 32 insertions(+), 12 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 312abd57ddce9..e69ee4ccc2658 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -54,10 +54,14 @@ MODULE_PARM_DESC(boot_enable, "Enable tracing on boot");
#define PARAM_PM_SAVE_NEVER 1 /* never save any state */
#define PARAM_PM_SAVE_SELF_HOSTED 2 /* save self-hosted state only */
+/*
+ * Save option for ETM4. ETE, sysreg ETM4s and ACPI boots ignore this option and
+ * will always save.
+ */
static int pm_save_enable = PARAM_PM_SAVE_FIRMWARE;
module_param(pm_save_enable, int, 0444);
MODULE_PARM_DESC(pm_save_enable,
- "Save/restore state on power down: 1 = never, 2 = self-hosted");
+ "Save/restore state on power down: 1 = never, 2 = self-hosted. MMIO and DT only.");
static struct etmv4_drvdata *etmdrvdata[NR_CPUS];
static void etm4_set_default_config(struct etmv4_config *config);
@@ -2114,6 +2118,17 @@ static void etm4_pm_clear(void)
}
}
+static bool etm4x_always_pm_save(struct device *dev, struct csdev_access *csa)
+{
+ /*
+ * Only IO mem ETM devices will benefit from skipping PM save and only
+ * DT has the option to control it, not ACPI. Otherwise system register
+ * based ETMs and ETEs will always lose context on CPU power down, so
+ * always save.
+ */
+ return !csa->io_mem || is_acpi_device_node(dev_fwnode(dev));
+}
+
static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
{
int ret;
@@ -2123,6 +2138,7 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
struct coresight_desc desc = { 0 };
u8 major, minor;
char *type_name;
+ bool pm_save;
if (!drvdata)
return -EINVAL;
@@ -2150,6 +2166,21 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
etm4_set_default(&drvdata->config);
+ if (etm4x_always_pm_save(dev, init_arg->csa))
+ pm_save = true;
+ else if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE)
+ pm_save = coresight_loses_context_with_cpu(dev);
+ else
+ pm_save = pm_save_enable != PARAM_PM_SAVE_NEVER;
+
+ if (pm_save) {
+ drvdata->save_state = devm_kmalloc(dev,
+ sizeof(struct etmv4_save_state),
+ GFP_KERNEL);
+ if (!drvdata->save_state)
+ return -ENOMEM;
+ }
+
pdata = coresight_get_platform_data(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
@@ -2206,17 +2237,6 @@ static int etm4_probe(struct device *dev)
if (IS_ERR(drvdata->atclk))
return PTR_ERR(drvdata->atclk);
- if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE)
- pm_save_enable = coresight_loses_context_with_cpu(dev) ?
- PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER;
-
- if (pm_save_enable != PARAM_PM_SAVE_NEVER) {
- drvdata->save_state = devm_kmalloc(dev,
- sizeof(struct etmv4_save_state), GFP_KERNEL);
- if (!drvdata->save_state)
- return -ENOMEM;
- }
-
spin_lock_init(&drvdata->spinlock);
drvdata->cpu = coresight_get_cpu(dev);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 532/869] ALSA: seq: oss: Serialize readq reset state with q->lock
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (530 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 531/869] coresight: ete: Always save state on power down Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 533/869] btrfs: lzo: reject compressed segment that overflows the compressed input Greg Kroah-Hartman
` (337 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Cen Zhang, Takashi Iwai, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <zzzccc427@gmail.com>
[ Upstream commit 49ce92d207820f588b0406add82f053decfbe5d9 ]
snd_seq_oss_readq_clear() resets qlen, head, and tail without
q->lock even though the normal reader and producer paths serialize the
same ring state under that spinlock. A reset can therefore race
snd_seq_oss_readq_free() or snd_seq_oss_readq_put_event() and leave
stale records in the queue, drop freshly queued ones, or report the
wrong readiness after wakeup. KCSAN reports a data race between
snd_seq_oss_readq_clear() and snd_seq_oss_readq_free().
Take q->lock while clearing the ring and resetting input_time. Factor
the enqueue logic into a caller-locked helper so
snd_seq_oss_readq_put_timestamp() updates its suppression state under
the same lock instead of racing the reset path.
The buggy scenario involves two paths, with each column showing the
order within that path:
reset path: locked readq updater:
1. snd_seq_oss_reset() or 1. A reader or callback producer
release reaches takes q->lock on the same queue.
snd_seq_oss_readq_clear().
2. snd_seq_oss_readq_clear() 2. The updater tests or modifies
resets qlen, head, tail, qlen, head, and tail.
and input_time.
3. snd_seq_oss_readq_clear() 3. The updater completes its
wakes sleepers on read-modify-write sequence.
q->midi_sleep.
4. Without q->lock, the reset 4. The resulting ring state drives
can overlap the locked later reads and readiness.
update.
KCSAN reports:
BUG: KCSAN: data-race in snd_seq_oss_readq_clear /
snd_seq_oss_readq_free
write to 0xffff8881069fe608 of 4 bytes by task 120516 on cpu 0:
snd_seq_oss_readq_free+0x6c/0x80
snd_seq_oss_read+0xcb/0x250
odev_read+0x38/0x60
vfs_read+0xff/0x600
ksys_read+0xb4/0x140
__x64_sys_read+0x46/0x60
do_syscall_64+0xbb/0x2f0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
read to 0xffff8881069fe608 of 4 bytes by task 120517 on cpu 1:
snd_seq_oss_readq_clear+0x1f/0x90
snd_seq_oss_reset+0xa7/0xf0
snd_seq_oss_ioctl+0x6f6/0x7e0
odev_ioctl+0x56/0xc0
__x64_sys_ioctl+0xd1/0x120
do_syscall_64+0xbb/0x2f0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
value changed: 0x00000001 -> 0x00000000
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Link: https://patch.msgid.link/20260614004801.3507773-1-zzzccc427@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/core/seq/oss/seq_oss_readq.c | 83 +++++++++++++++++++-----------
1 file changed, 52 insertions(+), 31 deletions(-)
diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c
index f0db5d3dcba47..b7cdb1c61f265 100644
--- a/sound/core/seq/oss/seq_oss_readq.c
+++ b/sound/core/seq/oss/seq_oss_readq.c
@@ -73,13 +73,17 @@ snd_seq_oss_readq_delete(struct seq_oss_readq *q)
void
snd_seq_oss_readq_clear(struct seq_oss_readq *q)
{
- if (q->qlen) {
- q->qlen = 0;
- q->head = q->tail = 0;
+ scoped_guard(spinlock_irqsave, &q->lock) {
+ if (q->qlen) {
+ q->qlen = 0;
+ q->head = 0;
+ q->tail = 0;
+ }
+ q->input_time = (unsigned long)-1;
}
+
/* if someone sleeping, wake'em up */
wake_up(&q->midi_sleep);
- q->input_time = (unsigned long)-1;
}
/*
@@ -136,28 +140,37 @@ int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev,
/*
* copy an event to input queue:
* return zero if enqueued
+ * caller must hold lock
*/
-int
-snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
+static int snd_seq_oss_readq_put_event_locked(struct seq_oss_readq *q,
+ union evrec *ev)
{
- unsigned long flags;
-
- spin_lock_irqsave(&q->lock, flags);
- if (q->qlen >= q->maxlen - 1) {
- spin_unlock_irqrestore(&q->lock, flags);
+ if (q->qlen >= q->maxlen - 1)
return -ENOMEM;
- }
memcpy(&q->q[q->tail], ev, sizeof(*ev));
q->tail = (q->tail + 1) % q->maxlen;
q->qlen++;
- /* wake up sleeper */
- wake_up(&q->midi_sleep);
+ return 0;
+}
- spin_unlock_irqrestore(&q->lock, flags);
+/*
+ * copy an event to input queue:
+ * return zero if enqueued
+ */
+int
+snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
+{
+ int rc;
- return 0;
+ scoped_guard(spinlock_irqsave, &q->lock) {
+ rc = snd_seq_oss_readq_put_event_locked(q, ev);
+ if (!rc)
+ wake_up(&q->midi_sleep);
+ }
+
+ return rc;
}
@@ -215,23 +228,31 @@ snd_seq_oss_readq_poll(struct seq_oss_readq *q, struct file *file, poll_table *w
int
snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *q, unsigned long curt, int seq_mode)
{
- if (curt != q->input_time) {
- union evrec rec;
- memset(&rec, 0, sizeof(rec));
- switch (seq_mode) {
- case SNDRV_SEQ_OSS_MODE_SYNTH:
- rec.echo = (curt << 8) | SEQ_WAIT;
- snd_seq_oss_readq_put_event(q, &rec);
- break;
- case SNDRV_SEQ_OSS_MODE_MUSIC:
- rec.t.code = EV_TIMING;
- rec.t.cmd = TMR_WAIT_ABS;
- rec.t.time = curt;
- snd_seq_oss_readq_put_event(q, &rec);
- break;
+ int queued = 0;
+
+ scoped_guard(spinlock_irqsave, &q->lock) {
+ if (curt != q->input_time) {
+ union evrec rec;
+
+ memset(&rec, 0, sizeof(rec));
+ switch (seq_mode) {
+ case SNDRV_SEQ_OSS_MODE_SYNTH:
+ rec.echo = (curt << 8) | SEQ_WAIT;
+ queued = !snd_seq_oss_readq_put_event_locked(q, &rec);
+ break;
+ case SNDRV_SEQ_OSS_MODE_MUSIC:
+ rec.t.code = EV_TIMING;
+ rec.t.cmd = TMR_WAIT_ABS;
+ rec.t.time = curt;
+ queued = !snd_seq_oss_readq_put_event_locked(q, &rec);
+ break;
+ }
+ q->input_time = curt;
}
- q->input_time = curt;
}
+ if (queued)
+ wake_up(&q->midi_sleep);
+
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 533/869] btrfs: lzo: reject compressed segment that overflows the compressed input
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (531 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 532/869] ALSA: seq: oss: Serialize readq reset state with q->lock Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 534/869] netfilter: flowtable: avoid num_encaps underflow on bridge VLAN untag Greg Kroah-Hartman
` (336 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Xiang Mei, Qu Wenruo, Weiming Shi,
David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <bestswngs@gmail.com>
[ Upstream commit b0d27d43791b7a3057c3c4aedf9b4aa033d37c46 ]
lzo_decompress_bio() validates each on-disk segment length seg_len only
against the workspace cbuf size, not against the compressed input size
(compressed_len, the total folio bytes of the bio). A crafted extent can
carry a segment whose seg_len passes the cbuf check but runs past the end
of the bio, so copy_compressed_segment() walks off the last folio:
get_current_folio() then returns the NULL folio from bio_next_folio(), and
with CONFIG_BTRFS_ASSERT disabled (default) folio_size(NULL) faults.
BUG: KASAN: null-ptr-deref in lzo_decompress_bio (fs/btrfs/lzo.c:383)
Read of size 8 at addr 0000000000000000 by task kworker/u8:1/29
Workqueue: btrfs-endio simple_end_io_work
kasan_report (mm/kasan/report.c:590)
lzo_decompress_bio (fs/btrfs/lzo.c:383)
end_bbio_compressed_read (fs/btrfs/compression.c:1065)
btrfs_bio_end_io (fs/btrfs/bio.c:135)
btrfs_check_read_bio (fs/btrfs/bio.c:180 fs/btrfs/bio.c:285)
simple_end_io_work
process_one_work
worker_thread
Reject any segment whose payload would extend beyond compressed_len before
copying it, treating it as corruption like the other on-disk validation
failures in this function.
Reported-by: Xiang Mei <xmei5@asu.edu>
Fixes: a6e66e6f8c1b ("btrfs: rework lzo_decompress_bio() to make it subpage compatible")
Assisted-by: Claude:claude-opus-4-8
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/lzo.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c
index 0d136da8b6be1..f2097e7cab435 100644
--- a/fs/btrfs/lzo.c
+++ b/fs/btrfs/lzo.c
@@ -400,6 +400,17 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
return -EIO;
}
+ /* The segment must not extend beyond the compressed input. */
+ if (unlikely(cur_in + seg_len > cb->compressed_len)) {
+ struct btrfs_inode *inode = cb->bbio.inode;
+
+ btrfs_err(fs_info,
+ "lzo segment overflows compressed input, root %llu inode %llu offset %llu cur_in %u len %u compressed len %u",
+ btrfs_root_id(inode->root), btrfs_ino(inode),
+ cb->start, cur_in, seg_len, cb->compressed_len);
+ return -EUCLEAN;
+ }
+
/* Copy the compressed segment payload into workspace */
copy_compressed_segment(cb, workspace->cbuf, seg_len, &cur_in);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 534/869] netfilter: flowtable: avoid num_encaps underflow on bridge VLAN untag
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (532 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 533/869] btrfs: lzo: reject compressed segment that overflows the compressed input Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 535/869] EDAC/igen6: Initialize edac_op_state according to the configuration data Greg Kroah-Hartman
` (335 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Carlier,
Fernando Fernandez Mancera, Pablo Neira Ayuso, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <devnexen@gmail.com>
[ Upstream commit e052f920773b73be49eb4d8702a9f85de7464363 ]
The DEV_PATH_BR_VLAN_UNTAG case post-decrements info->num_encaps
inside WARN_ON_ONCE(). num_encaps is u8, so if it's already 0 the
decrement still happens and wraps it to 255. The break only leaves
the inner switch -- a later path entry can set info->indev back to
a real device, and we end up returning with num_encaps == 255.
nft_dev_forward_path() then walks info.encap[] (size 2) up to
num_encaps, which means an OOB stack read and a bogus count copied
into the route descriptor.
Should only happen on a malformed bridge path stack, hence the WARN,
but worth handling sanely. Move the decrement out of the WARN.
[ While at this, remove the WARN_ON_ONCE since this can only happen
with a buggy bridge path stack --pablo ].
Fixes: e990cef6516d ("netfilter: flowtable: add bridge vlan filtering support")
Signed-off-by: David Carlier <devnexen@gmail.com>
Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/netfilter/nft_flow_offload.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
index 4ddf3eb002259..99d3454f9e3b1 100644
--- a/net/netfilter/nft_flow_offload.c
+++ b/net/netfilter/nft_flow_offload.c
@@ -150,10 +150,11 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
info->num_encaps++;
break;
case DEV_PATH_BR_VLAN_UNTAG:
- if (WARN_ON_ONCE(info->num_encaps-- == 0)) {
+ if (info->num_encaps == 0) {
info->indev = NULL;
break;
}
+ info->num_encaps--;
break;
case DEV_PATH_BR_VLAN_KEEP:
break;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 535/869] EDAC/igen6: Initialize edac_op_state according to the configuration data
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (533 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 534/869] netfilter: flowtable: avoid num_encaps underflow on bridge VLAN untag Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 536/869] EDAC/igen6: Add polling support Greg Kroah-Hartman
` (334 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Qiuxu Zhuo, Tony Luck, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
[ Upstream commit 1d512b1aa5a88f93170b0b9360de4fff7a2f8a0a ]
Currently, igen6_edac sets edac_op_state to EDAC_OPSTATE_NMI, while the
driver also supports memory errors reported from Machine Check. Initialize
edac_op_state to the correct value according to the configuration data
that the driver probed.
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Link: https://lore.kernel.org/all/20241106114024.941659-2-orange@aiven.io
Stable-dep-of: ab1f9d466c7d ("EDAC/igen6: Fix call trace due to missing release()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/edac/igen6_edac.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c
index 63a61932e67fd..003db3d9f1913 100644
--- a/drivers/edac/igen6_edac.c
+++ b/drivers/edac/igen6_edac.c
@@ -1357,6 +1357,15 @@ static void unregister_err_handler(void)
unregister_nmi_handler(NMI_SERR, IGEN6_NMI_NAME);
}
+static void opstate_set(struct res_config *cfg)
+{
+ /* Set the mode according to the configuration data. */
+ if (cfg->machine_check)
+ edac_op_state = EDAC_OPSTATE_INT;
+ else
+ edac_op_state = EDAC_OPSTATE_NMI;
+}
+
static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
u64 mchbar;
@@ -1374,6 +1383,8 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto fail;
+ opstate_set(res_cfg);
+
for (i = 0; i < res_cfg->num_imc; i++) {
rc = igen6_register_mci(i, mchbar, pdev);
if (rc)
@@ -1457,8 +1468,6 @@ static int __init igen6_init(void)
if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
return -EBUSY;
- edac_op_state = EDAC_OPSTATE_NMI;
-
rc = pci_register_driver(&igen6_driver);
if (rc)
return rc;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 536/869] EDAC/igen6: Add polling support
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (534 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 535/869] EDAC/igen6: Initialize edac_op_state according to the configuration data Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 537/869] EDAC/igen6: Skip absent memory controllers Greg Kroah-Hartman
` (333 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Orange Kao, Tony Luck, Qiuxu Zhuo,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Orange Kao <orange@aiven.io>
[ Upstream commit e14232afa94445e03fc3a0291b07a68f3408c120 ]
Some PCs with Intel N100 (with PCI device 8086:461c, DID_ADL_N_SKU4)
experienced issues with error interrupts not working, even with the
following configuration in the BIOS.
In-Band ECC Support: Enabled
In-Band ECC Operation Mode: 2 (make all requests protected and
ignore range checks)
IBECC Error Injection Control: Inject Correctable Error on insertion
counter
Error Injection Insertion Count: 251658240 (0xf000000)
Add polling mode support for these machines to ensure that memory error
events are handled.
Signed-off-by: Orange Kao <orange@aiven.io>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Reviewed-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Link: https://lore.kernel.org/all/20241106114024.941659-3-orange@aiven.io
Stable-dep-of: ab1f9d466c7d ("EDAC/igen6: Fix call trace due to missing release()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/edac/igen6_edac.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c
index 003db3d9f1913..6eb8bfff1ab0b 100644
--- a/drivers/edac/igen6_edac.c
+++ b/drivers/edac/igen6_edac.c
@@ -1177,6 +1177,20 @@ static int igen6_pci_setup(struct pci_dev *pdev, u64 *mchbar)
return -ENODEV;
}
+static void igen6_check(struct mem_ctl_info *mci)
+{
+ struct igen6_imc *imc = mci->pvt_info;
+ u64 ecclog;
+
+ /* errsts_clear() isn't NMI-safe. Delay it in the IRQ context */
+ ecclog = ecclog_read_and_clear(imc);
+ if (!ecclog)
+ return;
+
+ if (!ecclog_gen_pool_add(imc->mc, ecclog))
+ irq_work_queue(&ecclog_irq_work);
+}
+
static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev)
{
struct edac_mc_layer layers[2];
@@ -1218,6 +1232,8 @@ static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev)
mci->edac_cap = EDAC_FLAG_SECDED;
mci->mod_name = EDAC_MOD_STR;
mci->dev_name = pci_name(pdev);
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ mci->edac_check = igen6_check;
mci->pvt_info = &igen6_pvt->imc[mc];
imc = mci->pvt_info;
@@ -1357,8 +1373,18 @@ static void unregister_err_handler(void)
unregister_nmi_handler(NMI_SERR, IGEN6_NMI_NAME);
}
-static void opstate_set(struct res_config *cfg)
+static void opstate_set(struct res_config *cfg, const struct pci_device_id *ent)
{
+ /*
+ * Quirk: Certain SoCs' error reporting interrupts don't work.
+ * Force polling mode for them to ensure that memory error
+ * events can be handled.
+ */
+ if (ent->device == DID_ADL_N_SKU4) {
+ edac_op_state = EDAC_OPSTATE_POLL;
+ return;
+ }
+
/* Set the mode according to the configuration data. */
if (cfg->machine_check)
edac_op_state = EDAC_OPSTATE_INT;
@@ -1383,7 +1409,7 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto fail;
- opstate_set(res_cfg);
+ opstate_set(res_cfg, ent);
for (i = 0; i < res_cfg->num_imc; i++) {
rc = igen6_register_mci(i, mchbar, pdev);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 537/869] EDAC/igen6: Skip absent memory controllers
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (535 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 536/869] EDAC/igen6: Add polling support Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 538/869] EDAC/igen6: Fix call trace due to missing release() Greg Kroah-Hartman
` (332 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Qiuxu Zhuo, Tony Luck, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
[ Upstream commit 20e190b1c1fd88b21cc5106c12cfe6def5ab849d ]
Some BIOS versions may fuse off certain memory controllers and set the
registers of these absent memory controllers to ~0. The current igen6_edac
mistakenly enumerates these absent memory controllers and registers them
with the EDAC core.
Skip the absent memory controllers to avoid mistakenly enumerating them.
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Link: https://lore.kernel.org/r/20250408132455.489046-2-qiuxu.zhuo@intel.com
Stable-dep-of: ab1f9d466c7d ("EDAC/igen6: Fix call trace due to missing release()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/edac/igen6_edac.c | 78 +++++++++++++++++++++++++++++++--------
1 file changed, 62 insertions(+), 16 deletions(-)
diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c
index 6eb8bfff1ab0b..d4b034737e31f 100644
--- a/drivers/edac/igen6_edac.c
+++ b/drivers/edac/igen6_edac.c
@@ -127,6 +127,7 @@
static struct res_config {
bool machine_check;
+ /* The number of present memory controllers. */
int num_imc;
u32 imc_base;
u32 cmf_base;
@@ -1191,23 +1192,21 @@ static void igen6_check(struct mem_ctl_info *mci)
irq_work_queue(&ecclog_irq_work);
}
-static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev)
+/* Check whether the memory controller is absent. */
+static bool igen6_imc_absent(void __iomem *window)
+{
+ return readl(window + MAD_INTER_CHANNEL_OFFSET) == ~0;
+}
+
+static int igen6_register_mci(int mc, void __iomem *window, struct pci_dev *pdev)
{
struct edac_mc_layer layers[2];
struct mem_ctl_info *mci;
struct igen6_imc *imc;
- void __iomem *window;
int rc;
edac_dbg(2, "\n");
- mchbar += mc * MCHBAR_SIZE;
- window = ioremap(mchbar, MCHBAR_SIZE);
- if (!window) {
- igen6_printk(KERN_ERR, "Failed to ioremap 0x%llx\n", mchbar);
- return -ENODEV;
- }
-
layers[0].type = EDAC_MC_LAYER_CHANNEL;
layers[0].size = NUM_CHANNELS;
layers[0].is_virt_csrow = false;
@@ -1273,7 +1272,6 @@ static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev)
fail2:
edac_mc_free(mci);
fail:
- iounmap(window);
return rc;
}
@@ -1299,6 +1297,56 @@ static void igen6_unregister_mcis(void)
}
}
+static int igen6_register_mcis(struct pci_dev *pdev, u64 mchbar)
+{
+ void __iomem *window;
+ int lmc, pmc, rc;
+ u64 base;
+
+ for (lmc = 0, pmc = 0; pmc < NUM_IMC; pmc++) {
+ base = mchbar + pmc * MCHBAR_SIZE;
+ window = ioremap(base, MCHBAR_SIZE);
+ if (!window) {
+ igen6_printk(KERN_ERR, "Failed to ioremap 0x%llx for mc%d\n", base, pmc);
+ rc = -ENOMEM;
+ goto out_unregister_mcis;
+ }
+
+ if (igen6_imc_absent(window)) {
+ iounmap(window);
+ edac_dbg(2, "Skip absent mc%d\n", pmc);
+ continue;
+ }
+
+ rc = igen6_register_mci(lmc, window, pdev);
+ if (rc)
+ goto out_iounmap;
+
+ /* Done, if all present MCs are detected and registered. */
+ if (++lmc >= res_cfg->num_imc)
+ break;
+ }
+
+ if (!lmc) {
+ igen6_printk(KERN_ERR, "No mc found.\n");
+ return -ENODEV;
+ }
+
+ if (lmc < res_cfg->num_imc)
+ igen6_printk(KERN_WARNING, "Expected %d mcs, but only %d detected.",
+ res_cfg->num_imc, lmc);
+
+ return 0;
+
+out_iounmap:
+ iounmap(window);
+
+out_unregister_mcis:
+ igen6_unregister_mcis();
+
+ return rc;
+}
+
static int igen6_mem_slice_setup(u64 mchbar)
{
struct igen6_imc *imc = &igen6_pvt->imc[0];
@@ -1395,7 +1443,7 @@ static void opstate_set(struct res_config *cfg, const struct pci_device_id *ent)
static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
u64 mchbar;
- int i, rc;
+ int rc;
edac_dbg(2, "\n");
@@ -1411,11 +1459,9 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
opstate_set(res_cfg, ent);
- for (i = 0; i < res_cfg->num_imc; i++) {
- rc = igen6_register_mci(i, mchbar, pdev);
- if (rc)
- goto fail2;
- }
+ rc = igen6_register_mcis(pdev, mchbar);
+ if (rc)
+ goto fail;
if (res_cfg->num_imc > 1) {
rc = igen6_mem_slice_setup(mchbar);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 538/869] EDAC/igen6: Fix call trace due to missing release()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (536 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 537/869] EDAC/igen6: Skip absent memory controllers Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 539/869] scsi: hisi_sas: Add slave_destroy interface for v3 hw Greg Kroah-Hartman
` (331 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Qiuxu Zhuo, Tony Luck, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
[ Upstream commit ab1f9d466c7d83ab0d2a529e07984e53b5960dcd ]
When unloading the igen6_edac driver, there is a call trace:
Device '(null)' does not have a release() function, it is broken and must be fixed.
See Documentation/core-api/kobject.rst.
WARNING: drivers/base/core.c:2567 at device_release+0x84/0x90, CPU#5: rmmod/127209
...
RIP: 0010:device_release+0x84/0x90
Call Trace:
<TASK>
kobject_put+0x8c/0x220
put_device+0x17/0x30
igen6_unregister_mcis+0xa2/0xe0 [igen6_edac]
igen6_remove+0x82/0xb0 [igen6_edac]
...
Fix the call trace by providing empty release() functions for the
memory controller devices.
Fixes: 10590a9d4f23 ("EDAC/igen6: Add EDAC driver for Intel client SoCs using IBECC")
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Link: https://patch.msgid.link/20260403054029.3950383-2-qiuxu.zhuo@intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/edac/igen6_edac.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c
index d4b034737e31f..3a28b3d6242da 100644
--- a/drivers/edac/igen6_edac.c
+++ b/drivers/edac/igen6_edac.c
@@ -1198,6 +1198,11 @@ static bool igen6_imc_absent(void __iomem *window)
return readl(window + MAD_INTER_CHANNEL_OFFSET) == ~0;
}
+static void imc_release(struct device *dev)
+{
+ /* Nothing to do, the 'imc' owns the 'dev' and will also release it. */
+}
+
static int igen6_register_mci(int mc, void __iomem *window, struct pci_dev *pdev)
{
struct edac_mc_layer layers[2];
@@ -1236,6 +1241,7 @@ static int igen6_register_mci(int mc, void __iomem *window, struct pci_dev *pdev
mci->pvt_info = &igen6_pvt->imc[mc];
imc = mci->pvt_info;
+ imc->dev.release = imc_release;
device_initialize(&imc->dev);
/*
* EDAC core uses mci->pdev(pointer of structure device) as
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 539/869] scsi: hisi_sas: Add slave_destroy interface for v3 hw
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (537 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 538/869] EDAC/igen6: Fix call trace due to missing release() Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 540/869] soc: xilinx: Fix race condition in event registration Greg Kroah-Hartman
` (330 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yihang Li, Martin K. Petersen,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yihang Li <liyihang9@huawei.com>
[ Upstream commit 67b85a88265df19f049241d8c00571a5408f4eeb ]
WARNING is triggered when executing link reset of remote PHY and rmmod
SAS driver simultaneously. Following is the WARNING log:
WARNING: CPU: 61 PID: 21818 at drivers/base/core.c:1347 __device_links_no_driver+0xb4/0xc0
Call trace:
__device_links_no_driver+0xb4/0xc0
device_links_driver_cleanup+0xb0/0xfc
__device_release_driver+0x198/0x23c
device_release_driver+0x38/0x50
bus_remove_device+0x130/0x140
device_del+0x184/0x434
__scsi_remove_device+0x118/0x150
scsi_remove_target+0x1bc/0x240
sas_rphy_remove+0x90/0x94
sas_rphy_delete+0x24/0x3c
sas_destruct_devices+0x64/0xa0 [libsas]
sas_revalidate_domain+0xe4/0x150 [libsas]
process_one_work+0x1e0/0x46c
worker_thread+0x15c/0x464
kthread+0x160/0x170
ret_from_fork+0x10/0x20
---[ end trace 71e059eb58f85d4a ]---
During SAS phy up, link->status is set to DL_STATE_AVAILABLE in
device_links_driver_bound, then this setting influences
__device_links_no_driver() before driver rmmod and caused WARNING.
Add the slave_destroy interface to make sure link is removed after flush
workque.
Fixes: 16fd4a7c5917 ("scsi: hisi_sas: Add device link between SCSI devices and hisi_hba")
Signed-off-by: Yihang Li <liyihang9@huawei.com>
Link: https://patch.msgid.link/20260425082056.2749910-1-liyihang9@huawei.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index b7dd4efca0c7f..64aad320a04a3 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -2978,7 +2978,7 @@ static int device_configure_v3_hw(struct scsi_device *sdev,
return 0;
if (!device_link_add(&sdev->sdev_gendev, dev,
- DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE)) {
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE)) {
if (pm_runtime_enabled(dev)) {
dev_info(dev, "add device link failed, disable runtime PM for the host\n");
pm_runtime_disable(dev);
@@ -2988,6 +2988,15 @@ static int device_configure_v3_hw(struct scsi_device *sdev,
return 0;
}
+static void hisi_sas_sdev_destroy(struct scsi_device *sdev)
+{
+ struct Scsi_Host *shost = dev_to_shost(&sdev->sdev_gendev);
+ struct hisi_hba *hisi_hba = shost_priv(shost);
+ struct device *dev = hisi_hba->dev;
+
+ device_link_remove(&sdev->sdev_gendev, dev);
+}
+
static struct attribute *host_v3_hw_attrs[] = {
&dev_attr_phy_event_threshold.attr,
&dev_attr_intr_conv_v3_hw.attr,
@@ -3402,6 +3411,7 @@ static const struct scsi_host_template sht_v3_hw = {
.sg_tablesize = HISI_SAS_SGE_PAGE_CNT,
.sg_prot_tablesize = HISI_SAS_SGE_PAGE_CNT,
.slave_alloc = hisi_sas_slave_alloc,
+ .slave_destroy = hisi_sas_sdev_destroy,
.shost_groups = host_v3_hw_groups,
.sdev_groups = sdev_groups_v3_hw,
.tag_alloc_policy = BLK_TAG_ALLOC_RR,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 540/869] soc: xilinx: Fix race condition in event registration
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (538 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 539/869] scsi: hisi_sas: Add slave_destroy interface for v3 hw Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 541/869] cxl: Fix CXL_HEADERLOG_SIZE to match RAS Capability size Greg Kroah-Hartman
` (329 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Prasanna Kumar T S M, Michal Simek,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prasanna Kumar T S M <ptsm@linux.microsoft.com>
[ Upstream commit fb445935338405110baca8f541a2df3b4cb8d712 ]
The zynqmp_power driver registers handlers for suspend and subsystem
restart events using register_event(). However, the work structures
(zynqmp_pm_init_suspend_work and zynqmp_pm_init_restart_work) used by
these handlers were allocated and initialized after the registration
call.
This created a race window where, if the firmware triggered an event
immediately after registration but before allocation, the callback
(suspend_event_callback or subsystem_restart_event_callback) would
dereference a NULL pointer in work_pending(), leading to a crash.
Fix this by allocating and initializing the work structures before
registering the events.
Fixes: fcf544ac6439 ("soc: xilinx: Add cb event for subsystem restart")
Signed-off-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>
Signed-off-by: Michal Simek <michal.simek@amd.com>
Link: https://lore.kernel.org/r/20260320060306.1540928-1-ptsm@linux.microsoft.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/soc/xilinx/zynqmp_power.c | 43 ++++++++++++-------------------
1 file changed, 17 insertions(+), 26 deletions(-)
diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c
index 84ef7c87dfaa3..92f1ab1d269b8 100644
--- a/drivers/soc/xilinx/zynqmp_power.c
+++ b/drivers/soc/xilinx/zynqmp_power.c
@@ -303,18 +303,18 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
* is not available to use) or -ENODEV(Xilinx Event Manager not compiled),
* then use ipi-mailbox or interrupt method.
*/
+ zynqmp_pm_init_suspend_work = devm_kzalloc(&pdev->dev,
+ sizeof(struct zynqmp_pm_work_struct),
+ GFP_KERNEL);
+ if (!zynqmp_pm_init_suspend_work)
+ return -ENOMEM;
+
+ INIT_WORK(&zynqmp_pm_init_suspend_work->callback_work,
+ zynqmp_pm_init_suspend_work_fn);
+
ret = register_event(&pdev->dev, PM_INIT_SUSPEND_CB, 0, 0, false,
suspend_event_callback);
if (!ret) {
- zynqmp_pm_init_suspend_work = devm_kzalloc(&pdev->dev,
- sizeof(struct zynqmp_pm_work_struct),
- GFP_KERNEL);
- if (!zynqmp_pm_init_suspend_work)
- return -ENOMEM;
-
- INIT_WORK(&zynqmp_pm_init_suspend_work->callback_work,
- zynqmp_pm_init_suspend_work_fn);
-
ret = zynqmp_pm_get_family_info(&pm_family_code, &pm_sub_family_code);
if (ret < 0)
return ret;
@@ -324,14 +324,6 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
else
node_id = PM_DEV_ACPU_0;
- ret = register_event(&pdev->dev, PM_NOTIFY_CB, node_id, EVENT_SUBSYSTEM_RESTART,
- false, subsystem_restart_event_callback);
- if (ret) {
- dev_err(&pdev->dev, "Failed to Register with Xilinx Event manager %d\n",
- ret);
- return ret;
- }
-
zynqmp_pm_init_restart_work = devm_kzalloc(&pdev->dev,
sizeof(struct zynqmp_pm_work_struct),
GFP_KERNEL);
@@ -340,19 +332,18 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
INIT_WORK(&zynqmp_pm_init_restart_work->callback_work,
zynqmp_pm_subsystem_restart_work_fn);
+
+ ret = register_event(&pdev->dev, PM_NOTIFY_CB, node_id, EVENT_SUBSYSTEM_RESTART,
+ false, subsystem_restart_event_callback);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to Register with Xilinx Event manager %d\n",
+ ret);
+ return ret;
+ }
} else if (ret != -EACCES && ret != -ENODEV) {
dev_err(&pdev->dev, "Failed to Register with Xilinx Event manager %d\n", ret);
return ret;
} else if (of_property_present(pdev->dev.of_node, "mboxes")) {
- zynqmp_pm_init_suspend_work =
- devm_kzalloc(&pdev->dev,
- sizeof(struct zynqmp_pm_work_struct),
- GFP_KERNEL);
- if (!zynqmp_pm_init_suspend_work)
- return -ENOMEM;
-
- INIT_WORK(&zynqmp_pm_init_suspend_work->callback_work,
- zynqmp_pm_init_suspend_work_fn);
client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
if (!client)
return -ENOMEM;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 541/869] cxl: Fix CXL_HEADERLOG_SIZE to match RAS Capability size
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (539 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 540/869] soc: xilinx: Fix race condition in event registration Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 542/869] netfilter: nf_conntrack_expect: use conntrack GC to reap expectations Greg Kroah-Hartman
` (328 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Terry Bowman, Alison Schofield,
Dave Jiang, Ben Cheatham, Richard Cheng, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Terry Bowman <terry.bowman@amd.com>
[ Upstream commit c268f949e219f9e179558e836f457f6c5fbec416 ]
The CXL r4.0 8.2.4.17.7 RAS Capability Structure has total length 0x58
bytes (CXL_RAS_CAPABILITY_LENGTH); the Header Log occupies the trailing
64 bytes at offset 0x18. CXL_HEADERLOG_SIZE was defined as SZ_512,
eight times the actual on-device size.
header_log_copy() reads CXL_HEADERLOG_SIZE_U32 (128) dwords from the
RAS capability iomap, overrunning the 88-byte mapping by 448 bytes.
The cxl_aer_uncorrectable_error trace event memcpy()s CXL_HEADERLOG_SIZE
(512) bytes from its source. For the CPER caller the source is
struct cxl_ras_capability_regs::header_log[16] (64 bytes) embedded in a
stack-local cxl_cper_prot_err_work_data, so the memcpy reads 448 bytes
of kernel stack into the trace event ring buffer where userspace can
read it via tracefs.
Set CXL_HEADERLOG_SIZE to 64 and derive CXL_HEADERLOG_SIZE_U32 from it,
bringing all iomap readers into agreement on 16 dwords. Userspace tools
such as rasdaemon have grown a dependency on the buggy 512-byte (128 u32)
header_log layout in the cxl_aer_uncorrectable_error trace event. Add
CXL_HEADERLOG_TRACE_SIZE_U32 = 128 and use it for the trace event
__array and its memcpy to preserve that ABI. Both callers now pass a
zero-filled u32[CXL_HEADERLOG_TRACE_SIZE_U32] staging buffer with only
the first CXL_HEADERLOG_SIZE_U32 (16) entries populated from hardware;
the remaining 112 u32s are zero-padded, keeping the 512-byte trace ring
buffer layout intact.
[ dj: Replaced 64 with SZ_64 per RichardC ]
Fixes: 36f257e3b0ba ("acpi/ghes, cxl/pci: Process CXL CPER Protocol Errors")
Fixes: 2905cb5236cb ("cxl/pci: Add (hopeful) error handling support")
Cc: stable@vger.kernel.org
Reported-by: Sashiko
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
Reviewed-by: Richard Cheng <icheng@nvidia.com>
Link: https://patch.msgid.link/20260605180610.2249458-1-terry.bowman@amd.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/cxl/core/ras.c | 10 +++++++---
drivers/cxl/core/trace.h | 12 ++++++++----
drivers/cxl/cxl.h | 14 ++++++++++++--
3 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 6256b145a517f..b0d9e65bae2fa 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -7,6 +7,10 @@
#include "core.h"
#include "trace.h"
+/* Check that UCE header definition is maintained to keep ABI intact */
+static_assert(CXL_HEADERLOG_TRACE_SIZE_U32 == 128,
+ "rasdaemon ABI requires exactly 128 u32s");
+
void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base)
{
void __iomem *addr;
@@ -28,12 +32,12 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
{
void __iomem *addr;
u32 *log_addr;
- int i, log_u32_size = CXL_HEADERLOG_SIZE / sizeof(u32);
+ int i;
addr = ras_base + CXL_RAS_HEADER_LOG_OFFSET;
log_addr = log;
- for (i = 0; i < log_u32_size; i++) {
+ for (i = 0; i < CXL_HEADERLOG_SIZE_U32; i++) {
*log_addr = readl(addr);
log_addr++;
addr += sizeof(u32);
@@ -46,7 +50,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
*/
bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base)
{
- u32 hl[CXL_HEADERLOG_SIZE_U32];
+ u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {};
void __iomem *addr;
u32 status;
u32 fe;
diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h
index 8389a94adb1a6..2a7f257193198 100644
--- a/drivers/cxl/core/trace.h
+++ b/drivers/cxl/core/trace.h
@@ -57,7 +57,7 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
__field(u64, serial)
__field(u32, status)
__field(u32, first_error)
- __array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
+ __array(u32, header_log, CXL_HEADERLOG_TRACE_SIZE_U32)
),
TP_fast_assign(
__assign_str(memdev);
@@ -66,10 +66,14 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
__entry->status = status;
__entry->first_error = fe;
/*
- * Embed the 512B headerlog data for user app retrieval and
- * parsing, but no need to print this in the trace buffer.
+ * Embed headerlog data for user app retrieval and parsing,
+ * but no need to print in the trace buffer. Only
+ * CXL_HEADERLOG_SIZE_U32 (16) dwords are hardware data;
+ * the remaining entries preserve the 512-byte ABI layout
+ * rasdaemon depends on and are zero-filled by the caller.
*/
- memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
+ memcpy(__entry->header_log, hl,
+ CXL_HEADERLOG_TRACE_SIZE_U32 * sizeof(u32));
),
TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error: '%s'",
__get_str(memdev), __get_str(host), __entry->serial,
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 6d726ca28935d..bcd1d140fa0f2 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -147,8 +147,18 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
#define CXL_RAS_CAP_CONTROL_FE_MASK GENMASK(5, 0)
#define CXL_RAS_HEADER_LOG_OFFSET 0x18
#define CXL_RAS_CAPABILITY_LENGTH 0x58
-#define CXL_HEADERLOG_SIZE SZ_512
-#define CXL_HEADERLOG_SIZE_U32 SZ_512 / sizeof(u32)
+#define CXL_HEADERLOG_SIZE SZ_64
+#define CXL_HEADERLOG_SIZE_U32 (CXL_HEADERLOG_SIZE / sizeof(u32))
+
+/*
+ * The RAS UCE trace event header array was originally sized at SZ_512/sizeof(u32)
+ * = 128 u32s due to a bug. Userspace tools (rasdaemon) have grown a dependency
+ * on that 512-byte layout. Keep the trace array at 128 u32s to preserve the
+ * ABI; only CXL_HEADERLOG_SIZE_U32 (16) dwords are valid hardware data, the
+ * remainder are zero-filled.
+ */
+#define CXL_HEADERLOG_TRACE_SIZE SZ_512
+#define CXL_HEADERLOG_TRACE_SIZE_U32 (CXL_HEADERLOG_TRACE_SIZE / sizeof(u32))
/* CXL 2.0 8.2.8.1 Device Capabilities Array Register */
#define CXLDEV_CAP_ARRAY_OFFSET 0x0
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 542/869] netfilter: nf_conntrack_expect: use conntrack GC to reap expectations
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (540 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 541/869] cxl: Fix CXL_HEADERLOG_SIZE to match RAS Capability size Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 543/869] perf tools: Use perf_env__get_cpu_topology() in machine__resolve() Greg Kroah-Hartman
` (327 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Pablo Neira Ayuso, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <pablo@netfilter.org>
[ Upstream commit b8b09dc2bf35a00d4e0556b5d6308c7b917ebda2 ]
This patch replaces the timer API by GC worker approach for
expectations, as it already happened in many other subsystems.
Use the existing conntrack GC worker to iterate over the local list of
expectations in the master conntrack to reap expired expectations.
Check IPS_HELPER_BIT to run GC for expectations, set it on for nft_ct
expectation which nevers sets it. Hold the expectation spinlock while
iterating over the master conntrack expectation list to synchronize with
nf_ct_remove_expectations(). This also performs runtime packet path
garbage collection through the expectation insertion and lookup
functions while walking over one of the chains of the global expectation
hashtables. Unconfirmed conntrack entries are skipped since ct->ext can
be reallocated and dying are skipped since those will be gone soon.
Set on IPS_HELPER_BIT if the helper ct extension is added, then the new
GC worker does not need to bump the ct refcount to check if the ct->ext
helper is available.
This removes the extra bump on the refcount for expectation timers, this
allows to remove several nf_ct_expect_put() calls after the unlink,
after this update only refcount remains at 1 while on the expectation
hashes.
This patch implicitly addresses a race with the existing timer API
allowing an expectation to access a stale exp->master pointer which has
been already released when expectation removal loses races with an
expiring timer, ie. timer_del() reporting false.
Add a new NF_CT_EXPECT_DEAD flag to reap this expectation via GC. This
is needed by nf_conntrack_unexpect_related() which is called in error
paths to invalidate newly created expectations that has been added into
the hashes. These expectactions cannot be inmediately released as GC or
nf_ct_remove_expectations() could race to make it. On expectation
insert, the runtime GC reaps stale expectations before checking the
expectation limit set by policy.
Set current timestamp in nf_ct_expect_alloc(), then add the expectation
policy timeout (or custom timeout specified added on top of this) to
specify the expectation lifetime.
Fixes: bffcaad9afdf ("netfilter: ctnetlink: ensure safe access to master conntrack")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/netfilter/nf_conntrack_expect.h | 16 +-
.../linux/netfilter/nf_conntrack_common.h | 1 +
net/netfilter/nf_conntrack_core.c | 33 +++-
net/netfilter/nf_conntrack_expect.c | 148 +++++++++---------
net/netfilter/nf_conntrack_h323_main.c | 4 +-
net/netfilter/nf_conntrack_helper.c | 10 +-
net/netfilter/nf_conntrack_netlink.c | 22 ++-
net/netfilter/nf_conntrack_sip.c | 13 +-
net/netfilter/nft_ct.c | 3 +-
9 files changed, 140 insertions(+), 110 deletions(-)
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index 80f50fd0f7ad2..be4a120d549eb 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -54,8 +54,8 @@ struct nf_conntrack_expect {
/* The conntrack of the master connection */
struct nf_conn *master;
- /* Timer function; deletes the expectation. */
- struct timer_list timeout;
+ /* jiffies32 when this expectation expires */
+ u32 timeout;
#if IS_ENABLED(CONFIG_NF_NAT)
union nf_inet_addr saved_addr;
@@ -69,6 +69,14 @@ struct nf_conntrack_expect {
struct rcu_head rcu;
};
+static inline bool nf_ct_exp_is_expired(const struct nf_conntrack_expect *exp)
+{
+ if (READ_ONCE(exp->flags) & NF_CT_EXPECT_DEAD)
+ return true;
+
+ return (__s32)(READ_ONCE(exp->timeout) - nfct_time_stamp) <= 0;
+}
+
static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp)
{
return read_pnet(&exp->net);
@@ -130,7 +138,6 @@ static inline void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
void nf_ct_remove_expectations(struct nf_conn *ct);
void nf_ct_unexpect_related(struct nf_conntrack_expect *exp);
-bool nf_ct_remove_expect(struct nf_conntrack_expect *exp);
void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, void *data), void *data);
void nf_ct_expect_iterate_net(struct net *net,
@@ -153,5 +160,8 @@ static inline int nf_ct_expect_related(struct nf_conntrack_expect *expect,
return nf_ct_expect_related_report(expect, 0, 0, flags);
}
+struct nf_conn_help;
+void nf_ct_expectation_gc(struct nf_conn_help *master_help);
+
#endif /*_NF_CONNTRACK_EXPECT_H*/
diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h
index 56b6b60a814f5..ee51045ae1d62 100644
--- a/include/uapi/linux/netfilter/nf_conntrack_common.h
+++ b/include/uapi/linux/netfilter/nf_conntrack_common.h
@@ -160,6 +160,7 @@ enum ip_conntrack_expect_events {
#define NF_CT_EXPECT_USERSPACE 0x4
#ifdef __KERNEL__
+#define NF_CT_EXPECT_DEAD 0x8
#define NF_CT_EXPECT_MASK (NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE | \
NF_CT_EXPECT_USERSPACE)
#endif
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index f9a60576d119f..22b4ef2e0d60d 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1467,6 +1467,31 @@ static bool gc_worker_can_early_drop(const struct nf_conn *ct)
return false;
}
+static void nf_ct_help_gc(struct nf_conn *ct)
+{
+ struct nf_conn_help *help;
+
+ if (!refcount_inc_not_zero(&ct->ct_general.use))
+ return;
+
+ /* load ->status after refcount increase */
+ smp_acquire__after_ctrl_dep();
+
+ if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct)) {
+ nf_ct_put(ct);
+ return;
+ }
+
+ /* re-check helper due to SLAB_TYPESAFE_BY_RCU */
+ if (test_bit(IPS_HELPER_BIT, &ct->status)) {
+ help = nfct_help(ct);
+ if (help)
+ nf_ct_expectation_gc(help);
+ }
+
+ nf_ct_put(ct);
+}
+
static void gc_worker(struct work_struct *work)
{
unsigned int i, hashsz, nf_conntrack_max95 = 0;
@@ -1539,7 +1564,13 @@ static void gc_worker(struct work_struct *work)
expires = (expires - (long)next_run) / ++count;
next_run += expires;
- if (nf_conntrack_max95 == 0 || gc_worker_skip_ct(tmp))
+ if (gc_worker_skip_ct(tmp))
+ continue;
+
+ if (test_bit(IPS_HELPER_BIT, &tmp->status))
+ nf_ct_help_gc(tmp);
+
+ if (nf_conntrack_max95 == 0)
continue;
net = nf_ct_net(tmp);
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index a45288fcb0419..f9352dada84ee 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -43,6 +43,24 @@ unsigned int nf_ct_expect_max __read_mostly;
static struct kmem_cache *nf_ct_expect_cachep __read_mostly;
static siphash_aligned_key_t nf_ct_expect_hashrnd;
+void nf_ct_expectation_gc(struct nf_conn_help *master_help)
+{
+ struct nf_conntrack_expect *exp;
+ struct hlist_node *next;
+
+ if (hlist_empty(&master_help->expectations))
+ return;
+
+ spin_lock_bh(&nf_conntrack_expect_lock);
+ hlist_for_each_entry_safe(exp, next, &master_help->expectations, lnode) {
+ if (!nf_ct_exp_is_expired(exp))
+ continue;
+
+ nf_ct_unlink_expect(exp);
+ }
+ spin_unlock_bh(&nf_conntrack_expect_lock);
+}
+
/* nf_conntrack_expect helper functions */
void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
u32 portid, int report)
@@ -53,7 +71,6 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
lockdep_nfct_expect_lock_held();
WARN_ON(!master_help);
- WARN_ON(timer_pending(&exp->timeout));
hlist_del_rcu(&exp->hnode);
@@ -70,16 +87,6 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
}
EXPORT_SYMBOL_GPL(nf_ct_unlink_expect_report);
-static void nf_ct_expectation_timed_out(struct timer_list *t)
-{
- struct nf_conntrack_expect *exp = from_timer(exp, t, timeout);
-
- spin_lock_bh(&nf_conntrack_expect_lock);
- nf_ct_unlink_expect(exp);
- spin_unlock_bh(&nf_conntrack_expect_lock);
- nf_ct_expect_put(exp);
-}
-
static unsigned int nf_ct_expect_dst_hash(const struct net *n, const struct nf_conntrack_tuple *tuple)
{
struct {
@@ -117,19 +124,6 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,
nf_ct_exp_zone_equal_any(i, zone);
}
-bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
-{
- lockdep_nfct_expect_lock_held();
-
- if (del_timer(&exp->timeout)) {
- nf_ct_unlink_expect(exp);
- nf_ct_expect_put(exp);
- return true;
- }
- return false;
-}
-EXPORT_SYMBOL_GPL(nf_ct_remove_expect);
-
struct nf_conntrack_expect *
__nf_ct_expect_find(struct net *net,
const struct nf_conntrack_zone *zone,
@@ -144,6 +138,8 @@ __nf_ct_expect_find(struct net *net,
h = nf_ct_expect_dst_hash(net, tuple);
hlist_for_each_entry_rcu(i, &nf_ct_expect_hash[h], hnode) {
+ if (nf_ct_exp_is_expired(i))
+ continue;
if (nf_ct_exp_equal(tuple, i, zone, net))
return i;
}
@@ -178,6 +174,7 @@ nf_ct_find_expectation(struct net *net,
{
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
struct nf_conntrack_expect *i, *exp = NULL;
+ struct hlist_node *next;
unsigned int h;
lockdep_nfct_expect_lock_held();
@@ -186,7 +183,11 @@ nf_ct_find_expectation(struct net *net,
return NULL;
h = nf_ct_expect_dst_hash(net, tuple);
- hlist_for_each_entry(i, &nf_ct_expect_hash[h], hnode) {
+ hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) {
+ if (nf_ct_exp_is_expired(i)) {
+ nf_ct_unlink_expect(i);
+ continue;
+ }
if (!(i->flags & NF_CT_EXPECT_INACTIVE) &&
nf_ct_exp_equal(tuple, i, zone, net)) {
exp = i;
@@ -196,13 +197,16 @@ nf_ct_find_expectation(struct net *net,
if (!exp)
return NULL;
+ if (!refcount_inc_not_zero(&exp->use))
+ return NULL;
+
/* If master is not in hash table yet (ie. packet hasn't left
this machine yet), how can other end know about expected?
Hence these are not the droids you are looking for (if
master ct never got confirmed, we'd hold a reference to it
and weird things would happen to future packets). */
if (!nf_ct_is_confirmed(exp->master))
- return NULL;
+ goto err_release_exp;
/* Avoid race with other CPUs, that for exp->master ct, is
* about to invoke ->destroy(), or nf_ct_delete() via timeout
@@ -214,18 +218,17 @@ nf_ct_find_expectation(struct net *net,
*/
if (unlikely(nf_ct_is_dying(exp->master) ||
!refcount_inc_not_zero(&exp->master->ct_general.use)))
- return NULL;
+ goto err_release_exp;
- if (exp->flags & NF_CT_EXPECT_PERMANENT || !unlink) {
- refcount_inc(&exp->use);
- return exp;
- } else if (del_timer(&exp->timeout)) {
- nf_ct_unlink_expect(exp);
+ if (exp->flags & NF_CT_EXPECT_PERMANENT || !unlink)
return exp;
- }
- /* Undo exp->master refcnt increase, if del_timer() failed */
- nf_ct_put(exp->master);
+ nf_ct_unlink_expect(exp);
+
+ return exp;
+
+err_release_exp:
+ nf_ct_expect_put(exp);
return NULL;
}
@@ -241,9 +244,8 @@ void nf_ct_remove_expectations(struct nf_conn *ct)
return;
spin_lock_bh(&nf_conntrack_expect_lock);
- hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) {
- nf_ct_remove_expect(exp);
- }
+ hlist_for_each_entry_safe(exp, next, &help->expectations, lnode)
+ nf_ct_unlink_expect(exp);
spin_unlock_bh(&nf_conntrack_expect_lock);
}
EXPORT_SYMBOL_GPL(nf_ct_remove_expectations);
@@ -292,7 +294,7 @@ static bool master_matches(const struct nf_conntrack_expect *a,
void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
{
spin_lock_bh(&nf_conntrack_expect_lock);
- nf_ct_remove_expect(exp);
+ WRITE_ONCE(exp->flags, exp->flags | NF_CT_EXPECT_DEAD);
spin_unlock_bh(&nf_conntrack_expect_lock);
}
EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
@@ -308,6 +310,7 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
if (!new)
return NULL;
+ new->timeout = nfct_time_stamp;
new->master = me;
refcount_set(&new->use, 1);
return new;
@@ -414,17 +417,12 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
struct net *net = nf_ct_exp_net(exp);
unsigned int h = nf_ct_expect_dst_hash(net, &exp->tuple);
- /* two references : one for hash insert, one for the timer */
- refcount_add(2, &exp->use);
+ refcount_inc(&exp->use);
- timer_setup(&exp->timeout, nf_ct_expectation_timed_out, 0);
helper = rcu_dereference_protected(master_help->helper,
lockdep_is_held(&nf_conntrack_expect_lock));
- if (helper) {
- exp->timeout.expires = jiffies +
- helper->expect_policy[exp->class].timeout * HZ;
- }
- add_timer(&exp->timeout);
+ if (helper)
+ exp->timeout += helper->expect_policy[exp->class].timeout * HZ;
hlist_add_head_rcu(&exp->lnode, &master_help->expectations);
master_help->expecting[exp->class]++;
@@ -436,20 +434,26 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
NF_CT_STAT_INC(net, expect_create);
}
-/* Race with expectations being used means we could have none to find; OK. */
-static void evict_oldest_expect(struct nf_conn *master,
- struct nf_conntrack_expect *new)
+static void evict_oldest_expect(struct nf_conn_help *master_help,
+ struct nf_conntrack_expect *new,
+ const struct nf_conntrack_expect_policy *p)
{
- struct nf_conn_help *master_help = nfct_help(master);
struct nf_conntrack_expect *exp, *last = NULL;
+ struct hlist_node *next;
- hlist_for_each_entry(exp, &master_help->expectations, lnode) {
+ hlist_for_each_entry_safe(exp, next, &master_help->expectations, lnode) {
+ if (nf_ct_exp_is_expired(exp)) {
+ nf_ct_unlink_expect(exp);
+ continue;
+ }
if (exp->class == new->class)
last = exp;
}
- if (last)
- nf_ct_remove_expect(last);
+ /* Still worth to evict oldest expectation after garbage collection? */
+ if (last &&
+ master_help->expecting[last->class] >= p->max_expected)
+ nf_ct_unlink_expect(last);
}
static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect,
@@ -474,14 +478,18 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect,
}
h = nf_ct_expect_dst_hash(net, &expect->tuple);
hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) {
+ if (nf_ct_exp_is_expired(i)) {
+ nf_ct_unlink_expect(i);
+ continue;
+ }
if (master_matches(i, expect, flags) &&
expect_matches(i, expect)) {
if (i->class != expect->class ||
i->master != expect->master)
return -EALREADY;
- if (nf_ct_remove_expect(i))
- break;
+ nf_ct_unlink_expect(i);
+ break;
} else if (expect_clash(i, expect)) {
ret = -EBUSY;
goto out;
@@ -493,14 +501,8 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect,
if (helper) {
p = &helper->expect_policy[expect->class];
if (p->max_expected &&
- master_help->expecting[expect->class] >= p->max_expected) {
- evict_oldest_expect(master, expect);
- if (master_help->expecting[expect->class]
- >= p->max_expected) {
- ret = -EMFILE;
- goto out;
- }
- }
+ master_help->expecting[expect->class] >= p->max_expected)
+ evict_oldest_expect(master_help, expect, p);
}
cnet = nf_ct_pernet(net);
@@ -547,10 +549,8 @@ void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, vo
hlist_for_each_entry_safe(exp, next,
&nf_ct_expect_hash[i],
hnode) {
- if (iter(exp, data) && del_timer(&exp->timeout)) {
+ if (iter(exp, data))
nf_ct_unlink_expect(exp);
- nf_ct_expect_put(exp);
- }
}
}
@@ -577,10 +577,8 @@ void nf_ct_expect_iterate_net(struct net *net,
if (!net_eq(nf_ct_exp_net(exp), net))
continue;
- if (iter(exp, data) && del_timer(&exp->timeout)) {
+ if (iter(exp, data))
nf_ct_unlink_expect_report(exp, portid, report);
- nf_ct_expect_put(exp);
- }
}
}
@@ -657,17 +655,17 @@ static int exp_seq_show(struct seq_file *s, void *v)
struct net *net = seq_file_net(s);
struct hlist_node *n = v;
char *delim = "";
+ __s32 timeout;
expect = hlist_entry(n, struct nf_conntrack_expect, hnode);
if (!net_eq(nf_ct_exp_net(expect), net))
return 0;
+ if (nf_ct_exp_is_expired(expect))
+ return 0;
- if (expect->timeout.function)
- seq_printf(s, "%ld ", timer_pending(&expect->timeout)
- ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
- else
- seq_puts(s, "- ");
+ timeout = (__s32)(READ_ONCE(expect->timeout) - nfct_time_stamp) / HZ;
+ seq_printf(s, "%d ", timeout > 0 ? timeout : 0);
seq_printf(s, "l3proto = %u proto=%u ",
expect->tuple.src.l3num,
expect->tuple.dst.protonum);
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index a116c6629e2b8..279201f8a18f4 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -1396,8 +1396,8 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
"timeout to %u seconds for",
info->timeout);
nf_ct_dump_tuple(&exp->tuple);
- mod_timer_pending(&exp->timeout,
- jiffies + info->timeout * HZ);
+ WRITE_ONCE(exp->timeout,
+ nfct_time_stamp + (info->timeout * HZ));
}
spin_unlock_bh(&nf_conntrack_expect_lock);
}
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index ea0cdb7ec9151..2cef826e20fb9 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -180,10 +180,10 @@ nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
struct nf_conn_help *help;
help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp);
- if (help)
+ if (help) {
+ __set_bit(IPS_HELPER_BIT, &ct->status);
INIT_HLIST_HEAD(&help->expectations);
- else
- pr_debug("failed to add helper extension area");
+ }
return help;
}
EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
@@ -202,10 +202,8 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
return 0;
help = nfct_help(tmpl);
- if (help != NULL) {
+ if (help)
helper = rcu_dereference(help->helper);
- set_bit(IPS_HELPER_BIT, &ct->status);
- }
help = nfct_help(ct);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 8bb32965edb83..1c2bb4ee84ac2 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -3001,8 +3001,8 @@ static int
ctnetlink_exp_dump_expect(struct sk_buff *skb,
const struct nf_conntrack_expect *exp)
{
+ __s32 timeout = (__s32)(READ_ONCE(exp->timeout) - nfct_time_stamp) / HZ;
struct nf_conn *master = exp->master;
- long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
struct nf_conntrack_helper *helper;
#if IS_ENABLED(CONFIG_NF_NAT)
struct nlattr *nest_parms;
@@ -3165,6 +3165,9 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
restart:
hlist_for_each_entry_rcu(exp, &nf_ct_expect_hash[cb->args[0]],
hnode) {
+ if (nf_ct_exp_is_expired(exp))
+ continue;
+
if (l3proto && exp->tuple.src.l3num != l3proto)
continue;
@@ -3444,11 +3447,8 @@ static int ctnetlink_del_expect(struct sk_buff *skb,
}
/* after list removal, usage count == 1 */
- if (del_timer(&exp->timeout)) {
- nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid,
- nlmsg_report(info->nlh));
- nf_ct_expect_put(exp);
- }
+ nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid,
+ nlmsg_report(info->nlh));
spin_unlock_bh(&nf_conntrack_expect_lock);
/* have to put what we 'get' above.
* after this line usage count == 0 */
@@ -3472,14 +3472,10 @@ static int
ctnetlink_change_expect(struct nf_conntrack_expect *x,
const struct nlattr * const cda[])
{
- if (cda[CTA_EXPECT_TIMEOUT]) {
- if (!del_timer(&x->timeout))
- return -ETIME;
+ if (cda[CTA_EXPECT_TIMEOUT])
+ WRITE_ONCE(x->timeout, nfct_time_stamp +
+ ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ);
- x->timeout.expires = jiffies +
- ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ;
- add_timer(&x->timeout);
- }
return 0;
}
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 5b75e9bc99e9f..449a6e53feae4 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -894,11 +894,10 @@ static int refresh_signalling_expectation(struct nf_conn *ct,
exp->tuple.dst.protonum != proto ||
exp->tuple.dst.u.udp.port != port)
continue;
- if (mod_timer_pending(&exp->timeout, jiffies + expires * HZ)) {
- exp->flags &= ~NF_CT_EXPECT_INACTIVE;
- found = 1;
- break;
- }
+ WRITE_ONCE(exp->timeout, nfct_time_stamp + (expires * HZ));
+ WRITE_ONCE(exp->flags, exp->flags & ~NF_CT_EXPECT_INACTIVE);
+ found = 1;
+ break;
}
spin_unlock_bh(&nf_conntrack_expect_lock);
return found;
@@ -914,8 +913,7 @@ static void flush_expectations(struct nf_conn *ct, bool media)
hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) {
if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media)
continue;
- if (!nf_ct_remove_expect(exp))
- continue;
+ nf_ct_unlink_expect(exp);
if (!media)
break;
}
@@ -1385,7 +1383,6 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct),
saddr, &daddr, proto, NULL, &port);
- exp->timeout.expires = sip_timeout * HZ;
rcu_assign_pointer(exp->assign_helper, helper);
exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
index c238c97a90536..07a879f66fabe 100644
--- a/net/netfilter/nft_ct.c
+++ b/net/netfilter/nft_ct.c
@@ -1128,7 +1128,6 @@ static void nft_ct_helper_obj_eval(struct nft_object *obj,
help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
if (help) {
rcu_assign_pointer(help->helper, to_assign);
- set_bit(IPS_HELPER_BIT, &ct->status);
if ((ct->status & IPS_NAT_MASK) && !nfct_seqadj(ct))
if (!nfct_seqadj_ext_add(ct))
@@ -1310,7 +1309,7 @@ static void nft_ct_expect_obj_eval(struct nft_object *obj,
&ct->tuplehash[!dir].tuple.src.u3,
&ct->tuplehash[!dir].tuple.dst.u3,
priv->l4proto, NULL, &priv->dport);
- exp->timeout.expires = jiffies + priv->timeout * HZ;
+ exp->timeout += priv->timeout * HZ;
if (nf_ct_expect_related(exp, 0) != 0)
regs->verdict.code = NF_DROP;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 543/869] perf tools: Use perf_env__get_cpu_topology() in machine__resolve()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (541 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 542/869] netfilter: nf_conntrack_expect: use conntrack GC to reap expectations Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 544/869] Bluetooth: hci_sync: hold conn in hci_connect_acl/le_sync() callbacks Greg Kroah-Hartman
` (326 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, sashiko-bot, Ian Rogers, Kan Liang,
Arnaldo Carvalho de Melo, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <acme@redhat.com>
[ Upstream commit 5484b43a0ec8231c36fba6ead654cb72dbba8b8f ]
machine__resolve() accesses env->cpu[al->cpu].socket_id after checking
al->cpu >= 0 and env->cpu != NULL, but without validating al->cpu
against env->nr_cpus_avail. Since al->cpu comes from the untrusted
perf.data sample, a crafted file with a large CPU index causes an
out-of-bounds heap read.
Use perf_env__get_cpu_topology() which validates both NULL and bounds.
Also bounds-check al->cpu before the cast to struct perf_cpu (int16_t):
without this, values like 65536 silently truncate to 0, bypassing the
accessor's internal check and returning CPU 0's topology.
Fixes: 0c4c4debb0adda4c ("perf tools: Add processor socket info to hist_entry and addr_location")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Ian Rogers <irogers@google.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
tools/perf/util/event.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index aac96d5d19170..1e5085817e825 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -12,6 +12,7 @@
#include <linux/zalloc.h>
#include "cpumap.h"
#include "dso.h"
+#include "env.h"
#include "event.h"
#include "debug.h"
#include "hist.h"
@@ -763,8 +764,18 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
if (al->cpu >= 0) {
struct perf_env *env = machine->env;
- if (env && env->cpu)
- al->socket = env->cpu[al->cpu].socket_id;
+ /*
+ * Bounds-check al->cpu (s32) before casting to struct perf_cpu
+ * (int16_t): without this, e.g. 65536 truncates to 0 and silently
+ * returns CPU 0's topology. Can go once perf_cpu.cpu is widened.
+ */
+ if (env && al->cpu < env->nr_cpus_avail) {
+ struct cpu_topology_map *topo;
+
+ topo = perf_env__get_cpu_topology(env, (struct perf_cpu){ al->cpu });
+ if (topo)
+ al->socket = topo->socket_id;
+ }
}
if (al->map) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 544/869] Bluetooth: hci_sync: hold conn in hci_connect_acl/le_sync() callbacks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (542 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 543/869] perf tools: Use perf_env__get_cpu_topology() in machine__resolve() Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 545/869] idpf: bound interrupt-vector register fill to the allocated array Greg Kroah-Hartman
` (325 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pauli Virtanen,
Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <pav@iki.fi>
[ Upstream commit 2f5d635ad5906b0235bc0c870e8beba3116e1e98 ]
There is theoretical UAF if the conn is freed while the hci_sync task
is running.
Hold refcount to avoid that.
Fixes: 881559af5f5c ("Bluetooth: hci_sync: Attempt to dequeue connection attempt")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/hci_sync.c | 32 ++++++++++++++++++++++++--------
1 file changed, 24 insertions(+), 8 deletions(-)
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 92ef7d88f8e3c..dfa0150669551 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -7149,12 +7149,23 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
return err;
}
+static void hci_acl_create_conn_sync_complete(struct hci_dev *hdev, void *data,
+ int err)
+{
+ struct hci_conn *conn = data;
+
+ hci_conn_put(conn);
+}
+
int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
int err;
- err = hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn,
- NULL);
+ err = hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync,
+ hci_conn_get(conn),
+ hci_acl_create_conn_sync_complete);
+ if (err)
+ hci_conn_put(conn);
return (err == -EEXIST) ? 0 : err;
}
@@ -7165,36 +7176,41 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err);
if (err == -ECANCELED)
- return;
+ goto done;
hci_dev_lock(hdev);
if (!hci_conn_valid(hdev, conn))
- goto done;
+ goto unlock;
if (!err) {
hci_connect_le_scan_cleanup(conn, 0x00);
- goto done;
+ goto unlock;
}
/* Check if connection is still pending */
if (conn != hci_lookup_le_connect(hdev))
- goto done;
+ goto unlock;
/* Flush to make sure we send create conn cancel command if needed */
flush_delayed_work(&conn->le_conn_timeout);
hci_conn_failed(conn, bt_status(err));
-done:
+unlock:
hci_dev_unlock(hdev);
+done:
+ hci_conn_put(conn);
}
int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
int err;
- err = hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync, conn,
+ err = hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync,
+ hci_conn_get(conn),
create_le_conn_complete);
+ if (err)
+ hci_conn_put(conn);
return (err == -EEXIST) ? 0 : err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 545/869] idpf: bound interrupt-vector register fill to the allocated array
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (543 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 544/869] Bluetooth: hci_sync: hold conn in hci_connect_acl/le_sync() callbacks Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 546/869] dmaengine: idxd: fix double free of wq, engine, and group structs Greg Kroah-Hartman
` (324 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Michael Bommarito,
Aleksandr Loktionov, Samuel Salin, Tony Nguyen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <michael.bommarito@gmail.com>
[ Upstream commit 9f7007ee9858c99aa43101bc8352c672fee85644 ]
idpf_get_reg_intr_vecs() fills the caller-allocated reg_vals[] array from
the VIRTCHNL2_OP_ALLOC_VECTORS reply in adapter->req_vec_chunks, bounding
its inner loop only by the per-chunk num_vectors. The array is sized
separately: idpf_intr_reg_init() allocates
kzalloc_objs(struct idpf_vec_regs, total_vecs) from
caps.num_allocated_vectors and only checks the returned count after the
fill. The sum of per-chunk num_vectors is never reconciled against
total_vecs, so a reply with a small num_allocated_vectors but chunks
summing higher writes past the end of reg_vals[].
Impact: a control plane (a PF or hypervisor device model) that returns a
VIRTCHNL2_OP_ALLOC_VECTORS reply whose per-chunk num_vectors sum exceeds
num_allocated_vectors writes struct idpf_vec_regs entries past the end of
the reg_vals kmalloc allocation (KASAN slab-out-of-bounds write).
Bound the fill loop to the array capacity passed in by the callers,
mirroring the sibling idpf_vport_get_q_reg(). The existing
num_regs < num_vecs check then rejects an undersized reply without the
out-of-bounds write happening first.
Fixes: d4d558718266 ("idpf: initialize interrupts and enable vport")
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Samuel Salin <Samuel.salin@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/idpf/idpf_dev.c | 2 +-
drivers/net/ethernet/intel/idpf/idpf_vf_dev.c | 2 +-
drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 5 +++--
drivers/net/ethernet/intel/idpf/idpf_virtchnl.h | 2 +-
4 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c
index 45272bd9e472b..ceea5cb6b854a 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
@@ -84,7 +84,7 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,
if (!reg_vals)
return -ENOMEM;
- num_regs = idpf_get_reg_intr_vecs(vport, reg_vals);
+ num_regs = idpf_get_reg_intr_vecs(vport, reg_vals, total_vecs);
if (num_regs < num_vecs) {
err = -EINVAL;
goto free_reg_vals;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
index 61d6f774e2f66..84dc8b72c64b6 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
@@ -84,7 +84,7 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,
if (!reg_vals)
return -ENOMEM;
- num_regs = idpf_get_reg_intr_vecs(vport, reg_vals);
+ num_regs = idpf_get_reg_intr_vecs(vport, reg_vals, total_vecs);
if (num_regs < num_vecs) {
err = -EINVAL;
goto free_reg_vals;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 92cc3ba37b6d7..a4c04a7bac975 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -1004,11 +1004,12 @@ static void idpf_init_avail_queues(struct idpf_adapter *adapter)
* idpf_get_reg_intr_vecs - Get vector queue register offset
* @vport: virtual port structure
* @reg_vals: Register offsets to store in
+ * @num_vecs: number of entries the @reg_vals array can hold
*
* Returns number of registers that got populated
*/
int idpf_get_reg_intr_vecs(struct idpf_vport *vport,
- struct idpf_vec_regs *reg_vals)
+ struct idpf_vec_regs *reg_vals, int num_vecs)
{
struct virtchnl2_vector_chunks *chunks;
struct idpf_vec_regs reg_val;
@@ -1032,7 +1033,7 @@ int idpf_get_reg_intr_vecs(struct idpf_vport *vport,
dynctl_reg_spacing = le32_to_cpu(chunk->dynctl_reg_spacing);
itrn_reg_spacing = le32_to_cpu(chunk->itrn_reg_spacing);
- for (i = 0; i < num_vec; i++) {
+ for (i = 0; i < num_vec && num_regs < num_vecs; i++) {
reg_vals[num_regs].dyn_ctl_reg = reg_val.dyn_ctl_reg;
reg_vals[num_regs].itrn_reg = reg_val.itrn_reg;
reg_vals[num_regs].itrn_index_spacing =
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
index 0bfe44fa0385c..83068c65f9511 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
@@ -17,7 +17,7 @@ int idpf_vc_core_init(struct idpf_adapter *adapter);
void idpf_vc_core_deinit(struct idpf_adapter *adapter);
int idpf_get_reg_intr_vecs(struct idpf_vport *vport,
- struct idpf_vec_regs *reg_vals);
+ struct idpf_vec_regs *reg_vals, int num_vecs);
int idpf_queue_reg_init(struct idpf_vport *vport);
int idpf_vport_queue_ids_init(struct idpf_vport *vport);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 546/869] dmaengine: idxd: fix double free of wq, engine, and group structs
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (544 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 545/869] idpf: bound interrupt-vector register fill to the allocated array Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 547/869] drm/amd/display: check if dml21_add_phantom_plane() is successful Greg Kroah-Hartman
` (323 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yuho Choi, Vinicius Costa Gomes,
Frank Li, Vinod Koul, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <dbgh9129@gmail.com>
[ Upstream commit ec2d428b2e32dd157de8f86a86dd85c5b2c8f45c ]
The release callbacks for wq, engine, and group devices
(idxd_conf_wq_release, idxd_conf_engine_release,
idxd_conf_group_release) each call kfree() on the enclosing struct.
The setup error paths and cleanup functions also call kfree()
explicitly after put_device(), producing a double free whenever
put_device() drops the reference count to zero and fires the release.
In the setup functions, device_initialize() is called before
device_add(), so the reference count is exactly 1 at the error sites.
put_device() unconditionally fires the release, which frees the struct;
the subsequent explicit kfree() then operates on freed memory.
For idxd_setup_wqs(), the wq release callback also owns opcap_bmap
and wqcfg. The error unwind additionally freed those fields explicitly
before calling put_device(), causing further double frees on both.
Remove the redundant explicit kfree() calls from all setup error paths
and cleanup functions for wq, engine, and group structs, delegating
sole ownership of those allocations to the release callbacks.
Fixes: 7c5dd23e57c1 ("dmaengine: idxd: fix wq conf_dev 'struct device' lifetime")
Fixes: 75b911309060 ("dmaengine: idxd: fix engine conf_dev lifetime")
Fixes: defe49f96012 ("dmaengine: idxd: fix group conf_dev lifetime")
Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260415205452.67155-1-dbgh9129@gmail.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/dma/idxd/init.c | 36 +++++-------------------------------
1 file changed, 5 insertions(+), 31 deletions(-)
diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
index e55136bb525e2..4be7962481667 100644
--- a/drivers/dma/idxd/init.c
+++ b/drivers/dma/idxd/init.c
@@ -155,18 +155,12 @@ static void idxd_cleanup_interrupts(struct idxd_device *idxd)
static void idxd_clean_wqs(struct idxd_device *idxd)
{
- struct idxd_wq *wq;
struct device *conf_dev;
int i;
for (i = 0; i < idxd->max_wqs; i++) {
- wq = idxd->wqs[i];
- if (idxd->hw.wq_cap.op_config)
- bitmap_free(wq->opcap_bmap);
- kfree(wq->wqcfg);
- conf_dev = wq_confdev(wq);
+ conf_dev = wq_confdev(idxd->wqs[i]);
put_device(conf_dev);
- kfree(wq);
}
bitmap_free(idxd->wq_enable_map);
kfree(idxd->wqs);
@@ -208,7 +202,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
rc = dev_set_name(conf_dev, "wq%d.%d", idxd->id, wq->id);
if (rc < 0) {
put_device(conf_dev);
- kfree(wq);
goto err_unwind;
}
@@ -222,7 +215,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev));
if (!wq->wqcfg) {
put_device(conf_dev);
- kfree(wq);
rc = -ENOMEM;
goto err_unwind;
}
@@ -230,9 +222,7 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
if (idxd->hw.wq_cap.op_config) {
wq->opcap_bmap = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL);
if (!wq->opcap_bmap) {
- kfree(wq->wqcfg);
put_device(conf_dev);
- kfree(wq);
rc = -ENOMEM;
goto err_unwind;
}
@@ -247,13 +237,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
err_unwind:
while (--i >= 0) {
- wq = idxd->wqs[i];
- if (idxd->hw.wq_cap.op_config)
- bitmap_free(wq->opcap_bmap);
- kfree(wq->wqcfg);
- conf_dev = wq_confdev(wq);
+ conf_dev = wq_confdev(idxd->wqs[i]);
put_device(conf_dev);
- kfree(wq);
}
bitmap_free(idxd->wq_enable_map);
@@ -265,15 +250,12 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
static void idxd_clean_engines(struct idxd_device *idxd)
{
- struct idxd_engine *engine;
struct device *conf_dev;
int i;
for (i = 0; i < idxd->max_engines; i++) {
- engine = idxd->engines[i];
- conf_dev = engine_confdev(engine);
+ conf_dev = engine_confdev(idxd->engines[i]);
put_device(conf_dev);
- kfree(engine);
}
kfree(idxd->engines);
}
@@ -308,7 +290,6 @@ static int idxd_setup_engines(struct idxd_device *idxd)
rc = dev_set_name(conf_dev, "engine%d.%d", idxd->id, engine->id);
if (rc < 0) {
put_device(conf_dev);
- kfree(engine);
goto err;
}
@@ -319,10 +300,8 @@ static int idxd_setup_engines(struct idxd_device *idxd)
err:
while (--i >= 0) {
- engine = idxd->engines[i];
- conf_dev = engine_confdev(engine);
+ conf_dev = engine_confdev(idxd->engines[i]);
put_device(conf_dev);
- kfree(engine);
}
kfree(idxd->engines);
@@ -331,13 +310,10 @@ static int idxd_setup_engines(struct idxd_device *idxd)
static void idxd_clean_groups(struct idxd_device *idxd)
{
- struct idxd_group *group;
int i;
for (i = 0; i < idxd->max_groups; i++) {
- group = idxd->groups[i];
- put_device(group_confdev(group));
- kfree(group);
+ put_device(group_confdev(idxd->groups[i]));
}
kfree(idxd->groups);
}
@@ -372,7 +348,6 @@ static int idxd_setup_groups(struct idxd_device *idxd)
rc = dev_set_name(conf_dev, "group%d.%d", idxd->id, group->id);
if (rc < 0) {
put_device(conf_dev);
- kfree(group);
goto err;
}
@@ -397,7 +372,6 @@ static int idxd_setup_groups(struct idxd_device *idxd)
while (--i >= 0) {
group = idxd->groups[i];
put_device(group_confdev(group));
- kfree(group);
}
kfree(idxd->groups);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 547/869] drm/amd/display: check if dml21_add_phantom_plane() is successful
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (545 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 546/869] dmaengine: idxd: fix double free of wq, engine, and group structs Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 548/869] btrfs: initialize inode mapping flags for cached inodes Greg Kroah-Hartman
` (322 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dillon Varone, Fangzhi Zuo,
Dan Wheeler, Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <alexander.deucher@amd.com>
[ Upstream commit 000acb4ce7fb9feba3072ce468ad681f6585cd5d ]
Verify that the phantom plane was allocated to avoid a later
segfault.
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4970
Fixes: 70839da63605 ("drm/amd/display: Add new DCN401 sources")
Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 5adb54abe5a8e82cbff7f8806db30a5f4924329f)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../drm/amd/display/dc/dml2/dml21/dml21_utils.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_utils.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_utils.c
index 51d491bffa324..3f656e5dacf89 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_utils.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_utils.c
@@ -457,14 +457,13 @@ void dml21_handle_phantom_streams_planes(const struct dc *dc, struct dc_state *c
main_plane = main_stream_status->plane_states[dc_plane_index];
/* create phantom planes for subvp enabled plane */
- dml21_add_phantom_plane(dml_ctx,
- dc,
- context,
- phantom_stream,
- main_plane,
- &dml_ctx->v21.mode_programming.programming->plane_programming[dml_plane_index]);
-
- phantoms_added = true;
+ if (dml21_add_phantom_plane(dml_ctx,
+ dc,
+ context,
+ phantom_stream,
+ main_plane,
+ &dml_ctx->v21.mode_programming.programming->plane_programming[dml_plane_index]))
+ phantoms_added = true;
}
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 548/869] btrfs: initialize inode mapping flags for cached inodes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (546 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 547/869] drm/amd/display: check if dml21_add_phantom_plane() is successful Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 549/869] bpf: Check sk_state before sk_protocol in bpf_tcp_*_syncookie Greg Kroah-Hartman
` (321 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Filipe Manana, Qu Wenruo,
David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <wqu@suse.com>
[ Upstream commit 0ef349734a93227b45f65fc50a3311d1cc5f03e9 ]
[BUG]
When running generic/795 with 8K block size, 4K page size, the test
always fails, triggering some ASSERT()s related to folio size:
795 (241074): drop_caches: 3
assertion failed: IS_ALIGNED(start, blocksize) && IS_ALIGNED(end + 1, blocksize), in extent_io.c:1404 (blocksize=8192 root=262 ino=258 start=16826368 end=16830463 mapping min order=0)
------------[ cut here ]------------
kernel BUG at extent_io.c:1404!
Oops: invalid opcode: 0000 [#1] SMP
CPU: 8 UID: 0 PID: 241105 Comm: fsstress Tainted: G OE 7.2.0-rc5-custom+ #442 PREEMPT(full) f4bfb352566f3949f29c233ce6f735050a03b245
Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS unknown 02/02/2022
RIP: 0010:assert_folio_range.cold+0x3d/0x3f [btrfs]
Call Trace:
<TASK>
btrfs_read_folio+0x9e/0x170 [btrfs 4cd1dd93b341b8ef766643f9512f4a86259567a3]
prepare_one_folio.constprop.0+0x104/0x2a0 [btrfs 4cd1dd93b341b8ef766643f9512f4a86259567a3]
btrfs_buffered_write+0x285/0xa50 [btrfs 4cd1dd93b341b8ef766643f9512f4a86259567a3]
btrfs_do_write_iter+0x1aa/0x210 [btrfs 4cd1dd93b341b8ef766643f9512f4a86259567a3]
iter_file_splice_write+0x31a/0x540
direct_splice_actor+0x53/0x170
splice_direct_to_actor+0xe9/0x240
do_splice_direct+0x76/0xb0
vfs_copy_file_range+0x1fd/0x630
__x64_sys_copy_file_range+0xf9/0x220
do_syscall_64+0xe1/0x790
entry_SYSCALL_64_after_hwframe+0x4b/0x53
</TASK>
---[ end trace 0000000000000000 ]---
The ASSERT() itself is added by a later patch.
The crash is triggered with that new debug patch, and without this fix.
[CAUSE]
In the above case, the start 16826368 is properly 8K aligned, but the
end (16830463 + 1) is not 8K aligned.
Furthermore the mapping's minimal folio order is 0, not the expected 1
for 8K block size with 4K page size.
So this means some inodes do not have btrfs_set_inode_mapping_order()
called on it.
The missing btrfs_set_inode_mapping_order() call happens for cached
inodes, through the following events:
- btrfs_create_new_inode() called for inode X
Which properly sets minimal folio order for the VFS inode.
- btrfs_update_inode() called for inode X
Which calls btrfs_delayed_update_inode() to create a delayed_node
into root->delayed_nodes xarray.
- Drop cache/memory pressure, evicting in-memory inode X
Which evicted the inode X, but delayed_node is still in
root->delayed_nodes for future reuse.
- btrfs_iget() for inode X called again
btrfs_iget()
|- btrfs_iget_locked()
| |- iget5_locked_rcu()
| Which creates a new vfs_inode for btrfs, whose mapping still
| has the minimal order as 0.
|
|- btrfs_read_locked_inode()
|- btrfs_fill_inode()
| |- btrfs_get_delayed_node()
| Which found out the previous node, and use that delayed
| node to initialize the new inode.
|
|- filled = true;
|- if (filled) goto cache_index;
Which skips the btrfs_update_inode_mapping_flags() and
btrfs_set_inode_mapping_order() calls.
So the inode still has minimal folio order set as 0, not
the required 1.
Thus later page cache read will get a folio whose size is smaller than
block size, as the mapping has its minimal folio order set as 0 not 1,
then trigger the ASSERT().
[FIX]
Move the btrfs_update_inode_mapping_flags() and
btrfs_set_inode_mapping_order() calls under cache_index label,
so that the mapping flags and minimal folio order is always set
no matter if we have a cached inode.
Assisted-by: LLM (analysis)
Fixes: ecde48a1a6b3 ("btrfs: expose per-inode stable writes flag")
Fixes: cc38d178ff33 ("btrfs: enable large data folio support under CONFIG_BTRFS_EXPERIMENTAL")
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/inode.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 68bea533bb49d..9f3881db076fc 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3854,12 +3854,13 @@ static int btrfs_read_locked_inode(struct inode *inode,
btrfs_inode_split_flags(btrfs_inode_flags(leaf, inode_item),
&BTRFS_I(inode)->flags, &BTRFS_I(inode)->ro_flags);
+
+cache_index:
if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
mapping_clear_stable_writes(inode->i_mapping);
else
mapping_set_stable_writes(inode->i_mapping);
-cache_index:
/*
* If we were modified in the current generation and evicted from memory
* and then re-read we need to do a full sync since we don't have any
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 549/869] bpf: Check sk_state before sk_protocol in bpf_tcp_*_syncookie
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (547 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 548/869] btrfs: initialize inode mapping flags for cached inodes Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 550/869] drm/amdkfd: Fix infinite loop parsing CRAT with zero subtype length Greg Kroah-Hartman
` (320 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vega, Luxiao Xu, Ren Wei,
Daniel Borkmann, Eric Dumazet, Kuniyuki Iwashima, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luxiao Xu <rakukuip@gmail.com>
[ Upstream commit 31a420a822ff92e2090bd5d65efe8e34e2d6d9b8 ]
bpf_tcp_gen_syncookie and bpf_tcp_check_syncookie accept a socket pointer
'sk' with argument type ARG_PTR_TO_BTF_ID_SOCK_COMMON. However, they access
sk->sk_protocol without validating whether 'sk' represents a full socket.
Fix this issue by checking sk->sk_state != TCP_LISTEN before inspecting
sk->sk_protocol in both bpf_tcp_gen_syncookie and bpf_tcp_check_syncookie.
Since mini-sockets are never in the TCP_LISTEN state, the condition
short-circuits and prevents dereferencing fullsock-specific fields.
Fixes: 399040847084 ("bpf: add helper to check for a valid SYN cookie")
Fixes: 70d66244317e ("bpf: add bpf_tcp_gen_syncookie helper")
Reported-by: Vega <vega@nebusec.ai>
Signed-off-by: Luxiao Xu <rakukuip@gmail.com>
Signed-off-by: Ren Wei <enjou1224z@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://lore.kernel.org/bpf/6218aa3534d0d2d3f448fde70a8dc2769d7a8201.1785823138.git.rakukuip@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/core/filter.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/core/filter.c b/net/core/filter.c
index a680cf27ad820..ce290de4b1652 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -7475,7 +7475,7 @@ BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_len
return -EINVAL;
/* sk_listener() allows TCP_NEW_SYN_RECV, which makes no sense here. */
- if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)
+ if (sk->sk_state != TCP_LISTEN || sk->sk_protocol != IPPROTO_TCP)
return -EINVAL;
if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies))
@@ -7548,7 +7548,7 @@ BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len,
if (unlikely(!sk || th_len < sizeof(*th) || th_len != th->doff * 4))
return -EINVAL;
- if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)
+ if (sk->sk_state != TCP_LISTEN || sk->sk_protocol != IPPROTO_TCP)
return -EINVAL;
if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies))
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 550/869] drm/amdkfd: Fix infinite loop parsing CRAT with zero subtype length
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (548 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 549/869] bpf: Check sk_state before sk_protocol in bpf_tcp_*_syncookie Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 551/869] drm/amdkfd: Add bounds check for CRAT " Greg Kroah-Hartman
` (319 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yongqiang Sun, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongqiang Sun <Yongqiang.Sun@amd.com>
[ Upstream commit 961323c26ad4c895e3b0ea1711fc41dfd6368c12 ]
Malformed ACPI CRAT tables can advertise a zero or undersized subtype
length. The parser then fails to advance the cursor and loops forever
while the remaining image still looks large enough for a generic header.
Validate sub_type_hdr->length on each iteration before parsing or
advancing. Return -EINVAL and warn when length is zero or smaller than
the generic subtype header.
Signed-off-by: Yongqiang Sun <Yongqiang.Sun@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Stable-dep-of: 6e7566ba4739 ("drm/amdkfd: Add bounds check for CRAT subtype length")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
index d2993594c848a..36c259b34afd9 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
@@ -1403,6 +1403,14 @@ int kfd_parse_crat_table(void *crat_image, struct list_head *device_list,
sub_type_hdr = (struct crat_subtype_generic *)(crat_table+1);
while ((char *)sub_type_hdr + sizeof(struct crat_subtype_generic) <
((char *)crat_image) + image_len) {
+ if (!sub_type_hdr->length ||
+ sub_type_hdr->length < sizeof(struct crat_subtype_generic)) {
+ pr_warn("Invalid CRAT subtype length %u\n",
+ sub_type_hdr->length);
+ ret = -EINVAL;
+ break;
+ }
+
if (sub_type_hdr->flags & CRAT_SUBTYPE_FLAGS_ENABLED) {
ret = kfd_parse_subtype(sub_type_hdr, device_list);
if (ret)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 551/869] drm/amdkfd: Add bounds check for CRAT subtype length
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (549 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 550/869] drm/amdkfd: Fix infinite loop parsing CRAT with zero subtype length Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 552/869] Bluetooth: ISO: zero the sockaddr before returning it in getname Greg Kroah-Hartman
` (318 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, William Palacek, Alysa Liu,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: William Palacek <William.Palacek@amd.com>
[ Upstream commit 6e7566ba4739dd573c331adde1c96690f7a567bd ]
The CRAT parser validates that the subtype header fits within the image,
but does not verify that the advertised subtype length fits. A malformed
CRAT table with an oversized length field causes out-of-bounds reads when
kfd_parse_subtype() casts the header to specific subtype structures.
Add validation that sub_type_hdr + length does not exceed the image
boundary before parsing the subtype contents.
Signed-off-by: William Palacek <William.Palacek@amd.com>
Reviewed-by: Alysa Liu <Alysa.Liu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 48e1d1e6e8798aef0312e68d8e586021b5b3cf4d)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
index 36c259b34afd9..f4e40ed231fb0 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c
@@ -1411,6 +1411,15 @@ int kfd_parse_crat_table(void *crat_image, struct list_head *device_list,
break;
}
+ /* Validate subtype fits within remaining image */
+ if ((char *)sub_type_hdr + sub_type_hdr->length >
+ (char *)crat_image + image_len) {
+ pr_warn("CRAT subtype length %u exceeds image bounds\n",
+ sub_type_hdr->length);
+ ret = -EINVAL;
+ break;
+ }
+
if (sub_type_hdr->flags & CRAT_SUBTYPE_FLAGS_ENABLED) {
ret = kfd_parse_subtype(sub_type_hdr, device_list);
if (ret)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 552/869] Bluetooth: ISO: zero the sockaddr before returning it in getname
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (550 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 551/869] drm/amdkfd: Add bounds check for CRAT " Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 553/869] fbdev: Wrap user-invoked calls to fb_set_var() in helper Greg Kroah-Hartman
` (317 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ali Ahmet Memis,
Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <ali@iusegentoo.com>
[ Upstream commit 884cf2cc957da7ac178a0e6c6c69ddfec0481cc8 ]
iso_sock_getname() fills a struct sockaddr_iso in place and returns its
size without clearing it first, so bytes it does not write are copied to
user space from the kernel stack. The getsockname(2) and getpeername(2)
paths both run through do_getsockname(), which hands getname() an
uninitialized sockaddr_storage on the stack and copies back up to the
number of bytes getname() returns, so the driver has to initialize every
byte it accounts for.
Two ranges are left uninitialized:
- struct sockaddr_iso is 10 bytes but only 9 are written (family,
iso_bdaddr, iso_bdaddr_type), leaking the trailing pad byte on every
call.
- for a broadcast peer (BIS_LINK or PA_LINK) the returned length grows
by sizeof(struct sockaddr_iso_bc), but only bc_sid, bc_num_bis and
bc_bis are filled; bc_bdaddr and bc_bdaddr_type, the first 7 bytes of
that structure, are never written.
An unprivileged process can open a BTPROTO_ISO socket and reach the pad
leak with getsockname(); the broadcast leak needs an established BIS/PA
connection. l2cap and rfcomm already memset their sockaddr in getname
for the same reason; do the same here.
Fixes: ccf74f2390d6 ("Bluetooth: Add BTPROTO_ISO socket type")
Fixes: 0a766a0affb5 ("Bluetooth: ISO: Fix getpeername not returning sockaddr_iso_bc fields")
Cc: stable@vger.kernel.org
Signed-off-by: Ali Ahmet Memis <ali@iusegentoo.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/iso.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index eafa22468e5f0..98261072aa050 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -1397,6 +1397,7 @@ static int iso_sock_getname(struct socket *sock, struct sockaddr *addr,
BT_DBG("sock %p, sk %p", sock, sk);
+ memset(sa, 0, sizeof(struct sockaddr_iso));
addr->sa_family = AF_BLUETOOTH;
if (peer) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 553/869] fbdev: Wrap user-invoked calls to fb_set_var() in helper
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (551 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 552/869] Bluetooth: ISO: zero the sockaddr before returning it in getname Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 554/869] tipc: avoid busy looping in tipc_exit_net() Greg Kroah-Hartman
` (316 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Thomas Zimmermann, Helge Deller,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <tzimmermann@suse.de>
[ Upstream commit 6f611e5e5f3327cf2e2daabe6ee5acac58cc784e ]
Handle fbcon during display updates in fb_set_var_from_user(). Check
with fbcon if the mode change is possible, update hardware state and
finally update fbcon. Update all callers.
Only the FBIOPUT_VSCREENINFO ioctl currently does all steps. Other
mode-changes callers in sysfs and driver code are missing fbcon-related
steps.
With the new helper, ps3fb and sh_mobile_lcdcfb no longer maintain
fbcon state themselves.
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/video/fbdev/core/fb_chrdev.c | 6 +-----
drivers/video/fbdev/core/fbcon.c | 2 --
drivers/video/fbdev/core/fbmem.c | 13 +++++++++++++
drivers/video/fbdev/core/fbsysfs.c | 4 +---
drivers/video/fbdev/ps3fb.c | 5 +----
drivers/video/fbdev/sh_mobile_lcdcfb.c | 5 +----
include/linux/fb.h | 2 ++
7 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/drivers/video/fbdev/core/fb_chrdev.c b/drivers/video/fbdev/core/fb_chrdev.c
index 4ebd16b7e3b8d..54f926fb411bd 100644
--- a/drivers/video/fbdev/core/fb_chrdev.c
+++ b/drivers/video/fbdev/core/fb_chrdev.c
@@ -85,11 +85,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
var.activate &= ~FB_ACTIVATE_KD_TEXT;
console_lock();
lock_fb_info(info);
- ret = fbcon_modechange_possible(info, &var);
- if (!ret)
- ret = fb_set_var(info, &var);
- if (!ret)
- fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL);
+ ret = fb_set_var_from_user(info, &var);
unlock_fb_info(info);
console_unlock();
if (!ret && copy_to_user(argp, &var, sizeof(var)))
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 024cad45af930..5ce1aba2e7615 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2754,7 +2754,6 @@ void fbcon_update_vcs(struct fb_info *info, bool all)
else
fbcon_modechanged(info);
}
-EXPORT_SYMBOL(fbcon_update_vcs);
/* let fbcon check if it supports a new screen resolution */
int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *var)
@@ -2782,7 +2781,6 @@ int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *va
return 0;
}
-EXPORT_SYMBOL_GPL(fbcon_modechange_possible);
int fbcon_mode_deleted(struct fb_info *info,
struct fb_videomode *mode)
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index a689b390fce33..044a8f327cc22 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -341,6 +341,19 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
}
EXPORT_SYMBOL(fb_set_var);
+int fb_set_var_from_user(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+ int ret = fbcon_modechange_possible(info, var);
+
+ if (!ret)
+ ret = fb_set_var(info, var);
+ if (!ret)
+ fbcon_update_vcs(info, var->activate & FB_ACTIVATE_ALL);
+
+ return ret;
+}
+EXPORT_SYMBOL(fb_set_var_from_user);
+
int
fb_blank(struct fb_info *info, int blank)
{
diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c
index 10c3cfb959f4f..572bf45d9d980 100644
--- a/drivers/video/fbdev/core/fbsysfs.c
+++ b/drivers/video/fbdev/core/fbsysfs.c
@@ -22,9 +22,7 @@ static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
var->activate |= FB_ACTIVATE_FORCE;
console_lock();
lock_fb_info(fb_info);
- err = fb_set_var(fb_info, var);
- if (!err)
- fbcon_update_vcs(fb_info, var->activate & FB_ACTIVATE_ALL);
+ err = fb_set_var_from_user(fb_info, var);
unlock_fb_info(fb_info);
console_unlock();
if (err)
diff --git a/drivers/video/fbdev/ps3fb.c b/drivers/video/fbdev/ps3fb.c
index dbcda307f6a67..1376d19b19aeb 100644
--- a/drivers/video/fbdev/ps3fb.c
+++ b/drivers/video/fbdev/ps3fb.c
@@ -29,7 +29,6 @@
#include <linux/freezer.h>
#include <linux/uaccess.h>
#include <linux/fb.h>
-#include <linux/fbcon.h>
#include <linux/init.h>
#include <asm/cell-regs.h>
@@ -830,9 +829,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
/* Force, in case only special bits changed */
var.activate |= FB_ACTIVATE_FORCE;
par->new_mode_id = val;
- retval = fb_set_var(info, &var);
- if (!retval)
- fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL);
+ retval = fb_set_var_from_user(info, &var);
console_unlock();
}
break;
diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c
index 6b37b188af314..84aa2086d5ae2 100644
--- a/drivers/video/fbdev/sh_mobile_lcdcfb.c
+++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c
@@ -15,7 +15,6 @@
#include <linux/ctype.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
-#include <linux/fbcon.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ioctl.h>
@@ -1769,11 +1768,9 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
var.height = ch->display.height;
var.activate = FB_ACTIVATE_NOW;
- if (fb_set_var(info, &var) < 0)
+ if (fb_set_var_from_user(info, &var) < 0)
/* Couldn't reconfigure, hopefully, can continue as before */
return;
-
- fbcon_update_vcs(info, true);
}
/*
diff --git a/include/linux/fb.h b/include/linux/fb.h
index d87d6547c6e41..8f41d449fb9de 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -537,6 +537,8 @@ extern int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var);
extern int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var);
extern int fb_blank(struct fb_info *info, int blank);
+int fb_set_var_from_user(struct fb_info *info, struct fb_var_screeninfo *var);
+
/*
* Helpers for framebuffers in I/O memory
*/
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 554/869] tipc: avoid busy looping in tipc_exit_net()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (552 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 553/869] fbdev: Wrap user-invoked calls to fb_set_var() in helper Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 555/869] NTB: core: Add .get_dma_dev() callback to ntb_dev_ops Greg Kroah-Hartman
` (315 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Dumazet, Jon Maloy,
tipc-discussion, Xin Long, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit c1481c94e74c955e0448ddf46b8615a44d840c1e ]
Blamed commit introduced a busy-wait loop in tipc_exit_net()
to wait for pending UDP bearer cleanup works to complete:
while (atomic_read(&tn->wq_count))
cond_resched();
This loop can busy-wait for a long time if cond_resched() is a NOP. This
typically happens if the netns exit is executed by a high priority task,
or under kernels configured without preemption (CONFIG_PREEMPT_NONE). In
such cases, it wastes CPU cycles and can lead to soft lockups.
Fix this by replacing the busy loop with wait_var_event(), allowing the
thread to sleep properly until the work queue count reaches zero.
Accordingly, update cleanup_bearer() to use atomic_dec_and_test() and
wake_up_var() to wake up the waiter when the count drops to zero.
This uses the global wait queue hash table, avoiding the need to bloat
struct tipc_net with a wait_queue_head_t. The atomic_dec_and_test()
provides the necessary memory barrier to ensure the wakeup is not missed.
Fixes: 04c26faa51d1 ("tipc: wait and exit until all work queues are done")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Jon Maloy <jmaloy@redhat.com>
Cc: tipc-discussion@lists.sourceforge.net
Reviewed-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/20260623173030.2925059-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/tipc/core.c | 4 ++--
net/tipc/udp_media.c | 4 +++-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 1ddecea1df6e9..315975c3be818 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -45,6 +45,7 @@
#include "crypto.h"
#include <linux/module.h>
+#include <linux/wait_bit.h>
/* configurable TIPC parameters */
unsigned int tipc_net_id __read_mostly;
@@ -118,8 +119,7 @@ static void __net_exit tipc_exit_net(struct net *net)
#ifdef CONFIG_TIPC_CRYPTO
tipc_crypto_stop(&tipc_net(net)->crypto_tx);
#endif
- while (atomic_read(&tn->wq_count))
- cond_resched();
+ wait_var_event(&tn->wq_count, atomic_read(&tn->wq_count) == 0);
}
static void __net_exit tipc_pernet_pre_exit(struct net *net)
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
index 311ebc6163855..17385de8bfcde 100644
--- a/net/tipc/udp_media.c
+++ b/net/tipc/udp_media.c
@@ -40,6 +40,7 @@
#include <linux/igmp.h>
#include <linux/kernel.h>
#include <linux/workqueue.h>
+#include <linux/wait_bit.h>
#include <linux/list.h>
#include <net/sock.h>
#include <net/ip.h>
@@ -827,7 +828,8 @@ static void cleanup_bearer(struct work_struct *work)
synchronize_net();
dst_cache_destroy(&ub->rcast.dst_cache);
- atomic_dec(&tn->wq_count);
+ if (atomic_dec_and_test(&tn->wq_count))
+ wake_up_var(&tn->wq_count);
kfree(ub);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 555/869] NTB: core: Add .get_dma_dev() callback to ntb_dev_ops
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (553 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 554/869] tipc: avoid busy looping in tipc_exit_net() Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 556/869] NTB: ntb_transport: Use ntb_get_dma_dev() for DMA buffers Greg Kroah-Hartman
` (314 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Frank Li, Koichiro Den,
Manivannan Sadhasivam, Bjorn Helgaas, Dave Jiang, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <den@valinux.co.jp>
[ Upstream commit 362a4549f2acfb03390ddfcd91041e65a11a739f ]
Some NTB implementations are backed by a PCI function that is not the right
struct device to use with DMA API helpers (e.g. due to IOMMU topology, or
because the NTB device is virtual).
Add an optional .get_dma_dev() callback to struct ntb_dev_ops and provide a
helper, ntb_get_dma_dev(), so NTB clients can use the appropriate struct
device for DMA allocations and mappings.
If the callback is not implemented, ntb_get_dma_dev() returns the current
default (ntb->dev.parent). Drivers that implement .get_dma_dev() must
return a non-NULL device.
Suggested-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
[bhelgaas: format doc]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://patch.msgid.link/20260306031443.1911860-2-den@valinux.co.jp
Stable-dep-of: da6d997ac556 ("ntb: Store original DMA address for future release")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/ntb.h | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 191b524e5c0dc..5c29e904a9c52 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -256,6 +256,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @msg_clear_mask: See ntb_msg_clear_mask().
* @msg_read: See ntb_msg_read().
* @peer_msg_write: See ntb_peer_msg_write().
+ * @get_dma_dev: See ntb_get_dma_dev().
*/
struct ntb_dev_ops {
int (*port_number)(struct ntb_dev *ntb);
@@ -329,6 +330,7 @@ struct ntb_dev_ops {
int (*msg_clear_mask)(struct ntb_dev *ntb, u64 mask_bits);
u32 (*msg_read)(struct ntb_dev *ntb, int *pidx, int midx);
int (*peer_msg_write)(struct ntb_dev *ntb, int pidx, int midx, u32 msg);
+ struct device *(*get_dma_dev)(struct ntb_dev *ntb);
};
static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
@@ -391,6 +393,8 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
/* !ops->msg_clear_mask == !ops->msg_count && */
!ops->msg_read == !ops->msg_count &&
!ops->peer_msg_write == !ops->msg_count &&
+
+ /* ops->get_dma_dev is optional */
1;
}
@@ -1563,6 +1567,26 @@ static inline int ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx,
return ntb->ops->peer_msg_write(ntb, pidx, midx, msg);
}
+/**
+ * ntb_get_dma_dev() - get the device to use for DMA allocations/mappings
+ * @ntb: NTB device context.
+ *
+ * Return a struct device suitable for DMA API allocations and mappings.
+ * This is typically the parent of the NTB device, but may be overridden by a
+ * driver by implementing .get_dma_dev().
+ *
+ * Drivers that implement .get_dma_dev() must return a non-NULL pointer.
+ *
+ * Return: device pointer to use for DMA operations.
+ */
+static inline struct device *ntb_get_dma_dev(struct ntb_dev *ntb)
+{
+ if (!ntb->ops->get_dma_dev)
+ return ntb->dev.parent;
+
+ return ntb->ops->get_dma_dev(ntb);
+}
+
/**
* ntb_peer_resource_idx() - get a resource index for a given peer idx
* @ntb: NTB device context.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 556/869] NTB: ntb_transport: Use ntb_get_dma_dev() for DMA buffers
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (554 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 555/869] NTB: core: Add .get_dma_dev() callback to ntb_dev_ops Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 557/869] ntb: Store original DMA address for future release Greg Kroah-Hartman
` (313 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Frank Li, Koichiro Den,
Manivannan Sadhasivam, Bjorn Helgaas, Dave Jiang, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <den@valinux.co.jp>
[ Upstream commit 852b94ff92cbe26a0dbb15eed9474f5493767f3b ]
ntb_transport currently uses ndev->pdev->dev for coherent allocations
and frees.
Switch the coherent buffer allocation/free paths to use
ntb_get_dma_dev(), so ntb_transport can work with NTB implementations
where the NTB PCI function is not the right device to use for DMA
mappings.
Suggested-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://patch.msgid.link/20260306031443.1911860-3-den@valinux.co.jp
Stable-dep-of: da6d997ac556 ("ntb: Store original DMA address for future release")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ntb/ntb_transport.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index b9e465db20159..3928bcbc830d0 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -793,13 +793,13 @@ static void ntb_transport_msi_desc_changed(void *data)
static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
{
struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
- struct pci_dev *pdev = nt->ndev->pdev;
+ struct device *dma_dev = ntb_get_dma_dev(nt->ndev);
if (!mw->virt_addr)
return;
ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
- dma_free_coherent(&pdev->dev, mw->alloc_size,
+ dma_free_coherent(dma_dev, mw->alloc_size,
mw->alloc_addr, mw->dma_addr);
mw->xlat_size = 0;
mw->buff_size = 0;
@@ -869,7 +869,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
resource_size_t size)
{
struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
- struct pci_dev *pdev = nt->ndev->pdev;
+ struct device *dma_dev = ntb_get_dma_dev(nt->ndev);
size_t xlat_size, buff_size;
resource_size_t xlat_align;
resource_size_t xlat_align_size;
@@ -898,12 +898,12 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
mw->buff_size = buff_size;
mw->alloc_size = buff_size;
- rc = ntb_alloc_mw_buffer(mw, &pdev->dev, xlat_align);
+ rc = ntb_alloc_mw_buffer(mw, dma_dev, xlat_align);
if (rc) {
mw->alloc_size *= 2;
- rc = ntb_alloc_mw_buffer(mw, &pdev->dev, xlat_align);
+ rc = ntb_alloc_mw_buffer(mw, dma_dev, xlat_align);
if (rc) {
- dev_err(&pdev->dev,
+ dev_err(dma_dev,
"Unable to alloc aligned MW buff\n");
mw->xlat_size = 0;
mw->buff_size = 0;
@@ -916,7 +916,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
rc = ntb_mw_set_trans(nt->ndev, PIDX, num_mw, mw->dma_addr,
mw->xlat_size);
if (rc) {
- dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw);
+ dev_err(dma_dev, "Unable to set mw%d translation", num_mw);
ntb_free_mw(nt, num_mw);
return -EIO;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 557/869] ntb: Store original DMA address for future release
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (555 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 556/869] NTB: ntb_transport: Use ntb_get_dma_dev() for DMA buffers Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 558/869] tap: Keep hdr_len in tap_get_user() Greg Kroah-Hartman
` (312 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Leon Romanovsky, Dave Jiang,
Marek Szyprowski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <leonro@nvidia.com>
[ Upstream commit da6d997ac556479c112554ab5d95cbd04683eb11 ]
The DMA API requires that dma_free_attrs receive the exact dma_handle
originally returned by the allocation function. Do not modify it.
Fixes: fc5d1829f9bf ("NTB: transport: Try harder to alloc an aligned MW buffer")
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Link: https://lore.kernel.org/r/20260501-dma-attrs-debug-v2-1-8dbac75cd501@nvidia.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ntb/ntb_transport.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 3928bcbc830d0..398b0e0ff842e 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -211,6 +211,7 @@ struct ntb_transport_mw {
void *alloc_addr;
void *virt_addr;
dma_addr_t dma_addr;
+ dma_addr_t original_dma_addr;
};
struct ntb_transport_client_dev {
@@ -800,7 +801,7 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
dma_free_coherent(dma_dev, mw->alloc_size,
- mw->alloc_addr, mw->dma_addr);
+ mw->alloc_addr, mw->original_dma_addr);
mw->xlat_size = 0;
mw->buff_size = 0;
mw->alloc_size = 0;
@@ -836,6 +837,7 @@ static int ntb_alloc_mw_buffer(struct ntb_transport_mw *mw,
return -ENOMEM;
}
virt_addr = alloc_addr;
+ mw->original_dma_addr = dma_addr;
/*
* we must ensure that the memory address allocated is BAR size
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 558/869] tap: Keep hdr_len in tap_get_user()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (556 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 557/869] ntb: Store original DMA address for future release Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 559/869] net: tap: fix wrong transport_header when sending VLAN-tagged frame Greg Kroah-Hartman
` (311 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Akihiko Odaki, Willem de Bruijn,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Akihiko Odaki <akihiko.odaki@daynix.com>
[ Upstream commit 74212f20f366db41dd3148b951284ac38ef9bb10 ]
hdr_len is repeatedly used so keep it in a local variable.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Link: https://patch.msgid.link/20250207-tun-v6-6-fb49cf8b103e@daynix.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: cbb35cbe8db2 ("net: tap: fix wrong transport_header when sending VLAN-tagged frame")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/tap.c | 28 ++++++++++------------------
1 file changed, 10 insertions(+), 18 deletions(-)
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index 018bc2941a967..d5a1ab9b2a37d 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -645,6 +645,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
int err;
struct virtio_net_hdr vnet_hdr = { 0 };
int vnet_hdr_len = 0;
+ int hdr_len = 0;
int copylen = 0;
int depth;
bool zerocopy = false;
@@ -663,13 +664,13 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
if (!copy_from_iter_full(&vnet_hdr, sizeof(vnet_hdr), from))
goto err;
iov_iter_advance(from, vnet_hdr_len - sizeof(vnet_hdr));
- if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
- tap16_to_cpu(q, vnet_hdr.csum_start) +
- tap16_to_cpu(q, vnet_hdr.csum_offset) + 2 >
- tap16_to_cpu(q, vnet_hdr.hdr_len))
- vnet_hdr.hdr_len = cpu_to_tap16(q,
- tap16_to_cpu(q, vnet_hdr.csum_start) +
- tap16_to_cpu(q, vnet_hdr.csum_offset) + 2);
+ hdr_len = tap16_to_cpu(q, vnet_hdr.hdr_len);
+ if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
+ hdr_len = max(tap16_to_cpu(q, vnet_hdr.csum_start) +
+ tap16_to_cpu(q, vnet_hdr.csum_offset) + 2,
+ hdr_len);
+ vnet_hdr.hdr_len = cpu_to_tap16(q, hdr_len);
+ }
err = -EINVAL;
if (tap16_to_cpu(q, vnet_hdr.hdr_len) > len)
goto err;
@@ -682,12 +683,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
if (msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) {
struct iov_iter i;
- copylen = vnet_hdr.hdr_len ?
- tap16_to_cpu(q, vnet_hdr.hdr_len) : GOODCOPY_LEN;
- if (copylen > good_linear)
- copylen = good_linear;
- else if (copylen < ETH_HLEN)
- copylen = ETH_HLEN;
+ copylen = clamp(hdr_len ?: GOODCOPY_LEN, ETH_HLEN, good_linear);
linear = copylen;
i = *from;
iov_iter_advance(&i, copylen);
@@ -697,11 +693,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
if (!zerocopy) {
copylen = len;
- linear = tap16_to_cpu(q, vnet_hdr.hdr_len);
- if (linear > good_linear)
- linear = good_linear;
- else if (linear < ETH_HLEN)
- linear = ETH_HLEN;
+ linear = clamp(hdr_len, ETH_HLEN, good_linear);
}
skb = tap_alloc_skb(&q->sk, TAP_RESERVE, copylen,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 559/869] net: tap: fix wrong transport_header when sending VLAN-tagged frame
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (557 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 558/869] tap: Keep hdr_len in tap_get_user() Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 560/869] io_uring: defer eventfd signaling when queued from a wakeup handler Greg Kroah-Hartman
` (310 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Wei Fang, Willem de Bruijn,
Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Fang <wei.fang@nxp.com>
[ Upstream commit cbb35cbe8db268fefe34c23df15348cf99025298 ]
In tap_get_user_xdp(), when processing a VLAN-tagged frame (e.g.
ETH_P_8021Q), skb_set_network_header() is called first to advance
network_header past the VLAN tag to the inner protocol header.
skb_probe_transport_header() is then called with skb->protocol still
set to ETH_P_8021Q, while nhoff (derived from skb_network_offset())
already points past the VLAN tag to the inner protocol header.
In __skb_flow_dissect(), proto is initialized to ETH_P_8021Q and nhoff
points past the VLAN tag. When the dissector hits case ETH_P_8021Q, it
reads a struct vlan_hdr at the current nhoff via __skb_header_pointer(),
but that offset contains the inner protocol header (e.g. an IP header).
The bytes are misinterpreted as a VLAN header, yielding a garbage
encapsulated EtherType that matches no known protocol. The dissector
returns false, so skb_probe_transport_header() never calls
skb_set_transport_header(), leaving transport_header at its uninitialized
sentinel value (~0U).
Move skb_set_network_header() to after skb_probe_transport_header(). At
the time skb_probe_transport_header() is called, network_header still
points to the VLAN header (offset ETH_HLEN), so nhoff is correct and the
flow dissector can parse the VLAN header, extract the inner EtherType,
and advance nhoff to the inner protocol header, allowing transport_header
to be set correctly.
Fixes: 8c76e77f9069 ("tap: call skb_probe_transport_header after setting skb->dev")
Assisted-by: WChat:claude-opus-4-8
Signed-off-by: Wei Fang <wei.fang@nxp.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Link: https://patch.msgid.link/20260807063405.688780-3-wei.fang@oss.nxp.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/tap.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index d5a1ab9b2a37d..fcc9d135c5fc2 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -1208,12 +1208,13 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
}
}
+ skb_probe_transport_header(skb);
+
/* Move network header to the right position for VLAN tagged packets */
if (eth_type_vlan(skb->protocol) &&
vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)
skb_set_network_header(skb, depth);
- skb_probe_transport_header(skb);
dev_queue_xmit(skb);
rcu_read_unlock();
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 560/869] io_uring: defer eventfd signaling when queued from a wakeup handler
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (558 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 559/869] net: tap: fix wrong transport_header when sending VLAN-tagged frame Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 561/869] wifi: iwlwifi: dvm: pair transport op-mode enter/leave Greg Kroah-Hartman
` (309 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jens Axboe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <axboe@kernel.dk>
[ Upstream commit cd305ee3633a45fcf5f3a5d83f99f3cb77d87b6e ]
io_req_local_work_add() signals the CQ ring eventfd inline when it is the
one to push the first entry onto ->work_list. For DEFER_TASKRUN rings that
add is frequently done from a waitqueue wakeup handler, where an
arbitrary waitqueue lock is held.
eventfd_signal_mask() only refuses to recurse when current->in_eventfd
is set, but that bit is set by eventfd_signal_mask() itself. If the wake
chain starts somewhere else, signal goes out inline and can feed back
into epoll.
Add IOU_F_TWQ_IN_WAKE, set it on the task_work add done from the three
waitqueue callbacks, and use it to force io_eventfd_signal() down the
existing call_rcu_hurry() deferral instead of signaling inline.
Fixes: 21a091b970cd ("io_uring: signal registered eventfd to process deferred task work")
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/all/20260813133843.2933127-1-4ncienth@gmail.com/
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/io_uring_types.h | 8 ++++++++
io_uring/eventfd.c | 6 +++---
io_uring/eventfd.h | 2 +-
io_uring/futex.c | 4 ++--
io_uring/io_uring.c | 2 +-
io_uring/poll.c | 23 ++++++++++++-----------
io_uring/waitid.c | 2 +-
7 files changed, 28 insertions(+), 19 deletions(-)
diff --git a/include/linux/io_uring_types.h b/include/linux/io_uring_types.h
index 6d47d0d3fde01..7711d99201414 100644
--- a/include/linux/io_uring_types.h
+++ b/include/linux/io_uring_types.h
@@ -17,6 +17,14 @@ enum {
* It's also ignored unless IORING_SETUP_DEFER_TASKRUN is set.
*/
IOU_F_TWQ_LAZY_WAKE = 1,
+
+ /*
+ * Set when task_work is queued from a waitqueue wakeup handler, where
+ * an arbitrary provider waitqueue lock is held. Signaling the CQ ring
+ * eventfd inline from there can recurse back into that lock through
+ * epoll, so the eventfd signal must be deferred.
+ */
+ IOU_F_TWQ_IN_WAKE = 2,
};
enum io_uring_cmd_flags {
diff --git a/io_uring/eventfd.c b/io_uring/eventfd.c
index ffc4bd17d0786..6a6ec9d4d6402 100644
--- a/io_uring/eventfd.c
+++ b/io_uring/eventfd.c
@@ -41,7 +41,7 @@ static void io_eventfd_do_signal(struct rcu_head *rcu)
call_rcu(&ev_fd->rcu, io_eventfd_free);
}
-void io_eventfd_signal(struct io_ring_ctx *ctx)
+void io_eventfd_signal(struct io_ring_ctx *ctx, bool defer)
{
struct io_ev_fd *ev_fd = NULL;
@@ -68,7 +68,7 @@ void io_eventfd_signal(struct io_ring_ctx *ctx)
if (ev_fd->eventfd_async && !io_wq_current_is_worker())
goto out;
- if (likely(eventfd_signal_allowed())) {
+ if (likely(!defer && eventfd_signal_allowed())) {
eventfd_signal_mask(ev_fd->cq_ev_fd, EPOLL_URING_WAKE);
} else {
if (!atomic_fetch_or(BIT(IO_EVENTFD_OP_SIGNAL_BIT), &ev_fd->ops)) {
@@ -101,7 +101,7 @@ void io_eventfd_flush_signal(struct io_ring_ctx *ctx)
if (skip)
return;
- io_eventfd_signal(ctx);
+ io_eventfd_signal(ctx, false);
}
int io_eventfd_register(struct io_ring_ctx *ctx, void __user *arg,
diff --git a/io_uring/eventfd.h b/io_uring/eventfd.h
index d394f49c63210..c93f32d594072 100644
--- a/io_uring/eventfd.h
+++ b/io_uring/eventfd.h
@@ -5,4 +5,4 @@ int io_eventfd_register(struct io_ring_ctx *ctx, void __user *arg,
int io_eventfd_unregister(struct io_ring_ctx *ctx);
void io_eventfd_flush_signal(struct io_ring_ctx *ctx);
-void io_eventfd_signal(struct io_ring_ctx *ctx);
+void io_eventfd_signal(struct io_ring_ctx *ctx, bool defer);
diff --git a/io_uring/futex.c b/io_uring/futex.c
index a3d2b700b480c..589769761cea1 100644
--- a/io_uring/futex.c
+++ b/io_uring/futex.c
@@ -201,7 +201,7 @@ static void io_futex_wakev_fn(struct wake_q_head *wake_q, struct futex_q *q)
io_req_set_res(req, 0, 0);
req->io_task_work.func = io_futexv_complete;
- io_req_task_work_add(req);
+ __io_req_task_work_add(req, IOU_F_TWQ_IN_WAKE);
}
int io_futexv_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
@@ -248,7 +248,7 @@ static void io_futex_wake_fn(struct wake_q_head *wake_q, struct futex_q *q)
io_req_set_res(req, 0, 0);
req->io_task_work.func = io_futex_complete;
- io_req_task_work_add(req);
+ __io_req_task_work_add(req, IOU_F_TWQ_IN_WAKE);
}
static struct io_futex_data *io_alloc_ifd(struct io_ring_ctx *ctx)
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 1e7963cc30d3e..0076c7599c947 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -1201,7 +1201,7 @@ static inline void io_req_local_work_add(struct io_kiocb *req,
if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
atomic_or(IORING_SQ_TASKRUN, &ctx->rings->sq_flags);
if (ctx->has_evfd)
- io_eventfd_signal(ctx);
+ io_eventfd_signal(ctx, flags & IOU_F_TWQ_IN_WAKE);
}
nr_wait = atomic_read(&ctx->cq_wait_nr);
diff --git a/io_uring/poll.c b/io_uring/poll.c
index 002f1ae830b8a..1a6179ac491bf 100644
--- a/io_uring/poll.c
+++ b/io_uring/poll.c
@@ -231,9 +231,9 @@ enum {
IOU_POLL_REQUEUE = 4,
};
-static void __io_poll_execute(struct io_kiocb *req, int mask)
+static void __io_poll_execute(struct io_kiocb *req, int mask, unsigned tw_flags)
{
- unsigned flags = 0;
+ unsigned flags = tw_flags;
io_req_set_res(req, mask, 0);
req->io_task_work.func = io_poll_task_func;
@@ -241,14 +241,15 @@ static void __io_poll_execute(struct io_kiocb *req, int mask)
trace_io_uring_task_add(req, mask);
if (!(req->flags & REQ_F_POLL_NO_LAZY))
- flags = IOU_F_TWQ_LAZY_WAKE;
+ flags |= IOU_F_TWQ_LAZY_WAKE;
__io_req_task_work_add(req, flags);
}
-static inline void io_poll_execute(struct io_kiocb *req, int res)
+static inline void io_poll_execute(struct io_kiocb *req, int res,
+ unsigned tw_flags)
{
if (io_poll_get_ownership(req))
- __io_poll_execute(req, res);
+ __io_poll_execute(req, res, tw_flags);
}
/*
@@ -363,7 +364,7 @@ void io_poll_task_func(struct io_kiocb *req, struct io_tw_state *ts)
if (ret == IOU_POLL_NO_ACTION) {
return;
} else if (ret == IOU_POLL_REQUEUE) {
- __io_poll_execute(req, 0);
+ __io_poll_execute(req, 0, 0);
return;
}
io_poll_remove_entries(req);
@@ -401,7 +402,7 @@ static void io_poll_cancel_req(struct io_kiocb *req)
{
io_poll_mark_cancelled(req);
/* kick tw, which should complete the request */
- io_poll_execute(req, 0);
+ io_poll_execute(req, 0, 0);
}
#define IO_ASYNC_POLL_COMMON (EPOLLONESHOT | EPOLLPRI)
@@ -410,7 +411,7 @@ static __cold int io_pollfree_wake(struct io_kiocb *req, struct io_poll *poll)
{
io_poll_mark_cancelled(req);
/* we have to kick tw in case it's not already */
- io_poll_execute(req, 0);
+ io_poll_execute(req, 0, IOU_F_TWQ_IN_WAKE);
/*
* If the waitqueue is being freed early but someone is already
@@ -465,7 +466,7 @@ static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
else
req->flags &= ~REQ_F_SINGLE_POLL;
}
- __io_poll_execute(req, mask);
+ __io_poll_execute(req, mask, IOU_F_TWQ_IN_WAKE);
}
return 1;
}
@@ -657,7 +658,7 @@ static int __io_arm_poll_handler(struct io_kiocb *req,
if (mask && (poll->events & EPOLLET) &&
io_poll_can_finish_inline(req, ipt)) {
- __io_poll_execute(req, mask);
+ __io_poll_execute(req, mask, 0);
return 0;
}
io_napi_add(req);
@@ -668,7 +669,7 @@ static int __io_arm_poll_handler(struct io_kiocb *req,
* poll was waken up, queue up a tw, it'll deal with it.
*/
if (atomic_cmpxchg(&req->poll_refs, 1, 0) != 1)
- __io_poll_execute(req, 0);
+ __io_poll_execute(req, 0, 0);
}
return 0;
}
diff --git a/io_uring/waitid.c b/io_uring/waitid.c
index 7f3a6c2d9f807..4475b02bafbad 100644
--- a/io_uring/waitid.c
+++ b/io_uring/waitid.c
@@ -298,7 +298,7 @@ static int io_waitid_wait(struct wait_queue_entry *wait, unsigned mode,
return 1;
req->io_task_work.func = io_waitid_cb;
- io_req_task_work_add(req);
+ __io_req_task_work_add(req, IOU_F_TWQ_IN_WAKE);
return 1;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 561/869] wifi: iwlwifi: dvm: pair transport op-mode enter/leave
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (559 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 560/869] io_uring: defer eventfd signaling when queued from a wakeup handler Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 562/869] wifi: iwlwifi: dvm: fix memory leak in iwl_op_mode_dvm_start() Greg Kroah-Hartman
` (308 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johannes Berg, Miri Korenblit,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Berg <johannes.berg@intel.com>
[ Upstream commit 6b340a694cee9e7a24b2be827c738b5b6cb13c84 ]
If there's a failure and the op-mode didn't actually fully
initialize, it should leave the transport again. Fix that.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250504132447.714c3517548b.I49557e7ba8c03be2b558cc9fb5efa2a9fbab890e@changeid
Stable-dep-of: 67105abd6195 ("wifi: iwlwifi: dvm: fix memory leak in iwl_op_mode_dvm_start()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/intel/iwlwifi/dvm/main.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
index a4f6e5a8f3a9d..ee8f588465e61 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
@@ -1386,14 +1386,14 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
err = iwl_trans_start_hw(priv->trans);
if (err)
- goto out_free_hw;
+ goto out_leave_trans;
/* Read the EEPROM */
err = iwl_read_eeprom(priv->trans, &priv->eeprom_blob,
&priv->eeprom_blob_size);
if (err) {
IWL_ERR(priv, "Unable to init EEPROM\n");
- goto out_free_hw;
+ goto out_leave_trans;
}
/* Reset chip to save power until we load uCode during "up". */
@@ -1516,6 +1516,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
kfree(priv->eeprom_blob);
out_free_eeprom:
kfree(priv->nvm_data);
+out_leave_trans:
+ iwl_trans_op_mode_leave(priv->trans);
out_free_hw:
ieee80211_free_hw(priv->hw);
out:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 562/869] wifi: iwlwifi: dvm: fix memory leak in iwl_op_mode_dvm_start()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (560 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 561/869] wifi: iwlwifi: dvm: pair transport op-mode enter/leave Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 563/869] svcrdma: Reject Read lists that exceed the page budget Greg Kroah-Hartman
` (307 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Dawei Feng, Miri Korenblit,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <dawei.feng@seu.edu.cn>
[ Upstream commit 67105abd6195a685a84dcb8a5daf54a1f4bfdb60 ]
In iwl_op_mode_dvm_start(), jumping to out_free_eeprom currently bypasses
the out_free_eeprom_blob label. Consequently, error paths triggered after
successfully parsing the EEPROM free priv->nvm_data but leak
priv->eeprom_blob.
Fix this memory leak by reordering the error handling labels so
that out_free_eeprom falls through to out_free_eeprom_blob.
The bug was first flagged by an experimental analysis tool we are
developing for kernel memory-management bugs while analyzing
v6.13-rc1. The tool is still under development and is not yet publicly
available. Manual inspection confirms that the bug is still
present in v7.1-rc6.
An x86_64 allyesconfig build showed no new warnings. As we do not have
supported Intel DVM wireless hardware and firmware to test with, no
runtime testing was able to be performed.
Cc: stable@vger.kernel.org
Signed-off-by: Dawei Feng <dawei.feng@seu.edu.cn>
Link: https://patch.msgid.link/20260624084404.570703-1-dawei.feng@seu.edu.cn
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/intel/iwlwifi/dvm/main.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
index ee8f588465e61..e9b1a1b09eb29 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c
@@ -1512,10 +1512,10 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
priv->workqueue = NULL;
out_uninit_drv:
iwl_uninit_drv(priv);
-out_free_eeprom_blob:
- kfree(priv->eeprom_blob);
out_free_eeprom:
kfree(priv->nvm_data);
+out_free_eeprom_blob:
+ kfree(priv->eeprom_blob);
out_leave_trans:
iwl_trans_op_mode_leave(priv->trans);
out_free_hw:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 563/869] svcrdma: Reject Read lists that exceed the page budget
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (561 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 562/869] wifi: iwlwifi: dvm: fix memory leak in iwl_op_mode_dvm_start() Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 564/869] svcrdma: Add Write chunk WRs to the RPCs Send WR chain Greg Kroah-Hartman
` (306 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Chuck Lever, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <chuck.lever@oracle.com>
[ Upstream commit 0ca487abb3bdf581851664b5db21f364caf57682 ]
Individual Read segment lengths are validated at decode time, but
nothing prevents a requester from sending multiple segments whose
cumulative length exceeds the rq_pages array budget. When one
segment fills the page array exactly, the runtime guard in
svc_rdma_build_read_segment() is bypassed because len reaches zero.
A subsequent segment then accesses the NULL sentinel slot at
rq_pages[rq_maxpages], resulting in a NULL pointer dereference during
DMA mapping.
Accumulate pages across all Read segments and reject the message at
decode time when the total would overflow the page budget.
Fixes: 026d958b38c6 ("svcrdma: Add recvfrom helpers to svc_rdma_rw.c")
Cc: stable@vger.kernel.org
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
index 68a0aa627455d..1588363f76ac3 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
@@ -430,11 +430,14 @@ static void svc_rdma_build_arg_xdr(struct svc_rqst *rqstp,
* to the first byte past the Read list. rc_read_pcl and
* rc_call_pcl cl_count fields are set to the number of
* Read segments in the list.
- * %false: Read list is corrupt. @rctxt's xdr_stream is left in an
- * unknown state.
+ * %false: Read list is corrupt or exceeds the page budget. @rctxt's
+ * xdr_stream is left in an unknown state.
*/
static bool xdr_count_read_segments(struct svc_rdma_recv_ctxt *rctxt, __be32 *p)
{
+ unsigned int maxlen = (rctxt->rc_maxpages - 2) << PAGE_SHIFT;
+ unsigned int total_len = 0;
+
rctxt->rc_call_pcl.cl_count = 0;
rctxt->rc_read_pcl.cl_count = 0;
while (xdr_item_is_present(p)) {
@@ -448,6 +451,12 @@ static bool xdr_count_read_segments(struct svc_rdma_recv_ctxt *rctxt, __be32 *p)
xdr_decode_read_segment(p, &position, &handle,
&length, &offset);
+ if (length > maxlen)
+ return false;
+ total_len += length;
+ if (PAGE_ALIGN(total_len + rctxt->rc_byte_len -
+ xdr_stream_pos(&rctxt->rc_stream)) > maxlen)
+ return false;
if (position) {
if (position & 3)
return false;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 564/869] svcrdma: Add Write chunk WRs to the RPCs Send WR chain
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (562 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 563/869] svcrdma: Reject Read lists that exceed the page budget Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 565/869] svcrdma: wake sq waiters when the transport closes Greg Kroah-Hartman
` (305 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Chuck Lever, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <chuck.lever@oracle.com>
[ Upstream commit d16f060f3ee297424c0aba047b1d49208adb9318 ]
Previously, Write chunk RDMA Writes were posted via a separate
ib_post_send() call with their own completion handler. Each Write
chunk incurred a doorbell and generated a completion event.
Link Write chunk WRs onto the RPC Reply's Send WR chain so that a
single ib_post_send() call posts both the RDMA Writes and the Send
WR. A single completion event signals that all operations have
finished. This reduces both doorbell rate and completion rate, as
well as eliminating the latency of a round-trip between the Write
chunk completion and the subsequent Send WR posting.
The lifecycle of Write chunk resources changes: previously, the
svc_rdma_write_done() completion handler released Write chunk
resources when RDMA Writes completed. With WR chaining, resources
remain live until the Send completion. A new sc_write_info_list
tracks Write chunk metadata attached to each Send context, and
svc_rdma_write_chunk_release() frees these resources when the
Send context is released.
The svc_rdma_write_done() handler now handles only error cases.
On success it returns immediately since the Send completion handles
resource release. On failure (WR flush), it closes the connection
to signal to the client that the RPC Reply is incomplete.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Stable-dep-of: 01500306e1d5 ("svcrdma: Clear sc_cm_id when ADDR_CHANGE replacement fails")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/sunrpc/svc_rdma.h | 13 +++-
net/sunrpc/xprtrdma/svc_rdma_rw.c | 94 ++++++++++++++++++++-------
net/sunrpc/xprtrdma/svc_rdma_sendto.c | 10 ++-
3 files changed, 91 insertions(+), 26 deletions(-)
diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h
index 1016f2feddc4b..c6f358a6e1597 100644
--- a/include/linux/sunrpc/svc_rdma.h
+++ b/include/linux/sunrpc/svc_rdma.h
@@ -213,6 +213,7 @@ struct svc_rdma_recv_ctxt {
*/
struct svc_rdma_write_info {
struct svcxprt_rdma *wi_rdma;
+ struct list_head wi_list;
const struct svc_rdma_chunk *wi_chunk;
@@ -241,7 +242,10 @@ struct svc_rdma_send_ctxt {
struct ib_cqe sc_cqe;
struct xdr_buf sc_hdrbuf;
struct xdr_stream sc_stream;
+
+ struct list_head sc_write_info_list;
struct svc_rdma_write_info sc_reply_info;
+
void *sc_xprt_buf;
int sc_page_count;
int sc_cur_sge_no;
@@ -273,11 +277,14 @@ extern void svc_rdma_cc_init(struct svcxprt_rdma *rdma,
extern void svc_rdma_cc_release(struct svcxprt_rdma *rdma,
struct svc_rdma_chunk_ctxt *cc,
enum dma_data_direction dir);
+extern void svc_rdma_write_chunk_release(struct svcxprt_rdma *rdma,
+ struct svc_rdma_send_ctxt *ctxt);
extern void svc_rdma_reply_chunk_release(struct svcxprt_rdma *rdma,
struct svc_rdma_send_ctxt *ctxt);
-extern int svc_rdma_send_write_list(struct svcxprt_rdma *rdma,
- const struct svc_rdma_recv_ctxt *rctxt,
- const struct xdr_buf *xdr);
+extern int svc_rdma_prepare_write_list(struct svcxprt_rdma *rdma,
+ const struct svc_rdma_recv_ctxt *rctxt,
+ struct svc_rdma_send_ctxt *sctxt,
+ const struct xdr_buf *xdr);
extern int svc_rdma_prepare_reply_chunk(struct svcxprt_rdma *rdma,
const struct svc_rdma_pcl *write_pcl,
const struct svc_rdma_pcl *reply_pcl,
diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c
index 448d3ee936a5b..ac6f6d15c8335 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_rw.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c
@@ -230,6 +230,28 @@ static void svc_rdma_write_info_free(struct svc_rdma_write_info *info)
queue_work(svcrdma_wq, &info->wi_work);
}
+/**
+ * svc_rdma_write_chunk_release - Release Write chunk I/O resources
+ * @rdma: controlling transport
+ * @ctxt: Send context that is being released
+ *
+ * Write chunk resources remain live until Send completion because
+ * Write WRs are chained to the Send WR. This function releases all
+ * write_info structures accumulated on @ctxt->sc_write_info_list.
+ */
+void svc_rdma_write_chunk_release(struct svcxprt_rdma *rdma,
+ struct svc_rdma_send_ctxt *ctxt)
+{
+ struct svc_rdma_write_info *info;
+
+ while (!list_empty(&ctxt->sc_write_info_list)) {
+ info = list_first_entry(&ctxt->sc_write_info_list,
+ struct svc_rdma_write_info, wi_list);
+ list_del(&info->wi_list);
+ svc_rdma_write_info_free(info);
+ }
+}
+
/**
* svc_rdma_reply_chunk_release - Release Reply chunk I/O resources
* @rdma: controlling transport
@@ -286,13 +308,11 @@ static void svc_rdma_write_done(struct ib_cq *cq, struct ib_wc *wc)
struct ib_cqe *cqe = wc->wr_cqe;
struct svc_rdma_chunk_ctxt *cc =
container_of(cqe, struct svc_rdma_chunk_ctxt, cc_cqe);
- struct svc_rdma_write_info *info =
- container_of(cc, struct svc_rdma_write_info, wi_cc);
switch (wc->status) {
case IB_WC_SUCCESS:
trace_svcrdma_wc_write(&cc->cc_cid);
- break;
+ return;
case IB_WC_WR_FLUSH_ERR:
trace_svcrdma_wc_write_flush(wc, &cc->cc_cid);
break;
@@ -300,12 +320,11 @@ static void svc_rdma_write_done(struct ib_cq *cq, struct ib_wc *wc)
trace_svcrdma_wc_write_err(wc, &cc->cc_cid);
}
- svc_rdma_wake_send_waiters(rdma, cc->cc_sqecount);
-
- if (unlikely(wc->status != IB_WC_SUCCESS))
- svc_xprt_deferred_close(&rdma->sc_xprt);
-
- svc_rdma_write_info_free(info);
+ /* The RDMA Write has flushed, so the client won't get
+ * some of the outgoing RPC message. Signal the loss
+ * to the client by closing the connection.
+ */
+ svc_xprt_deferred_close(&rdma->sc_xprt);
}
/**
@@ -601,13 +620,27 @@ static int svc_rdma_xb_write(const struct xdr_buf *xdr, void *data)
return xdr->len;
}
-static int svc_rdma_send_write_chunk(struct svcxprt_rdma *rdma,
- const struct svc_rdma_chunk *chunk,
- const struct xdr_buf *xdr)
+/*
+ * svc_rdma_prepare_write_chunk - Link Write WRs for @chunk onto @sctxt's chain
+ *
+ * Write WRs are prepended to the Send WR chain so that a single
+ * ib_post_send() posts both RDMA Writes and the final Send. Only
+ * the first WR in each chunk gets a CQE for error detection;
+ * subsequent WRs complete without individual completion events.
+ * The Send WR's signaled completion indicates all chained
+ * operations have finished.
+ */
+static int svc_rdma_prepare_write_chunk(struct svcxprt_rdma *rdma,
+ struct svc_rdma_send_ctxt *sctxt,
+ const struct svc_rdma_chunk *chunk,
+ const struct xdr_buf *xdr)
{
struct svc_rdma_write_info *info;
struct svc_rdma_chunk_ctxt *cc;
+ struct ib_send_wr *first_wr;
struct xdr_buf payload;
+ struct list_head *pos;
+ struct ib_cqe *cqe;
int ret;
if (xdr_buf_subsegment(xdr, &payload, chunk->ch_position,
@@ -623,10 +656,25 @@ static int svc_rdma_send_write_chunk(struct svcxprt_rdma *rdma,
if (ret != payload.len)
goto out_err;
- trace_svcrdma_post_write_chunk(&cc->cc_cid, cc->cc_sqecount);
- ret = svc_rdma_post_chunk_ctxt(rdma, cc);
- if (ret < 0)
+ ret = -EINVAL;
+ if (unlikely(sctxt->sc_sqecount + cc->cc_sqecount > rdma->sc_sq_depth))
goto out_err;
+
+ first_wr = sctxt->sc_wr_chain;
+ cqe = &cc->cc_cqe;
+ list_for_each(pos, &cc->cc_rwctxts) {
+ struct svc_rdma_rw_ctxt *rwc;
+
+ rwc = list_entry(pos, struct svc_rdma_rw_ctxt, rw_list);
+ first_wr = rdma_rw_ctx_wrs(&rwc->rw_ctx, rdma->sc_qp,
+ rdma->sc_port_num, cqe, first_wr);
+ cqe = NULL;
+ }
+ sctxt->sc_wr_chain = first_wr;
+ sctxt->sc_sqecount += cc->cc_sqecount;
+ list_add(&info->wi_list, &sctxt->sc_write_info_list);
+
+ trace_svcrdma_post_write_chunk(&cc->cc_cid, cc->cc_sqecount);
return 0;
out_err:
@@ -635,17 +683,19 @@ static int svc_rdma_send_write_chunk(struct svcxprt_rdma *rdma,
}
/**
- * svc_rdma_send_write_list - Send all chunks on the Write list
+ * svc_rdma_prepare_write_list - Construct WR chain for sending Write list
* @rdma: controlling RDMA transport
* @rctxt: Write list provisioned by the client
+ * @sctxt: Send WR resources
* @xdr: xdr_buf containing an RPC Reply message
*
- * Returns zero on success, or a negative errno if one or more
- * Write chunks could not be sent.
+ * Returns zero on success, or a negative errno if WR chain
+ * construction fails for one or more Write chunks.
*/
-int svc_rdma_send_write_list(struct svcxprt_rdma *rdma,
- const struct svc_rdma_recv_ctxt *rctxt,
- const struct xdr_buf *xdr)
+int svc_rdma_prepare_write_list(struct svcxprt_rdma *rdma,
+ const struct svc_rdma_recv_ctxt *rctxt,
+ struct svc_rdma_send_ctxt *sctxt,
+ const struct xdr_buf *xdr)
{
struct svc_rdma_chunk *chunk;
int ret;
@@ -653,7 +703,7 @@ int svc_rdma_send_write_list(struct svcxprt_rdma *rdma,
pcl_for_each_chunk(chunk, &rctxt->rc_write_pcl) {
if (!chunk->ch_payload_length)
break;
- ret = svc_rdma_send_write_chunk(rdma, chunk, xdr);
+ ret = svc_rdma_prepare_write_chunk(rdma, sctxt, chunk, xdr);
if (ret < 0)
return ret;
}
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index 02aed4932f57d..cdc3f7a1cef53 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -142,6 +142,7 @@ svc_rdma_send_ctxt_alloc(struct svcxprt_rdma *rdma)
ctxt->sc_send_wr.sg_list = ctxt->sc_sges;
ctxt->sc_send_wr.send_flags = IB_SEND_SIGNALED;
ctxt->sc_cqe.done = svc_rdma_wc_send;
+ INIT_LIST_HEAD(&ctxt->sc_write_info_list);
ctxt->sc_xprt_buf = buffer;
xdr_buf_init(&ctxt->sc_hdrbuf, ctxt->sc_xprt_buf,
rdma->sc_max_req_size);
@@ -227,6 +228,7 @@ static void svc_rdma_send_ctxt_release(struct svcxprt_rdma *rdma,
struct ib_device *device = rdma->sc_cm_id->device;
unsigned int i;
+ svc_rdma_write_chunk_release(rdma, ctxt);
svc_rdma_reply_chunk_release(rdma, ctxt);
if (ctxt->sc_page_count)
@@ -983,6 +985,12 @@ void svc_rdma_send_error_msg(struct svcxprt_rdma *rdma,
sctxt->sc_send_wr.num_sge = 1;
sctxt->sc_send_wr.opcode = IB_WR_SEND;
sctxt->sc_sges[0].length = sctxt->sc_hdrbuf.len;
+
+ /* Ensure only the error message is posted, not any previously
+ * prepared Write chunk WRs.
+ */
+ sctxt->sc_wr_chain = &sctxt->sc_send_wr;
+ sctxt->sc_sqecount = 1;
if (svc_rdma_post_send(rdma, sctxt))
goto put_ctxt;
return;
@@ -1030,7 +1038,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
if (!p)
goto put_ctxt;
- ret = svc_rdma_send_write_list(rdma, rctxt, &rqstp->rq_res);
+ ret = svc_rdma_prepare_write_list(rdma, rctxt, sctxt, &rqstp->rq_res);
if (ret < 0)
goto put_ctxt;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 565/869] svcrdma: wake sq waiters when the transport closes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (563 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 564/869] svcrdma: Add Write chunk WRs to the RPCs Send WR chain Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 566/869] svcrdma: Clear sc_cm_id when ADDR_CHANGE replacement fails Greg Kroah-Hartman
` (304 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Chris Mason, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <chuck.lever@oracle.com>
[ Upstream commit e5248a7426030db1e126363f72afdb3b71339a5c ]
Threads parked in svc_rdma_sq_wait() on sc_sq_ticket_wait or
sc_send_wait can hang indefinitely in TASK_UNINTERRUPTIBLE state
across transport teardown, pinning svc_xprt references and
blocking svc_rdma_free().
The close path sets XPT_CLOSE before invoking xpo_detach and both
wait_event predicates include an XPT_CLOSE term, but the
predicates are re-evaluated only on wakeup. sc_sq_ticket_wait has
no completion-driven wake path; it is advanced solely by the
chained ticket handoff inside svc_rdma_sq_wait() itself. Without
an explicit wake at close, parked threads never observe
XPT_CLOSE, hold their svc_xprt_get reference forever, and
svc_rdma_free() blocks on xpt_ref dropping to zero.
Two close entry points reach this transport. Local teardown runs
svc_rdma_detach() from svc_handle_xprt() -> svc_delete_xprt() ->
xpo_detach() on a worker thread. A remote disconnect arrives at
svc_rdma_cma_handler(), which calls svc_xprt_deferred_close():
that sets XPT_CLOSE and enqueues the transport but does not
access either RDMA waitqueue, so a worker already parked in
svc_rdma_sq_wait() never re-evaluates its predicate. With every
worker parked on this transport, no thread is available to run
the local teardown either, and the wake site there is
unreachable.
Introduce svc_rdma_xprt_deferred_close(), a thin svcrdma wrapper
that calls svc_xprt_deferred_close() and then wakes both
sc_sq_ticket_wait and sc_send_wait. Convert the svcrdma producers
that called svc_xprt_deferred_close() directly:
svc_rdma_cma_handler(), qp_event_handler(),
svc_rdma_post_send_err(), svc_rdma_wc_send(), the sendto drop
path, the rw completion error paths, and the recvfrom flush and
read-list error paths.
Wake both waitqueues from svc_rdma_detach() as well. The
synchronous svc_xprt_close() path (backchannel ENOTCONN, device
removal via svc_rdma_xprt_done) reaches detach without flowing
through svc_xprt_deferred_close() and therefore does not invoke
the new helper.
Fixes: ccc89b9d1ed2 ("svcrdma: Add fair queuing for Send Queue access")
Cc: stable@vger.kernel.org
Assisted-by: kres (claude-opus-4-7)
Signed-off-by: Chris Mason <clm@meta.com>
[ cel: add svc_rdma_xprt_deferred_close() to complete the fix ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
[ Adapted: this tree has no ticket-based SQ wait, so only sc_send_wait is
woken, and the XPT_CLOSE predicate and svc_rdma_sq_wait() changes are
omitted. The detach comment is kept to carry context for follow-up patches. ]
Stable-dep-of: 01500306e1d5 ("svcrdma: Clear sc_cm_id when ADDR_CHANGE replacement fails")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/sunrpc/svc_rdma.h | 1 +
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 4 ++--
net/sunrpc/xprtrdma/svc_rdma_rw.c | 8 ++++----
net/sunrpc/xprtrdma/svc_rdma_sendto.c | 6 +++---
net/sunrpc/xprtrdma/svc_rdma_transport.c | 26 ++++++++++++++++++++++--
5 files changed, 34 insertions(+), 11 deletions(-)
diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h
index c6f358a6e1597..65ce45d95f1c2 100644
--- a/include/linux/sunrpc/svc_rdma.h
+++ b/include/linux/sunrpc/svc_rdma.h
@@ -317,6 +317,7 @@ extern int svc_rdma_result_payload(struct svc_rqst *rqstp, unsigned int offset,
unsigned int length);
/* svc_rdma_transport.c */
+extern void svc_rdma_xprt_deferred_close(struct svcxprt_rdma *rdma);
extern struct svc_xprt_class svc_rdma_class;
#ifdef CONFIG_SUNRPC_BACKCHANNEL
extern struct svc_xprt_class svc_rdma_bc_class;
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
index 1588363f76ac3..533ad339054bf 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
@@ -376,7 +376,7 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
trace_svcrdma_wc_recv_err(wc, &ctxt->rc_cid);
dropped:
svc_rdma_recv_ctxt_put(rdma, ctxt);
- svc_xprt_deferred_close(&rdma->sc_xprt);
+ svc_rdma_xprt_deferred_close(rdma);
}
/**
@@ -1019,7 +1019,7 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
if (ret == -EINVAL)
svc_rdma_send_error(rdma_xprt, ctxt, ret);
svc_rdma_recv_ctxt_put(rdma_xprt, ctxt);
- svc_xprt_deferred_close(xprt);
+ svc_rdma_xprt_deferred_close(rdma_xprt);
return ret;
}
return 0;
diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c
index ac6f6d15c8335..4b1571d700390 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_rw.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c
@@ -292,7 +292,7 @@ static void svc_rdma_reply_done(struct ib_cq *cq, struct ib_wc *wc)
trace_svcrdma_wc_reply_err(wc, &cc->cc_cid);
}
- svc_xprt_deferred_close(&rdma->sc_xprt);
+ svc_rdma_xprt_deferred_close(rdma);
}
/**
@@ -324,7 +324,7 @@ static void svc_rdma_write_done(struct ib_cq *cq, struct ib_wc *wc)
* some of the outgoing RPC message. Signal the loss
* to the client by closing the connection.
*/
- svc_xprt_deferred_close(&rdma->sc_xprt);
+ svc_rdma_xprt_deferred_close(rdma);
}
/**
@@ -369,7 +369,7 @@ static void svc_rdma_wc_read_done(struct ib_cq *cq, struct ib_wc *wc)
*/
svc_rdma_cc_release(rdma, cc, DMA_FROM_DEVICE);
svc_rdma_recv_ctxt_put(rdma, ctxt);
- svc_xprt_deferred_close(&rdma->sc_xprt);
+ svc_rdma_xprt_deferred_close(rdma);
}
/*
@@ -422,7 +422,7 @@ static int svc_rdma_post_chunk_ctxt(struct svcxprt_rdma *rdma,
} while (1);
trace_svcrdma_sq_post_err(rdma, &cc->cc_cid, ret);
- svc_xprt_deferred_close(&rdma->sc_xprt);
+ svc_rdma_xprt_deferred_close(rdma);
/* If even one was posted, there will be a completion. */
if (bad_wr != first_wr)
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index cdc3f7a1cef53..3b623817862d7 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -316,7 +316,7 @@ static void svc_rdma_wc_send(struct ib_cq *cq, struct ib_wc *wc)
else
trace_svcrdma_wc_send_flush(wc, &ctxt->sc_cid);
svc_rdma_send_ctxt_put(rdma, ctxt);
- svc_xprt_deferred_close(&rdma->sc_xprt);
+ svc_rdma_xprt_deferred_close(rdma);
}
/**
@@ -377,7 +377,7 @@ int svc_rdma_post_send(struct svcxprt_rdma *rdma,
ret = ib_post_send(rdma->sc_qp, first_wr, &bad_wr);
if (ret) {
trace_svcrdma_sq_post_err(rdma, &cid, ret);
- svc_xprt_deferred_close(&rdma->sc_xprt);
+ svc_rdma_xprt_deferred_close(rdma);
/* If even one WR was posted, there will be a
* Send completion that bumps sc_sq_avail.
@@ -1087,7 +1087,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
svc_rdma_send_ctxt_put(rdma, sctxt);
drop_connection:
trace_svcrdma_send_err(rqstp, ret);
- svc_xprt_deferred_close(&rdma->sc_xprt);
+ svc_rdma_xprt_deferred_close(rdma);
return -ENOTCONN;
}
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 1f9d14e46c9df..767af51a782ed 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -99,10 +99,24 @@ struct svc_xprt_class svc_rdma_class = {
.xcl_ident = XPRT_TRANSPORT_RDMA,
};
+/**
+ * svc_rdma_xprt_deferred_close - Close an RDMA transport (deferred)
+ * @rdma: transport to close
+ */
+void svc_rdma_xprt_deferred_close(struct svcxprt_rdma *rdma)
+{
+ svc_xprt_deferred_close(&rdma->sc_xprt);
+
+ /* Release threads parked on sc_send_wait. */
+ wake_up_all(&rdma->sc_send_wait);
+}
+
/* QP event handler */
static void qp_event_handler(struct ib_event *event, void *context)
{
struct svc_xprt *xprt = context;
+ struct svcxprt_rdma *rdma =
+ container_of(xprt, struct svcxprt_rdma, sc_xprt);
trace_svcrdma_qp_error(event, (struct sockaddr *)&xprt->xpt_remote);
switch (event->event) {
@@ -120,7 +134,7 @@ static void qp_event_handler(struct ib_event *event, void *context)
case IB_EVENT_QP_ACCESS_ERR:
case IB_EVENT_DEVICE_FATAL:
default:
- svc_xprt_deferred_close(xprt);
+ svc_rdma_xprt_deferred_close(rdma);
break;
}
}
@@ -344,7 +358,7 @@ static int svc_rdma_cma_handler(struct rdma_cm_id *cma_id,
svc_xprt_enqueue(xprt);
break;
case RDMA_CM_EVENT_DISCONNECTED:
- svc_xprt_deferred_close(xprt);
+ svc_rdma_xprt_deferred_close(rdma);
break;
default:
break;
@@ -617,6 +631,14 @@ static void svc_rdma_detach(struct svc_xprt *xprt)
container_of(xprt, struct svcxprt_rdma, sc_xprt);
rdma_disconnect(rdma->sc_cm_id);
+
+ /*
+ * Most close paths go through svc_rdma_xprt_deferred_close(),
+ * which wakes the SQ waitqueue. svc_xprt_close() reaches
+ * detach without that helper, so wake any threads parked on
+ * sc_send_wait here as well.
+ */
+ wake_up_all(&rdma->sc_send_wait);
}
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 566/869] svcrdma: Clear sc_cm_id when ADDR_CHANGE replacement fails
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (564 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 565/869] svcrdma: wake sq waiters when the transport closes Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 567/869] SUNRPC: Reject short RFC 4121 MIC tokens in gss_krb5_verify_mic_v2 Greg Kroah-Hartman
` (303 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <chuck.lever@oracle.com>
[ Upstream commit 01500306e1d50de7ca7a2cdcdfa28ac0523eb747 ]
When svc_rdma_listen_handler() handles RDMA_CM_EVENT_ADDR_CHANGE,
it creates a replacement listener cm_id and returns 1, telling
the CM core to destroy the old one. If the replacement allocation
fails, sc_cm_id still points at the old cm_id that the CM core is
about to destroy. Any subsequent dereference of sc_cm_id --
such as svc_rdma_detach()'s rdma_disconnect() call -- is a
use-after-free.
NULL sc_cm_id on the failure path and guard svc_rdma_detach()'s
rdma_disconnect() call against NULL so that the listener can
be torn down safely when the server shuts down.
Fixes: d1b586e75ec6 ("svcrdma: Handle ADDR_CHANGE CM event properly")
Cc: stable@vger.kernel.org
Acked-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260527-rdma-follow-on-v1-5-1b09bd87b6cd@oracle.com
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sunrpc/xprtrdma/svc_rdma_transport.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 767af51a782ed..b6044a1911ee9 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -325,6 +325,7 @@ static int svc_rdma_listen_handler(struct rdma_cm_id *cma_id,
if (IS_ERR(listen_id)) {
pr_err("Listener dead, address change failed for device %s\n",
cma_id->device->name);
+ cma_xprt->sc_cm_id = NULL;
} else
cma_xprt->sc_cm_id = listen_id;
return 1;
@@ -630,7 +631,8 @@ static void svc_rdma_detach(struct svc_xprt *xprt)
struct svcxprt_rdma *rdma =
container_of(xprt, struct svcxprt_rdma, sc_xprt);
- rdma_disconnect(rdma->sc_cm_id);
+ if (rdma->sc_cm_id)
+ rdma_disconnect(rdma->sc_cm_id);
/*
* Most close paths go through svc_rdma_xprt_deferred_close(),
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 567/869] SUNRPC: Reject short RFC 4121 MIC tokens in gss_krb5_verify_mic_v2
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (565 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 566/869] svcrdma: Clear sc_cm_id when ADDR_CHANGE replacement fails Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 568/869] ext2: Fix lost inode updates for IS_SYNC inodes Greg Kroah-Hartman
` (302 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Chris Mason, Jeff Layton,
Chuck Lever, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <chuck.lever@oracle.com>
[ Upstream commit b94f6719dcd9f7a609bc5f459f85795900e77d25 ]
gss_krb5_verify_mic_v2() reads the token ID at ptr[0..1], the flags
byte at ptr[2], and padding at ptr[3..7], then passes
ptr + GSS_KRB5_TOK_HDR_LEN and cksum_len to gss_krb5_mic_build_sg().
None of these accesses check read_token->len first.
The minimum safe token size is GSS_KRB5_TOK_HDR_LEN (16) plus
ctx->krb5e->cksum_len (12-24, depending on the enctype). All callers
accept shorter tokens from the wire:
- gss_unwrap_resp_integ() enforces only an upper bound
(offset + len <= rcv_buf->len) before allocating
mic.data = kmalloc(len) and passing it to gss_verify_mic().
A malicious NFS server can therefore supply a short checksum
opaque, producing a small slab allocation that the Kerberos MIC
verifier reads past.
- gss_validate() enforces only len <= RPC_MAX_AUTH_SIZE (400)
before passing the wire-supplied length to
gss_validate_seqno_mic(), which constructs a mic xdr_netobj
and calls gss_verify_mic().
- svcauth_gss_verify_header() enforces only
checksum.len >= XDR_UNIT (4 bytes) before dispatching to
gss_verify_mic().
- svcauth_gss_unwrap_integ() checks only that the checksum fits
in gsd->gsd_scratch.
Add a length guard at the top of gss_krb5_verify_mic_v2(), before any
ptr[] access or scatterlist construction. Well-formed MIC tokens from
gss_krb5_get_mic_v2() already have exactly GSS_KRB5_TOK_HDR_LEN +
cksum_len bytes, so valid traffic is unaffected.
Reported-by: Chris Mason <clm@meta.com>
Fixes: de9c17eb4a91 ("gss_krb5: add support for new token formats in rfc4121")
Cc: stable@vger.kernel.org
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260523165237.510204-1-cel@kernel.org
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sunrpc/auth_gss/gss_krb5_unseal.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index ef0e6af9fc959..711697e43f226 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -86,6 +86,9 @@ gss_krb5_verify_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *message_buffer,
dprintk("RPC: %s\n", __func__);
+ if (read_token->len < GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength)
+ return GSS_S_DEFECTIVE_TOKEN;
+
memcpy(&be16_ptr, (char *) ptr, 2);
if (be16_to_cpu(be16_ptr) != KG2_TOK_MIC)
return GSS_S_DEFECTIVE_TOKEN;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 568/869] ext2: Fix lost inode updates for IS_SYNC inodes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (566 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 567/869] SUNRPC: Reject short RFC 4121 MIC tokens in gss_krb5_verify_mic_v2 Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 569/869] smb: client: reject a tree connect response whose byte count is too small Greg Kroah-Hartman
` (301 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jan Kara,
Christian Brauner (Amutable), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara <jack@suse.cz>
[ Upstream commit 356984d1a5c32e94810cbb6c8dc7d8ff2d4d919a ]
ext2_setsize() and ext2_xattr_set2() had a construct like:
if (IS_SYNC(inode)) {
sync_inode_metadata(inode, 1);
} else {
mark_inode_dirty(inode);
}
which leads to lost inode updates for IS_SYNC inodes because
sync_inode_metadata() does anything only if the inode is already dirty
and hence inode updates may be simply lost. Fix the problem by
unconditionally marking the inode dirty and *then* call
sync_inode_metadata().
CC: stable@vger.kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-26-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ext2/inode.c | 3 +--
fs/ext2/xattr.c | 4 ++--
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 3fcf8191da42a..f3149022257a4 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1300,11 +1300,10 @@ static int ext2_setsize(struct inode *inode, loff_t newsize)
filemap_invalidate_unlock(inode->i_mapping);
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
+ mark_inode_dirty(inode);
if (inode_needs_sync(inode)) {
sync_mapping_buffers(inode->i_mapping);
sync_inode_metadata(inode, 1);
- } else {
- mark_inode_dirty(inode);
}
return 0;
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
index c885dcc3bd0d1..5574b601ae09c 100644
--- a/fs/ext2/xattr.c
+++ b/fs/ext2/xattr.c
@@ -777,6 +777,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
/* Update the inode. */
EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0;
inode_set_ctime_current(inode);
+ mark_inode_dirty(inode);
if (IS_SYNC(inode)) {
error = sync_inode_metadata(inode, 1);
/* In case sync failed due to ENOSPC the inode was actually
@@ -789,8 +790,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
}
goto cleanup;
}
- } else
- mark_inode_dirty(inode);
+ }
error = 0;
if (old_bh && old_bh != new_bh) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 569/869] smb: client: reject a tree connect response whose byte count is too small
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (567 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 568/869] ext2: Fix lost inode updates for IS_SYNC inodes Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 570/869] cifs: call pagecache_isize_extended() in cifs_setsize() when extending Greg Kroah-Hartman
` (300 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bryam Vargas, Namjae Jeon,
Paulo Alcantara, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <hexlabsecurity@proton.me>
[ Upstream commit 65deb18359341141d37dc86fc7853511be3c87a7 ]
CIFSTCon() bounds its strnlen() over the byte area with the server's
ByteCount minus two, which for ByteCount 0 or 1 goes negative as an int
and converts to a huge size_t. The later subtraction wraps the __u16
bytes_left, and that is what bounds cifs_strndup_from_utf16(): a bound of
up to 65535 against a ~16 KB cifs_req_poolp object runs off the end of the
slab object, and the bytes reach userspace through tcon->nativeFileSystem
in /proc/fs/cifs/DebugData.
Reject a byte area too small for what the parser consumes. Two bytes is
the least it can consume, and no conformant response carries fewer. The
new trace point is the 129th smb_eio_trace entry, which __mode(byte)
cannot represent, so the attribute goes with it.
Fixes: cc20c031bb06 ("cifs: convert CIFSTCon to use new unicode helper functions")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/connect.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index a7261fb38379f..7db347fc8faa2 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -3895,6 +3895,10 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
tcon->tid = smb_buffer_response->Tid;
bcc_ptr = pByteArea(smb_buffer_response);
bytes_left = get_bcc(smb_buffer_response);
+ if (bytes_left < 2) {
+ rc = -EIO;
+ goto out;
+ }
length = strnlen(bcc_ptr, bytes_left - 2);
if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
is_unicode = true;
@@ -3950,6 +3954,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
reset_cifs_unix_caps(xid, tcon, NULL, NULL);
}
}
+out:
cifs_buf_release(smb_buffer);
return rc;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 570/869] cifs: call pagecache_isize_extended() in cifs_setsize() when extending
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (568 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 569/869] smb: client: reject a tree connect response whose byte count is too small Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 571/869] ceph: cap delegated inode count in ceph_parse_deleg_inos() Greg Kroah-Hartman
` (299 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Frank Sorenson,
Namjae Jeon, Paulo Alcantara, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frank Sorenson <sorenson@redhat.com>
[ Upstream commit c510edb9734af1c274d18f4f31a471a166bbc7e8 ]
cifs_setsize() calls truncate_pagecache() but skips
pagecache_isize_extended() on extension. truncate_setsize() shows
the correct pattern:
i_size_write(inode, newsize);
if (newsize > oldsize)
pagecache_isize_extended(inode, oldsize, newsize);
truncate_pagecache(inode, newsize);
pagecache_isize_extended() zeroes the tail of the page straddling old
EOF. Without it, dirty bytes in that region can be written back to
the server, exposing stale data in the newly extended range.
Cc: stable@vger.kernel.org
Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/inode.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index db8a96e04e4d7..e75ac895d3b4a 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -2959,13 +2959,17 @@ int cifs_truncate_page(struct address_space *mapping, loff_t from)
void cifs_setsize(struct inode *inode, loff_t offset)
{
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
+ loff_t old_size;
spin_lock(&inode->i_lock);
+ old_size = i_size_read(inode);
i_size_write(inode, offset);
spin_unlock(&inode->i_lock);
/* Cached inode must be refreshed on truncate */
cifs_i->time = 0;
+ if (offset > old_size)
+ pagecache_isize_extended(inode, old_size, offset);
truncate_pagecache(inode, offset);
netfs_wait_for_outstanding_io(inode);
fscache_resize_cookie(cifs_inode_cookie(inode), offset);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 571/869] ceph: cap delegated inode count in ceph_parse_deleg_inos()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (569 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 570/869] cifs: call pagecache_isize_extended() in cifs_setsize() when extending Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 572/869] ceph: fix UAF in check_new_map() on session freed during unlock Greg Kroah-Hartman
` (298 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Viacheslav Dubeyko,
Michael Bommarito, Ilya Dryomov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <michael.bommarito@gmail.com>
[ Upstream commit 4bd3158bd62466d57ed72a3f7bc5f205fedd6919 ]
ceph_parse_deleg_inos() decodes interval sets of delegated inode numbers
from an MDS create-with-delegation reply. For each set it reads a 64-bit
start and a 64-bit len with ceph_decode_64_safe(), which only validates
that the eight bytes are present in the message, not the value, and then
loops over len while inserting entries into s_delegated_inos.
len is fully attacker controlled. A malicious or compromised MDS can send
one huge interval, many intervals in one reply, duplicate intervals, or
repeated replies that accumulate delegated inodes on the same session.
The original code bounded none of these and could spin the insert loop or
grow the xarray without limit.
Bound both dimensions with a single enforcement point. Track the number
of delegated inodes held by each MDS session in an atomic counter and
grow it only in ceph_insert_deleg_ino(), which uses atomic_add_unless()
to refuse to push the count past CEPH_MAX_DELEG_INOS. Because that helper
is the only place the counter grows, the per-session population can never
exceed the cap, so no separate per-session pre-check is needed. The
counter is decremented when async create consumes a delegated inode or
when an insert fails, incremented when a delegated inode is restored,
initialized with the session xarray, and reset when reconnect destroys
the xarray.
A per-session cap alone still lets one reply spin the insert loop on
duplicate ranges without growing the counter, so also cap the aggregate
interval length accepted from a single reply. Together these bound both
the loop trip count per reply and the xarray population across replies.
The cap is a fixed, client-chosen constant rather than a value derived
from the MDS. mds_client_prealloc_inos is a userspace MDS configuration
option; it is never sent to the kernel client on the wire, and a
server-supplied bound could not be trusted for a defensive limit in any
case. The constant is set well above that option's documented default of
1000 (a generous multiple), so legitimate refill behavior is unaffected
while the CPU and xarray memory a malformed delegation stream can consume
stays bounded.
Impact: a malicious or compromised Ceph MDS can no longer make a client
spin through an unbounded delegated-inode interval or grow one session's
delegated-inode xarray without limit.
Cc: stable@vger.kernel.org
Fixes: d48464878708 ("ceph: decode interval_sets for delegated inos")
Suggested-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ceph/mds_client.c | 59 +++++++++++++++++++++++++++++++++++++++-----
fs/ceph/mds_client.h | 1 +
fs/ceph/super.h | 9 +++++++
3 files changed, 63 insertions(+), 6 deletions(-)
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index bc1d4386b349f..144483d932300 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -574,10 +574,36 @@ static int parse_reply_info_filelock(void **p, void *end,
#define DELEGATED_INO_AVAILABLE xa_mk_value(1)
+static int ceph_insert_deleg_ino(struct ceph_mds_session *s, u64 ino)
+{
+ struct ceph_client *cl = s->s_mdsc->fsc->client;
+ int err;
+
+ /*
+ * Cap how many delegated inodes a single session may hold. This is
+ * the only place that grows the count, so atomic_add_unless() bounds
+ * it at exactly CEPH_MAX_DELEG_INOS; s_num_deleg_inos can never exceed
+ * that.
+ */
+ if (!atomic_add_unless(&s->s_num_deleg_inos, 1, CEPH_MAX_DELEG_INOS)) {
+ pr_warn_ratelimited_client(cl,
+ "MDS session already holds %d delegated inodes\n",
+ CEPH_MAX_DELEG_INOS);
+ return -EOVERFLOW;
+ }
+
+ err = xa_insert(&s->s_delegated_inos, ino, DELEGATED_INO_AVAILABLE,
+ GFP_KERNEL);
+ if (err)
+ atomic_dec(&s->s_num_deleg_inos);
+ return err;
+}
+
static int ceph_parse_deleg_inos(void **p, void *end,
struct ceph_mds_session *s)
{
struct ceph_client *cl = s->s_mdsc->fsc->client;
+ u64 msg_deleg_inos = 0;
u32 sets;
ceph_decode_32_safe(p, end, sets, bad);
@@ -595,16 +621,34 @@ static int ceph_parse_deleg_inos(void **p, void *end,
start, len);
continue;
}
+
+ /*
+ * Bound the number of inodes one reply may delegate.
+ * ceph_insert_deleg_ino() separately caps the per-session
+ * population, so this only has to stop one reply from spinning
+ * the insert loop under an attacker-controlled len.
+ */
+ if (len > (u64)CEPH_MAX_DELEG_INOS ||
+ msg_deleg_inos > (u64)CEPH_MAX_DELEG_INOS - len) {
+ pr_warn_ratelimited_client(cl,
+ "MDS reply delegates too many inodes (have %llu, +%llu, max %d)\n",
+ msg_deleg_inos, len, CEPH_MAX_DELEG_INOS);
+ return -EIO;
+ }
+ msg_deleg_inos += len;
+
while (len--) {
- int err = xa_insert(&s->s_delegated_inos, start++,
- DELEGATED_INO_AVAILABLE,
- GFP_KERNEL);
+ int err = ceph_insert_deleg_ino(s, start++);
+
if (!err) {
doutc(cl, "added delegated inode 0x%llx\n", start - 1);
} else if (err == -EBUSY) {
pr_warn_client(cl,
"MDS delegated inode 0x%llx more than once.\n",
start - 1);
+ } else if (err == -EOVERFLOW) {
+ /* ceph_insert_deleg_ino() already warned. */
+ return -EIO;
} else {
return err;
}
@@ -622,16 +666,17 @@ u64 ceph_get_deleg_ino(struct ceph_mds_session *s)
xa_for_each(&s->s_delegated_inos, ino, val) {
val = xa_erase(&s->s_delegated_inos, ino);
- if (val == DELEGATED_INO_AVAILABLE)
+ if (val == DELEGATED_INO_AVAILABLE) {
+ atomic_dec(&s->s_num_deleg_inos);
return ino;
+ }
}
return 0;
}
int ceph_restore_deleg_ino(struct ceph_mds_session *s, u64 ino)
{
- return xa_insert(&s->s_delegated_inos, ino, DELEGATED_INO_AVAILABLE,
- GFP_KERNEL);
+ return ceph_insert_deleg_ino(s, ino);
}
#else /* BITS_PER_LONG == 64 */
/*
@@ -1015,6 +1060,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
INIT_LIST_HEAD(&s->s_waiting);
INIT_LIST_HEAD(&s->s_unsafe);
xa_init(&s->s_delegated_inos);
+ atomic_set(&s->s_num_deleg_inos, 0);
INIT_LIST_HEAD(&s->s_cap_releases);
INIT_WORK(&s->s_cap_release_work, ceph_cap_release_work);
@@ -4923,6 +4969,7 @@ static int send_mds_reconnect(struct ceph_mds_client *mdsc,
/* Serialized by s_mutex against concurrent ceph_get_deleg_ino(). */
xa_destroy(&session->s_delegated_inos);
+ atomic_set(&session->s_num_deleg_inos, 0);
if (session->s_state == CEPH_MDS_SESSION_CLOSED ||
session->s_state == CEPH_MDS_SESSION_REJECTED) {
pr_info_client(cl, "mds%d skipping reconnect, session %s\n",
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
index 0e82e61e19c4c..a1629e61e75bf 100644
--- a/fs/ceph/mds_client.h
+++ b/fs/ceph/mds_client.h
@@ -252,6 +252,7 @@ struct ceph_mds_session {
struct list_head s_waiting; /* waiting requests */
struct list_head s_unsafe; /* unsafe requests */
struct xarray s_delegated_inos;
+ atomic_t s_num_deleg_inos;
};
/*
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index c0763e2f54d7d..83ddd61e16475 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -623,6 +623,15 @@ static inline int ceph_ino_compare(struct inode *inode, void *data)
#define CEPH_MDS_INO_LOG_OFFSET (2 * CEPH_MAX_MDS)
#define CEPH_INO_SYSTEM_BASE ((6*CEPH_MAX_MDS) + (CEPH_MAX_MDS * CEPH_NUM_STRAY))
+/*
+ * Upper bound on the number of delegated inodes a single MDS session may
+ * hold. The MDS normally hands out a small preallocation window (the
+ * userspace mds_client_prealloc_inos option defaults to 1000) and refills
+ * it as the client consumes entries. This leaves generous headroom while
+ * bounding the CPU and memory a malformed delegation interval can consume.
+ */
+#define CEPH_MAX_DELEG_INOS 8192
+
static inline bool ceph_vino_is_reserved(const struct ceph_vino vino)
{
if (vino.ino >= CEPH_INO_SYSTEM_BASE ||
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 572/869] ceph: fix UAF in check_new_map() on session freed during unlock
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (570 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 571/869] ceph: cap delegated inode count in ceph_parse_deleg_inos() Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 573/869] nfsd: fix fcache_disposal UAF by inlining dispose state into nfsd_net Greg Kroah-Hartman
` (297 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Xiubo Li, Viacheslav Dubeyko,
Ilya Dryomov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiubo Li <xiubo.li@clyso.com>
[ Upstream commit ee611a7509554c4ca1f54f6aefe592fb1df7ea70 ]
check_new_map() iterates mdsc->sessions[] and for each active session
drops mdsc->mutex to perform per-session operations. The forced-close
path (rank removed from map) correctly takes a reference on s via
ceph_get_mds_session() before releasing mdsc->mutex, but three other
paths do not:
Path A (address changed): mutex_unlock → mutex_lock(&s->s_mutex)
Path B (reconnect): mutex_unlock → send_mds_reconnect(mdsc, s)
Path C (active transition): mutex_unlock → mutex_lock(&s->s_mutex)
Without the extra reference, another thread can acquire mdsc->mutex
during the unlock window, call __unregister_session() which drops the
last reference on s, and free it. The original thread then accesses
freed memory via s->s_mutex.
Fix by adding ceph_get_mds_session(s) before each mutex_unlock and
ceph_put_mds_session(s) after the corresponding mutex_lock, matching
the pattern already used in the forced-close path.
Race timeline (Path A):
Thread A (check_new_map) Thread B (another map update
holds mdsc->mutex or session teardown)
-------------------------- --------------------------
s = mdsc->sessions[i]
(refcount == 1, held only by
sessions[] array)
mutex_unlock(&mdsc->mutex)
---> acquires mdsc->mutex
__unregister_session(mdsc, s)
sessions[i] = NULL
ceph_put_mds_session(s)
refcount: 1 -> 0
kfree(s) <--- freed!
mutex_lock(&s->s_mutex)
UAF on freed s->s_mutex
Cc: stable@vger.kernel.org
Signed-off-by: Xiubo Li <xiubo.li@clyso.com>
Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ceph/mds_client.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 144483d932300..6694aac76a2dd 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -5219,9 +5219,11 @@ static void check_new_map(struct ceph_mds_client *mdsc,
ceph_mdsmap_get_addr(newmap, i),
sizeof(struct ceph_entity_addr))) {
/* just close it */
+ ceph_get_mds_session(s);
mutex_unlock(&mdsc->mutex);
mutex_lock(&s->s_mutex);
mutex_lock(&mdsc->mutex);
+ ceph_put_mds_session(s);
ceph_con_close(&s->s_con);
mutex_unlock(&s->s_mutex);
s->s_state = CEPH_MDS_SESSION_RESTARTING;
@@ -5236,6 +5238,7 @@ static void check_new_map(struct ceph_mds_client *mdsc,
newstate >= CEPH_MDS_STATE_RECONNECT) {
int rc;
+ ceph_get_mds_session(s);
mutex_unlock(&mdsc->mutex);
clear_bit(i, targets);
rc = send_mds_reconnect(mdsc, s);
@@ -5244,6 +5247,7 @@ static void check_new_map(struct ceph_mds_client *mdsc,
"mds%d reconnect failed: %d\n",
i, rc);
mutex_lock(&mdsc->mutex);
+ ceph_put_mds_session(s);
}
/*
@@ -5256,9 +5260,11 @@ static void check_new_map(struct ceph_mds_client *mdsc,
pr_info_client(cl, "mds%d recovery completed\n",
s->s_mds);
kick_requests(mdsc, i);
+ ceph_get_mds_session(s);
mutex_unlock(&mdsc->mutex);
mutex_lock(&s->s_mutex);
mutex_lock(&mdsc->mutex);
+ ceph_put_mds_session(s);
ceph_kick_flushing_caps(mdsc, s);
mutex_unlock(&s->s_mutex);
wake_up_session_caps(s, RECONNECT);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 573/869] nfsd: fix fcache_disposal UAF by inlining dispose state into nfsd_net
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (571 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 572/869] ceph: fix UAF in check_new_map() on session freed during unlock Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 574/869] nfsd: restore rq_status_counter to even on all nfsd_dispatch() exit paths Greg Kroah-Hartman
` (296 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <jlayton@kernel.org>
[ Upstream commit bbf13732f74351d21c5e0e8dd9bd8e1c48dc35d4 ]
nfsd_file_dispose_list_delayed() defers fput() to nfsd service threads
via a per-net freeme queue, preventing the shrinker and GC worker from
bearing the cost of closing files (see ffb402596147). However, the
queue lives in a separately-allocated struct nfsd_fcache_disposal that
is freed by nfsd_free_fcache_disposal_net() during per-net teardown.
The global shrinker, laundrette, and fsnotify callbacks can still be
inside nfsd_file_dispose_list_delayed() dereferencing that pointer,
causing a use-after-free.
Inline the spinlock and freeme list directly into struct nfsd_net (as
fcache_dispose_lock and fcache_dispose_list), eliminating the separately
allocated struct nfsd_fcache_disposal entirely. These fields now have
the same lifetime as the net namespace itself, so there is no dangling
pointer to chase.
nfsd_file_cache_start_net() now just initializes the inline fields and
cannot fail due to allocation. nfsd_file_cache_shutdown_net() drains
the inline list directly instead of freeing a separate struct. The
alloc/free helpers are removed.
Fixes: 1463b38e7cf3 ("NFSD: simplify per-net file cache management")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260602-nfsd-testing-v2-7-e4ea62e3cd5c@kernel.org
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/filecache.c | 75 +++++++++++++--------------------------------
fs/nfsd/netns.h | 3 +-
2 files changed, 23 insertions(+), 55 deletions(-)
diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index 1eee2dc936d9f..a08974e268b8c 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -67,11 +67,6 @@ static DEFINE_PER_CPU(unsigned long, nfsd_file_releases);
static DEFINE_PER_CPU(unsigned long, nfsd_file_total_age);
static DEFINE_PER_CPU(unsigned long, nfsd_file_evictions);
-struct nfsd_fcache_disposal {
- spinlock_t lock;
- struct list_head freeme;
-};
-
static struct kmem_cache *nfsd_file_slab;
static struct kmem_cache *nfsd_file_mark_slab;
static struct list_lru nfsd_file_lru;
@@ -437,11 +432,12 @@ nfsd_file_dispose_list(struct list_head *dispose)
}
/**
- * nfsd_file_dispose_list_delayed - move list of dead files to net's freeme list
+ * nfsd_file_dispose_list_delayed - queue dead files for nfsd thread disposal
* @dispose: list of nfsd_files to be disposed
*
- * Transfers each file to the "freeme" list for its nfsd_net, to eventually
- * be disposed of by the per-net garbage collector.
+ * Transfers each file to the dispose list in its nfsd_net and wakes an nfsd
+ * thread to do the actual close. This keeps the cost of fput() in the nfsd
+ * threads rather than in the shrinker or GC worker.
*
* All callers must hold nfsd_gc_lock, so that nfsd_file_cache_shutdown_net()
* can synchronize against them before draining the per-net dispose list.
@@ -456,12 +452,11 @@ nfsd_file_dispose_list_delayed(struct list_head *dispose)
struct nfsd_file *nf = list_first_entry(dispose,
struct nfsd_file, nf_gc);
struct nfsd_net *nn = net_generic(nf->nf_net, nfsd_net_id);
- struct nfsd_fcache_disposal *l = nn->fcache_disposal;
struct svc_serv *serv;
- spin_lock(&l->lock);
- list_move_tail(&nf->nf_gc, &l->freeme);
- spin_unlock(&l->lock);
+ spin_lock(&nn->fcache_dispose_lock);
+ list_move_tail(&nf->nf_gc, &nn->fcache_dispose_list);
+ spin_unlock(&nn->fcache_dispose_lock);
/*
* The filecache laundrette is shut down after the
@@ -485,17 +480,15 @@ nfsd_file_dispose_list_delayed(struct list_head *dispose)
*/
void nfsd_file_net_dispose(struct nfsd_net *nn)
{
- struct nfsd_fcache_disposal *l = nn->fcache_disposal;
-
- if (!list_empty(&l->freeme)) {
+ if (!list_empty(&nn->fcache_dispose_list)) {
LIST_HEAD(dispose);
int i;
- spin_lock(&l->lock);
- for (i = 0; i < 8 && !list_empty(&l->freeme); i++)
- list_move(l->freeme.next, &dispose);
- spin_unlock(&l->lock);
- if (!list_empty(&l->freeme)) {
+ spin_lock(&nn->fcache_dispose_lock);
+ for (i = 0; i < 8 && !list_empty(&nn->fcache_dispose_list); i++)
+ list_move(nn->fcache_dispose_list.next, &dispose);
+ spin_unlock(&nn->fcache_dispose_lock);
+ if (!list_empty(&nn->fcache_dispose_list)) {
/*
* Wake up another thread to share the work
* *before* doing any actual disposing.
@@ -685,11 +678,11 @@ nfsd_file_queue_for_close(struct inode *inode, struct list_head *dispose)
}
/**
- * nfsd_file_close_inode - attempt a delayed close of a nfsd_file
+ * nfsd_file_close_inode - attempt a deferred close of a nfsd_file
* @inode: inode of the file to attempt to remove
*
* Close out any open nfsd_files that can be reaped for @inode. The
- * actual freeing is deferred to the dispose_list_delayed infrastructure.
+ * actual freeing is deferred to the nfsd service threads.
*
* This is used by the fsnotify callbacks and setlease notifier.
*/
@@ -892,42 +885,14 @@ __nfsd_file_cache_purge(struct net *net)
nfsd_file_dispose_list(&dispose);
}
-static struct nfsd_fcache_disposal *
-nfsd_alloc_fcache_disposal(void)
-{
- struct nfsd_fcache_disposal *l;
-
- l = kmalloc(sizeof(*l), GFP_KERNEL);
- if (!l)
- return NULL;
- spin_lock_init(&l->lock);
- INIT_LIST_HEAD(&l->freeme);
- return l;
-}
-
-static void
-nfsd_free_fcache_disposal(struct nfsd_fcache_disposal *l)
-{
- nfsd_file_dispose_list(&l->freeme);
- kfree(l);
-}
-
-static void
-nfsd_free_fcache_disposal_net(struct net *net)
-{
- struct nfsd_net *nn = net_generic(net, nfsd_net_id);
- struct nfsd_fcache_disposal *l = nn->fcache_disposal;
-
- nfsd_free_fcache_disposal(l);
-}
-
int
nfsd_file_cache_start_net(struct net *net)
{
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
- nn->fcache_disposal = nfsd_alloc_fcache_disposal();
- return nn->fcache_disposal ? 0 : -ENOMEM;
+ spin_lock_init(&nn->fcache_dispose_lock);
+ INIT_LIST_HEAD(&nn->fcache_dispose_list);
+ return 0;
}
/**
@@ -946,6 +911,8 @@ nfsd_file_cache_purge(struct net *net)
void
nfsd_file_cache_shutdown_net(struct net *net)
{
+ struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
nfsd_file_cache_purge(net);
/*
* Ensure any in-progress shrinker, GC, or fsnotify/lease callback
@@ -955,7 +922,7 @@ nfsd_file_cache_shutdown_net(struct net *net)
*/
spin_lock(&nfsd_gc_lock);
spin_unlock(&nfsd_gc_lock);
- nfsd_free_fcache_disposal_net(net);
+ nfsd_file_dispose_list(&nn->fcache_dispose_list);
}
void
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index b203a15a909da..550ee3c4fc26c 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -216,7 +216,8 @@ struct nfsd_net {
/* utsname taken from the process that starts the server */
char nfsd_name[UNX_MAXNODENAME+1];
- struct nfsd_fcache_disposal *fcache_disposal;
+ spinlock_t fcache_dispose_lock;
+ struct list_head fcache_dispose_list;
siphash_key_t siphash_key;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 574/869] nfsd: restore rq_status_counter to even on all nfsd_dispatch() exit paths
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (572 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 573/869] nfsd: fix fcache_disposal UAF by inlining dispose state into nfsd_net Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 575/869] lockd, nfsd: RCU-protect nlmsvc_ops dispatch Greg Kroah-Hartman
` (295 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <jlayton@kernel.org>
[ Upstream commit f6045886fe3f14f269f683d64021b004a50d0efa ]
nfsd_dispatch() sets rq_status_counter to an odd value once a request has
been decoded, and back to an even value once it has been fully processed,
forming a seq-lock like protocol with the lockless reader in
nfsd_nl_rpc_status_get_dumpit().
Only the fully successful path restored the counter to even. The cache-hit
(RC_REPLY), drop (RC_DROPIT / RQ_DROPME) and encode-error paths all return
after the odd-valued store without ever bringing the counter back to even.
Once one of those paths is taken, rq_status_counter is left odd: the next
request's decode ORs in 1 (still odd) and only a subsequent successful
encode restores even. While stuck odd, the dumpit reader treats the rqstp
fields as stable and its retry check compares against the same unchanging
odd value, so it never detects concurrent mutation. This exposes actively
mutating fields (e.g. args->ops / args->opcnt during compound decode and
release) to the lockless reader, which can read past the end of the
8-element inline ops array.
Add a helper that advances the counter to the next even value and call it
on every return path that follows the odd-valued store. The decode-error
path is left untouched as it is reached before the counter is set odd.
Fixes: bd9d6a3efa97 ("NFSD: add rpc_status netlink support")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260611-nfsd-testing-v2-19-5b90e276f2d9@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/nfssvc.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 421f474b75ce8..57754dfacf9cb 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -974,6 +974,20 @@ nfsd(void *vrqstp)
return 0;
}
+/*
+ * Set rq_status_counter back to an even value, indicating that the rqstp
+ * fields are no longer meaningful to a lockless reader. This pairs with the
+ * odd-valued store made once the request has been decoded, and must run on
+ * every return path that follows it so that the seq-lock like protocol used
+ * by nfsd_nl_rpc_status_get_dumpit() is not left permanently odd. The store
+ * also advances the counter so a concurrent reader detects the transition.
+ */
+static void nfsd_status_counter_set_idle(struct svc_rqst *rqstp)
+{
+ smp_store_release(&rqstp->rq_status_counter,
+ (rqstp->rq_status_counter | 1) + 1);
+}
+
/**
* nfsd_dispatch - Process an NFS or NFSACL or LOCALIO Request
* @rqstp: incoming request
@@ -1035,14 +1049,9 @@ int nfsd_dispatch(struct svc_rqst *rqstp)
if (!proc->pc_encode(rqstp, &rqstp->rq_res_stream))
goto out_encode_err;
- /*
- * Release rq_status_counter setting it to an even value after the rpc
- * request has been properly processed.
- */
- smp_store_release(&rqstp->rq_status_counter, rqstp->rq_status_counter + 1);
-
nfsd_cache_update(rqstp, rp, rqstp->rq_cachetype, nfs_reply);
out_cached_reply:
+ nfsd_status_counter_set_idle(rqstp);
return 1;
out_decode_err:
@@ -1053,12 +1062,14 @@ int nfsd_dispatch(struct svc_rqst *rqstp)
out_update_drop:
nfsd_cache_update(rqstp, rp, RC_NOCACHE, NULL);
out_dropit:
+ nfsd_status_counter_set_idle(rqstp);
return 0;
out_encode_err:
trace_nfsd_cant_encode_err(rqstp);
nfsd_cache_update(rqstp, rp, RC_NOCACHE, NULL);
*statp = rpc_system_err;
+ nfsd_status_counter_set_idle(rqstp);
return 1;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 575/869] lockd, nfsd: RCU-protect nlmsvc_ops dispatch
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (573 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 574/869] nfsd: restore rq_status_counter to even on all nfsd_dispatch() exit paths Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 576/869] mm/mglru: reset page lru tier bits when activating Greg Kroah-Hartman
` (294 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeff Layton, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <jlayton@kernel.org>
[ Upstream commit 641e5e20852359b8c31149be4598884e30652f60 ]
nlmsvc_ops is published by nfsd_lockd_init() and cleared by
nfsd_lockd_shutdown() with plain stores, while lockd dereferences
it unguarded from dispatch sites in fs/lockd/svcsubs.c. The pointer
targets nfsd's .rodata and the fopen/fclose callbacks live in nfsd's
.text, so a stale load after rmmod nfsd results in either a NULL
deref or a module-text use-after-free.
Declare nlmsvc_ops as __rcu, publish via rcu_assign_pointer(), clear
via RCU_INIT_POINTER() + synchronize_rcu(). Add a struct module
*owner field to nlmsvc_binding and pin the module across indirect
calls with try_module_get/module_put. When the binding is torn down,
fall back to fput() to avoid leaking struct file references.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260611-nfsd-testing-v2-16-5b90e276f2d9@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/lockd/svc.c | 4 ++--
fs/lockd/svc4proc.c | 4 ++--
fs/lockd/svcproc.c | 4 ++--
fs/lockd/svcsubs.c | 45 +++++++++++++++++++++++++++++++++-----
fs/nfsd/lockd.c | 6 +++--
include/linux/lockd/bind.h | 12 +++++++---
6 files changed, 59 insertions(+), 16 deletions(-)
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 4ec22c2f2ea3c..87f20d1edb2c2 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -47,7 +47,7 @@
static struct svc_program nlmsvc_program;
-const struct nlmsvc_binding *nlmsvc_ops;
+const struct nlmsvc_binding __rcu *nlmsvc_ops;
EXPORT_SYMBOL_GPL(nlmsvc_ops);
static DEFINE_MUTEX(nlmsvc_mutex);
@@ -142,7 +142,7 @@ lockd(void *vrqstp)
nlmsvc_retry_blocked(rqstp);
svc_recv(rqstp);
}
- if (nlmsvc_ops)
+ if (rcu_access_pointer(nlmsvc_ops))
nlmsvc_invalidate_all();
nlm_shutdown_hosts();
cancel_delayed_work_sync(&ln->grace_period_end);
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 3f633bb24623a..ea3b689f8b93a 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -29,7 +29,7 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
__be32 error = 0;
/* nfsd callbacks must have been installed for this procedure */
- if (!nlmsvc_ops)
+ if (!rcu_access_pointer(nlmsvc_ops))
return nlm_lck_denied_nolocks;
if (lock->lock_start > OFFSET_MAX ||
@@ -487,7 +487,7 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp)
{
struct nlm_res *argp = rqstp->rq_argp;
- if (!nlmsvc_ops)
+ if (!rcu_access_pointer(nlmsvc_ops))
return rpc_success;
dprintk("lockd: GRANTED_RES called\n");
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 8cda2aba82d25..44da63392a09d 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -59,7 +59,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
__be32 error = 0;
/* nfsd callbacks must have been installed for this procedure */
- if (!nlmsvc_ops)
+ if (!rcu_access_pointer(nlmsvc_ops))
return nlm_lck_denied_nolocks;
/* Obtain host handle */
@@ -521,7 +521,7 @@ nlmsvc_proc_granted_res(struct svc_rqst *rqstp)
{
struct nlm_res *argp = rqstp->rq_argp;
- if (!nlmsvc_ops)
+ if (!rcu_access_pointer(nlmsvc_ops))
return rpc_success;
dprintk("lockd: GRANTED_RES called\n");
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 90c6527ad712c..3e3cd67e167a2 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -86,12 +86,23 @@ int lock_to_openmode(struct file_lock *lock)
static __be32 nlm_do_fopen(struct svc_rqst *rqstp,
struct nlm_file *file, int mode)
{
+ const struct nlmsvc_binding *ops;
struct file **fp = &file->f_file[mode];
__be32 nfserr;
if (*fp)
return 0;
- nfserr = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode);
+
+ rcu_read_lock();
+ ops = rcu_dereference(nlmsvc_ops);
+ if (!ops || !try_module_get(ops->owner)) {
+ rcu_read_unlock();
+ return nlm_lck_denied_nolocks;
+ }
+ rcu_read_unlock();
+
+ nfserr = ops->fopen(rqstp, &file->f_handle, fp, mode);
+ module_put(ops->owner);
if (nfserr)
dprintk("lockd: open failed (error %d)\n", nfserr);
return nfserr;
@@ -159,6 +170,33 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
goto out_unlock;
}
+/*
+ * Release the struct file references held by a nlm_file.
+ */
+static void nlm_release_files(struct nlm_file *file)
+{
+ const struct nlmsvc_binding *ops;
+ bool have_ops;
+
+ rcu_read_lock();
+ ops = rcu_dereference(nlmsvc_ops);
+ have_ops = ops && try_module_get(ops->owner);
+ rcu_read_unlock();
+
+ if (have_ops) {
+ if (file->f_file[O_RDONLY])
+ ops->fclose(file->f_file[O_RDONLY]);
+ if (file->f_file[O_WRONLY])
+ ops->fclose(file->f_file[O_WRONLY]);
+ module_put(ops->owner);
+ } else {
+ if (file->f_file[O_RDONLY])
+ fput(file->f_file[O_RDONLY]);
+ if (file->f_file[O_WRONLY])
+ fput(file->f_file[O_WRONLY]);
+ }
+}
+
/*
* Delete a file after having released all locks, blocks and shares
*/
@@ -168,10 +206,7 @@ nlm_delete_file(struct nlm_file *file)
nlm_debug_print_file("closing file", file);
if (!hlist_unhashed(&file->f_list)) {
hlist_del(&file->f_list);
- if (file->f_file[O_RDONLY])
- nlmsvc_ops->fclose(file->f_file[O_RDONLY]);
- if (file->f_file[O_WRONLY])
- nlmsvc_ops->fclose(file->f_file[O_WRONLY]);
+ nlm_release_files(file);
kfree(file);
} else {
printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 6b042218668b8..e933788e7a350 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -88,6 +88,7 @@ nlm_fclose(struct file *filp)
}
static const struct nlmsvc_binding nfsd_nlm_ops = {
+ .owner = THIS_MODULE,
.fopen = nlm_fopen, /* open file for locking */
.fclose = nlm_fclose, /* close file */
};
@@ -96,11 +97,12 @@ void
nfsd_lockd_init(void)
{
dprintk("nfsd: initializing lockd\n");
- nlmsvc_ops = &nfsd_nlm_ops;
+ rcu_assign_pointer(nlmsvc_ops, &nfsd_nlm_ops);
}
void
nfsd_lockd_shutdown(void)
{
- nlmsvc_ops = NULL;
+ RCU_INIT_POINTER(nlmsvc_ops, NULL);
+ synchronize_rcu();
}
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index c53c81242e727..e25943e485c5c 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -21,11 +21,17 @@
struct svc_rqst;
struct rpc_task;
struct rpc_clnt;
+struct module;
-/*
- * This is the set of functions for lockd->nfsd communication
+/**
+ * struct nlmsvc_binding - lockd -> nfsd callback table
+ * @owner: module that provides this binding.
+ * @fopen: open a file by NFS file handle on behalf of an NLM request.
+ * @fclose: close a file that was previously opened via @fopen.
+ * Implementations MUST be semantically equivalent to fput().
*/
struct nlmsvc_binding {
+ struct module *owner;
__be32 (*fopen)(struct svc_rqst *,
struct nfs_fh *,
struct file **,
@@ -33,7 +39,7 @@ struct nlmsvc_binding {
void (*fclose)(struct file *);
};
-extern const struct nlmsvc_binding *nlmsvc_ops;
+extern const struct nlmsvc_binding __rcu *nlmsvc_ops;
/*
* Similar to nfs_client_initdata, but without the NFS-specific
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 576/869] mm/mglru: reset page lru tier bits when activating
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (574 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 575/869] lockd, nfsd: RCU-protect nlmsvc_ops dispatch Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 577/869] mm/mglru: use the common routine for dirty/writeback reactivation Greg Kroah-Hartman
` (293 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Wei Xu, Axel Rasmussen, Brian Geffon,
Jan Alexander Steffens, Suleiman Souhlal, Yu Zhao, Andrew Morton,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Xu <weixugc@google.com>
[ Upstream commit f1001f3d3b6868998cab73d10fda1a5c99ddf963 ]
When a folio is activated, lru_gen_add_folio() moves the folio to the
youngest generation. But unlike folio_update_gen()/folio_inc_gen(),
lru_gen_add_folio() doesn't reset the folio lru tier bits (LRU_REFS_MASK |
LRU_REFS_FLAGS). This inconsistency can affect how pages are aged via
folio_mark_accessed() (e.g. fd accesses), though no user visible impact
related to this has been detected yet.
Note that lru_gen_add_folio() cannot clear PG_workingset if the activation
is due to workingset refault, otherwise PSI accounting will be skipped.
So fix lru_gen_add_folio() to clear the lru tier bits other than
PG_workingset when activating a folio, and also clear all the lru tier
bits when a folio is activated via folio_activate() in
lru_gen_look_around().
Link: https://lkml.kernel.org/r/20241017181528.3358821-1-weixugc@google.com
Fixes: 018ee47f1489 ("mm: multi-gen LRU: exploit locality in rmap")
Signed-off-by: Wei Xu <weixugc@google.com>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Brian Geffon <bgeffon@google.com>
Cc: Jan Alexander Steffens <heftig@archlinux.org>
Cc: Suleiman Souhlal <suleiman@google.com>
Cc: Yu Zhao <yuzhao@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Stable-dep-of: f7e698e326b2 ("mm/mglru: fix and remove redundant unevictable folio handling")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/mm_inline.h | 15 ++++++++++++++-
include/linux/mmzone.h | 2 ++
mm/vmscan.c | 8 ++++----
3 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index f4fe593c1400e..622dfe2545d79 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -155,6 +155,11 @@ static inline int folio_lru_refs(struct folio *folio)
return ((flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF) + workingset;
}
+static inline void folio_clear_lru_refs(struct folio *folio)
+{
+ set_mask_bits(&folio->flags, LRU_REFS_MASK | LRU_REFS_FLAGS, 0);
+}
+
static inline int folio_lru_gen(struct folio *folio)
{
unsigned long flags = READ_ONCE(folio->flags);
@@ -222,6 +227,7 @@ static inline bool lru_gen_add_folio(struct lruvec *lruvec, struct folio *folio,
{
unsigned long seq;
unsigned long flags;
+ unsigned long mask;
int gen = folio_lru_gen(folio);
int type = folio_is_file_lru(folio);
int zone = folio_zonenum(folio);
@@ -257,7 +263,14 @@ static inline bool lru_gen_add_folio(struct lruvec *lruvec, struct folio *folio,
gen = lru_gen_from_seq(seq);
flags = (gen + 1UL) << LRU_GEN_PGOFF;
/* see the comment on MIN_NR_GENS about PG_active */
- set_mask_bits(&folio->flags, LRU_GEN_MASK | BIT(PG_active), flags);
+ mask = LRU_GEN_MASK;
+ /*
+ * Don't clear PG_workingset here because it can affect PSI accounting
+ * if the activation is due to workingset refault.
+ */
+ if (folio_test_active(folio))
+ mask |= LRU_REFS_MASK | BIT(PG_referenced) | BIT(PG_active);
+ set_mask_bits(&folio->flags, mask, flags);
lru_gen_update_size(lruvec, folio, -1, gen);
/* for folio_rotate_reclaimable() */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 8f932c4350fcb..9d52485541529 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -403,6 +403,8 @@ enum {
NR_LRU_GEN_CAPS
};
+#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset))
+
#define MIN_LRU_BATCH BITS_PER_LONG
#define MAX_LRU_BATCH (MIN_LRU_BATCH * 64)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 4c13524afaaaf..460943a562c92 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2625,8 +2625,6 @@ static bool should_clear_pmd_young(void)
* shorthand helpers
******************************************************************************/
-#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset))
-
#define DEFINE_MAX_SEQ(lruvec) \
unsigned long max_seq = READ_ONCE((lruvec)->lrugen.max_seq)
@@ -4157,8 +4155,10 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
old_gen = folio_lru_gen(folio);
if (old_gen < 0)
folio_set_referenced(folio);
- else if (old_gen != new_gen)
+ else if (old_gen != new_gen) {
+ folio_clear_lru_refs(folio);
folio_activate(folio);
+ }
}
arch_leave_lazy_mmu_mode();
@@ -4400,7 +4400,7 @@ static bool isolate_folio(struct lruvec *lruvec, struct folio *folio, struct sca
/* see the comment on MAX_NR_TIERS */
if (!folio_test_referenced(folio))
- set_mask_bits(&folio->flags, LRU_REFS_MASK | LRU_REFS_FLAGS, 0);
+ folio_clear_lru_refs(folio);
/* for shrink_folio_list() */
folio_clear_reclaim(folio);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 577/869] mm/mglru: use the common routine for dirty/writeback reactivation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (575 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 576/869] mm/mglru: reset page lru tier bits when activating Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 578/869] mm/mglru: fix and remove redundant unevictable folio handling Greg Kroah-Hartman
` (292 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kairui Song, Axel Rasmussen,
Barry Song, Baolin Wang, Chen Ridong, Chris Li, David Hildenbrand,
David Stevens, Johannes Weiner, Kalesh Singh, Leno Hou,
Lorenzo Stoakes, Michal Hocko, Shakeel Butt, Suren Baghdasaryan,
Vernon Yang, Wei Xu, Yafang, Yuanchu Xie, Yu Zhao, Andrew Morton,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kairui Song <kasong@tencent.com>
[ Upstream commit 75d4c3f5fb980de1b620adede47e43dff4d6a5f3 ]
Currently MGLRU will move the dirty writeback folios to the second oldest
gen instead of reactivate them like the classical LRU. This might help to
reduce the LRU contention as it skipped the isolation. But as a result we
will see these folios at the LRU tail more frequently leading to
inefficient reclaim.
Besides, the dirty / writeback check after isolation in shrink_folio_list
is more accurate and covers more cases. So instead, just drop the special
handling for dirty writeback, use the common routine and re-activate it
like the classical LRU.
This should in theory improve the scan efficiency. These folios will be
rotated back to LRU tail once writeback is done so there is no risk of
hotness inversion. And now each reclaim loop will have a higher success
rate. This also prepares for unifying the writeback and throttling
mechanism with classical LRU, we keep these folios far from tail so
detecting the tail batch will have a similar pattern with classical LRU.
The micro optimization that avoids LRU contention by skipping the
isolation is gone, which should be fine. Compared to IO and writeback
cost, the isolation overhead is trivial.
And using the common routine also keeps the folio's referenced bits (tier
bits), which could improve metrics in the long term. Also no more need to
clean reclaim bit as the common routine will make use of it.
Note the common routine updates a few throttling and writeback counters,
which are not used, and never have been for the MGLRU case. We will start
making use of these in later commits.
Link: https://lore.kernel.org/20260428-mglru-reclaim-v7-10-02fabb92dc43@tencent.com
Signed-off-by: Kairui Song <kasong@tencent.com>
Reviewed-by: Axel Rasmussen <axelrasmussen@google.com>
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Chen Ridong <chenridong@huaweicloud.com>
Cc: Chris Li <chrisl@kernel.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: David Stevens <stevensd@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Kalesh Singh <kaleshsingh@google.com>
Cc: Leno Hou <lenohou@gmail.com>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vernon Yang <vernon2gm@gmail.com>
Cc: Wei Xu <weixugc@google.com>
Cc: Yafang <laoar.shao@gmail.com>
Cc: Yuanchu Xie <yuanchu@google.com>
Cc: Yu Zhao <yuzhao@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Stable-dep-of: f7e698e326b2 ("mm/mglru: fix and remove redundant unevictable folio handling")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/vmscan.c | 20 +-------------------
1 file changed, 1 insertion(+), 19 deletions(-)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 460943a562c92..ec19d061232e7 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -4313,7 +4313,6 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_c
int tier_idx)
{
bool success;
- bool dirty, writeback;
int gen = folio_lru_gen(folio);
int type = folio_is_file_lru(folio);
int zone = folio_zonenum(folio);
@@ -4359,22 +4358,6 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_c
return true;
}
- dirty = folio_test_dirty(folio);
- writeback = folio_test_writeback(folio);
- if (type == LRU_GEN_FILE && dirty) {
- sc->nr.file_taken += delta;
- if (!writeback)
- sc->nr.unqueued_dirty += delta;
- }
-
- /* waiting for writeback */
- if (folio_test_locked(folio) || writeback ||
- (type == LRU_GEN_FILE && dirty)) {
- gen = folio_inc_gen(lruvec, folio, true);
- list_move(&folio->lru, &lrugen->folios[gen][type][zone]);
- return true;
- }
-
return false;
}
@@ -4384,7 +4367,7 @@ static bool isolate_folio(struct lruvec *lruvec, struct folio *folio, struct sca
/* swap constrained */
if (!(sc->gfp_mask & __GFP_IO) &&
- (folio_test_dirty(folio) ||
+ ((folio_test_dirty(folio) && !folio_is_file_lru(folio)) ||
(folio_test_anon(folio) && !folio_test_swapcache(folio))))
return false;
@@ -4403,7 +4386,6 @@ static bool isolate_folio(struct lruvec *lruvec, struct folio *folio, struct sca
folio_clear_lru_refs(folio);
/* for shrink_folio_list() */
- folio_clear_reclaim(folio);
folio_clear_referenced(folio);
success = lru_gen_del_folio(lruvec, folio, true);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 578/869] mm/mglru: fix and remove redundant unevictable folio handling
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (576 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 577/869] mm/mglru: use the common routine for dirty/writeback reactivation Greg Kroah-Hartman
@ 2026-10-17 15:56 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 579/869] ksmbd: fix tree connection use-after-free in smb2_tree_connect() Greg Kroah-Hartman
` (291 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:56 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kairui Song, Barry Song, Baolin Wang,
Axel Rasmussen, Brian Geffon, David Hildenbrand,
Jan Alexander Steffens (heftig), Johannes Weiner, Lorenzo Stoakes,
Michal Hocko, Oleksandr Natalenko, Shakeel Butt, Steven Barrett,
Suleiman Souhlal, Wei Xu, Yuanchu Xie, Yu Zhao, Andrew Morton,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kairui Song <kasong@tencent.com>
[ Upstream commit f7e698e326b239a91ea15844817551921209e826 ]
sort_folio() has a shortcut for moving folios that are no longer evictable
but are still sitting on a generation list. However, this shortcut is
buggy. It does not follow the PG_lru usage convention, and it has a more
serious issue.
Unevictable folios are not threaded on lists[LRU_UNEVICTABLE], so that
folio->lru can be reused to hold folio->mlock_count (see the comment in
lruvec_init()). Hence lruvec_add_folio() skips the list_add() for them,
and every other place that turns a folio unevictable initialises
mlock_count explicitly: lru_add() sets it to 0, __mlock_folio() and
__mlock_new_folio() set it to !!folio_test_mlocked(folio). sort_folio()
sets nothing, and the lru_gen_del_folio() right above it may have already
poisoned folio->lru via list_del(), so mlock_count ends up aliasing
LIST_POISON2, which reads as 0x122, i.e. 290. The result is user
visible. On munlock, __munlock_folio() decrements that bogus count, finds
it still non-zero and bails out before clearing PG_mlocked, so the folio
remains unevictable and the Mlocked accounting stays inflated until the
folio is freed.
The shortcut also touches the LRU flags in the wrong order. It calls
lru_gen_del_folio() while PG_lru is still set, so a concurrent
folio_test_clear_lru() (e.g. compaction, folio_isolate_lru()) can succeed
on a folio that has already been taken off the generation list, which may
lead to unexpected behavior.
So fix it by isolating them as common folios and letting the generic
shrink path cull them. This matches the classical LRU behavior, and there
should be no visible effect on the generic eviction or isolation behavior.
There is no performance concern either, such a folio goes through this
once, and then it is off the generation lists for good.
Link: https://lore.kernel.org/20260812-mglru-mlock-fix-v2-1-a3fec5853c08@tencent.com
Fixes: ac35a4902374 ("mm: multi-gen LRU: minimal implementation")
Signed-off-by: Kairui Song <kasong@tencent.com>
Reviewed-by: Barry Song <baohua@kernel.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Brian Geffon <bgeffon@google.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: Jan Alexander Steffens (heftig) <heftig@archlinux.org>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Oleksandr Natalenko <oleksandr@natalenko.name>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Steven Barrett <steven@liquorix.net>
Cc: Suleiman Souhlal <suleiman@google.com>
Cc: Wei Xu <weixugc@google.com>
Cc: Yuanchu Xie <yuanchu@google.com>
Cc: Yu Zhao <yuzhao@google.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/vmscan.c | 19 +++++--------------
1 file changed, 5 insertions(+), 14 deletions(-)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index ec19d061232e7..f9b5fbd072db5 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -4312,7 +4312,6 @@ void lru_gen_soft_reclaim(struct mem_cgroup *memcg, int nid)
static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_control *sc,
int tier_idx)
{
- bool success;
int gen = folio_lru_gen(folio);
int type = folio_is_file_lru(folio);
int zone = folio_zonenum(folio);
@@ -4323,15 +4322,9 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_c
VM_WARN_ON_ONCE_FOLIO(gen >= MAX_NR_GENS, folio);
- /* unevictable */
- if (!folio_evictable(folio)) {
- success = lru_gen_del_folio(lruvec, folio, true);
- VM_WARN_ON_ONCE_FOLIO(!success, folio);
- folio_set_unevictable(folio);
- lruvec_add_folio(lruvec, folio);
- __count_vm_events(UNEVICTABLE_PGCULLED, delta);
- return true;
- }
+ /* unevictable: let it through and the generic path will cull it */
+ if (!folio_evictable(folio))
+ return false;
/* promoted */
if (gen != lru_gen_from_seq(lrugen->min_seq[type])) {
@@ -4609,11 +4602,9 @@ static int evict_folios(struct lruvec *lruvec, struct scan_control *sc, int swap
type ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON);
list_for_each_entry_safe_reverse(folio, next, &list, lru) {
- if (!folio_evictable(folio)) {
- list_del(&folio->lru);
- folio_putback_lru(folio);
+ /* move_folios_to_lru() culls unevictable folios via folio_putback_lru() */
+ if (!folio_evictable(folio))
continue;
- }
if (folio_test_reclaim(folio) &&
(folio_test_dirty(folio) || folio_test_writeback(folio))) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 579/869] ksmbd: fix tree connection use-after-free in smb2_tree_connect()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (577 preceding siblings ...)
2026-10-17 15:56 ` [PATCH 6.12 578/869] mm/mglru: fix and remove redundant unevictable folio handling Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 580/869] drm/amdkfd: Fix partial migrate issue Greg Kroah-Hartman
` (290 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Xiang Mei (Microsoft),
AutonomousCodeSecurity, Cen Zhang (Microsoft Security FORGE Labs),
Namjae Jeon, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang (Microsoft Security FORGE Labs) <cenzhang@linux.microsoft.com>
[ Upstream commit b5ec6c462aab1062cf5d1e667ba7c6442f737055 ]
ksmbd_tree_conn_connect() publishes a new tree connection in
sess->tree_conns with a single reference and returns its pointer to
smb2_tree_connect(). The handler continues to initialize the object and
build the response after publication. A concurrent session logoff can
erase the connection and drop that reference, freeing the object while
the handler still uses it.
BUG: KASAN: slab-use-after-free in smb2_tree_connect+0xe3d/0xf90
smb2_tree_connect (fs/smb/server/smb2pdu.c:2872)
handle_ksmbd_work
process_one_work
worker_thread
kthread
After xa_store() succeeds, take a second reference before releasing
tree_conns_lock. The original reference belongs to the xarray entry and
the second belongs to the creating smb2_tree_connect() handler.
Keep the references balanced in every path:
- On normal exit or an error after publication, smb2_tree_connect()
drops its creator reference. Error cleanup also calls
ksmbd_tree_conn_disconnect(), which drops the xarray reference only if
it removes the exact entry.
- SMB2 TREE_DISCONNECT uses the same helper to remove the entry and drop
its xarray reference. The request's existing lookup reference remains
owned by the request and is released by the existing cleanup.
- Session LOGOFF removes each entry and drops its xarray reference. If
it wins the race, later cleanup sees that the entry is gone and does
not drop that reference again.
To enforce this ownership, claim the disconnected state and erase the
exact entry atomically under tree_conns_lock. This guarantees one drop
for the xarray reference and one drop by each in-flight user, regardless
of which teardown path wins. If logoff removes the entry before
initialization completes, fail the connect instead of marking the
detached object TREE_CONNECTED.
Fixes: 33b235a6e6eb ("ksmbd: fix race condition between tree conn lookup and disconnect")
Reported-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
Cc: AutonomousCodeSecurity@microsoft.com
Cc: stable@vger.kernel.org
Signed-off-by: Cen Zhang (Microsoft Security FORGE Labs) <cenzhang@linux.microsoft.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/mgmt/tree_connect.c | 26 +++++++++++-----------
fs/smb/server/smb2pdu.c | 36 ++++++++++++++++++-------------
2 files changed, 34 insertions(+), 28 deletions(-)
diff --git a/fs/smb/server/mgmt/tree_connect.c b/fs/smb/server/mgmt/tree_connect.c
index d3483d9c757c7..5f75f19f9f9f9 100644
--- a/fs/smb/server/mgmt/tree_connect.c
+++ b/fs/smb/server/mgmt/tree_connect.c
@@ -77,7 +77,7 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name)
tree_conn->share_conf = sc;
tree_conn->t_state = TREE_NEW;
status.tree_conn = tree_conn;
- atomic_set(&tree_conn->refcount, 1);
+ atomic_set(&tree_conn->refcount, 2);
ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn,
KSMBD_DEFAULT_GFP));
@@ -99,8 +99,10 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name)
void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon)
{
- if (atomic_dec_and_test(&tcon->refcount))
+ if (atomic_dec_and_test(&tcon->refcount)) {
+ ksmbd_share_config_put(tcon->share_conf);
kfree(tcon);
+ }
}
int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
@@ -109,14 +111,21 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
int ret;
write_lock(&sess->tree_conns_lock);
+ if (tree_conn->t_state == TREE_DISCONNECTED ||
+ xa_load(&sess->tree_conns, tree_conn->id) != tree_conn) {
+ write_unlock(&sess->tree_conns_lock);
+ return -ENOENT;
+ }
+ tree_conn->t_state = TREE_DISCONNECTED;
xa_erase(&sess->tree_conns, tree_conn->id);
write_unlock(&sess->tree_conns_lock);
ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id);
ksmbd_release_tree_conn_id(sess, tree_conn->id);
- ksmbd_share_config_put(tree_conn->share_conf);
- if (atomic_dec_and_test(&tree_conn->refcount))
+ if (atomic_dec_and_test(&tree_conn->refcount)) {
+ ksmbd_share_config_put(tree_conn->share_conf);
kfree(tree_conn);
+ }
return ret;
}
@@ -148,15 +157,6 @@ int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess)
return -EINVAL;
xa_for_each(&sess->tree_conns, id, tc) {
- write_lock(&sess->tree_conns_lock);
- if (tc->t_state == TREE_DISCONNECTED) {
- write_unlock(&sess->tree_conns_lock);
- ret = -ENOENT;
- continue;
- }
- tc->t_state = TREE_DISCONNECTED;
- write_unlock(&sess->tree_conns_lock);
-
ret |= ksmbd_tree_conn_disconnect(sess, tc);
}
xa_destroy(&sess->tree_conns);
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 5795a19bb4cb9..892fcc06c1ab0 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2001,6 +2001,7 @@ int smb2_tree_connect(struct ksmbd_work *work)
struct ksmbd_session *sess = work->sess;
char *treename = NULL, *name = NULL;
struct ksmbd_tree_conn_status status;
+ struct ksmbd_tree_connect *tree_conn = NULL;
struct ksmbd_share_config *share = NULL;
int rc = -EINVAL;
@@ -2025,9 +2026,10 @@ int smb2_tree_connect(struct ksmbd_work *work)
name, treename);
status = ksmbd_tree_conn_connect(work, name);
- if (status.ret == KSMBD_TREE_CONN_STATUS_OK)
+ if (status.ret == KSMBD_TREE_CONN_STATUS_OK) {
+ tree_conn = status.tree_conn;
rsp->hdr.Id.SyncId.TreeId = cpu_to_le32(status.tree_conn->id);
- else
+ } else
goto out_err1;
share = status.tree_conn->share_conf;
@@ -2059,8 +2061,15 @@ int smb2_tree_connect(struct ksmbd_work *work)
status.tree_conn->posix_extensions = true;
write_lock(&sess->tree_conns_lock);
- status.tree_conn->t_state = TREE_CONNECTED;
+ if (status.tree_conn->t_state == TREE_DISCONNECTED) {
+ status.ret = KSMBD_TREE_CONN_STATUS_ERROR;
+ share = NULL;
+ } else {
+ status.tree_conn->t_state = TREE_CONNECTED;
+ }
write_unlock(&sess->tree_conns_lock);
+ if (status.ret != KSMBD_TREE_CONN_STATUS_OK)
+ goto out_err1;
rsp->StructureSize = cpu_to_le16(16);
out_err1:
/*
@@ -2073,8 +2082,13 @@ int smb2_tree_connect(struct ksmbd_work *work)
rsp->ShareFlags = SMB2_SHAREFLAG_MANUAL_CACHING;
rc = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_tree_connect_rsp));
- if (rc)
+ if (rc) {
+ if (status.ret == KSMBD_TREE_CONN_STATUS_OK) {
+ ksmbd_tree_conn_disconnect(sess, status.tree_conn);
+ status.tree_conn = NULL;
+ }
status.ret = KSMBD_TREE_CONN_STATUS_NOMEM;
+ }
if (!IS_ERR(treename))
kfree(treename);
@@ -2110,6 +2124,9 @@ int smb2_tree_connect(struct ksmbd_work *work)
if (status.ret != KSMBD_TREE_CONN_STATUS_OK)
smb2_set_err_rsp(work);
+ if (tree_conn)
+ ksmbd_tree_connect_put(tree_conn);
+
return rc;
}
@@ -2213,17 +2230,6 @@ int smb2_tree_disconnect(struct ksmbd_work *work)
ksmbd_close_tree_conn_fds(work);
- write_lock(&sess->tree_conns_lock);
- if (tcon->t_state == TREE_DISCONNECTED) {
- write_unlock(&sess->tree_conns_lock);
- rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
- err = -ENOENT;
- goto err_out;
- }
-
- tcon->t_state = TREE_DISCONNECTED;
- write_unlock(&sess->tree_conns_lock);
-
err = ksmbd_tree_conn_disconnect(sess, tcon);
if (err) {
rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 580/869] drm/amdkfd: Fix partial migrate issue
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (578 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 579/869] ksmbd: fix tree connection use-after-free in smb2_tree_connect() Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 581/869] drm/amdkfd: return migration pages from copy function Greg Kroah-Hartman
` (289 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Emily Deng, Philip Yang,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emily Deng <Emily.Deng@amd.com>
[ Upstream commit b5f022fe8ec58540e29a32e328f89b7298f70313 ]
For partial migrate from ram to vram, the migrate->cpages is not
equal to migrate->npages, should use migrate->npages to check all needed
migrate pages which could be copied or not.
And only need to set those pages could be migrated to migrate->dst[i], or
the migrate_vma_pages will migrate the wrong pages based on the migrate->dst[i].
v2:
Add mpages to break the loop earlier.
v3:
Uses MIGRATE_PFN_MIGRATE to identify whether page could be migrated.
v4:
Correct the error part.
Signed-off-by: Emily Deng <Emily.Deng@amd.com>
Reviewed-by: Philip Yang<Philip.Yang@amd.com>
Suggested-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Stable-dep-of: 520e345ffe05 ("drm/amdkfd: Fix the case that vm range is hole at svm_migrate_copy_to_vram")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index ca6c48e3703cc..c61b4ec4e141f 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -279,10 +279,11 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
struct migrate_vma *migrate, struct dma_fence **mfence,
dma_addr_t *scratch, uint64_t ttm_res_offset)
{
- uint64_t npages = migrate->cpages;
+ uint64_t npages = migrate->npages;
struct amdgpu_device *adev = node->adev;
struct device *dev = adev->dev;
struct amdgpu_res_cursor cursor;
+ uint64_t mpages = 0;
dma_addr_t *src;
uint64_t *dst;
uint64_t i, j;
@@ -296,14 +297,16 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
amdgpu_res_first(prange->ttm_res, ttm_res_offset,
npages << PAGE_SHIFT, &cursor);
- for (i = j = 0; i < npages; i++) {
+ for (i = j = 0; (i < npages) && (mpages < migrate->cpages); i++) {
struct page *spage;
- dst[i] = cursor.start + (j << PAGE_SHIFT);
- migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]);
- svm_migrate_get_vram_page(prange, migrate->dst[i]);
- migrate->dst[i] = migrate_pfn(migrate->dst[i]);
-
+ if (migrate->src[i] & MIGRATE_PFN_MIGRATE) {
+ dst[i] = cursor.start + (j << PAGE_SHIFT);
+ migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]);
+ svm_migrate_get_vram_page(prange, migrate->dst[i]);
+ migrate->dst[i] = migrate_pfn(migrate->dst[i]);
+ mpages++;
+ }
spage = migrate_pfn_to_page(migrate->src[i]);
if (spage && !is_zone_device_page(spage)) {
src[i] = dma_map_page(dev, spage, 0, PAGE_SIZE,
@@ -354,9 +357,12 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
out_free_vram_pages:
if (r) {
pr_debug("failed %d to copy memory to vram\n", r);
- while (i--) {
+ for (i = 0; i < npages && mpages; i++) {
+ if (!dst[i])
+ continue;
svm_migrate_put_vram_page(adev, dst[i]);
migrate->dst[i] = 0;
+ mpages--;
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 581/869] drm/amdkfd: return migration pages from copy function
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (579 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 580/869] drm/amdkfd: Fix partial migrate issue Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 582/869] Revert "drm/amdkfd: return migration pages from copy function" Greg Kroah-Hartman
` (288 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, James Zhu, Felix Kuehling,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Zhu <James.Zhu@amd.com>
[ Upstream commit bd6093e2f1601c0c83906f5115a2efb6b93050b1 ]
dst MIGRATE_PFN_VALID bit and src MIGRATE_PFN_MIGRATE bit
should always be set when migration success. cpage includes
src MIGRATE_PFN_MIGRATE bit set and MIGRATE_PFN_VALID bit
unset pages for both ram and vram when memory is only allocated
without being populated before migration, those ram pages should
be counted as migrate pages and those vram pages should not be
counted as migrate pages. Here migration pages refer to how many
vram pages involved.
-v2 use dst to check MIGRATE_PFN_VALID bit (suggested-by Philip)
-v3 add warning when vram pages is less than migration pages
return migration pages directly from copy function
-v4 correct comments and copy function return mpage (suggested-by Felix)
Signed-off-by: James Zhu <James.Zhu@amd.com>
Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Stable-dep-of: 520e345ffe05 ("drm/amdkfd: Fix the case that vm range is hole at svm_migrate_copy_to_vram")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 72 ++++++++++++------------
1 file changed, 36 insertions(+), 36 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index c61b4ec4e141f..ee2adb41cb93f 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -261,20 +261,7 @@ static void svm_migrate_put_sys_page(unsigned long addr)
put_page(page);
}
-static unsigned long svm_migrate_unsuccessful_pages(struct migrate_vma *migrate)
-{
- unsigned long upages = 0;
- unsigned long i;
-
- for (i = 0; i < migrate->npages; i++) {
- if (migrate->src[i] & MIGRATE_PFN_VALID &&
- !(migrate->src[i] & MIGRATE_PFN_MIGRATE))
- upages++;
- }
- return upages;
-}
-
-static int
+static long
svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
struct migrate_vma *migrate, struct dma_fence **mfence,
dma_addr_t *scratch, uint64_t ttm_res_offset)
@@ -283,7 +270,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
struct amdgpu_device *adev = node->adev;
struct device *dev = adev->dev;
struct amdgpu_res_cursor cursor;
- uint64_t mpages = 0;
+ long mpages;
dma_addr_t *src;
uint64_t *dst;
uint64_t i, j;
@@ -297,6 +284,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
amdgpu_res_first(prange->ttm_res, ttm_res_offset,
npages << PAGE_SHIFT, &cursor);
+ mpages = 0;
for (i = j = 0; (i < npages) && (mpages < migrate->cpages); i++) {
struct page *spage;
@@ -357,13 +345,14 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
out_free_vram_pages:
if (r) {
pr_debug("failed %d to copy memory to vram\n", r);
- for (i = 0; i < npages && mpages; i++) {
+ while (i-- && mpages) {
if (!dst[i])
continue;
svm_migrate_put_vram_page(adev, dst[i]);
migrate->dst[i] = 0;
mpages--;
}
+ mpages = r;
}
#ifdef DEBUG_FORCE_MIXED_DOMAINS
@@ -381,7 +370,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
}
#endif
- return r;
+ return mpages;
}
static long
@@ -396,7 +385,7 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
struct dma_fence *mfence = NULL;
struct migrate_vma migrate = { 0 };
unsigned long cpages = 0;
- unsigned long mpages = 0;
+ long mpages = 0;
dma_addr_t *scratch;
void *buf;
int r = -ENOMEM;
@@ -442,15 +431,17 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
else
pr_debug("0x%lx pages collected\n", cpages);
- r = svm_migrate_copy_to_vram(node, prange, &migrate, &mfence, scratch, ttm_res_offset);
+ mpages = svm_migrate_copy_to_vram(node, prange, &migrate, &mfence, scratch, ttm_res_offset);
migrate_vma_pages(&migrate);
svm_migrate_copy_done(adev, mfence);
migrate_vma_finalize(&migrate);
- mpages = cpages - svm_migrate_unsuccessful_pages(&migrate);
- pr_debug("successful/cpages/npages 0x%lx/0x%lx/0x%lx\n",
+ if (mpages >= 0)
+ pr_debug("migrated/collected/requested 0x%lx/0x%lx/0x%lx\n",
mpages, cpages, migrate.npages);
+ else
+ r = mpages;
kfd_smi_event_migration_end(node, p->lead_thread->pid,
start >> PAGE_SHIFT, end >> PAGE_SHIFT,
@@ -461,14 +452,13 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
out_free:
kvfree(buf);
out:
- if (!r && mpages) {
+ if (!r && mpages > 0) {
pdd = svm_range_get_pdd_by_node(prange, node);
if (pdd)
WRITE_ONCE(pdd->page_in, pdd->page_in + mpages);
-
- return mpages;
}
- return r;
+
+ return r ? r : mpages;
}
/**
@@ -579,7 +569,7 @@ static void svm_migrate_page_free(struct page *page)
}
}
-static int
+static long
svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
struct migrate_vma *migrate, struct dma_fence **mfence,
dma_addr_t *scratch, uint64_t npages)
@@ -588,6 +578,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
uint64_t *src;
dma_addr_t *dst;
struct page *dpage;
+ long mpages;
uint64_t i = 0, j;
uint64_t addr;
int r = 0;
@@ -600,6 +591,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
src = (uint64_t *)(scratch + npages);
dst = scratch;
+ mpages = 0;
for (i = 0, j = 0; i < npages; i++, addr += PAGE_SIZE) {
struct page *spage;
@@ -648,6 +640,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
dst[i] >> PAGE_SHIFT, page_to_pfn(dpage));
migrate->dst[i] = migrate_pfn(page_to_pfn(dpage));
+ mpages++;
j++;
}
@@ -657,13 +650,17 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
out_oom:
if (r) {
pr_debug("failed %d copy to ram\n", r);
- while (i--) {
+ while (i-- && mpages) {
+ if (!migrate->dst[i])
+ continue;
svm_migrate_put_sys_page(dst[i]);
migrate->dst[i] = 0;
+ mpages--;
}
+ mpages = r;
}
- return r;
+ return mpages;
}
/**
@@ -690,9 +687,8 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
{
struct kfd_process *p = container_of(prange->svms, struct kfd_process, svms);
uint64_t npages = (end - start) >> PAGE_SHIFT;
- unsigned long upages = npages;
unsigned long cpages = 0;
- unsigned long mpages = 0;
+ long mpages = 0;
struct amdgpu_device *adev = node->adev;
struct kfd_process_device *pdd;
struct dma_fence *mfence = NULL;
@@ -747,13 +743,15 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
else
pr_debug("0x%lx pages collected\n", cpages);
- r = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence,
+ mpages = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence,
scratch, npages);
migrate_vma_pages(&migrate);
- upages = svm_migrate_unsuccessful_pages(&migrate);
- pr_debug("unsuccessful/cpages/npages 0x%lx/0x%lx/0x%lx\n",
- upages, cpages, migrate.npages);
+ if (mpages >= 0)
+ pr_debug("migrated/collected/requested 0x%lx/0x%lx/0x%lx\n",
+ mpages, cpages, migrate.npages);
+ else
+ r = mpages;
svm_migrate_copy_done(adev, mfence);
migrate_vma_finalize(&migrate);
@@ -767,8 +765,7 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
out_free:
kvfree(buf);
out:
- if (!r && cpages) {
- mpages = cpages - upages;
+ if (!r && mpages > 0) {
pdd = svm_range_get_pdd_by_node(prange, node);
if (pdd)
WRITE_ONCE(pdd->page_out, pdd->page_out + mpages);
@@ -851,6 +848,9 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm,
}
if (r >= 0) {
+ WARN_ONCE(prange->vram_pages < mpages,
+ "Recorded vram pages(0x%llx) should not be less than migration pages(0x%lx).",
+ prange->vram_pages, mpages);
prange->vram_pages -= mpages;
/* prange does not have vram page set its actual_loc to system
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 582/869] Revert "drm/amdkfd: return migration pages from copy function"
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (580 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 581/869] drm/amdkfd: return migration pages from copy function Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 583/869] drm/amdkfd: Fix the case that vm range is hole at svm_migrate_copy_to_vram Greg Kroah-Hartman
` (287 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, James Zhu, Philip Yang, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Zhu <James.Zhu@amd.com>
[ Upstream commit 7ccaaf13197fddb525571d6646bc174405efb37c ]
This reverts commit bd6093e2f1601c0c83906f5115a2efb6b93050b1.
migrate_vma_pages can fail if a CPU thread faults on the same page.
However, the page table is locked and only one of the new pages will
be inserted. The device driver will see that the MIGRATE_PFN_MIGRATE
bit is cleared if it loses the race.
Signed-off-by: James Zhu <James.Zhu@amd.com>
Reviewed-by: Philip Yang <Philip.Yang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Stable-dep-of: 520e345ffe05 ("drm/amdkfd: Fix the case that vm range is hole at svm_migrate_copy_to_vram")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 130 +++++++++++------------
1 file changed, 65 insertions(+), 65 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index ee2adb41cb93f..1befda9f40685 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -39,22 +39,22 @@
#endif
#define dev_fmt(fmt) "kfd_migrate: " fmt
-static uint64_t
-svm_migrate_direct_mapping_addr(struct amdgpu_device *adev, uint64_t addr)
+static u64
+svm_migrate_direct_mapping_addr(struct amdgpu_device *adev, u64 addr)
{
return addr + amdgpu_ttm_domain_start(adev, TTM_PL_VRAM);
}
static int
-svm_migrate_gart_map(struct amdgpu_ring *ring, uint64_t npages,
- dma_addr_t *addr, uint64_t *gart_addr, uint64_t flags)
+svm_migrate_gart_map(struct amdgpu_ring *ring, u64 npages,
+ dma_addr_t *addr, u64 *gart_addr, u64 flags)
{
struct amdgpu_device *adev = ring->adev;
struct amdgpu_job *job;
unsigned int num_dw, num_bytes;
struct dma_fence *fence;
- uint64_t src_addr, dst_addr;
- uint64_t pte_flags;
+ u64 src_addr, dst_addr;
+ u64 pte_flags;
void *cpu_addr;
int r;
@@ -123,15 +123,15 @@ svm_migrate_gart_map(struct amdgpu_ring *ring, uint64_t npages,
static int
svm_migrate_copy_memory_gart(struct amdgpu_device *adev, dma_addr_t *sys,
- uint64_t *vram, uint64_t npages,
+ u64 *vram, u64 npages,
enum MIGRATION_COPY_DIR direction,
struct dma_fence **mfence)
{
- const uint64_t GTT_MAX_PAGES = AMDGPU_GTT_MAX_TRANSFER_SIZE;
+ const u64 GTT_MAX_PAGES = AMDGPU_GTT_MAX_TRANSFER_SIZE;
struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
- uint64_t gart_s, gart_d;
+ u64 gart_s, gart_d;
struct dma_fence *next;
- uint64_t size;
+ u64 size;
int r;
mutex_lock(&adev->mman.gtt_window_lock);
@@ -261,30 +261,42 @@ static void svm_migrate_put_sys_page(unsigned long addr)
put_page(page);
}
-static long
+static unsigned long svm_migrate_unsuccessful_pages(struct migrate_vma *migrate)
+{
+ unsigned long upages = 0;
+ unsigned long i;
+
+ for (i = 0; i < migrate->npages; i++) {
+ if (migrate->src[i] & MIGRATE_PFN_VALID &&
+ !(migrate->src[i] & MIGRATE_PFN_MIGRATE))
+ upages++;
+ }
+ return upages;
+}
+
+static int
svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
struct migrate_vma *migrate, struct dma_fence **mfence,
- dma_addr_t *scratch, uint64_t ttm_res_offset)
+ dma_addr_t *scratch, u64 ttm_res_offset)
{
- uint64_t npages = migrate->npages;
+ u64 npages = migrate->npages;
struct amdgpu_device *adev = node->adev;
struct device *dev = adev->dev;
struct amdgpu_res_cursor cursor;
- long mpages;
+ u64 mpages = 0;
dma_addr_t *src;
- uint64_t *dst;
- uint64_t i, j;
+ u64 *dst;
+ u64 i, j;
int r;
pr_debug("svms 0x%p [0x%lx 0x%lx 0x%llx]\n", prange->svms, prange->start,
prange->last, ttm_res_offset);
src = scratch;
- dst = (uint64_t *)(scratch + npages);
+ dst = (u64 *)(scratch + npages);
amdgpu_res_first(prange->ttm_res, ttm_res_offset,
npages << PAGE_SHIFT, &cursor);
- mpages = 0;
for (i = j = 0; (i < npages) && (mpages < migrate->cpages); i++) {
struct page *spage;
@@ -345,14 +357,13 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
out_free_vram_pages:
if (r) {
pr_debug("failed %d to copy memory to vram\n", r);
- while (i-- && mpages) {
+ for (i = 0; i < npages && mpages; i++) {
if (!dst[i])
continue;
svm_migrate_put_vram_page(adev, dst[i]);
migrate->dst[i] = 0;
mpages--;
}
- mpages = r;
}
#ifdef DEBUG_FORCE_MIXED_DOMAINS
@@ -370,22 +381,22 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
}
#endif
- return mpages;
+ return r;
}
static long
svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
- struct vm_area_struct *vma, uint64_t start,
- uint64_t end, uint32_t trigger, uint64_t ttm_res_offset)
+ struct vm_area_struct *vma, u64 start,
+ u64 end, uint32_t trigger, u64 ttm_res_offset)
{
struct kfd_process *p = container_of(prange->svms, struct kfd_process, svms);
- uint64_t npages = (end - start) >> PAGE_SHIFT;
+ u64 npages = (end - start) >> PAGE_SHIFT;
struct amdgpu_device *adev = node->adev;
struct kfd_process_device *pdd;
struct dma_fence *mfence = NULL;
struct migrate_vma migrate = { 0 };
unsigned long cpages = 0;
- long mpages = 0;
+ unsigned long mpages = 0;
dma_addr_t *scratch;
void *buf;
int r = -ENOMEM;
@@ -398,7 +409,7 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev);
buf = kvcalloc(npages,
- 2 * sizeof(*migrate.src) + sizeof(uint64_t) + sizeof(dma_addr_t),
+ 2 * sizeof(*migrate.src) + sizeof(u64) + sizeof(dma_addr_t),
GFP_KERNEL);
if (!buf)
goto out;
@@ -431,17 +442,15 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
else
pr_debug("0x%lx pages collected\n", cpages);
- mpages = svm_migrate_copy_to_vram(node, prange, &migrate, &mfence, scratch, ttm_res_offset);
+ r = svm_migrate_copy_to_vram(node, prange, &migrate, &mfence, scratch, ttm_res_offset);
migrate_vma_pages(&migrate);
svm_migrate_copy_done(adev, mfence);
migrate_vma_finalize(&migrate);
- if (mpages >= 0)
- pr_debug("migrated/collected/requested 0x%lx/0x%lx/0x%lx\n",
- mpages, cpages, migrate.npages);
- else
- r = mpages;
+ mpages = cpages - svm_migrate_unsuccessful_pages(&migrate);
+ pr_debug("successful/cpages/npages 0x%lx/0x%lx/0x%lx\n",
+ mpages, cpages, migrate.npages);
kfd_smi_event_migration_end(node, p->lead_thread->pid,
start >> PAGE_SHIFT, end >> PAGE_SHIFT,
@@ -452,13 +461,14 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
out_free:
kvfree(buf);
out:
- if (!r && mpages > 0) {
+ if (!r && mpages) {
pdd = svm_range_get_pdd_by_node(prange, node);
if (pdd)
WRITE_ONCE(pdd->page_in, pdd->page_in + mpages);
- }
- return r ? r : mpages;
+ return mpages;
+ }
+ return r;
}
/**
@@ -482,7 +492,7 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc,
{
unsigned long addr, start, end;
struct vm_area_struct *vma;
- uint64_t ttm_res_offset;
+ u64 ttm_res_offset;
struct kfd_node *node;
unsigned long mpages = 0;
long r = 0;
@@ -569,18 +579,17 @@ static void svm_migrate_page_free(struct page *page)
}
}
-static long
+static int
svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
struct migrate_vma *migrate, struct dma_fence **mfence,
- dma_addr_t *scratch, uint64_t npages)
+ dma_addr_t *scratch, u64 npages)
{
struct device *dev = adev->dev;
- uint64_t *src;
+ u64 *src;
dma_addr_t *dst;
struct page *dpage;
- long mpages;
- uint64_t i = 0, j;
- uint64_t addr;
+ u64 i = 0, j;
+ u64 addr;
int r = 0;
pr_debug("svms 0x%p [0x%lx 0x%lx]\n", prange->svms, prange->start,
@@ -588,10 +597,9 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
addr = migrate->start;
- src = (uint64_t *)(scratch + npages);
+ src = (u64 *)(scratch + npages);
dst = scratch;
- mpages = 0;
for (i = 0, j = 0; i < npages; i++, addr += PAGE_SIZE) {
struct page *spage;
@@ -640,7 +648,6 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
dst[i] >> PAGE_SHIFT, page_to_pfn(dpage));
migrate->dst[i] = migrate_pfn(page_to_pfn(dpage));
- mpages++;
j++;
}
@@ -650,17 +657,13 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
out_oom:
if (r) {
pr_debug("failed %d copy to ram\n", r);
- while (i-- && mpages) {
- if (!migrate->dst[i])
- continue;
+ while (i--) {
svm_migrate_put_sys_page(dst[i]);
migrate->dst[i] = 0;
- mpages--;
}
- mpages = r;
}
- return mpages;
+ return r;
}
/**
@@ -682,13 +685,14 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
*/
static long
svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
- struct vm_area_struct *vma, uint64_t start, uint64_t end,
+ struct vm_area_struct *vma, u64 start, u64 end,
uint32_t trigger, struct page *fault_page)
{
struct kfd_process *p = container_of(prange->svms, struct kfd_process, svms);
- uint64_t npages = (end - start) >> PAGE_SHIFT;
+ u64 npages = (end - start) >> PAGE_SHIFT;
+ unsigned long upages = npages;
unsigned long cpages = 0;
- long mpages = 0;
+ unsigned long mpages = 0;
struct amdgpu_device *adev = node->adev;
struct kfd_process_device *pdd;
struct dma_fence *mfence = NULL;
@@ -708,7 +712,7 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
migrate.flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE;
buf = kvcalloc(npages,
- 2 * sizeof(*migrate.src) + sizeof(uint64_t) + sizeof(dma_addr_t),
+ 2 * sizeof(*migrate.src) + sizeof(u64) + sizeof(dma_addr_t),
GFP_KERNEL);
if (!buf)
goto out;
@@ -743,15 +747,13 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
else
pr_debug("0x%lx pages collected\n", cpages);
- mpages = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence,
+ r = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence,
scratch, npages);
migrate_vma_pages(&migrate);
- if (mpages >= 0)
- pr_debug("migrated/collected/requested 0x%lx/0x%lx/0x%lx\n",
- mpages, cpages, migrate.npages);
- else
- r = mpages;
+ upages = svm_migrate_unsuccessful_pages(&migrate);
+ pr_debug("unsuccessful/cpages/npages 0x%lx/0x%lx/0x%lx\n",
+ upages, cpages, migrate.npages);
svm_migrate_copy_done(adev, mfence);
migrate_vma_finalize(&migrate);
@@ -765,7 +767,8 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
out_free:
kvfree(buf);
out:
- if (!r && mpages > 0) {
+ if (!r && cpages) {
+ mpages = cpages - upages;
pdd = svm_range_get_pdd_by_node(prange, node);
if (pdd)
WRITE_ONCE(pdd->page_out, pdd->page_out + mpages);
@@ -848,9 +851,6 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm,
}
if (r >= 0) {
- WARN_ONCE(prange->vram_pages < mpages,
- "Recorded vram pages(0x%llx) should not be less than migration pages(0x%lx).",
- prange->vram_pages, mpages);
prange->vram_pages -= mpages;
/* prange does not have vram page set its actual_loc to system
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 583/869] drm/amdkfd: Fix the case that vm range is hole at svm_migrate_copy_to_vram
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (581 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 582/869] Revert "drm/amdkfd: return migration pages from copy function" Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 584/869] drm/amdkfd: return migration pages from copy function - again Greg Kroah-Hartman
` (286 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Xiaogang Chen, Felix Kuehling,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiaogang Chen <xiaogang.chen@amd.com>
[ Upstream commit 520e345ffe05aabef1db82beda4288afb1757ff2 ]
When migration vm range is hole at cpu side(MIGRATE_PFN_MIGRATE set +
MIGRATE_PFN_VALID unset) driver still allocates device pages. There is no
dma map of src pages and migration. j is 0 and svm_migrate_copy_memory_gart()
will return an uninitialized r. That can trigger out_free_vram_pages to drop
all VRAM just set up.
Initialize r and only call the last svm_migrate_copy_memory_gart if j > 0.
Current code postponed the last page to the final copy. This patch flushes on
the last page when reach to the end of current drm_buddy_block; avoids another
svm_migrate_copy_memory_gart.
Cc: stable@vger.kernel.org
Signed-off-by: Xiaogang Chen <xiaogang.chen@amd.com>
Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index 1befda9f40685..bdfba8b3faffa 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -132,7 +132,7 @@ svm_migrate_copy_memory_gart(struct amdgpu_device *adev, dma_addr_t *sys,
u64 gart_s, gart_d;
struct dma_fence *next;
u64 size;
- int r;
+ int r = 0;
mutex_lock(&adev->mman.gtt_window_lock);
@@ -287,7 +287,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
dma_addr_t *src;
u64 *dst;
u64 i, j;
- int r;
+ int r = 0;
pr_debug("svms 0x%p [0x%lx 0x%lx 0x%llx]\n", prange->svms, prange->start,
prange->last, ttm_res_offset);
@@ -313,6 +313,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
DMA_BIDIRECTIONAL);
r = dma_mapping_error(dev, src[i]);
if (r) {
+ src[i] = 0;
dev_err(dev, "%s: fail %d dma_map_page\n",
__func__, r);
goto out_free_vram_pages;
@@ -337,7 +338,8 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
pr_debug_ratelimited("dma mapping src to 0x%llx, pfn 0x%lx\n",
src[i] >> PAGE_SHIFT, page_to_pfn(spage));
- if (j >= (cursor.size >> PAGE_SHIFT) - 1 && i < npages - 1) {
+ /* accumulated j + 1 pages reach end of current drm_buddy_block */
+ if (j + 1 >= (cursor.size >> PAGE_SHIFT)) {
r = svm_migrate_copy_memory_gart(adev, src + i - j,
dst + i - j, j + 1,
FROM_RAM_TO_VRAM,
@@ -351,7 +353,8 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
}
}
- r = svm_migrate_copy_memory_gart(adev, src + i - j, dst + i - j, j,
+ if (j > 0)
+ r = svm_migrate_copy_memory_gart(adev, src + i - j, dst + i - j, j,
FROM_RAM_TO_VRAM, mfence);
out_free_vram_pages:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 584/869] drm/amdkfd: return migration pages from copy function - again
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (582 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 583/869] drm/amdkfd: Fix the case that vm range is hole at svm_migrate_copy_to_vram Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 585/869] drm/amdkfd: Fix error path at svm_migrate_copy_to_ram Greg Kroah-Hartman
` (285 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, James Zhu, Felix Kuehling,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Zhu <James.Zhu@amd.com>
[ Upstream commit bd6093e2f1601c0c83906f5115a2efb6b93050b1 ]
dst MIGRATE_PFN_VALID bit and src MIGRATE_PFN_MIGRATE bit
should always be set when migration success. cpage includes
src MIGRATE_PFN_MIGRATE bit set and MIGRATE_PFN_VALID bit
unset pages for both ram and vram when memory is only allocated
without being populated before migration, those ram pages should
be counted as migrate pages and those vram pages should not be
counted as migrate pages. Here migration pages refer to how many
vram pages involved.
-v2 use dst to check MIGRATE_PFN_VALID bit (suggested-by Philip)
-v3 add warning when vram pages is less than migration pages
return migration pages directly from copy function
-v4 correct comments and copy function return mpage (suggested-by Felix)
Signed-off-by: James Zhu <James.Zhu@amd.com>
Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
[ Dropped the leftover svm_migrate_unsuccessful_pages() call in the
no-collected-pages path of svm_migrate_vma_to_ram(), since the helper
and upages no longer exist after this change. ]
[ Kept the forward unwind loop in svm_migrate_copy_to_vram() so the page
at the failing index is released too. ]
Stable-dep-of: 960c4a8069bf ("drm/amdkfd: Fix error path at svm_migrate_copy_to_ram")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 73 ++++++++++++------------
1 file changed, 36 insertions(+), 37 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index bdfba8b3faffa..b8e11ffc72204 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -261,20 +261,7 @@ static void svm_migrate_put_sys_page(unsigned long addr)
put_page(page);
}
-static unsigned long svm_migrate_unsuccessful_pages(struct migrate_vma *migrate)
-{
- unsigned long upages = 0;
- unsigned long i;
-
- for (i = 0; i < migrate->npages; i++) {
- if (migrate->src[i] & MIGRATE_PFN_VALID &&
- !(migrate->src[i] & MIGRATE_PFN_MIGRATE))
- upages++;
- }
- return upages;
-}
-
-static int
+static long
svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
struct migrate_vma *migrate, struct dma_fence **mfence,
dma_addr_t *scratch, u64 ttm_res_offset)
@@ -283,7 +270,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
struct amdgpu_device *adev = node->adev;
struct device *dev = adev->dev;
struct amdgpu_res_cursor cursor;
- u64 mpages = 0;
+ long mpages;
dma_addr_t *src;
u64 *dst;
u64 i, j;
@@ -297,6 +284,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
amdgpu_res_first(prange->ttm_res, ttm_res_offset,
npages << PAGE_SHIFT, &cursor);
+ mpages = 0;
for (i = j = 0; (i < npages) && (mpages < migrate->cpages); i++) {
struct page *spage;
@@ -367,6 +355,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
migrate->dst[i] = 0;
mpages--;
}
+ mpages = r;
}
#ifdef DEBUG_FORCE_MIXED_DOMAINS
@@ -384,7 +373,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
}
#endif
- return r;
+ return mpages;
}
static long
@@ -399,7 +388,7 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
struct dma_fence *mfence = NULL;
struct migrate_vma migrate = { 0 };
unsigned long cpages = 0;
- unsigned long mpages = 0;
+ long mpages = 0;
dma_addr_t *scratch;
void *buf;
int r = -ENOMEM;
@@ -445,15 +434,17 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
else
pr_debug("0x%lx pages collected\n", cpages);
- r = svm_migrate_copy_to_vram(node, prange, &migrate, &mfence, scratch, ttm_res_offset);
+ mpages = svm_migrate_copy_to_vram(node, prange, &migrate, &mfence, scratch, ttm_res_offset);
migrate_vma_pages(&migrate);
svm_migrate_copy_done(adev, mfence);
migrate_vma_finalize(&migrate);
- mpages = cpages - svm_migrate_unsuccessful_pages(&migrate);
- pr_debug("successful/cpages/npages 0x%lx/0x%lx/0x%lx\n",
- mpages, cpages, migrate.npages);
+ if (mpages >= 0)
+ pr_debug("migrated/collected/requested 0x%lx/0x%lx/0x%lx\n",
+ mpages, cpages, migrate.npages);
+ else
+ r = mpages;
kfd_smi_event_migration_end(node, p->lead_thread->pid,
start >> PAGE_SHIFT, end >> PAGE_SHIFT,
@@ -464,14 +455,13 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
out_free:
kvfree(buf);
out:
- if (!r && mpages) {
+ if (!r && mpages > 0) {
pdd = svm_range_get_pdd_by_node(prange, node);
if (pdd)
WRITE_ONCE(pdd->page_in, pdd->page_in + mpages);
-
- return mpages;
}
- return r;
+
+ return r ? r : mpages;
}
/**
@@ -582,7 +572,7 @@ static void svm_migrate_page_free(struct page *page)
}
}
-static int
+static long
svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
struct migrate_vma *migrate, struct dma_fence **mfence,
dma_addr_t *scratch, u64 npages)
@@ -591,6 +581,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
u64 *src;
dma_addr_t *dst;
struct page *dpage;
+ long mpages;
u64 i = 0, j;
u64 addr;
int r = 0;
@@ -603,6 +594,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
src = (u64 *)(scratch + npages);
dst = scratch;
+ mpages = 0;
for (i = 0, j = 0; i < npages; i++, addr += PAGE_SIZE) {
struct page *spage;
@@ -651,6 +643,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
dst[i] >> PAGE_SHIFT, page_to_pfn(dpage));
migrate->dst[i] = migrate_pfn(page_to_pfn(dpage));
+ mpages++;
j++;
}
@@ -660,13 +653,17 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
out_oom:
if (r) {
pr_debug("failed %d copy to ram\n", r);
- while (i--) {
+ while (i-- && mpages) {
+ if (!migrate->dst[i])
+ continue;
svm_migrate_put_sys_page(dst[i]);
migrate->dst[i] = 0;
+ mpages--;
}
+ mpages = r;
}
- return r;
+ return mpages;
}
/**
@@ -693,9 +690,8 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
{
struct kfd_process *p = container_of(prange->svms, struct kfd_process, svms);
u64 npages = (end - start) >> PAGE_SHIFT;
- unsigned long upages = npages;
unsigned long cpages = 0;
- unsigned long mpages = 0;
+ long mpages = 0;
struct amdgpu_device *adev = node->adev;
struct kfd_process_device *pdd;
struct dma_fence *mfence = NULL;
@@ -741,7 +737,6 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
if (!cpages) {
pr_debug("failed collect migrate device pages [0x%lx 0x%lx]\n",
prange->start, prange->last);
- upages = svm_migrate_unsuccessful_pages(&migrate);
goto out_free;
}
if (cpages != npages)
@@ -750,13 +745,15 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
else
pr_debug("0x%lx pages collected\n", cpages);
- r = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence,
+ mpages = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence,
scratch, npages);
migrate_vma_pages(&migrate);
- upages = svm_migrate_unsuccessful_pages(&migrate);
- pr_debug("unsuccessful/cpages/npages 0x%lx/0x%lx/0x%lx\n",
- upages, cpages, migrate.npages);
+ if (mpages >= 0)
+ pr_debug("migrated/collected/requested 0x%lx/0x%lx/0x%lx\n",
+ mpages, cpages, migrate.npages);
+ else
+ r = mpages;
svm_migrate_copy_done(adev, mfence);
migrate_vma_finalize(&migrate);
@@ -770,8 +767,7 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
out_free:
kvfree(buf);
out:
- if (!r && cpages) {
- mpages = cpages - upages;
+ if (!r && mpages > 0) {
pdd = svm_range_get_pdd_by_node(prange, node);
if (pdd)
WRITE_ONCE(pdd->page_out, pdd->page_out + mpages);
@@ -854,6 +850,9 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm,
}
if (r >= 0) {
+ WARN_ONCE(prange->vram_pages < mpages,
+ "Recorded vram pages(0x%llx) should not be less than migration pages(0x%lx).",
+ prange->vram_pages, mpages);
prange->vram_pages -= mpages;
/* prange does not have vram page set its actual_loc to system
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 585/869] drm/amdkfd: Fix error path at svm_migrate_copy_to_ram
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (583 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 584/869] drm/amdkfd: return migration pages from copy function - again Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 586/869] drm/amdkfd: Add TLB flush after MES queue eviction/suspension Greg Kroah-Hartman
` (284 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Xiaogang Chen, Felix Kuehling,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiaogang Chen <xiaogang.chen@amd.com>
[ Upstream commit 960c4a8069bfd352c48cc88592618f1ebe24c69e ]
If page migration from device to sys ram fails for some reasons driver needs
release and unlock allocated system pages. To do that driver should use page
physical address, or pfn, then get struct page*. Current driver uses dma
address(for adev) that is not correct with IOMMU enabled, or even in general.
The patch releases and unlocks allocated system pages based on where migration
failed by struct page* of sys ram pages. Also dma_unmap correspodent system
ram pages at error path.
Cc: stable@vger.kernel.org
Signed-off-by: Xiaogang Chen <xiaogang.chen@amd.com>
Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 47 +++++++++++++++---------
1 file changed, 30 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index b8e11ffc72204..39bc24e86c2a2 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -252,15 +252,6 @@ svm_migrate_get_sys_page(struct vm_area_struct *vma, unsigned long addr)
return page;
}
-static void svm_migrate_put_sys_page(unsigned long addr)
-{
- struct page *page;
-
- page = pfn_to_page(addr >> PAGE_SHIFT);
- unlock_page(page);
- put_page(page);
-}
-
static long
svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange,
struct migrate_vma *migrate, struct dma_fence **mfence,
@@ -578,10 +569,11 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
dma_addr_t *scratch, u64 npages)
{
struct device *dev = adev->dev;
- u64 *src;
+ struct page *dpage = NULL;
dma_addr_t *dst;
- struct page *dpage;
+ u64 *src;
long mpages;
+
u64 i = 0, j;
u64 addr;
int r = 0;
@@ -636,6 +628,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
r = dma_mapping_error(dev, dst[i]);
if (r) {
dev_err(adev->dev, "%s: fail %d dma_map_page\n", __func__, r);
+ dst[i] = 0;
goto out_oom;
}
@@ -644,19 +637,39 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
migrate->dst[i] = migrate_pfn(page_to_pfn(dpage));
mpages++;
+
+ dpage = NULL;
j++;
}
- r = svm_migrate_copy_memory_gart(adev, dst + i - j, src + i - j, j,
- FROM_VRAM_TO_RAM, mfence);
-
+ if (j > 0)
+ r = svm_migrate_copy_memory_gart(adev, dst + i - j, src + i - j, j,
+ FROM_VRAM_TO_RAM, mfence);
out_oom:
if (r) {
pr_debug("failed %d copy to ram\n", r);
- while (i-- && mpages) {
- if (!migrate->dst[i])
+
+ /* first release current dpage when dma_map_page fail */
+ if (dpage) {
+ unlock_page(dpage);
+ put_page(dpage);
+ }
+
+ /* release previous allocated sys pages and unmap dma address */
+ while (i--) {
+
+ if (dst[i]) {
+ dma_unmap_page(dev, dst[i], PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+ dst[i] = 0;
+ }
+
+ dpage = migrate_pfn_to_page(migrate->dst[i]);
+ if (!dpage)
continue;
- svm_migrate_put_sys_page(dst[i]);
+
+ unlock_page(dpage);
+ put_page(dpage);
migrate->dst[i] = 0;
mpages--;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 586/869] drm/amdkfd: Add TLB flush after MES queue eviction/suspension
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (584 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 585/869] drm/amdkfd: Fix error path at svm_migrate_copy_to_ram Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 587/869] drm/amdgpu: force complete the MES ring fences on reset Greg Kroah-Hartman
` (283 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Priya Hosur, Felix Kuehling,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Priya Hosur <Priya.Hosur@amd.com>
[ Upstream commit 94e25cb6ab7f4f025bcdcd8ea79fda30f12843a4 ]
MES (Micro Engine Scheduler) does not perform heavy-weight TLB
invalidation after unmapping queues, unlike HWS which does this
automatically. This causes a race condition where in-flight DMA
descriptors can access memory that has been unmapped, leading to page
faults and GPU queue hangs during SVM page migration.
The issue manifests as KFDSVMRangeTest.MultiThreadMigrationTest
failures on gfx1151 (Strix Point) with XNACK mode 1 enabled - the GPU
compute queue hangs with packets submitted but never consumed.
Add kfd_flush_tlb() calls after MES queue removal in two locations:
- evict_process_queues_cpsch(): after all queues removed during eviction
- suspend_queues(): after debug/criu queue suspension (with mem_fence barrier)
This ensures all in-flight memory accesses from unmapped queues are
flushed before memory is freed or migrated.
Signed-off-by: Priya Hosur <Priya.Hosur@amd.com>
Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit f5c4f88e0f9c45a8fb9dfac0c1df726c95e41b77)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index 8a6c59af4a4ba..a411ea1a20dca 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -1222,6 +1222,15 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm,
}
}
}
+
+ /*
+ * Heavy-weight TLB flush after MES removes queues to ensure
+ * in-flight memory accesses complete before memory is freed/migrated.
+ * HWS does this automatically, MES does not.
+ */
+ if (dqm->dev->kfd->shared_resources.enable_mes)
+ kfd_flush_tlb(pdd);
+
pdd->last_evict_timestamp = get_jiffies_64();
if (!dqm->dev->kfd->shared_resources.enable_mes)
retval = execute_queues_cpsch(dqm,
@@ -3404,8 +3413,11 @@ int suspend_queues(struct kfd_process *p,
if (!per_device_suspended) {
dqm_unlock(dqm);
mutex_unlock(&p->event_mutex);
- if (total_suspended)
+ if (total_suspended) {
amdgpu_amdkfd_debug_mem_fence(dqm->dev->adev);
+ /* Heavy-weight TLB flush after MES suspends queues */
+ kfd_flush_tlb(pdd);
+ }
continue;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 587/869] drm/amdgpu: force complete the MES ring fences on reset
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (585 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 586/869] drm/amdkfd: Add TLB flush after MES queue eviction/suspension Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 588/869] drm/amdgpu: force complete the KIQ " Greg Kroah-Hartman
` (282 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jesse Zhang, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jesse Zhang <Jesse.Zhang@amd.com>
[ Upstream commit 48dc279c3010ac8f91b1845b2abb3a1e9943a0f5 ]
The MES scheduler ring has no drm scheduler (no_scheduler = true), so it is
skipped by the force-completion loop in amdgpu_device_pre_asic_reset(). It uses
a polling fence whose hw value lives in wb (GTT) memory and survives a MODE1
reset, while fence_drv.sync_seq keeps advancing for every packet.
When the reset is triggered because MES itself stopped responding, the
timed-out packets advance sync_seq past the last hw fence value MES wrote.
After resume the first MES submission polls forever on a seq that is never
written back, failing the resume and wedging the box on a second reset:
amdgpu: MES ring buffer is full.
amdgpu: *ERROR* ring gfx_0.0.0 test failed (-110)
amdgpu: resume of IP block <gfx_v11_0> failed -110
amdgpu: GPU reset end with ret = -110
Force complete the MES scheduler ring fences together with the scheduler rings
so their hw fence is realigned to sync_seq.
v2: cover all XCCs (one scheduler ring each), not just mes.ring[0].
Cc: stable@vger.kernel.org
Signed-off-by: Jesse Zhang <Jesse.Zhang@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 3e74e8dc2e186..ef0f6e75d718b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -5498,6 +5498,19 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
amdgpu_fence_driver_force_completion(ring, fence);
}
+ /*
+ * MES scheduler rings have no drm scheduler, so they are missed by the
+ * loop above. Realign their polling fence too (one per XCC), otherwise the
+ * first post-reset submission polls forever on a stale seq. sched.ready is
+ * only set while the driver owns the ring.
+ */
+ for (i = 0; i < AMDGPU_MAX_MES_PIPES; i++) {
+ struct amdgpu_ring *mes_ring = &adev->mes.ring[i];
+
+ if (mes_ring->fence_drv.initialized && mes_ring->sched.ready)
+ amdgpu_fence_driver_force_completion(mes_ring, fence);
+ }
+
amdgpu_fence_driver_isr_toggle(adev, false);
if (job && job->vm)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 588/869] drm/amdgpu: force complete the KIQ ring fences on reset
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (586 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 587/869] drm/amdgpu: force complete the MES ring fences on reset Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 589/869] f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages() Greg Kroah-Hartman
` (281 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Alex Deucher, Jesse Zhang,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jesse Zhang <Jesse.Zhang@amd.com>
[ Upstream commit fd65d1742992361fc2201ecb4e43411e6e417fcb ]
Like the MES scheduler ring, the KIQ ring sets no_scheduler = true and uses a
polling fence, so it is skipped by the force-completion loop in
amdgpu_device_pre_asic_reset(). Its hw fence value lives in wb (GTT) memory and
survives a MODE1 reset while fence_drv.sync_seq keeps advancing, so after a
reset the first KIQ submission can poll forever on a seq that is never written
back.
Force complete the KIQ ring fences too so their hw fence is realigned to
sync_seq.
Cc: stable@vger.kernel.org
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Suggested-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Jesse Zhang <Jesse.Zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index ef0f6e75d718b..692c8883a0364 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -5511,6 +5511,18 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
amdgpu_fence_driver_force_completion(mes_ring, fence);
}
+ /*
+ * KIQ rings are polling-fence/no_scheduler like MES, so realign their
+ * fence too (one ring per XCC), otherwise the first post-reset KIQ
+ * submission polls forever on a stale seq.
+ */
+ for (i = 0; i < AMDGPU_MAX_GC_INSTANCES; i++) {
+ struct amdgpu_ring *kiq_ring = &adev->gfx.kiq[i].ring;
+
+ if (kiq_ring->fence_drv.initialized && kiq_ring->sched.ready)
+ amdgpu_fence_driver_force_completion(kiq_ring, fence);
+ }
+
amdgpu_fence_driver_isr_toggle(adev, false);
if (job && job->vm)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 589/869] f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (587 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 588/869] drm/amdgpu: force complete the KIQ " Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 590/869] LoongArch: BPF: Refactor jump offset calculation in tail call Greg Kroah-Hartman
` (280 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, stable, Chao Yu, Jaegeuk Kim,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <chao@kernel.org>
[ Upstream commit ce366bfa821ec81dd45bde547ee31e659306cc61 ]
There is potential deadloop in race condition:
Thread A Thread B
- fsync
- f2fs_do_sync_file
- f2fs_fsync_node_pages
- last_fsync_dnode
- folio_get(last_folio)
- f2fs_setattr
- f2fs_truncate
- f2fs_truncate_blocks
- f2fs_do_truncate_blocks
- f2fs_truncate_inode_blocks
- truncate_dnode
- truncate_node
- invalidate_mapping_pages
- folio->mapping = NULL
- is_node_folio alwasy return false
- atomic && !marked is always true,
then goto retry
Cc: stable@kernel.org
Fixes: 608514deba38 ("f2fs: set fsync mark only for the last dnode")
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/f2fs/node.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 111eba597a4a4..8a11623dbf1ef 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -1916,6 +1916,11 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
f2fs_debug(sbi, "Retry to write fsync mark: ino=%u, idx=%lx",
ino, page_folio(last_page)->index);
lock_page(last_page);
+ if (unlikely(last_page->mapping != NODE_MAPPING(sbi))) {
+ f2fs_put_page(last_page, 1);
+ ret = -EAGAIN;
+ goto out;
+ }
f2fs_wait_on_page_writeback(last_page, NODE, true, true);
set_page_dirty(last_page);
unlock_page(last_page);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 590/869] LoongArch: BPF: Refactor jump offset calculation in tail call
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (588 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 589/869] f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages() Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 591/869] KVM: arm64: vgic-v3: take an LPI reference in vgic_v3_save_pending_tables Greg Kroah-Hartman
` (279 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Tiezhu Yang, Huacai Chen,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tiezhu Yang <yangtiezhu@loongson.cn>
[ Upstream commit 37d545d12f21c4d50612ecaebd7ae1e5bf91b2d8 ]
The old macro-based jmp_offset calculation derives the jump distance
from a stale prior-pass code stride, which can lead to wrong branch
offsets and soft lockups under extra JIT passes.
Fix this by calculating the offset directly on the absolute target:
"ctx->offset[insn + 1] - ctx->idx".
To avoid a false 16-bit range check abort during size estimation, add
a "ctx->image == NULL" guard to inject a safe dummy offset.
Cc: stable@vger.kernel.org
Fixes: cd39d9e6b7e4 ("LoongArch: BPF: Fix jump offset calculation in tailcall")
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/loongarch/net/bpf_jit.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
index f1aaa4367fc88..4797b0bcc4fd7 100644
--- a/arch/loongarch/net/bpf_jit.c
+++ b/arch/loongarch/net/bpf_jit.c
@@ -210,17 +210,13 @@ bool bpf_jit_supports_far_kfunc_call(void)
static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn)
{
- int off, tc_ninsn = 0;
+ int off, jmp_offset;
u8 tcc = tail_call_reg(ctx);
u8 a1 = LOONGARCH_GPR_A1;
u8 a2 = LOONGARCH_GPR_A2;
u8 t1 = LOONGARCH_GPR_T1;
u8 t2 = LOONGARCH_GPR_T2;
u8 t3 = LOONGARCH_GPR_T3;
- const int idx0 = ctx->idx;
-
-#define cur_offset (ctx->idx - idx0)
-#define jmp_offset (tc_ninsn - (cur_offset))
/*
* a0: &ctx
@@ -230,12 +226,12 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn)
* if (index >= array->map.max_entries)
* goto out;
*/
- tc_ninsn = insn ? ctx->offset[insn+1] - ctx->offset[insn] : ctx->offset[0];
emit_zext_32(ctx, a2, true);
off = offsetof(struct bpf_array, map.max_entries);
emit_insn(ctx, ldwu, t1, a1, off);
/* bgeu $a2, $t1, jmp_offset */
+ jmp_offset = ctx->image ? (ctx->offset[insn + 1] - ctx->idx) : 0;
if (emit_tailcall_jmp(ctx, BPF_JGE, a2, t1, jmp_offset) < 0)
goto toofar;
@@ -244,6 +240,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn)
* goto out;
*/
emit_insn(ctx, addid, REG_TCC, tcc, -1);
+ jmp_offset = ctx->image ? (ctx->offset[insn + 1] - ctx->idx) : 0;
if (emit_tailcall_jmp(ctx, BPF_JSLT, REG_TCC, LOONGARCH_GPR_ZERO, jmp_offset) < 0)
goto toofar;
@@ -256,6 +253,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn)
off = offsetof(struct bpf_array, ptrs);
emit_insn(ctx, ldd, t2, t2, off);
/* beq $t2, $zero, jmp_offset */
+ jmp_offset = ctx->image ? (ctx->offset[insn + 1] - ctx->idx) : 0;
if (emit_tailcall_jmp(ctx, BPF_JEQ, t2, LOONGARCH_GPR_ZERO, jmp_offset) < 0)
goto toofar;
@@ -269,8 +267,6 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn)
toofar:
pr_info_once("tail_call: jump too far\n");
return -1;
-#undef cur_offset
-#undef jmp_offset
}
static void emit_atomic(const struct bpf_insn *insn, struct jit_ctx *ctx)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 591/869] KVM: arm64: vgic-v3: take an LPI reference in vgic_v3_save_pending_tables
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (589 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 590/869] LoongArch: BPF: Refactor jump offset calculation in tail call Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 592/869] KVM: s390: Fix memory corruption by not reinjecting CK machine checks Greg Kroah-Hartman
` (278 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Qihang, Marc Zyngier, Oliver Upton,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qihang <q.h.hack.winter@gmail.com>
[ Upstream commit f5b8f203bfc07a5a257dff859e66d2c500f9f509 ]
vgic_v3_save_pending_tables() iterates dist->lpi_xa using xa_for_each()
and dereferences the returned struct vgic_irq in the loop body without
holding a reference on the LPI.
The xarray iterator only provides temporary RCU coverage while looking up
the current entry. That is not sufficient for this loop body, which reads
fields from struct vgic_irq and performs guest memory accesses before the
iteration completes.
A concurrent path can trigger this race: the irqfd cached injection path
(vgic_its_inject_cached_translation) obtains a transient LPI reference
via vgic_its_check_cache() without holding kvm->lock, vcpu->mutex,
config_lock, or its_lock. If guest ITS DISCARD then drops the cache and
ITE references under its_lock, the transient inject reference may become
the final one. When vgic_put_irq() drops it, the LPI is erased from
lpi_xa and freed via kfree_rcu(). Meanwhile, vgic_v3_save_pending_tables()
may still hold a stale pointer obtained from the xarray iterator and
dereference it after the RCU grace period completes.
Fix this by re-fetching each iterated LPI via vgic_get_irq(), which takes
a stable reference, and dropping it with vgic_put_irq() on all paths.
This matches the pattern already used by other lpi_xa iterators in the
vgic ITS code.
Cc: stable@vger.kernel.org
Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://patch.msgid.link/20260807025534.34125-1-q.h.hack.winter@gmail.com
Signed-off-by: Oliver Upton <oupton@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm64/kvm/vgic/vgic-v3.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c
index b217b256853c2..3d5e74585505a 100644
--- a/arch/arm64/kvm/vgic/vgic-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-v3.c
@@ -416,9 +416,13 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
bool is_pending;
bool stored;
+ irq = vgic_get_irq(kvm, NULL, index);
+ if (!irq)
+ continue;
+
vcpu = irq->target_vcpu;
if (!vcpu)
- continue;
+ goto put_irq;
pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
@@ -429,7 +433,7 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
if (ptr != last_ptr) {
ret = kvm_read_guest_lock(kvm, ptr, &val, 1);
if (ret)
- goto out;
+ goto put_irq;
last_ptr = ptr;
}
@@ -441,7 +445,7 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
vgic_v4_get_vlpi_state(irq, &is_pending);
if (stored == is_pending)
- continue;
+ goto put_irq;
if (is_pending)
val |= 1 << bit_nr;
@@ -449,6 +453,8 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
val &= ~(1 << bit_nr);
ret = vgic_write_guest_lock(kvm, ptr, &val, 1);
+put_irq:
+ vgic_put_irq(kvm, irq);
if (ret)
goto out;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 592/869] KVM: s390: Fix memory corruption by not reinjecting CK machine checks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (590 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 591/869] KVM: arm64: vgic-v3: take an LPI reference in vgic_v3_save_pending_tables Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 593/869] mm/huge_memory: transfer the pmd dirty bit to the folio on zap Greg Kroah-Hartman
` (277 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Borntraeger,
Heiko Carstens, Claudio Imbrenda, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Borntraeger <borntraeger@linux.ibm.com>
[ Upstream commit 546dde823a36d7283dcf46127c2f3d093443860f ]
Channel-subsystem damage machine checks are for the host channel
subsystem. The guest channel subsystem is emulated in the userspace VMM.
There is no point in forwarding such machine checks into the guest.
This also simplifies the machine check reinjection and avoids kfree of a
stack variable as reported by sashiko. There might be still machine
checks that have the ck bit set with another bit (like instruction
damage), mask out the CK bit in s390_backup_mcck_info(), like the CP and
ED bits already are.
Fixes: 4d62fcc0b692 ("KVM: s390: Inject machine check into the guest")
Cc: stable@vger.kernel.org
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Acked-by: Heiko Carstens <hca@linux.ibm.com>
Acked-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260806145835.31818-1-borntraeger@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/include/asm/nmi.h | 3 +++
arch/s390/kernel/nmi.c | 5 +----
arch/s390/kvm/interrupt.c | 24 ++++++++----------------
3 files changed, 12 insertions(+), 20 deletions(-)
diff --git a/arch/s390/include/asm/nmi.h b/arch/s390/include/asm/nmi.h
index 227466ce9e416..da5a98183cb65 100644
--- a/arch/s390/include/asm/nmi.h
+++ b/arch/s390/include/asm/nmi.h
@@ -22,6 +22,7 @@
#define MCCK_CODE_SYSTEM_DAMAGE BIT(63)
#define MCCK_CODE_EXT_DAMAGE BIT(63 - 5)
#define MCCK_CODE_CP BIT(63 - 9)
+#define MCCK_CODE_CK BIT(63 - 11)
#define MCCK_CODE_STG_ERROR BIT(63 - 16)
#define MCCK_CODE_STG_KEY_ERROR BIT(63 - 18)
#define MCCK_CODE_STG_DEGRAD BIT(63 - 19)
@@ -33,6 +34,8 @@
#define MCCK_CODE_FC_VALID BIT(63 - 43)
#define MCCK_CODE_CPU_TIMER_VALID BIT(63 - 46)
+#define MCCK_CODE_NO_GUEST (MCCK_CODE_CP | MCCK_CODE_EXT_DAMAGE | MCCK_CODE_CK)
+
#ifndef __ASSEMBLY__
union mci {
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c
index fbd218b6fc8e4..e8d65f87a17df 100644
--- a/arch/s390/kernel/nmi.c
+++ b/arch/s390/kernel/nmi.c
@@ -279,8 +279,7 @@ static void notrace s390_backup_mcck_info(struct pt_regs *regs)
sie_page = container_of(sie_block, struct sie_page, sie_block);
mcck_backup = &sie_page->mcck_info;
- mcck_backup->mcic = get_lowcore()->mcck_interruption_code &
- ~(MCCK_CODE_CP | MCCK_CODE_EXT_DAMAGE);
+ mcck_backup->mcic = get_lowcore()->mcck_interruption_code & ~MCCK_CODE_NO_GUEST;
mcck_backup->ext_damage_code = get_lowcore()->external_damage_code;
mcck_backup->failing_storage_address = get_lowcore()->failing_storage_address;
}
@@ -292,8 +291,6 @@ NOKPROBE_SYMBOL(s390_backup_mcck_info);
#define ED_STP_ISLAND 6 /* External damage STP island check */
#define ED_STP_SYNC 7 /* External damage STP sync check */
-#define MCCK_CODE_NO_GUEST (MCCK_CODE_CP | MCCK_CODE_EXT_DAMAGE)
-
/*
* machine check handler.
*/
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 0f3ad8c80381f..1474a776efa3e 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -2865,9 +2865,7 @@ static int set_adapter_int(struct kvm_kernel_irq_routing_entry *e,
void kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu,
struct mcck_volatile_info *mcck_info)
{
- struct kvm_s390_interrupt_info inti;
struct kvm_s390_irq irq = {};
- struct kvm_s390_mchk_info *mchk;
union mci mci;
__u64 cr14 = 0; /* upper bits are not used */
int rc;
@@ -2880,20 +2878,14 @@ void kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu,
if (mci.w)
cr14 |= CR14_WARNING_SUBMASK;
- mchk = mci.ck ? &inti.mchk : &irq.u.mchk;
- mchk->cr14 = cr14;
- mchk->mcic = mcck_info->mcic;
- mchk->ext_damage_code = mcck_info->ext_damage_code;
- mchk->failing_storage_address = mcck_info->failing_storage_address;
- if (mci.ck) {
- /* Inject the floating machine check */
- inti.type = KVM_S390_MCHK;
- rc = __inject_vm(vcpu->kvm, &inti);
- } else {
- /* Inject the machine check to specified vcpu */
- irq.type = KVM_S390_MCHK;
- rc = kvm_s390_inject_vcpu(vcpu, &irq);
- }
+ irq.u.mchk.cr14 = cr14;
+ irq.u.mchk.mcic = mcck_info->mcic;
+ irq.u.mchk.ext_damage_code = mcck_info->ext_damage_code;
+ irq.u.mchk.failing_storage_address = mcck_info->failing_storage_address;
+
+ /* Inject the machine check to specified vcpu */
+ irq.type = KVM_S390_MCHK;
+ rc = kvm_s390_inject_vcpu(vcpu, &irq);
WARN_ON_ONCE(rc);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 593/869] mm/huge_memory: transfer the pmd dirty bit to the folio on zap
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (591 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 592/869] KVM: s390: Fix memory corruption by not reinjecting CK machine checks Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 594/869] netfilter: nf_tables: prefer nft_trans_elem_alloc helper Greg Kroah-Hartman
` (276 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Usama Arif, David Hildenbrand (Arm),
Kiryl Shutsemau, Hugh Dickins, Lance Yang, Zi Yan,
Lorenzo Stoakes (ARM), Baolin Wang, Barry Song, Dev Jain,
Johannes Weiner, Liam R. Howlett, Nhat Pham, Rik van Riel,
Ryan Roberts, Shakeel Butt, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Usama Arif <usama.arif@linux.dev>
[ Upstream commit fe6cf984939d8e12cb33a99673c8d026c5135e68 ]
zap_huge_pmd_folio() propagates the pmd young bit to the folio for the
file case, but not the dirty bit. The pte path does propagate it, in
zap_present_folio_ptes() and so does the pmd split path, in
__split_huge_pmd_locked().
For most file mappings the omission is harmless, because writing to a
shared file mapping goes through page_mkwrite(), which dirties the folio.
tmpfs is different: it has no page_mkwrite(), and vma_wants_writenotify()
is false for it, so a *read* fault on a MAP_SHARED tmpfs mapping installs
a writable pmd via do_read_fault(). do_read_fault() does not call
fault_dirty_shared_page(), so subsequent stores through that mapping set
only the hardware dirty bit in the pmd and never call folio_mark_dirty().
A shmem folio allocated by a fault is marked uptodate but not dirty (see
the clear: block in shmem_get_folio_gfp()), so PG_dirty is never set at
all.
Unmapping such a folio - munmap(), or exit_mmap() when the process dies -
then loses the only record that it was written, because zap_huge_pmd()
drops the pmd without transferring the dirty bit. Reclaim afterwards sees
a clean shmem folio: the whole swap-out block in shrink_folio_list() is
inside "if (folio_test_dirty(folio))", so pageout() is skipped and the
folio falls into __remove_mapping(). There, folio_is_file_lru() is false
for a swapbacked folio, so no shadow entry is created and
__filemap_remove_folio(folio, NULL) simply empties the i_pages slot. The
data is freed without ever being written to swap, and the next fault on
that index returns a freshly zeroed folio.
This is silent data loss for any process that keeps state in a MAP_SHARED
tmpfs segment across an unmap - for example a cache handed from one
process generation to the next through /dev/shm. It requires the folio to
be PMD-mapped, so it only shows up once shmem THP is enabled (which is
what we did in Meta fleet and started noticing crashes); with THP off the
pte path transfers the dirty bit correctly. It also only becomes visible
when swap is enabled, because with no swap device shmem folios (which are
on the anon LRU) are not scanned by reclaim at all, so the clean folio is
never dropped.
Reproduced on x86_64 with a tmpfs mounted huge=within_size: read-fault a
2MB-backed region, write a known pattern through the resulting mapping,
munmap, force reclaim of the cgroup, then re-map and read back. Without
this patch the region reads back as zeros and vmstat shows zswpout 0 - the
data was discarded rather than swapped. With this patch the region reads
back correctly and the pages are swapped out as expected. With
huge=never, or when the first touch is a write, the test passes either
way.
Link: https://lore.kernel.org/20260819101222.3732660-1-usama.arif@linux.dev
Fixes: b5072380eb61 ("thp: support file pages in zap_huge_pmd()")
Signed-off-by: Usama Arif <usama.arif@linux.dev>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Kiryl Shutsemau <kas@kernel.org>
Acked-by: Hugh Dickins <hughd@google.com>
Tested-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
shared file mapping goes through page_mkwrite(), which dirties the folio.
tmpfs is different: it has no page_mkwrite(), and vma_wants_writenotify()
is false for it, so a *read* fault on a MAP_SHARED tmpfs mapping installs
a writable pmd via do_read_fault(). do_read_fault() does not call
fault_dirty_shared_page(), so subsequent stores through that mapping set
only the hardware dirty bit in the pmd and never call folio_mark_dirty().
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/huge_memory.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 1a76a21724d40..348fb144e63be 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2112,6 +2112,9 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
zap_deposited_table(tlb->mm, pmd);
add_mm_counter(tlb->mm, mm_counter_file(folio),
-HPAGE_PMD_NR);
+
+ if (pmd_present(orig_pmd) && pmd_dirty(orig_pmd))
+ folio_mark_dirty(folio);
}
spin_unlock(ptl);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 594/869] netfilter: nf_tables: prefer nft_trans_elem_alloc helper
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (592 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 593/869] mm/huge_memory: transfer the pmd dirty bit to the folio on zap Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 595/869] netfilter: nf_tables: add nft_trans_commit_list_add_elem helper Greg Kroah-Hartman
` (275 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Florian Westphal, Pablo Neira Ayuso,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <fw@strlen.de>
[ Upstream commit 08e52cccae11a4148a5810f0bd5614796994d221 ]
Reduce references to sizeof(struct nft_trans_elem).
Preparation patch to move this to a flexiable array to store
elem references.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Stable-dep-of: 43559058d21e ("netfilter: nf_tables: skip double clone set expressions on element insert")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/netfilter/nf_tables_api.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index d6745e9b63370..b5e5eae856fe7 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -6357,7 +6357,7 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx,
nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
}
-static struct nft_trans *nft_trans_elem_alloc(struct nft_ctx *ctx,
+static struct nft_trans *nft_trans_elem_alloc(const struct nft_ctx *ctx,
int msg_type,
struct nft_set *set)
{
@@ -7453,13 +7453,11 @@ static int __nft_set_catchall_flush(const struct nft_ctx *ctx,
{
struct nft_trans *trans;
- trans = nft_trans_alloc_gfp(ctx, NFT_MSG_DELSETELEM,
- sizeof(struct nft_trans_elem), GFP_KERNEL);
+ trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
if (!trans)
return -ENOMEM;
nft_setelem_data_deactivate(ctx->net, set, elem_priv);
- nft_trans_elem_set(trans) = set;
nft_trans_elem_priv(trans) = elem_priv;
nft_trans_commit_list_add_tail(ctx->net, trans);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 595/869] netfilter: nf_tables: add nft_trans_commit_list_add_elem helper
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (593 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 594/869] netfilter: nf_tables: prefer nft_trans_elem_alloc helper Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 596/869] netfilter: nf_tables: prepare for multiple elements in nft_trans_elem structure Greg Kroah-Hartman
` (274 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Florian Westphal, Pablo Neira Ayuso,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <fw@strlen.de>
[ Upstream commit 4ee29181216d2acb7be210126324ec3bc0e3bd01 ]
Add and use a wrapper to append trans_elem structures to the
transaction log.
Unlike the existing helper, pass a gfp_t to indicate if sleeping
is allowed.
This will be used by a followup patch to realloc nft_trans_elem
structures after they gain a flexible array member to reduce
number of such container structures on the transaction list.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Stable-dep-of: 43559058d21e ("netfilter: nf_tables: skip double clone set expressions on element insert")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/netfilter/nf_tables_api.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index b5e5eae856fe7..0e2c5052977cd 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -440,6 +440,17 @@ static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *tr
}
}
+static void nft_trans_commit_list_add_elem(struct net *net, struct nft_trans *trans,
+ gfp_t gfp)
+{
+ WARN_ON_ONCE(trans->msg_type != NFT_MSG_NEWSETELEM &&
+ trans->msg_type != NFT_MSG_DELSETELEM);
+
+ might_alloc(gfp);
+
+ nft_trans_commit_list_add_tail(net, trans);
+}
+
static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
{
struct nft_trans *trans;
@@ -7167,7 +7178,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
if (update_flags) {
nft_trans_elem_priv(trans) = elem_priv;
nft_trans_elem_update_flags(trans) = update_flags;
- nft_trans_commit_list_add_tail(ctx->net, trans);
+ nft_trans_commit_list_add_elem(ctx->net, trans, GFP_KERNEL);
goto err_set_size;
}
}
@@ -7187,7 +7198,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
}
nft_trans_elem_priv(trans) = elem.priv;
- nft_trans_commit_list_add_tail(ctx->net, trans);
+ nft_trans_commit_list_add_elem(ctx->net, trans, GFP_KERNEL);
return set_full ? -ENFILE : 0;
@@ -7406,7 +7417,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
nft_setelem_data_deactivate(ctx->net, set, elem.priv);
nft_trans_elem_priv(trans) = elem.priv;
- nft_trans_commit_list_add_tail(ctx->net, trans);
+ nft_trans_commit_list_add_elem(ctx->net, trans, GFP_KERNEL);
return 0;
fail_ops:
@@ -7442,7 +7453,7 @@ static int nft_setelem_flush(const struct nft_ctx *ctx,
nft_setelem_data_deactivate(ctx->net, set, elem_priv);
nft_trans_elem_set(trans) = set;
nft_trans_elem_priv(trans) = elem_priv;
- nft_trans_commit_list_add_tail(ctx->net, trans);
+ nft_trans_commit_list_add_elem(ctx->net, trans, GFP_ATOMIC);
return 0;
}
@@ -7459,7 +7470,7 @@ static int __nft_set_catchall_flush(const struct nft_ctx *ctx,
nft_setelem_data_deactivate(ctx->net, set, elem_priv);
nft_trans_elem_priv(trans) = elem_priv;
- nft_trans_commit_list_add_tail(ctx->net, trans);
+ nft_trans_commit_list_add_elem(ctx->net, trans, GFP_KERNEL);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 596/869] netfilter: nf_tables: prepare for multiple elements in nft_trans_elem structure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (594 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 595/869] netfilter: nf_tables: add nft_trans_commit_list_add_elem helper Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 597/869] netfilter: nf_tables: skip double clone set expressions on element insert Greg Kroah-Hartman
` (273 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Florian Westphal, Pablo Neira Ayuso,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <fw@strlen.de>
[ Upstream commit a8ee6b900c147d3bedced6c52ba6cb603226aaa3 ]
Add helpers to release the individual elements contained in the
trans_elem container structure.
No functional change intended.
Followup patch will add 'nelems' member and will turn 'priv' into
a flexible array.
These helpers can then loop over all elements.
Care needs to be taken to handle a mix of new elements and existing
elements that are being updated (e.g. timeout refresh).
Before this patch, NEWSETELEM transaction with update is released
early so nft_trans_set_elem_destroy() won't get called, so we need
to skip elements marked as update.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Stable-dep-of: 43559058d21e ("netfilter: nf_tables: skip double clone set expressions on element insert")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/netfilter/nf_tables.h | 21 ++-
net/netfilter/nf_tables_api.c | 228 +++++++++++++++++++++---------
2 files changed, 173 insertions(+), 76 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 99cc25c233b8e..d440915addd6e 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -1774,28 +1774,25 @@ enum nft_trans_elem_flags {
NFT_TRANS_UPD_EXPIRATION = (1 << 1),
};
-struct nft_trans_elem {
- struct nft_trans nft_trans;
- struct nft_set *set;
- struct nft_elem_priv *elem_priv;
+struct nft_trans_one_elem {
+ struct nft_elem_priv *priv;
u64 timeout;
u64 expiration;
u8 update_flags;
+};
+
+struct nft_trans_elem {
+ struct nft_trans nft_trans;
+ struct nft_set *set;
bool bound;
+ unsigned int nelems;
+ struct nft_trans_one_elem elems[] __counted_by(nelems);
};
#define nft_trans_container_elem(t) \
container_of(t, struct nft_trans_elem, nft_trans)
#define nft_trans_elem_set(trans) \
nft_trans_container_elem(trans)->set
-#define nft_trans_elem_priv(trans) \
- nft_trans_container_elem(trans)->elem_priv
-#define nft_trans_elem_update_flags(trans) \
- nft_trans_container_elem(trans)->update_flags
-#define nft_trans_elem_timeout(trans) \
- nft_trans_container_elem(trans)->timeout
-#define nft_trans_elem_expiration(trans) \
- nft_trans_container_elem(trans)->expiration
#define nft_trans_elem_set_bound(trans) \
nft_trans_container_elem(trans)->bound
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 0e2c5052977cd..92a86e81084b1 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -6372,13 +6372,17 @@ static struct nft_trans *nft_trans_elem_alloc(const struct nft_ctx *ctx,
int msg_type,
struct nft_set *set)
{
+ struct nft_trans_elem *te;
struct nft_trans *trans;
- trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_elem));
+ trans = nft_trans_alloc(ctx, msg_type, struct_size(te, elems, 1));
if (trans == NULL)
return NULL;
- nft_trans_elem_set(trans) = set;
+ te = nft_trans_container_elem(trans);
+ te->nelems = 1;
+ te->set = set;
+
return trans;
}
@@ -6500,28 +6504,51 @@ void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
}
/* Drop references and destroy. Called from gc, dynset and abort path. */
-void nft_set_elem_destroy(const struct nft_set *set,
- const struct nft_elem_priv *elem_priv,
- bool destroy_expr)
+static void __nft_set_elem_destroy(const struct nft_ctx *ctx,
+ const struct nft_set *set,
+ const struct nft_elem_priv *elem_priv,
+ bool destroy_expr)
{
struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);
- struct nft_ctx ctx = {
- .net = read_pnet(&set->net),
- .family = set->table->family,
- };
nft_data_release(nft_set_ext_key(ext), NFT_DATA_VALUE);
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
nft_data_release(nft_set_ext_data(ext), set->dtype);
if (destroy_expr && nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
- nft_set_elem_expr_destroy(&ctx, nft_set_ext_expr(ext));
+ nft_set_elem_expr_destroy(ctx, nft_set_ext_expr(ext));
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
nft_use_dec(&(*nft_set_ext_obj(ext))->use);
kfree(elem_priv);
}
+
+/* Drop references and destroy. Called from gc and dynset. */
+void nft_set_elem_destroy(const struct nft_set *set,
+ const struct nft_elem_priv *elem_priv,
+ bool destroy_expr)
+{
+ struct nft_ctx ctx = {
+ .net = read_pnet(&set->net),
+ .family = set->table->family,
+ };
+
+ __nft_set_elem_destroy(&ctx, set, elem_priv, destroy_expr);
+}
EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
+/* Drop references and destroy. Called from abort path. */
+static void nft_trans_set_elem_destroy(const struct nft_ctx *ctx, struct nft_trans_elem *te)
+{
+ int i;
+
+ for (i = 0; i < te->nelems; i++) {
+ if (te->elems[i].update_flags)
+ continue;
+
+ __nft_set_elem_destroy(ctx, te->set, te->elems[i].priv, true);
+ }
+}
+
/* Destroy element. References have been already dropped in the preparation
* path via nft_setelem_data_deactivate().
*/
@@ -6537,6 +6564,15 @@ void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
kfree(elem_priv);
}
+static void nft_trans_elems_destroy(const struct nft_ctx *ctx,
+ const struct nft_trans_elem *te)
+{
+ int i;
+
+ for (i = 0; i < te->nelems; i++)
+ nf_tables_set_elem_destroy(ctx, te->set, te->elems[i].priv);
+}
+
int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_expr *expr_array[])
{
@@ -6696,6 +6732,36 @@ static void nft_setelem_activate(struct net *net, struct nft_set *set,
}
}
+static void nft_trans_elem_update(const struct nft_set *set,
+ const struct nft_trans_one_elem *elem)
+{
+ const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
+
+ if (elem->update_flags & NFT_TRANS_UPD_TIMEOUT)
+ WRITE_ONCE(nft_set_ext_timeout(ext)->timeout, elem->timeout);
+
+ if (elem->update_flags & NFT_TRANS_UPD_EXPIRATION)
+ WRITE_ONCE(nft_set_ext_timeout(ext)->expiration, get_jiffies_64() + elem->expiration);
+}
+
+static void nft_trans_elems_add(const struct nft_ctx *ctx,
+ struct nft_trans_elem *te)
+{
+ int i;
+
+ for (i = 0; i < te->nelems; i++) {
+ const struct nft_trans_one_elem *elem = &te->elems[i];
+
+ if (elem->update_flags)
+ nft_trans_elem_update(te->set, elem);
+ else
+ nft_setelem_activate(ctx->net, te->set, elem->priv);
+
+ nf_tables_setelem_notify(ctx, te->set, elem->priv,
+ NFT_MSG_NEWSETELEM);
+ }
+}
+
static int nft_setelem_catchall_deactivate(const struct net *net,
struct nft_set *set,
struct nft_set_elem *elem)
@@ -6781,6 +6847,24 @@ static void nft_setelem_remove(const struct net *net,
set->ops->remove(net, set, elem_priv);
}
+static void nft_trans_elems_remove(const struct nft_ctx *ctx,
+ const struct nft_trans_elem *te)
+{
+ int i;
+
+ for (i = 0; i < te->nelems; i++) {
+ nf_tables_setelem_notify(ctx, te->set,
+ te->elems[i].priv,
+ te->nft_trans.msg_type);
+
+ nft_setelem_remove(ctx->net, te->set, te->elems[i].priv);
+ if (!nft_setelem_is_catchall(te->set, te->elems[i].priv)) {
+ atomic_dec(&te->set->nelems);
+ te->set->ndeact--;
+ }
+ }
+}
+
static bool nft_setelem_valid_key_end(const struct nft_set *set,
struct nlattr **nla, u32 flags)
{
@@ -7162,22 +7246,26 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
else if (!(nlmsg_flags & NLM_F_EXCL)) {
err = 0;
if (nft_set_ext_exists(ext2, NFT_SET_EXT_TIMEOUT)) {
+ struct nft_trans_one_elem *update;
+
+ update = &nft_trans_container_elem(trans)->elems[0];
+
update_flags = 0;
if (timeout != nft_set_ext_timeout(ext2)->timeout) {
- nft_trans_elem_timeout(trans) = timeout;
+ update->timeout = timeout;
if (expiration == 0)
expiration = timeout;
update_flags |= NFT_TRANS_UPD_TIMEOUT;
}
if (expiration) {
- nft_trans_elem_expiration(trans) = expiration;
+ update->expiration = expiration;
update_flags |= NFT_TRANS_UPD_EXPIRATION;
}
if (update_flags) {
- nft_trans_elem_priv(trans) = elem_priv;
- nft_trans_elem_update_flags(trans) = update_flags;
+ update->priv = elem_priv;
+ update->update_flags = update_flags;
nft_trans_commit_list_add_elem(ctx->net, trans, GFP_KERNEL);
goto err_set_size;
}
@@ -7197,7 +7285,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
goto err_element_clash;
}
- nft_trans_elem_priv(trans) = elem.priv;
+ nft_trans_container_elem(trans)->elems[0].priv = elem.priv;
nft_trans_commit_list_add_elem(ctx->net, trans, GFP_KERNEL);
return set_full ? -ENFILE : 0;
@@ -7337,6 +7425,50 @@ void nft_setelem_data_deactivate(const struct net *net,
nft_use_dec(&(*nft_set_ext_obj(ext))->use);
}
+/* similar to nft_trans_elems_remove, but called from abort path to undo newsetelem.
+ * No notifications and no ndeact changes.
+ *
+ * Returns true if set had been added to (i.e., elements need to be removed again).
+ */
+static bool nft_trans_elems_new_abort(const struct nft_ctx *ctx,
+ const struct nft_trans_elem *te)
+{
+ bool removed = false;
+ int i;
+
+ for (i = 0; i < te->nelems; i++) {
+ if (te->elems[i].update_flags)
+ continue;
+
+ if (!te->set->ops->abort || nft_setelem_is_catchall(te->set, te->elems[i].priv))
+ nft_setelem_remove(ctx->net, te->set, te->elems[i].priv);
+
+ if (!nft_setelem_is_catchall(te->set, te->elems[i].priv))
+ atomic_dec(&te->set->nelems);
+
+ removed = true;
+ }
+
+ return removed;
+}
+
+/* Called from abort path to undo DELSETELEM/DESTROYSETELEM. */
+static void nft_trans_elems_destroy_abort(const struct nft_ctx *ctx,
+ const struct nft_trans_elem *te)
+{
+ int i;
+
+ for (i = 0; i < te->nelems; i++) {
+ if (!nft_setelem_active_next(ctx->net, te->set, te->elems[i].priv)) {
+ nft_setelem_data_activate(ctx->net, te->set, te->elems[i].priv);
+ nft_setelem_activate(ctx->net, te->set, te->elems[i].priv);
+ }
+
+ if (!nft_setelem_is_catchall(te->set, te->elems[i].priv))
+ te->set->ndeact--;
+ }
+}
+
static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr)
{
@@ -7416,7 +7548,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
nft_setelem_data_deactivate(ctx->net, set, elem.priv);
- nft_trans_elem_priv(trans) = elem.priv;
+ nft_trans_container_elem(trans)->elems[0].priv = elem.priv;
nft_trans_commit_list_add_elem(ctx->net, trans, GFP_KERNEL);
return 0;
@@ -7443,7 +7575,8 @@ static int nft_setelem_flush(const struct nft_ctx *ctx,
return 0;
trans = nft_trans_alloc_gfp(ctx, NFT_MSG_DELSETELEM,
- sizeof(struct nft_trans_elem), GFP_ATOMIC);
+ struct_size_t(struct nft_trans_elem, elems, 1),
+ GFP_ATOMIC);
if (!trans)
return -ENOMEM;
@@ -7452,7 +7585,8 @@ static int nft_setelem_flush(const struct nft_ctx *ctx,
nft_setelem_data_deactivate(ctx->net, set, elem_priv);
nft_trans_elem_set(trans) = set;
- nft_trans_elem_priv(trans) = elem_priv;
+ nft_trans_container_elem(trans)->nelems = 1;
+ nft_trans_container_elem(trans)->elems[0].priv = elem_priv;
nft_trans_commit_list_add_elem(ctx->net, trans, GFP_ATOMIC);
return 0;
@@ -7469,7 +7603,7 @@ static int __nft_set_catchall_flush(const struct nft_ctx *ctx,
return -ENOMEM;
nft_setelem_data_deactivate(ctx->net, set, elem_priv);
- nft_trans_elem_priv(trans) = elem_priv;
+ nft_trans_container_elem(trans)->elems[0].priv = elem_priv;
nft_trans_commit_list_add_elem(ctx->net, trans, GFP_KERNEL);
return 0;
@@ -9619,9 +9753,7 @@ static void nft_commit_release(struct nft_trans *trans)
break;
case NFT_MSG_DELSETELEM:
case NFT_MSG_DESTROYSETELEM:
- nf_tables_set_elem_destroy(&ctx,
- nft_trans_elem_set(trans),
- nft_trans_elem_priv(trans));
+ nft_trans_elems_destroy(&ctx, nft_trans_container_elem(trans));
break;
case NFT_MSG_DELOBJ:
case NFT_MSG_DESTROYOBJ:
@@ -10464,25 +10596,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
case NFT_MSG_NEWSETELEM:
te = nft_trans_container_elem(trans);
- if (te->update_flags) {
- const struct nft_set_ext *ext =
- nft_set_elem_ext(te->set, te->elem_priv);
+ nft_trans_elems_add(&ctx, te);
- if (te->update_flags & NFT_TRANS_UPD_TIMEOUT) {
- WRITE_ONCE(nft_set_ext_timeout(ext)->timeout,
- te->timeout);
- }
- if (te->update_flags & NFT_TRANS_UPD_EXPIRATION) {
- WRITE_ONCE(nft_set_ext_timeout(ext)->expiration,
- get_jiffies_64() + te->expiration);
- }
- } else {
- nft_setelem_activate(net, te->set, te->elem_priv);
- }
-
- nf_tables_setelem_notify(&ctx, te->set,
- te->elem_priv,
- NFT_MSG_NEWSETELEM);
if (te->set->ops->commit &&
list_empty(&te->set->pending_update)) {
list_add_tail(&te->set->pending_update,
@@ -10494,14 +10609,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
case NFT_MSG_DESTROYSETELEM:
te = nft_trans_container_elem(trans);
- nf_tables_setelem_notify(&ctx, te->set,
- te->elem_priv,
- trans->msg_type);
- nft_setelem_remove(net, te->set, te->elem_priv);
- if (!nft_setelem_is_catchall(te->set, te->elem_priv)) {
- atomic_dec(&te->set->nelems);
- te->set->ndeact--;
- }
+ nft_trans_elems_remove(&ctx, te);
+
if (te->set->ops->commit &&
list_empty(&te->set->pending_update)) {
list_add_tail(&te->set->pending_update,
@@ -10623,8 +10732,7 @@ static void nf_tables_abort_release(struct nft_trans *trans)
nft_set_destroy(&ctx, nft_trans_set(trans));
break;
case NFT_MSG_NEWSETELEM:
- nft_set_elem_destroy(nft_trans_elem_set(trans),
- nft_trans_elem_priv(trans), true);
+ nft_trans_set_elem_destroy(&ctx, nft_trans_container_elem(trans));
break;
case NFT_MSG_NEWOBJ:
nft_obj_destroy(&ctx, nft_trans_obj(trans));
@@ -10781,18 +10889,15 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
nft_trans_destroy(trans);
break;
case NFT_MSG_NEWSETELEM:
- if (nft_trans_elem_update_flags(trans) ||
- nft_trans_elem_set_bound(trans)) {
+ if (nft_trans_elem_set_bound(trans)) {
nft_trans_destroy(trans);
break;
}
te = nft_trans_container_elem(trans);
- if (!te->set->ops->abort ||
- nft_setelem_is_catchall(te->set, te->elem_priv))
- nft_setelem_remove(net, te->set, te->elem_priv);
-
- if (!nft_setelem_is_catchall(te->set, te->elem_priv))
- atomic_dec(&te->set->nelems);
+ if (!nft_trans_elems_new_abort(&ctx, te)) {
+ nft_trans_destroy(trans);
+ break;
+ }
if (te->set->ops->abort &&
list_empty(&te->set->pending_update)) {
@@ -10804,12 +10909,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
case NFT_MSG_DESTROYSETELEM:
te = nft_trans_container_elem(trans);
- if (!nft_setelem_active_next(net, te->set, te->elem_priv)) {
- nft_setelem_data_activate(net, te->set, te->elem_priv);
- nft_setelem_activate(net, te->set, te->elem_priv);
- }
- if (!nft_setelem_is_catchall(te->set, te->elem_priv))
- te->set->ndeact--;
+ nft_trans_elems_destroy_abort(&ctx, te);
if (te->set->ops->abort &&
list_empty(&te->set->pending_update)) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 597/869] netfilter: nf_tables: skip double clone set expressions on element insert
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (595 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 596/869] netfilter: nf_tables: prepare for multiple elements in nft_trans_elem structure Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 598/869] net_sched: sch_fq: add three drop_reason Greg Kroah-Hartman
` (272 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Xingyuan Mo, Pablo Neira Ayuso,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <pablo@netfilter.org>
[ Upstream commit 43559058d21e0493aa220ac167e0279334dea5f9 ]
Both the dynset and newsetelem path clone the existing set expressions
when setting set element expressions if no override expressions are
provided. This results in a double clone, once to clone the template set
expressions then another clone on the new element. Add a flag to
annotate if userspace provides a override expression (ie. expression of
the same type of the set but different configuration), otherwise borrow
the existing expression from the set. Add conditionals to release
expression iif they represent an override. Use this new override_exprs
flag to dump the dynset expression override to userspace.
This simplifies the existing logic and it also fixes a bug with the
connlimit expression which results in a module refcount imbalance
WARNING splat when resorting on the default set expressions.
Fixes: 65038428b2c6 ("netfilter: nf_tables: allow to specify stateful expression in set definition")
Fixes: fca05d4d61e6 ("netfilter: nft_dynset: honor stateful expressions in set definition")
Reported-by: Xingyuan Mo <hdthky0@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/netfilter/nf_tables.h | 2 --
net/netfilter/nf_tables_api.c | 56 ++++++++++---------------------
net/netfilter/nft_dynset.c | 25 ++++++++------
3 files changed, 33 insertions(+), 50 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index d440915addd6e..eaddf2aacb2f4 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -867,8 +867,6 @@ struct nft_elem_priv *nft_set_elem_init(const struct nft_set *set,
const u32 *key, const u32 *key_end,
const u32 *data,
u64 timeout, u64 expiration, gfp_t gfp);
-int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
- struct nft_expr *expr_array[]);
void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
struct nft_set_elem_expr *elem_expr);
void nft_set_elem_destroy(const struct nft_set *set,
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 92a86e81084b1..4b6cb990ab743 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -6573,39 +6573,11 @@ static void nft_trans_elems_destroy(const struct nft_ctx *ctx,
nf_tables_set_elem_destroy(ctx, te->set, te->elems[i].priv);
}
-int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
- struct nft_expr *expr_array[])
-{
- struct nft_expr *expr;
- int err, i, k;
-
- for (i = 0; i < set->num_exprs; i++) {
- expr = kzalloc(set->exprs[i]->ops->size, GFP_KERNEL_ACCOUNT);
- if (!expr)
- goto err_expr;
-
- err = nft_expr_clone(expr, set->exprs[i], GFP_KERNEL_ACCOUNT);
- if (err < 0) {
- kfree(expr);
- goto err_expr;
- }
- expr_array[i] = expr;
- }
-
- return 0;
-
-err_expr:
- for (k = i - 1; k >= 0; k--)
- nft_expr_destroy(ctx, expr_array[k]);
-
- return -ENOMEM;
-}
-
static int nft_set_elem_expr_setup(struct nft_ctx *ctx,
const struct nft_set_ext_tmpl *tmpl,
const struct nft_set_ext *ext,
struct nft_expr *expr_array[],
- u32 num_exprs)
+ u32 num_exprs, bool override_exprs)
{
struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext);
u32 len = sizeof(struct nft_set_elem_expr);
@@ -6628,7 +6600,8 @@ static int nft_set_elem_expr_setup(struct nft_ctx *ctx,
goto err_elem_expr_setup;
elem_expr->size += expr_array[i]->ops->size;
- nft_expr_destroy(ctx, expr_array[i]);
+ if (override_exprs)
+ nft_expr_destroy(ctx, expr_array[i]);
expr_array[i] = NULL;
}
@@ -6636,7 +6609,9 @@ static int nft_set_elem_expr_setup(struct nft_ctx *ctx,
err_elem_expr_setup:
for (; i < num_exprs; i++) {
- nft_expr_destroy(ctx, expr_array[i]);
+ if (override_exprs)
+ nft_expr_destroy(ctx, expr_array[i]);
+
expr_array[i] = NULL;
}
@@ -6918,6 +6893,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_binding *binding;
struct nft_elem_priv *elem_priv;
struct nft_object *obj = NULL;
+ bool override_exprs = false;
struct nft_userdata *udata;
struct nft_data_desc desc;
enum nft_registers dreg;
@@ -7024,6 +7000,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
expr_array[0] = expr;
num_exprs = 1;
+ override_exprs = true;
if (set->num_exprs && set->exprs[0]->ops != expr->ops) {
err = -EOPNOTSUPP;
@@ -7052,6 +7029,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
}
expr_array[i] = expr;
num_exprs++;
+ override_exprs = true;
if (set->num_exprs && expr->ops != set->exprs[i]->ops) {
err = -EOPNOTSUPP;
@@ -7065,9 +7043,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
}
} else if (set->num_exprs > 0 &&
!(flags & NFT_SET_ELEM_INTERVAL_END)) {
- err = nft_set_elem_expr_clone(ctx, set, expr_array);
- if (err < 0)
- goto err_set_elem_expr_clone;
+ for (i = 0; i < set->num_exprs; i++)
+ expr_array[i] = set->exprs[i];
num_exprs = set->num_exprs;
}
@@ -7206,7 +7183,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
udata->len = ulen - 1;
nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen);
}
- err = nft_set_elem_expr_setup(ctx, &tmpl, ext, expr_array, num_exprs);
+ err = nft_set_elem_expr_setup(ctx, &tmpl, ext, expr_array, num_exprs,
+ override_exprs);
if (err < 0)
goto err_elem_free;
@@ -7308,9 +7286,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
err_parse_key:
nft_data_release(&elem.key.val, NFT_DATA_VALUE);
err_set_elem_expr:
- for (i = 0; i < num_exprs && expr_array[i]; i++)
- nft_expr_destroy(ctx, expr_array[i]);
-err_set_elem_expr_clone:
+ if (override_exprs) {
+ for (i = 0; i < num_exprs && expr_array[i]; i++)
+ nft_expr_destroy(ctx, expr_array[i]);
+ }
+
return err;
}
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index 0d78de9d2d754..59b14e6a2ca82 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -19,7 +19,8 @@ struct nft_dynset {
u8 sreg_key;
u8 sreg_data;
bool invert;
- bool expr;
+ bool expr:1,
+ override_exprs:1;
u8 num_exprs;
u64 timeout;
struct nft_expr *expr_array[NFT_SET_EXPR_MAX];
@@ -257,6 +258,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
priv->num_exprs++;
priv->expr_array[0] = dynset_expr;
+ priv->override_exprs = true;
if (set->num_exprs > 1 ||
(set->num_exprs == 1 &&
@@ -289,6 +291,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
}
priv->expr_array[i] = dynset_expr;
priv->num_exprs++;
+ priv->override_exprs = true;
if (set->num_exprs) {
if (i >= set->num_exprs) {
@@ -307,9 +310,8 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
goto err_expr_free;
}
} else if (set->num_exprs > 0) {
- err = nft_set_elem_expr_clone(ctx, set, priv->expr_array);
- if (err < 0)
- return err;
+ for (i = 0; i < set->num_exprs; i++)
+ priv->expr_array[i] = set->exprs[i];
priv->num_exprs = set->num_exprs;
}
@@ -339,8 +341,10 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
return 0;
err_expr_free:
- for (i = 0; i < priv->num_exprs; i++)
- nft_expr_destroy(ctx, priv->expr_array[i]);
+ if (priv->override_exprs) {
+ for (i = 0; i < priv->num_exprs; i++)
+ nft_expr_destroy(ctx, priv->expr_array[i]);
+ }
return err;
}
@@ -367,9 +371,10 @@ static void nft_dynset_destroy(const struct nft_ctx *ctx,
struct nft_dynset *priv = nft_expr_priv(expr);
int i;
- for (i = 0; i < priv->num_exprs; i++)
- nft_expr_destroy(ctx, priv->expr_array[i]);
-
+ if (priv->override_exprs) {
+ for (i = 0; i < priv->num_exprs; i++)
+ nft_expr_destroy(ctx, priv->expr_array[i]);
+ }
nf_tables_destroy_set(ctx, priv->set);
}
@@ -393,7 +398,7 @@ static int nft_dynset_dump(struct sk_buff *skb,
nf_jiffies64_to_msecs(priv->timeout),
NFTA_DYNSET_PAD))
goto nla_put_failure;
- if (priv->set->num_exprs == 0) {
+ if (priv->set->num_exprs == 0 || priv->override_exprs) {
if (priv->num_exprs == 1) {
if (nft_expr_dump(skb, NFTA_DYNSET_EXPR,
priv->expr_array[0], reset))
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 598/869] net_sched: sch_fq: add three drop_reason
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (596 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 597/869] netfilter: nf_tables: skip double clone set expressions on element insert Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 599/869] net/sched: add qstats_cpu_drop_inc() helper Greg Kroah-Hartman
` (271 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Dumazet, Victor Nogueira,
Toke Høiland-Jørgensen, Jamal Hadi Salim,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 5765c7f6e3173eb894889a29963a497aeb721c5e ]
Add three new drop_reason, more precise than generic QDISC_DROP:
"tc -s qd" show aggregate counters, it might be more useful
to use drop_reason infrastructure for bug hunting.
1) SKB_DROP_REASON_FQ_BAND_LIMIT
Whenever a packet is added while its band limit is hit.
Corresponding value in "tc -s qd" is bandX_drops XXXX
2) SKB_DROP_REASON_FQ_HORIZON_LIMIT
Whenever a packet has a timestamp too far in the future.
Corresponding value in "tc -s qd" is horizon_drops XXXX
3) SKB_DROP_REASON_FQ_FLOW_LIMIT
Whenever a flow has reached its limit.
Corresponding value in "tc -s qd" is flows_plimit XXXX
Tested:
tc qd replace dev eth1 root fq flow_limit 10 limit 100000
perf record -a -e skb:kfree_skb sleep 1; perf script
udp_stream 12329 [004] 216.929492: skb:kfree_skb: skbaddr=0xffff888eabe17e00 rx_sk=(nil) protocol=34525 location=__dev_queue_xmit+0x9d9 reason: FQ_FLOW_LIMIT
udp_stream 12385 [006] 216.929593: skb:kfree_skb: skbaddr=0xffff888ef8827f00 rx_sk=(nil) protocol=34525 location=__dev_queue_xmit+0x9d9 reason: FQ_FLOW_LIMIT
udp_stream 12389 [005] 216.929871: skb:kfree_skb: skbaddr=0xffff888ecb9ba500 rx_sk=(nil) protocol=34525 location=__dev_queue_xmit+0x9d9 reason: FQ_FLOW_LIMIT
udp_stream 12316 [009] 216.930398: skb:kfree_skb: skbaddr=0xffff888eca286b00 rx_sk=(nil) protocol=34525 location=__dev_queue_xmit+0x9d9 reason: FQ_FLOW_LIMIT
udp_stream 12400 [008] 216.930490: skb:kfree_skb: skbaddr=0xffff888eabf93d00 rx_sk=(nil) protocol=34525 location=__dev_queue_xmit+0x9d9 reason: FQ_FLOW_LIMIT
tc qd replace dev eth1 root fq flow_limit 100 limit 10000
perf record -a -e skb:kfree_skb sleep 1; perf script
udp_stream 18074 [001] 1058.318040: skb:kfree_skb: skbaddr=0xffffa23c881fc000 rx_sk=(nil) protocol=34525 location=__dev_queue_xmit+0x9d9 reason: FQ_BAND_LIMIT
udp_stream 18126 [005] 1058.320651: skb:kfree_skb: skbaddr=0xffffa23c6aad4000 rx_sk=(nil) protocol=34525 location=__dev_queue_xmit+0x9d9 reason: FQ_BAND_LIMIT
udp_stream 18118 [006] 1058.321065: skb:kfree_skb: skbaddr=0xffffa23df0d48a00 rx_sk=(nil) protocol=34525 location=__dev_queue_xmit+0x9d9 reason: FQ_BAND_LIMIT
udp_stream 18074 [001] 1058.321126: skb:kfree_skb: skbaddr=0xffffa23c881ffa00 rx_sk=(nil) protocol=34525 location=__dev_queue_xmit+0x9d9 reason: FQ_BAND_LIMIT
udp_stream 15815 [003] 1058.321224: skb:kfree_skb: skbaddr=0xffffa23c9835db00 rx_sk=(nil) protocol=34525 location=__dev_queue_xmit+0x9d9 reason: FQ_BAND_LIMIT
tc -s -d qd sh dev eth1
qdisc fq 8023: root refcnt 257 limit 10000p flow_limit 100p buckets 1024 orphan_mask 1023
bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 weights 589824 196608 65536 quantum 18Kb
initial_quantum 92120b low_rate_threshold 550Kbit refill_delay 40ms
timer_slack 10us horizon 10s horizon_drop
Sent 492439603330 bytes 336953991 pkt (dropped 61724094, overlimits 0 requeues 4463)
backlog 14611228b 9995p requeues 4463
flows 2965 (inactive 1151 throttled 0) band0_pkts 0 band1_pkts 9993 band2_pkts 0
gc 6347 highprio 0 fastpath 30 throttled 5 latency 2.32us flows_plimit 7403693
band1_drops 54320401
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Victor Nogueira <victor@mojatatu.com>
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Link: https://patch.msgid.link/20241204171950.89829-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 5b483f7791b0 ("net/sched: act_ife: Only operate on Ethernet frames")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/dropreason-core.h | 18 ++++++++++++++++++
include/net/sch_generic.h | 8 ++++++++
net/sched/sch_fq.c | 14 ++++++++++----
3 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h
index f8f4d2b77e6ac..31e0cc1b64ff1 100644
--- a/include/net/dropreason-core.h
+++ b/include/net/dropreason-core.h
@@ -60,6 +60,9 @@
FN(TC_EGRESS) \
FN(SECURITY_HOOK) \
FN(QDISC_DROP) \
+ FN(FQ_BAND_LIMIT) \
+ FN(FQ_HORIZON_LIMIT) \
+ FN(FQ_FLOW_LIMIT) \
FN(CPU_BACKLOG) \
FN(XDP) \
FN(TC_INGRESS) \
@@ -316,6 +319,21 @@ enum skb_drop_reason {
* failed to enqueue to current qdisc)
*/
SKB_DROP_REASON_QDISC_DROP,
+ /**
+ * @SKB_DROP_REASON_FQ_BAND_LIMIT: dropped by fq qdisc when per band
+ * limit is reached.
+ */
+ SKB_DROP_REASON_FQ_BAND_LIMIT,
+ /**
+ * @SKB_DROP_REASON_FQ_HORIZON_LIMIT: dropped by fq qdisc when packet
+ * timestamp is too far in the future.
+ */
+ SKB_DROP_REASON_FQ_HORIZON_LIMIT,
+ /**
+ * @SKB_DROP_REASON_FQ_FLOW_LIMIT: dropped by fq qdisc when a flow
+ * exceeds its limits.
+ */
+ SKB_DROP_REASON_FQ_FLOW_LIMIT,
/**
* @SKB_DROP_REASON_CPU_BACKLOG: failed to enqueue the skb to the per CPU
* backlog queue. This can be caused by backlog queue full (see
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index d174283373470..016d9cf827069 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -1320,6 +1320,14 @@ static inline int qdisc_drop(struct sk_buff *skb, struct Qdisc *sch,
return NET_XMIT_DROP;
}
+static inline int qdisc_drop_reason(struct sk_buff *skb, struct Qdisc *sch,
+ struct sk_buff **to_free,
+ enum skb_drop_reason reason)
+{
+ tcf_set_drop_reason(skb, reason);
+ return qdisc_drop(skb, sch, to_free);
+}
+
static inline int qdisc_drop_all(struct sk_buff *skb, struct Qdisc *sch,
struct sk_buff **to_free)
{
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
index d06e12d16b0e5..cf70468b67607 100644
--- a/net/sched/sch_fq.c
+++ b/net/sched/sch_fq.c
@@ -535,6 +535,8 @@ static bool fq_packet_beyond_horizon(const struct sk_buff *skb,
return unlikely((s64)skb->tstamp > (s64)(now + q->horizon));
}
+#define FQDR(reason) SKB_DROP_REASON_FQ_##reason
+
static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
struct sk_buff **to_free)
{
@@ -546,7 +548,8 @@ static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
band = fq_prio2band(q->prio2band, skb->priority & TC_PRIO_MAX);
if (unlikely(q->band_pkt_count[band] >= sch->limit)) {
q->stat_band_drops[band]++;
- return qdisc_drop(skb, sch, to_free);
+ return qdisc_drop_reason(skb, sch, to_free,
+ FQDR(BAND_LIMIT));
}
now = ktime_get_ns();
@@ -556,8 +559,9 @@ static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
/* Check if packet timestamp is too far in the future. */
if (fq_packet_beyond_horizon(skb, q, now)) {
if (q->horizon_drop) {
- q->stat_horizon_drops++;
- return qdisc_drop(skb, sch, to_free);
+ q->stat_horizon_drops++;
+ return qdisc_drop_reason(skb, sch, to_free,
+ FQDR(HORIZON_LIMIT));
}
q->stat_horizon_caps++;
skb->tstamp = now + q->horizon;
@@ -570,7 +574,8 @@ static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
if (f != &q->internal) {
if (unlikely(f->qlen >= q->flow_plimit)) {
q->stat_flows_plimit++;
- return qdisc_drop(skb, sch, to_free);
+ return qdisc_drop_reason(skb, sch, to_free,
+ FQDR(FLOW_LIMIT));
}
if (fq_flow_is_detached(f)) {
@@ -595,6 +600,7 @@ static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch,
return NET_XMIT_SUCCESS;
}
+#undef FQDR
static void fq_check_throttled(struct fq_sched_data *q, u64 now)
{
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 599/869] net/sched: add qstats_cpu_drop_inc() helper
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (597 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 598/869] net_sched: sch_fq: add three drop_reason Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 600/869] net/sched: act_ife: Only operate on Ethernet frames Greg Kroah-Hartman
` (270 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Dumazet, Jamal Hadi Salim,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 3f3aa77ff1c8b45ec8c9e40212f1a24a93e00df3 ]
1) Using this_cpu_inc() is better than going through this_cpu_ptr():
- Single instruction on x86.
- Store tearing prevention.
2) Change tcf_action_update_stats() to use this_cpu_add().
3) Add WRITE_ONCE() to __qdisc_qstats_drop() and qstats_drop_inc()
in preparation for lockless "tc qdisc show".
$ scripts/bloat-o-meter -t vmlinux.old vmlinux.new
add/remove: 0/0 grow/shrink: 3/17 up/down: 72/-216 (-144)
Function old new delta
dualpi2_enqueue_skb 462 511 +49
tcf_ife_act 1061 1077 +16
taprio_enqueue 613 620 +7
codel_qdisc_enqueue 149 143 -6
tcf_vlan_act 684 676 -8
tcf_skbedit_act 626 618 -8
tcf_police_act 725 717 -8
tcf_mpls_act 1297 1289 -8
tcf_gate_act 310 302 -8
tcf_gact_act 222 214 -8
tcf_csum_act 2438 2430 -8
tcf_bpf_act 709 701 -8
tcf_action_update_stats 124 115 -9
pie_qdisc_enqueue 865 856 -9
pfifo_enqueue 116 107 -9
choke_enqueue 2069 2059 -10
plug_enqueue 139 128 -11
bfifo_enqueue 121 110 -11
tcf_nat_act 1501 1489 -12
gred_enqueue 1743 1668 -75
Total: Before=24388609, After=24388465, chg -0.00%
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
Link: https://patch.msgid.link/20260501135916.2566766-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 5b483f7791b0 ("net/sched: act_ife: Only operate on Ethernet frames")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/act_api.h | 2 +-
include/net/sch_generic.h | 9 +++++++--
net/sched/act_api.c | 2 +-
net/sched/act_bpf.c | 2 +-
net/sched/act_ife.c | 8 ++++----
net/sched/act_mpls.c | 2 +-
net/sched/act_police.c | 2 +-
net/sched/act_skbedit.c | 2 +-
net/sched/sch_cake.c | 2 +-
net/sched/sch_fq_codel.c | 2 +-
net/sched/sch_gred.c | 2 +-
11 files changed, 20 insertions(+), 15 deletions(-)
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 76c31ce80fe52..29b72635abe71 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -238,7 +238,7 @@ static inline void tcf_action_update_bstats(struct tc_action *a,
static inline void tcf_action_inc_drop_qstats(struct tc_action *a)
{
if (likely(a->cpu_qstats)) {
- qstats_drop_inc(this_cpu_ptr(a->cpu_qstats));
+ qstats_cpu_drop_inc(a->cpu_qstats);
return;
}
spin_lock(&a->tcfa_lock);
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 016d9cf827069..5f83b4970f792 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -976,12 +976,17 @@ static inline void qdisc_qstats_cpu_requeues_inc(struct Qdisc *sch)
static inline void __qdisc_qstats_drop(struct Qdisc *sch, int count)
{
- sch->qstats.drops += count;
+ WRITE_ONCE(sch->qstats.drops, sch->qstats.drops + count);
}
static inline void qstats_drop_inc(struct gnet_stats_queue *qstats)
{
- qstats->drops++;
+ WRITE_ONCE(qstats->drops, qstats->drops + 1);
+}
+
+static inline void qstats_cpu_drop_inc(struct gnet_stats_queue __percpu *qstats)
+{
+ this_cpu_inc(qstats->drops);
}
static inline void qstats_overlimit_inc(struct gnet_stats_queue *qstats)
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index ca851146f6958..94feb3961dcd2 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -1570,7 +1570,7 @@ void tcf_action_update_stats(struct tc_action *a, u64 bytes, u64 packets,
if (a->cpu_bstats) {
_bstats_update(this_cpu_ptr(a->cpu_bstats), bytes, packets);
- this_cpu_ptr(a->cpu_qstats)->drops += drops;
+ this_cpu_add(a->cpu_qstats->drops, drops);
if (hw)
_bstats_update(this_cpu_ptr(a->cpu_bstats_hw),
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index e99b9269ea1a9..06d8f78b73683 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -76,7 +76,7 @@ TC_INDIRECT_SCOPE int tcf_bpf_act(struct sk_buff *skb,
break;
case TC_ACT_SHOT:
action = filter_res;
- qstats_drop_inc(this_cpu_ptr(prog->common.cpu_qstats));
+ qstats_cpu_drop_inc(prog->common.cpu_qstats);
break;
case TC_ACT_UNSPEC:
action = prog->tcf_action;
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index a90d7959fc432..3333714b68650 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -727,7 +727,7 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
tlv_data = ife_decode(skb, &metalen);
if (unlikely(!tlv_data)) {
- qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats));
+ qstats_cpu_drop_inc(ife->common.cpu_qstats);
return TC_ACT_SHOT;
}
@@ -740,7 +740,7 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
curr_data = ife_tlv_meta_decode(tlv_data, ifehdr_end, &mtype,
&dlen, NULL);
if (!curr_data) {
- qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats));
+ qstats_cpu_drop_inc(ife->common.cpu_qstats);
return TC_ACT_SHOT;
}
@@ -755,7 +755,7 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
}
if (WARN_ON(tlv_data != ifehdr_end)) {
- qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats));
+ qstats_cpu_drop_inc(ife->common.cpu_qstats);
return TC_ACT_SHOT;
}
@@ -821,7 +821,7 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a,
* so lets be conservative.. */
if ((action == TC_ACT_SHOT) || exceed_mtu) {
drop:
- qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats));
+ qstats_cpu_drop_inc(ife->common.cpu_qstats);
return TC_ACT_SHOT;
}
diff --git a/net/sched/act_mpls.c b/net/sched/act_mpls.c
index 44a37a71ae923..24d9cb7c1c4db 100644
--- a/net/sched/act_mpls.c
+++ b/net/sched/act_mpls.c
@@ -125,7 +125,7 @@ TC_INDIRECT_SCOPE int tcf_mpls_act(struct sk_buff *skb,
return ret;
drop:
- qstats_drop_inc(this_cpu_ptr(m->common.cpu_qstats));
+ qstats_cpu_drop_inc(m->common.cpu_qstats);
return TC_ACT_SHOT;
}
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 1ad8a79486902..098eddcd36b6c 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -317,7 +317,7 @@ TC_INDIRECT_SCOPE int tcf_police_act(struct sk_buff *skb,
qstats_overlimit_inc(this_cpu_ptr(police->common.cpu_qstats));
inc_drops:
if (ret == TC_ACT_SHOT)
- qstats_drop_inc(this_cpu_ptr(police->common.cpu_qstats));
+ qstats_cpu_drop_inc(police->common.cpu_qstats);
end:
return ret;
}
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 4cddf2674373f..c52f25e0c0a09 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -85,7 +85,7 @@ TC_INDIRECT_SCOPE int tcf_skbedit_act(struct sk_buff *skb,
return params->action;
err:
- qstats_drop_inc(this_cpu_ptr(d->common.cpu_qstats));
+ qstats_cpu_drop_inc(d->common.cpu_qstats);
return TC_ACT_SHOT;
}
diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
index 7eb3e7485539f..a60aae42398a3 100644
--- a/net/sched/sch_cake.c
+++ b/net/sched/sch_cake.c
@@ -1824,7 +1824,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
if (ack) {
b->ack_drops++;
- sch->qstats.drops++;
+ qdisc_qstats_drop(sch);
ack_pkt_len = qdisc_pkt_len(ack);
b->bytes += ack_pkt_len;
q->buffer_used += skb->truesize - ack->truesize;
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
index 4da7525c3e7cf..d41a55863d165 100644
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -175,7 +175,7 @@ static unsigned int fq_codel_drop(struct Qdisc *sch, unsigned int max_packets,
flow->cvars.count += i;
q->backlogs[idx] -= len;
q->memory_usage -= mem;
- sch->qstats.drops += i;
+ __qdisc_qstats_drop(sch, i);
sch->qstats.backlog -= len;
sch->q.qlen -= i;
return idx;
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index 53b348b83c913..26103178a4ce4 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -389,7 +389,7 @@ static int gred_offload_dump_stats(struct Qdisc *sch)
packets += u64_stats_read(&hw_stats->stats.bstats[i].packets);
sch->qstats.qlen += hw_stats->stats.qstats[i].qlen;
sch->qstats.backlog += hw_stats->stats.qstats[i].backlog;
- sch->qstats.drops += hw_stats->stats.qstats[i].drops;
+ __qdisc_qstats_drop(sch, hw_stats->stats.qstats[i].drops);
sch->qstats.requeues += hw_stats->stats.qstats[i].requeues;
sch->qstats.overlimits += hw_stats->stats.qstats[i].overlimits;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 600/869] net/sched: act_ife: Only operate on Ethernet frames
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (598 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 599/869] net/sched: add qstats_cpu_drop_inc() helper Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 601/869] octeontx2-vf: fix workqueue and netdev race in probe/remove Greg Kroah-Hartman
` (269 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, vega, Jamal Hadi Salim,
Victor Nogueira, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <victor@mojatatu.com>
[ Upstream commit 5b483f7791b079bb97d411f1066652ff659207ff ]
act_ife encapsulates/decapsulates the original Ethernet header and uses
skb->dev->hard_header_len as the length of that header. That is only
correct for Ethernet devices: on a device where hard_header_len does not
match the L2 header that was actually pulled (PPP reports PPP_HDRLEN
while nothing is stripped on ingress), the ingress skb_push()/skb_pull()
use the wrong length and can hit skb_under_panic when headroom is tight.
IFE is Ethernet-only by design - it builds an outer ethhdr, rewrites
h_source/h_dest/h_proto, and calls eth_type_trans() on decode - so
instead of trying to make the offsets work for arbitrary link types,
simply drop packets that do not carry an Ethernet header.
Checking skb->dev->type alone is not enough. We have to cater for a
corner case where mirred can redirect an skb from a non-Ethernet device
to an Ethernet one, and skb->dev then says nothing about the framing the
skb actually has: an skb redirected from ppp0 reaches the target's ingress
hook with mac_len 0 and no Ethernet header at all. So at ingress also
require mac_len to be ETH_HLEN. On egress mac_len is not maintained, so
the device type is all we have; a bogus redirect there yields a malformed
frame rather than an out-of-bounds push, and it would be malformed with or
without IFE.
That corner case is not theoretical - redirecting from ppp0 into a veth
that has an ife encode action on its ingress hook panics without this
patch:
skbuff: skb_under_panic: len:98 put:14 head:ffff88800e410000
data:ffff88800e40fff5 tail:0x57 end:0x640 dev:veth3
kernel BUG at net/core/skbuff.c:214!
Call Trace:
skb_push (net/core/skbuff.c:224 net/core/skbuff.c:2657)
tcf_ife_act (net/sched/act_ife.c:829 net/sched/act_ife.c:874)
tc_run (net/core/dev.c:4463)
netif_receive_skb (net/core/dev.c:6463 net/core/dev.c:6522)
tcf_mirred_to_dev (net/sched/act_mirred.c:248 net/sched/act_mirred.c:328)
tcf_mirred_act (net/sched/act_mirred.c:489)
tc_run (net/core/dev.c:4463)
process_backlog (net/core/dev.c:6728)
With Ethernet framing guaranteed, use ETH_HLEN instead of
hard_header_len.
Fixes: 295a6e06d21e ("net/sched: act_ife: Change to use ife module")
Reported-by: vega@nebusec.ai
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Link: https://patch.msgid.link/20260821164031.32824-1-victor@mojatatu.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ife/ife.c | 14 +++++++-------
net/sched/act_ife.c | 32 ++++++++++++++++++++++++++++----
2 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/net/ife/ife.c b/net/ife/ife.c
index 7a75947a31e31..2ddf725d3389e 100644
--- a/net/ife/ife.c
+++ b/net/ife/ife.c
@@ -37,7 +37,7 @@ void *ife_encode(struct sk_buff *skb, u16 metalen)
* where ORIGDATA = original ethernet header ...
*/
int hdrm = metalen + IFE_METAHDRLEN;
- int total_push = hdrm + skb->dev->hard_header_len;
+ int total_push = hdrm + ETH_HLEN;
struct ifeheadr *ifehdr;
struct ethhdr *iethh; /* inner ether header */
int skboff = 0;
@@ -50,9 +50,9 @@ void *ife_encode(struct sk_buff *skb, u16 metalen)
iethh = (struct ethhdr *) skb->data;
__skb_push(skb, total_push);
- memcpy(skb->data, iethh, skb->dev->hard_header_len);
+ memcpy(skb->data, iethh, ETH_HLEN);
skb_reset_mac_header(skb);
- skboff += skb->dev->hard_header_len;
+ skboff += ETH_HLEN;
/* total metadata length */
ifehdr = (struct ifeheadr *) (skb->data + skboff);
@@ -69,12 +69,12 @@ void *ife_decode(struct sk_buff *skb, u16 *metalen)
int total_pull;
u16 ifehdrln;
- if (!pskb_may_pull(skb, skb->dev->hard_header_len + IFE_METAHDRLEN))
+ if (!pskb_may_pull(skb, ETH_HLEN + IFE_METAHDRLEN))
return NULL;
- ifehdr = (struct ifeheadr *) (skb->data + skb->dev->hard_header_len);
+ ifehdr = (struct ifeheadr *)(skb->data + ETH_HLEN);
ifehdrln = ntohs(ifehdr->metalen);
- total_pull = skb->dev->hard_header_len + ifehdrln;
+ total_pull = ETH_HLEN + ifehdrln;
if (unlikely(ifehdrln < 2))
return NULL;
@@ -82,7 +82,7 @@ void *ife_decode(struct sk_buff *skb, u16 *metalen)
if (unlikely(!pskb_may_pull(skb, total_pull + ETH_HLEN)))
return NULL;
- ifehdr = (struct ifeheadr *)(skb->data + skb->dev->hard_header_len);
+ ifehdr = (struct ifeheadr *)(skb->data + ETH_HLEN);
skb_set_mac_header(skb, total_pull);
__skb_pull(skb, total_pull);
*metalen = ifehdrln - IFE_METAHDRLEN;
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 3333714b68650..b0d66ba80baad 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -28,6 +28,7 @@
#include <uapi/linux/tc_act/tc_ife.h>
#include <net/tc_act/tc_ife.h>
#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
#include <net/ife.h>
#include <net/tc_wrapper.h>
@@ -723,7 +724,7 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
tcf_lastuse_update(&ife->tcf_tm);
if (skb_at_tc_ingress(skb))
- skb_push(skb, skb->dev->hard_header_len);
+ skb_push(skb, ETH_HLEN);
tlv_data = ife_decode(skb, &metalen);
if (unlikely(!tlv_data)) {
@@ -795,7 +796,7 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a,
where ORIGDATA = original ethernet header ...
*/
u16 metalen = ife_get_sz(skb, p);
- int hdrm = metalen + skb->dev->hard_header_len + IFE_METAHDRLEN;
+ int hdrm = metalen + ETH_HLEN + IFE_METAHDRLEN;
unsigned int skboff = 0;
int new_len = skb->len + hdrm;
bool exceed_mtu = false;
@@ -826,7 +827,7 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a,
}
if (skb_at_tc_ingress(skb))
- skb_push(skb, skb->dev->hard_header_len);
+ skb_push(skb, ETH_HLEN);
ife_meta = ife_encode(skb, metalen);
if (!ife_meta)
@@ -856,11 +857,27 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a,
oethh->h_proto = htons(p->eth_type);
if (skb_at_tc_ingress(skb))
- skb_pull(skb, skb->dev->hard_header_len);
+ skb_pull(skb, ETH_HLEN);
return action;
}
+/* IFE encapsulates the original Ethernet header and, on decode, expects to
+ * find one, so it can only ever work on skbs that carry one. Loopback carries
+ * Ethernet header as well, so it qualifies here.
+ * At ingress, also verify that the L2 header about to be pushed back really
+ * is an Ethernet header because the skb could've been redirected with mirred
+ * from a non-Ethernet device.
+ */
+static bool tcf_ife_is_eth_skb(const struct sk_buff *skb)
+{
+ if (skb->dev->type != ARPHRD_ETHER &&
+ skb->dev->type != ARPHRD_LOOPBACK)
+ return false;
+
+ return !skb_at_tc_ingress(skb) || skb->mac_len == ETH_HLEN;
+}
+
TC_INDIRECT_SCOPE int tcf_ife_act(struct sk_buff *skb,
const struct tc_action *a,
struct tcf_result *res)
@@ -869,6 +886,13 @@ TC_INDIRECT_SCOPE int tcf_ife_act(struct sk_buff *skb,
struct tcf_ife_params *p;
int ret;
+ if (unlikely(!tcf_ife_is_eth_skb(skb))) {
+ bstats_update(this_cpu_ptr(ife->common.cpu_bstats), skb);
+ tcf_lastuse_update(&ife->tcf_tm);
+ qstats_cpu_drop_inc(ife->common.cpu_qstats);
+ return TC_ACT_SHOT;
+ }
+
p = rcu_dereference_bh(ife->params);
if (p->flags & IFE_ENCODE) {
ret = tcf_ife_encode(skb, a, res, p);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 601/869] octeontx2-vf: fix workqueue and netdev race in probe/remove
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (599 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 600/869] net/sched: act_ife: Only operate on Ethernet frames Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 602/869] xsk: honor XDP_TX_METADATA in zero-copy path Greg Kroah-Hartman
` (268 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nitin Shetty J, Anshumali Gaur,
Simon Horman, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anshumali Gaur <agaur@marvell.com>
[ Upstream commit 3ba97ff4f873481d370bee7f7dfb87f8296af9be ]
Initialize the VF workqueue before register_netdev() so ndo_set_rx_mode
does not queue work on a NULL workqueue. Unregister the netdev before
destroying the workqueue, and add proper probe error cleanup.
Fixes: cbc100aa2205 ("octeontx2-nicvf: add ndo_set_rx_mode support for multicast & promisc")
Signed-off-by: Nitin Shetty J <nshettyj@marvell.com>
Signed-off-by: Anshumali Gaur <agaur@marvell.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260820083634.1641740-1-nshettyj@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../ethernet/marvell/octeontx2/nic/otx2_vf.c | 20 ++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
index e26c830ae1ffc..37d36cedd157c 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
@@ -685,16 +685,16 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
snprintf(netdev->name, sizeof(netdev->name), "lbk%d", n);
}
+ err = otx2_wq_init(vf);
+ if (err)
+ goto err_ptp_destroy;
+
err = register_netdev(netdev);
if (err) {
dev_err(dev, "Failed to register netdevice\n");
- goto err_ptp_destroy;
+ goto err_wq_destroy;
}
- err = otx2_wq_init(vf);
- if (err)
- goto err_unreg_netdev;
-
otx2vf_set_ethtool_ops(netdev);
err = otx2vf_mcam_flow_init(vf);
@@ -722,6 +722,10 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
otx2_shutdown_tc(vf);
err_unreg_netdev:
unregister_netdev(netdev);
+err_wq_destroy:
+ cancel_work_sync(&vf->reset_task);
+ cancel_work_sync(&vf->rx_mode_work);
+ destroy_workqueue(vf->otx2_wq);
err_ptp_destroy:
otx2_ptp_destroy(vf);
err_detach_rsrc:
@@ -769,11 +773,13 @@ static void otx2vf_remove(struct pci_dev *pdev)
}
#endif
- cancel_work_sync(&vf->reset_task);
otx2_unregister_dl(vf);
unregister_netdev(netdev);
- if (vf->otx2_wq)
+ if (vf->otx2_wq) {
+ cancel_work_sync(&vf->reset_task);
+ cancel_work_sync(&vf->rx_mode_work);
destroy_workqueue(vf->otx2_wq);
+ }
otx2_ptp_destroy(vf);
otx2_mcam_flow_del(vf);
otx2_shutdown_tc(vf);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 602/869] xsk: honor XDP_TX_METADATA in zero-copy path
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (600 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 601/869] octeontx2-vf: fix workqueue and netdev race in probe/remove Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 603/869] Bluetooth: do not leak an hci_conn when a second LE connect is rejected Greg Kroah-Hartman
` (267 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alexander Lobakin,
Stanislav Fomichev, Maciej Fijalkowski, Aleksandr Loktionov,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislav Fomichev <sdf.kernel@gmail.com>
[ Upstream commit a6e4b9a6deb9362ef7a0706c70d674e92fe1411a ]
The zero-copy path reads TX metadata whenever the UMEM has metadata space,
even if the descriptor does not set XDP_TX_METADATA. Pass descriptor
options through the metadata helpers and ignore metadata unless the option
is set.
This does not fix the existing per-WQE metadata handling for mlx5 MPWQEs.
Only the descriptor that starts a session passes through
xsk_tx_metadata_request() and configures offload state shared by the batch.
Metadata on descriptors joining an open session is therefore not validated
and does not configure its requested offloads. In addition, a non-NULL
metadata pointer from such a descriptor is treated as a timestamp
completion request even when XDP_TXMD_FLAGS_TIMESTAMP is not set, so its
metadata union can be overwritten with an unrequested timestamp. Fixing
mixed metadata states within one MPWQE requires a separate change.
Fixes: 48eb03dd2630 ("xsk: Add TX timestamp and TX checksum offload support")
Reviewed-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Link: https://patch.msgid.link/20260819160535.1472459-3-sdf@fomichev.me
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/ethernet/intel/igc/igc_main.c | 3 ++-
drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c | 4 ++--
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 +++-
include/net/xdp_sock_drv.h | 6 +++---
4 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index e4a4d930dd226..ae5aebfd6be10 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -3002,7 +3002,8 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring)
olinfo_status = xdp_desc.len << IGC_ADVTXD_PAYLEN_SHIFT;
dma = xsk_buff_raw_get_dma(pool, xdp_desc.addr);
- meta = xsk_buff_get_metadata(pool, xdp_desc.addr);
+ meta = xsk_buff_get_metadata(pool, xdp_desc.addr,
+ xdp_desc.options);
xsk_buff_raw_dma_sync_for_device(pool, dma, xdp_desc.len);
bi = &ring->tx_buffer_info[ntu];
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
index a59199ed590da..0cc1d40c40b75 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
@@ -97,7 +97,7 @@ bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget)
xdptxd.dma_addr = xsk_buff_raw_get_dma(pool, desc.addr);
xdptxd.data = xsk_buff_raw_get_data(pool, desc.addr);
xdptxd.len = desc.len;
- meta = xsk_buff_get_metadata(pool, desc.addr);
+ meta = xsk_buff_get_metadata(pool, desc.addr, desc.options);
xsk_buff_raw_dma_sync_for_device(pool, xdptxd.dma_addr, xdptxd.len);
@@ -112,7 +112,7 @@ bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget)
} else {
mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo, xdpi);
if (xp_tx_metadata_enabled(sq->xsk_pool)) {
- struct xsk_tx_metadata_compl compl;
+ struct xsk_tx_metadata_compl compl = {};
xsk_tx_metadata_to_compl(meta, &compl);
XSK_TX_COMPL_FITS(void *);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index dfab95896adde..73f079a7cb537 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2521,7 +2521,8 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
tx_desc = tx_q->dma_tx + entry;
dma_addr = xsk_buff_raw_get_dma(pool, xdp_desc.addr);
- meta = xsk_buff_get_metadata(pool, xdp_desc.addr);
+ meta = xsk_buff_get_metadata(pool, xdp_desc.addr,
+ xdp_desc.options);
xsk_buff_raw_dma_sync_for_device(pool, dma_addr, xdp_desc.len);
tx_q->tx_skbuff_dma[entry].buf_type = STMMAC_TXBUF_T_XSK_TX;
@@ -2566,6 +2567,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
stmmac_enable_dma_transmission(priv, priv->ioaddr, queue);
+ tx_q->tx_skbuff_dma[entry].xsk_meta.tx_timestamp = NULL;
xsk_tx_metadata_to_compl(meta,
&tx_q->tx_skbuff_dma[entry].xsk_meta);
diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h
index 8d254e4b35716..71e219a749747 100644
--- a/include/net/xdp_sock_drv.h
+++ b/include/net/xdp_sock_drv.h
@@ -232,11 +232,11 @@ xsk_buff_valid_tx_metadata(const struct xsk_tx_metadata *meta)
return !(meta->flags & ~XDP_TXMD_FLAGS_VALID);
}
-static inline struct xsk_tx_metadata *xsk_buff_get_metadata(struct xsk_buff_pool *pool, u64 addr)
+static inline struct xsk_tx_metadata *xsk_buff_get_metadata(struct xsk_buff_pool *pool, u64 addr, u32 options)
{
struct xsk_tx_metadata *meta;
- if (!pool->tx_metadata_len)
+ if (!pool->tx_metadata_len || !(options & XDP_TX_METADATA))
return NULL;
meta = xp_raw_get_data(pool, addr) - pool->tx_metadata_len;
@@ -426,7 +426,7 @@ static inline bool xsk_buff_valid_tx_metadata(struct xsk_tx_metadata *meta)
return false;
}
-static inline struct xsk_tx_metadata *xsk_buff_get_metadata(struct xsk_buff_pool *pool, u64 addr)
+static inline struct xsk_tx_metadata *xsk_buff_get_metadata(struct xsk_buff_pool *pool, u64 addr, u32 options)
{
return NULL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 603/869] Bluetooth: do not leak an hci_conn when a second LE connect is rejected
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (601 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 602/869] xsk: honor XDP_TX_METADATA in zero-copy path Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 604/869] net: add getsockopt_iter callback to proto_ops Greg Kroah-Hartman
` (266 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Radek Podgorny,
Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Radek Podgorny <radek@podgorny.cz>
[ Upstream commit 7e1e4047200fd7519f9bdfe8a001437715e618b4 ]
create_le_conn_complete() decides whether the failed connection is
still pending by comparing it against hci_lookup_le_connect(), which
returns the first LE connection in BT_CONNECT. That is the same
connection only while at most one is pending.
Two can be pending. Connections created on the passive scan path sit
in BT_CONNECT with HCI_CONN_SCANNING set and are invisible to
hci_lookup_le_connect() until hci_le_create_conn_sync() clears the
flag when their command is issued, so the -EBUSY guard in
hci_connect_le() does not prevent a second connection from being
queued while the first is still on the scan path. Whenever two
connections are in BT_CONNECT at once, the lookup may return one
connection while create_le_conn_complete() is reporting the failure
of the other; the early exit then drops the error and hci_conn_failed()
never runs on the connection that failed.
The controller also rejects a second HCI_OP_LE_CREATE_CONN issued
while another connection creation is still outstanding, per Core Spec
Vol 4, Part E. The spec calls for Command Disallowed there; the
bcm43438 observed here answers with an LMP/LL error code instead,
which bt_to_errno() maps to the -EPROTO (-71) in the log below.
The leaked connection stays in BT_CONNECT forever, and because
hci_connect_le() refuses to dial while hci_lookup_le_connect() finds
anything, every subsequent attempt to reach any peer fails with
-EBUSY and no command reaches the controller at all.
Seen on a bcm43438 with two BLE peers polled on the same interval
(state 5 is BT_CONNECT; both handles are UNSET ones, allocated from
the ida above HCI_CONN_HANDLE_MAX):
Bluetooth: hci1: Opcode 0x2013 failed: -71
# hcitool con
< LE 14:9C:EF:03:68:81 handle 3840 state 5 lm CENTRAL
< LE C4:D3:6A:8C:B5:38 handle 3841 state 5 lm CENTRAL
A btmon capture across the next ten minutes of connect attempts
contains no HCI_OP_LE_CREATE_CONN at all; outgoing LE connections
do not recover until the adapter is reset. With this change the same
scenario fails the rejected connection cleanly and further connects
to both peers go through.
Ask about the connection itself instead of about the device.
Fixes: c9f73a2178c1 ("Bluetooth: hci_conn: Fix hci_connect_le_sync")
Signed-off-by: Radek Podgorny <radek@podgorny.cz>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/hci_sync.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index dfa0150669551..de4db563e247e 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -7188,8 +7188,13 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
goto unlock;
}
- /* Check if connection is still pending */
- if (conn != hci_lookup_le_connect(hdev))
+ /* Check if this connection is still pending.
+ *
+ * hci_lookup_le_connect() returns only the first LE connection
+ * in BT_CONNECT, which is not necessarily this one when two are
+ * pending at once, so ask the connection itself.
+ */
+ if (conn->state != BT_CONNECT)
goto unlock;
/* Flush to make sure we send create conn cancel command if needed */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 604/869] net: add getsockopt_iter callback to proto_ops
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (602 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 603/869] Bluetooth: do not leak an hci_conn when a second LE connect is rejected Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 605/869] Bluetooth: L2CAP: convert to getsockopt_iter Greg Kroah-Hartman
` (265 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Linus Torvalds, Breno Leitao,
Stanislav Fomichev, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <leitao@debian.org>
[ Upstream commit 67fab22a7adcec0279b9b057eb3dc669e32834f0 ]
Add a new getsockopt_iter callback to struct proto_ops that uses
sockopt_t, a type-safe wrapper around iov_iter. This provides a clean
interface for socket option operations that works with both user and
kernel buffers.
The sockopt_t type encapsulates an iov_iter and an optlen field.
The optlen field, although not suggested by Linus, serves as both input
(buffer size) and output (returned data size), allowing callbacks to
return random values independent of the bytes written via
copy_to_iter(), so, keep it separated from iov_iter.count.
This is preparatory work for removing the SOL_SOCKET level restriction
from io_uring getsockopt operations.
Keep in mind that both iter_out and iter_in always point to the same
data at all times, and we just have two of them to make the callback
implementation sane.
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Breno Leitao <leitao@debian.org>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20260408-getsockopt-v3-1-061bb9cb355d@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: ca2c4c264986 ("Bluetooth: L2CAP: access chan->conn safely in get/setsockopt")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/net.h | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/include/linux/net.h b/include/linux/net.h
index b75bc534c1b35..c6d92428c71a5 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -23,9 +23,30 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/sockptr.h>
+#include <linux/uio.h>
#include <uapi/linux/net.h>
+/**
+ * struct sockopt - socket option value container
+ * @iter_in: iov_iter for reading optval with the content from the caller.
+ * Use copy_from_iter() given this iov direction is ITER_SOURCE
+ * @iter_out: iov_iter for protocols to update optval data to userspace
+ * Use _copy_to_iter() given iov direction is ITER_DEST
+ * @optlen: serves as both input (buffer size) and output (returned data size).
+ *
+ * Type-safe wrapper for socket option data that works with both
+ * user and kernel buffers.
+ *
+ * The optlen field allows callbacks to return a specific length value
+ * independent of the bytes written via copy_to_iter().
+ */
+typedef struct sockopt {
+ struct iov_iter iter_in;
+ struct iov_iter iter_out;
+ int optlen;
+} sockopt_t;
+
struct poll_table_struct;
struct pipe_inode_info;
struct inode;
@@ -194,6 +215,8 @@ struct proto_ops {
unsigned int optlen);
int (*getsockopt)(struct socket *sock, int level,
int optname, char __user *optval, int __user *optlen);
+ int (*getsockopt_iter)(struct socket *sock, int level,
+ int optname, sockopt_t *opt);
void (*show_fdinfo)(struct seq_file *m, struct socket *sock);
int (*sendmsg) (struct socket *sock, struct msghdr *m,
size_t total_len);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 605/869] Bluetooth: L2CAP: convert to getsockopt_iter
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (603 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 604/869] net: add getsockopt_iter callback to proto_ops Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 606/869] Bluetooth: L2CAP: access chan->conn safely in get/setsockopt Greg Kroah-Hartman
` (264 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Breno Leitao, Luiz Augusto von Dentz,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <leitao@debian.org>
[ Upstream commit bf01627cc04b70c04a6d68eda06f836fed3078bc ]
Convert L2CAP socket's getsockopt implementation to use the new
getsockopt_iter callback with sockopt_t.
Key changes:
- Replace (char __user *optval, int __user *optlen) with sockopt_t *sopt
- Use sopt->optlen for buffer length (input)
- Use copy_to_iter() instead of put_user()/copy_to_user()
- Add linux/uio.h for copy_to_iter()
The sockopt_t parameter is named sopt rather than opt to avoid
collision with the existing local u32 opt used by L2CAP_LM. The same
naming is reused for the new u32 helper in l2cap_sock_getsockopt(),
with mtu and mval helpers covering the u16 and u8 cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Stable-dep-of: ca2c4c264986 ("Bluetooth: L2CAP: access chan->conn safely in get/setsockopt")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/l2cap_sock.c | 61 +++++++++++++++++++++++---------------
1 file changed, 37 insertions(+), 24 deletions(-)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index d5b1b5a231a19..a44a49c70b2f3 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -31,6 +31,7 @@
#include <linux/export.h>
#include <linux/filter.h>
#include <linux/sched/signal.h>
+#include <linux/uio.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -439,7 +440,7 @@ static int l2cap_get_mode(struct l2cap_chan *chan)
}
static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
- char __user *optval, int __user *optlen)
+ sockopt_t *sopt)
{
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -451,8 +452,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
BT_DBG("sk %p", sk);
- if (get_user(len, optlen))
- return -EFAULT;
+ len = sopt->optlen;
lock_sock(sk);
@@ -494,7 +494,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
BT_DBG("mode 0x%2.2x", chan->mode);
len = min(len, sizeof(opts));
- if (copy_to_user(optval, (char *) &opts, len))
+ if (copy_to_iter(&opts, len, &sopt->iter_out) != len)
err = -EFAULT;
break;
@@ -526,7 +526,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
opt |= L2CAP_LM_RELIABLE;
- if (put_user(opt, (u32 __user *) optval))
+ if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) !=
+ sizeof(opt))
err = -EFAULT;
break;
@@ -544,7 +545,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3);
len = min(len, sizeof(cinfo));
- if (copy_to_user(optval, (char *) &cinfo, len))
+ if (copy_to_iter(&cinfo, len, &sopt->iter_out) != len)
err = -EFAULT;
break;
@@ -559,25 +560,26 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
}
static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
- char __user *optval, int __user *optlen)
+ sockopt_t *sopt)
{
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct bt_security sec;
struct bt_power pwr;
- u32 phys;
int len, mode, err = 0;
+ u32 opt;
+ u16 mtu;
+ u8 mval;
BT_DBG("sk %p", sk);
if (level == SOL_L2CAP)
- return l2cap_sock_getsockopt_old(sock, optname, optval, optlen);
+ return l2cap_sock_getsockopt_old(sock, optname, sopt);
if (level != SOL_BLUETOOTH)
return -ENOPROTOOPT;
- if (get_user(len, optlen))
- return -EFAULT;
+ len = sopt->optlen;
lock_sock(sk);
@@ -601,7 +603,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
}
len = min_t(unsigned int, len, sizeof(sec));
- if (copy_to_user(optval, (char *) &sec, len))
+ if (copy_to_iter(&sec, len, &sopt->iter_out) != len)
err = -EFAULT;
break;
@@ -612,15 +614,17 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
break;
}
- if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
- (u32 __user *) optval))
+ opt = test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
+ if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) !=
+ sizeof(opt))
err = -EFAULT;
break;
case BT_FLUSHABLE:
- if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags),
- (u32 __user *) optval))
+ opt = test_bit(FLAG_FLUSHABLE, &chan->flags);
+ if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) !=
+ sizeof(opt))
err = -EFAULT;
break;
@@ -635,13 +639,15 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
pwr.force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
len = min_t(unsigned int, len, sizeof(pwr));
- if (copy_to_user(optval, (char *) &pwr, len))
+ if (copy_to_iter(&pwr, len, &sopt->iter_out) != len)
err = -EFAULT;
break;
case BT_CHANNEL_POLICY:
- if (put_user(chan->chan_policy, (u32 __user *) optval))
+ opt = chan->chan_policy;
+ if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) !=
+ sizeof(opt))
err = -EFAULT;
break;
@@ -656,7 +662,9 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
break;
}
- if (put_user(chan->omtu, (u16 __user *) optval))
+ mtu = chan->omtu;
+ if (copy_to_iter(&mtu, sizeof(mtu), &sopt->iter_out) !=
+ sizeof(mtu))
err = -EFAULT;
break;
@@ -666,7 +674,9 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
break;
}
- if (put_user(chan->imtu, (u16 __user *) optval))
+ mtu = chan->imtu;
+ if (copy_to_iter(&mtu, sizeof(mtu), &sopt->iter_out) !=
+ sizeof(mtu))
err = -EFAULT;
break;
@@ -676,9 +686,10 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
break;
}
- phys = hci_conn_get_phy(chan->conn->hcon);
+ opt = hci_conn_get_phy(chan->conn->hcon);
- if (put_user(phys, (u32 __user *) optval))
+ if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) !=
+ sizeof(opt))
err = -EFAULT;
break;
@@ -699,7 +710,9 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
break;
}
- if (put_user(mode, (u8 __user *) optval))
+ mval = mode;
+ if (copy_to_iter(&mval, sizeof(mval), &sopt->iter_out) !=
+ sizeof(mval))
err = -EFAULT;
break;
@@ -2019,7 +2032,7 @@ static const struct proto_ops l2cap_sock_ops = {
.socketpair = sock_no_socketpair,
.shutdown = l2cap_sock_shutdown,
.setsockopt = l2cap_sock_setsockopt,
- .getsockopt = l2cap_sock_getsockopt
+ .getsockopt_iter = l2cap_sock_getsockopt
};
static const struct net_proto_family l2cap_sock_family_ops = {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 606/869] Bluetooth: L2CAP: access chan->conn safely in get/setsockopt
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (604 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 605/869] Bluetooth: L2CAP: convert to getsockopt_iter Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 607/869] Drivers: hv: vmbus: Skip VMBus module cleanup for non-nested root partition Greg Kroah-Hartman
` (263 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+b106284c2a0b7bc80cf9,
Pauli Virtanen, Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <pav@iki.fi>
[ Upstream commit ca2c4c26498643f421d35ffe258fafbd3ed461c3 ]
Since commit b66774b48dd9 ("Bluetooth: L2CAP: Fix UAF in channel timeout by holding conn ref")
l2cap_chan::conn has held reference and remains non-NULL also after the
corresponding hci_conn is deleted. In this state accessing various
fields eg. hci_conn::hdev is invalid, which leads to KASAN crash in
l2cap_sock_setsockopt() access of conn->hcon->hdev.
Check l2cap_chan::conn.hcon corresponds to an alive hci_conn before
trying to use it in l2cap_sock.c. Hold l2cap_chan_lock() in
getsockopt/setsockopt to ensure it stays alive, and to avoid data races
in l2cap_chan fields.
Fixes: b66774b48dd9 ("Bluetooth: L2CAP: Fix UAF in channel timeout by holding conn ref")
Reported-by: syzbot+b106284c2a0b7bc80cf9@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=b106284c2a0b7bc80cf9
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/l2cap_sock.c | 57 ++++++++++++++++++++++++++++++--------
1 file changed, 46 insertions(+), 11 deletions(-)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index a44a49c70b2f3..ef3af57e4637f 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -439,11 +439,26 @@ static int l2cap_get_mode(struct l2cap_chan *chan)
return -EINVAL;
}
+static struct l2cap_conn *l2cap_chan_conn(struct l2cap_chan *chan)
+{
+ lockdep_assert_held(&chan->lock);
+
+ /* l2cap_conn_del() sets FLAG_DEL while holding chan->lock before
+ * conn->hcon is deleted. If not set and conn is non-NULL, conn->hcon
+ * remains alive during this chan->lock critical section.
+ */
+ if (test_bit(FLAG_DEL, &chan->flags))
+ return NULL;
+
+ return chan->conn;
+}
+
static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
sockopt_t *sopt)
{
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+ struct l2cap_conn *conn;
struct l2cap_options opts;
struct l2cap_conninfo cinfo;
int err = 0;
@@ -454,6 +469,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
len = sopt->optlen;
+ l2cap_chan_lock(chan);
lock_sock(sk);
switch (optname) {
@@ -540,9 +556,15 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
break;
}
+ conn = l2cap_chan_conn(chan);
+ if (!conn) {
+ err = -ENOTCONN;
+ break;
+ }
+
memset(&cinfo, 0, sizeof(cinfo));
- cinfo.hci_handle = chan->conn->hcon->handle;
- memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3);
+ cinfo.hci_handle = conn->hcon->handle;
+ memcpy(cinfo.dev_class, conn->hcon->dev_class, 3);
len = min(len, sizeof(cinfo));
if (copy_to_iter(&cinfo, len, &sopt->iter_out) != len)
@@ -556,6 +578,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
}
release_sock(sk);
+ l2cap_chan_unlock(chan);
+
return err;
}
@@ -564,6 +588,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
{
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+ struct l2cap_conn *conn;
struct bt_security sec;
struct bt_power pwr;
int len, mode, err = 0;
@@ -581,6 +606,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
len = sopt->optlen;
+ l2cap_chan_lock(chan);
lock_sock(sk);
switch (optname) {
@@ -592,12 +618,14 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
break;
}
+ conn = l2cap_chan_conn(chan);
+
memset(&sec, 0, sizeof(sec));
- if (chan->conn) {
- sec.level = chan->conn->hcon->sec_level;
+ if (conn) {
+ sec.level = conn->hcon->sec_level;
if (sk->sk_state == BT_CONNECTED)
- sec.key_size = chan->conn->hcon->enc_key_size;
+ sec.key_size = conn->hcon->enc_key_size;
} else {
sec.level = chan->sec_level;
}
@@ -681,12 +709,14 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
break;
case BT_PHY:
- if (sk->sk_state != BT_CONNECTED) {
+ conn = l2cap_chan_conn(chan);
+
+ if (sk->sk_state != BT_CONNECTED || !conn) {
err = -ENOTCONN;
break;
}
- opt = hci_conn_get_phy(chan->conn->hcon);
+ opt = hci_conn_get_phy(conn->hcon);
if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) !=
sizeof(opt))
@@ -722,6 +752,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
}
release_sock(sk);
+ l2cap_chan_unlock(chan);
return err;
}
@@ -752,6 +783,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
BT_DBG("sk %p", sk);
+ l2cap_chan_lock(chan);
lock_sock(sk);
switch (optname) {
@@ -853,6 +885,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
}
release_sock(sk);
+ l2cap_chan_unlock(chan);
return err;
}
@@ -916,6 +949,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
if (level != SOL_BLUETOOTH)
return -ENOPROTOOPT;
+ l2cap_chan_lock(chan);
lock_sock(sk);
switch (optname) {
@@ -941,11 +975,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
chan->sec_level = sec.level;
- if (!chan->conn)
+ conn = l2cap_chan_conn(chan);
+ if (!conn)
break;
- conn = chan->conn;
-
/* change security for LE channels */
if (chan->scid == L2CAP_CID_ATT) {
if (smp_conn_security(conn->hcon, sec.level)) {
@@ -1000,7 +1033,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
}
if (opt == BT_FLUSHABLE_OFF) {
- conn = chan->conn;
+ conn = l2cap_chan_conn(chan);
+
/* proceed further only when we have l2cap_conn and
No Flush support in the LM */
if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) {
@@ -1124,6 +1158,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
}
release_sock(sk);
+ l2cap_chan_unlock(chan);
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 607/869] Drivers: hv: vmbus: Skip VMBus module cleanup for non-nested root partition
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (605 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 606/869] Bluetooth: L2CAP: access chan->conn safely in get/setsockopt Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 608/869] net/sched: account classifier filter allocations to memcg Greg Kroah-Hartman
` (262 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Michael Kelley,
Easwar Hariharan, Wei Liu, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Kelley <mhkelley58@gmail.com>
[ Upstream commit cee0d90bceae1dee3bcc70f8d6b2ceb5b87deb42 ]
The VMBus module initialization function, hv_acpi_init(), currently
does nothing when running in the root partition and root is not nested
in another VM. But the initialization function reports success, so the
VMBus module is indeed loaded. VMBus functionality is not actually
needed, but the VMBus module must be loaded so that hv_vmbus_exists()
can answer correctly. Furthermore, the mshv_root dependency on the
VMBus module is needed as described in the commit message for
840b740a35bf ("mshv: Add conditional VMBus dependency").
Loading the VMBus module without actually initializing it causes
failures if the module should later be unloaded. The module unload code
tries to clean up things that were never initialized, resulting in
memory faults and a panic.
Fix this by having VMBus module exit function perform the same
check for non-nested root partition, and do nothing in such a
case, just like hv_acpi_init().
In the long run, the code that manages the Hyper-V provided SynIC
should be refactored to better coordinate the requirements of
root partition scenarios and normal VM scenarios, and to hopefully
remove the hv_vmbus_exists() dependnecy between mshv_root and
VMBus modules. Preventing the current unload failure scenario is
an expediency until such a refactoring is done.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/linux-hyperv/20260721154943.A09BD1F00A3D@smtp.kernel.org/
Fixes: 7e279d78664aa ("Drivers: hv: vmbus: skip VMBus initialization if Linux is root")
Signed-off-by: Michael Kelley <mhklinux@outlook.com>
Reviewed-by: Easwar Hariharan <easwar.hariharan@linux.microsoft.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hv/vmbus_drv.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 4d3c78c388418..1ddbbc80cf13f 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -2832,6 +2832,13 @@ static int __init hv_acpi_init(void)
return -ENODEV;
if (hv_root_partition && !hv_nested)
+ /*
+ * A non-nested root partition does not need VMBus client
+ * functionality. However, the mshv_root module may have
+ * a dependency on the VMBus module as described in
+ * commit 840b740a35bf. Return success so the module
+ * loads even though no VMBus initialization is done.
+ */
return 0;
/*
@@ -2880,6 +2887,14 @@ static void __exit vmbus_exit(void)
{
int cpu;
+ if (hv_root_partition && !hv_nested)
+ /*
+ * If a non-nested root partition loaded the VMBus module,
+ * hv_acpi_init() did not do any VMBus initialization.
+ * There's nothing to clean up, so just return.
+ */
+ return;
+
unregister_syscore(&hv_synic_syscore);
hv_remove_kexec_handler();
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 608/869] net/sched: account classifier filter allocations to memcg
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (606 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 607/869] Drivers: hv: vmbus: Skip VMBus module cleanup for non-nested root partition Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 609/869] NFSv4.1: zero referring call lists before decoding Greg Kroah-Hartman
` (261 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, vega, Jamal Hadi Salim, Breno Leitao,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <jhs@mojatatu.com>
[ Upstream commit 1beb81947eb486716af80db7a584f9e9fef7e003 ]
Allocations in the tc classifier *_change() paths (filter objects,
per-CPU counters, and per-filter aux data) use plain GFP_KERNEL without
__GFP_ACCOUNT, allowing unprivileged users to pin kernel memory outside
memcg charging. The shared tcf_exts_init_ex() action array allocation in
cls_api.c was also uncharged; this patch closes it along with the
per-classifier filter-object/percpu/aux allocations that remain
unaccounted.
Add GFP_KERNEL_ACCOUNT to:
- the shared tcf_exts_init_ex() action array (cls_api.c), common to every
filter of every classifier (32 pointers, 256 bytes);
- the filter-object, per-CPU-counter, and per-filter aux allocations in
cls_basic, cls_bpf, cls_cgroup, cls_flow, cls_flower, cls_fw,
cls_matchall, cls_route and cls_u32;
- the u32_init_knode() replace-path knode allocation (cls_u32.c), which
allocates the same struct tc_u_knode + sel.keys on every replace of an
existing knode and was missed by the create-path-only conversion.
Also fix the cls_basic error path: basic_change() inserts fnew into the
IDR before allocating the per-CPU counter. If alloc_percpu() fails the
errout path kfree'd fnew without idr_remove, leaving a dangling pointer
in the IDR. With GFP_KERNEL_ACCOUNT the percpu alloc becomes failable
on demand (memcg at memory.max), making the dead path attacker-reachable
and burning the handle permanently. Add the idr_remove on the percpu
failure path, matching the basic_set_parms failure-path pattern.
Note: vega@nebusec.ai provided a poc for basic_cls, but it was easy to
extend to the other classifiers.
Conditions to recreate the bug:
- CONFIG_NET_SCHED, CONFIG_NET_CLS_* (the classifier being used),
CONFIG_NET_CLS_ACT, CONFIG_MEMCG, CONFIG_USER_NS, CONFIG_NET_NS.
- Unprivileged user in a fresh user+network namespace (unshare -Urn),
or root with CAP_NET_ADMIN.
- Create a large number of tc filters (e.g. tc filter add dev lo
ingress ... <classifier> ...) while watching a memcg-limited cgroup:
system slab grows far faster than memory.current, pinning kernel
memory outside memcg charging.
Fixes: 0da974f4f303 ("[NET]: Conversions from kmalloc+memset to k(z|c)alloc.")
Reported-by: vega@nebusec.ai
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: Breno Leitao <leitao@debian.org>
Link: https://patch.msgid.link/20260819143733.57538-1-jhs@mojatatu.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sched/cls_api.c | 2 +-
net/sched/cls_basic.c | 6 ++++--
net/sched/cls_bpf.c | 6 +++---
net/sched/cls_cgroup.c | 2 +-
net/sched/cls_flow.c | 2 +-
net/sched/cls_flower.c | 4 ++--
net/sched/cls_fw.c | 4 ++--
net/sched/cls_matchall.c | 4 ++--
net/sched/cls_route.c | 4 ++--
net/sched/cls_u32.c | 11 ++++++-----
10 files changed, 24 insertions(+), 21 deletions(-)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index f8d1cc0f23c15..1e2dccd6cc4e1 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -3375,7 +3375,7 @@ int tcf_exts_init_ex(struct tcf_exts *exts, struct net *net, int action,
*/
exts->net = net;
exts->actions = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *),
- GFP_KERNEL);
+ GFP_KERNEL_ACCOUNT);
if (!exts->actions)
return -ENOMEM;
#endif
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index ecfaa4f9a04ea..d5ef0a66a73fa 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -193,7 +193,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
return -EINVAL;
}
- fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
+ fnew = kzalloc(sizeof(*fnew), GFP_KERNEL_ACCOUNT);
if (!fnew)
return -ENOBUFS;
@@ -212,9 +212,11 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
if (err)
goto errout;
fnew->handle = handle;
- fnew->pf = alloc_percpu(struct tc_basic_pcnt);
+ fnew->pf = alloc_percpu_gfp(struct tc_basic_pcnt, GFP_KERNEL_ACCOUNT);
if (!fnew->pf) {
err = -ENOMEM;
+ if (!fold)
+ idr_remove(&head->handle_idr, fnew->handle);
goto errout;
}
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index a6003fa35c7c5..66b525a852875 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -352,7 +352,7 @@ static int cls_bpf_prog_from_ops(struct nlattr **tb, struct cls_bpf_prog *prog)
if (bpf_size != nla_len(tb[TCA_BPF_OPS]))
return -EINVAL;
- bpf_ops = kmemdup(nla_data(tb[TCA_BPF_OPS]), bpf_size, GFP_KERNEL);
+ bpf_ops = kmemdup(nla_data(tb[TCA_BPF_OPS]), bpf_size, GFP_KERNEL_ACCOUNT);
if (bpf_ops == NULL)
return -ENOMEM;
@@ -403,7 +403,7 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
}
if (tb[TCA_BPF_NAME]) {
- name = nla_memdup(tb[TCA_BPF_NAME], GFP_KERNEL);
+ name = nla_memdup(tb[TCA_BPF_NAME], GFP_KERNEL_ACCOUNT);
if (!name) {
bpf_prog_put(fp);
return -ENOMEM;
@@ -443,7 +443,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
if (ret < 0)
return ret;
- prog = kzalloc(sizeof(*prog), GFP_KERNEL);
+ prog = kzalloc(sizeof(*prog), GFP_KERNEL_ACCOUNT);
if (!prog)
return -ENOBUFS;
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
index 424252982d6ae..8f6563e50e63e 100644
--- a/net/sched/cls_cgroup.c
+++ b/net/sched/cls_cgroup.c
@@ -95,7 +95,7 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
if (head && handle != head->handle)
return -ENOENT;
- new = kzalloc(sizeof(*head), GFP_KERNEL);
+ new = kzalloc(sizeof(*head), GFP_KERNEL_ACCOUNT);
if (!new)
return -ENOBUFS;
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index a8b900a27d2f0..334f8fc82ddcc 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -438,7 +438,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
return -EOPNOTSUPP;
}
- fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
+ fnew = kzalloc(sizeof(*fnew), GFP_KERNEL_ACCOUNT);
if (!fnew)
return -ENOBUFS;
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index 099ff6a3e1f51..5e61bf334ed84 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -2237,7 +2237,7 @@ static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head,
struct fl_flow_mask *newmask;
int err;
- newmask = kzalloc(sizeof(*newmask), GFP_KERNEL);
+ newmask = kzalloc(sizeof(*newmask), GFP_KERNEL_ACCOUNT);
if (!newmask)
return ERR_PTR(-ENOMEM);
@@ -2398,7 +2398,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
goto errout_tb;
}
- fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
+ fnew = kzalloc(sizeof(*fnew), GFP_KERNEL_ACCOUNT);
if (!fnew) {
err = -ENOBUFS;
goto errout_tb;
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index fd9c6c2815a1c..e32eecdf675fe 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -276,7 +276,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
if (f->id != handle && handle)
return -EINVAL;
- fnew = kzalloc(sizeof(struct fw_filter), GFP_KERNEL);
+ fnew = kzalloc(sizeof(struct fw_filter), GFP_KERNEL_ACCOUNT);
if (!fnew)
return -ENOBUFS;
@@ -330,7 +330,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
rcu_assign_pointer(tp->root, head);
}
- f = kzalloc(sizeof(struct fw_filter), GFP_KERNEL);
+ f = kzalloc(sizeof(struct fw_filter), GFP_KERNEL_ACCOUNT);
if (f == NULL)
return -ENOBUFS;
diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c
index f03bf5da39ee8..762ba74aa7be0 100644
--- a/net/sched/cls_matchall.c
+++ b/net/sched/cls_matchall.c
@@ -189,7 +189,7 @@ static int mall_change(struct net *net, struct sk_buff *in_skb,
return -EINVAL;
}
- new = kzalloc(sizeof(*new), GFP_KERNEL);
+ new = kzalloc(sizeof(*new), GFP_KERNEL_ACCOUNT);
if (!new)
return -ENOBUFS;
@@ -201,7 +201,7 @@ static int mall_change(struct net *net, struct sk_buff *in_skb,
handle = 1;
new->handle = handle;
new->flags = userflags;
- new->pf = alloc_percpu(struct tc_matchall_pcnt);
+ new->pf = alloc_percpu_gfp(struct tc_matchall_pcnt, GFP_KERNEL_ACCOUNT);
if (!new->pf) {
err = -ENOMEM;
goto err_alloc_percpu;
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index 6d5b734e7c48e..1a41237d07aac 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -455,7 +455,7 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp,
h1 = to_hash(nhandle);
b = rtnl_dereference(head->table[h1]);
if (!b) {
- b = kzalloc(sizeof(struct route4_bucket), GFP_KERNEL);
+ b = kzalloc(sizeof(struct route4_bucket), GFP_KERNEL_ACCOUNT);
if (b == NULL)
return -ENOBUFS;
@@ -530,7 +530,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
return -EINVAL;
err = -ENOBUFS;
- f = kzalloc(sizeof(struct route4_filter), GFP_KERNEL);
+ f = kzalloc(sizeof(struct route4_filter), GFP_KERNEL_ACCOUNT);
if (!f)
goto errout;
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index ea021dc39fea3..ac344aabe8595 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -841,7 +841,7 @@ static struct tc_u_knode *u32_init_knode(struct net *net, struct tcf_proto *tp,
struct tc_u32_sel *s = &n->sel;
struct tc_u_knode *new;
- new = kzalloc(struct_size(new, sel.keys, s->nkeys), GFP_KERNEL);
+ new = kzalloc(struct_size(new, sel.keys, s->nkeys), GFP_KERNEL_ACCOUNT);
if (!new)
return NULL;
@@ -1139,15 +1139,16 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
goto erridr;
}
- n = kzalloc(struct_size(n, sel.keys, s->nkeys), GFP_KERNEL);
+ n = kzalloc(struct_size(n, sel.keys, s->nkeys), GFP_KERNEL_ACCOUNT);
if (n == NULL) {
err = -ENOBUFS;
goto erridr;
}
#ifdef CONFIG_CLS_U32_PERF
- n->pf = __alloc_percpu(struct_size(n->pf, kcnts, s->nkeys),
- __alignof__(struct tc_u32_pcnt));
+ n->pf = __alloc_percpu_gfp(struct_size(n->pf, kcnts, s->nkeys),
+ __alignof__(struct tc_u32_pcnt),
+ GFP_KERNEL_ACCOUNT);
if (!n->pf) {
err = -ENOBUFS;
goto errfree;
@@ -1169,7 +1170,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
goto errout;
#ifdef CONFIG_CLS_U32_MARK
- n->pcpu_success = alloc_percpu(u32);
+ n->pcpu_success = alloc_percpu_gfp(u32, GFP_KERNEL_ACCOUNT);
if (!n->pcpu_success) {
err = -ENOMEM;
goto errout;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 609/869] NFSv4.1: zero referring call lists before decoding
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (607 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 608/869] net/sched: account classifier filter allocations to memcg Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 610/869] vxlan: fix reading neigh ha Greg Kroah-Hartman
` (260 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jérémy Jean,
Trond Myklebust, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
[ Upstream commit 8fa4804fe62ca4155a2d8fc2789d630376cbf2fc ]
decode_cb_sequence_args() allocates csa_rclists with kmalloc_objs(), so
each referring_call_list starts uninitialized. decode_rc_list() assigns
rcl_refcalls only when rcl_nrefcalls is nonzero. A valid list with zero
referring calls therefore leaves the pointer uninitialized, and
nfs4_callback_sequence() later passes stale slab contents to kfree().
Allocate csa_rclists with kzalloc_objs() so every rcl_refcalls member is
NULL from the beginning, including valid empty referring call lists.
Fixes: 4aece6a19cf7 ("nfs41: cb_sequence xdr implementation")
Assisted-by: Codex:gpt-5
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfs/callback_xdr.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 4254ba3ee7c57..ada04a7230c22 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -422,9 +422,9 @@ static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp,
args->csa_nrclists = ntohl(*p++);
args->csa_rclists = NULL;
if (args->csa_nrclists) {
- args->csa_rclists = kmalloc_array(args->csa_nrclists,
- sizeof(*args->csa_rclists),
- GFP_KERNEL);
+ args->csa_rclists = kcalloc(args->csa_nrclists,
+ sizeof(*args->csa_rclists),
+ GFP_KERNEL);
if (unlikely(args->csa_rclists == NULL))
return htonl(NFS4ERR_RESOURCE);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 610/869] vxlan: fix reading neigh ha
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (608 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 609/869] NFSv4.1: zero referring call lists before decoding Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 611/869] net: bridge: arp/nd proxy: " Greg Kroah-Hartman
` (259 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nikolay Aleksandrov, Petr Machata,
Ido Schimmel, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikolay Aleksandrov <razor@blackwall.org>
[ Upstream commit b824059a673b2283e78c7aae2c7d257aad7f0e1d ]
Currently arp/neigh_reduce read neigh ha directly which can lead to
partial reads while the neigh is being updated. Use neigh_ha_snapshot to
take a stable snapshot of the address similar to route_shortcircuit which
already does the right thing.
Fixes: e4f67addf158 ("add DOVE extensions for VXLAN")
Fixes: f564f45c4518 ("vxlan: add ipv6 proxy support")
Signed-off-by: Nikolay Aleksandrov <razor@blackwall.org>
Reviewed-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260818150756.890025-3-razor@blackwall.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/vxlan/vxlan_core.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 567793aea4a21..e70a0b6575709 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -1917,6 +1917,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
if (n) {
struct vxlan_rdst *rdst = NULL;
+ u8 ha[ETH_ALEN] __aligned(2);
struct vxlan_fdb *f;
struct sk_buff *reply;
@@ -1925,8 +1926,10 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
goto out;
}
+ neigh_ha_snapshot(ha, n, n->dev);
+
rcu_read_lock();
- f = vxlan_find_mac_tx(vxlan, n->ha, vni);
+ f = vxlan_find_mac_tx(vxlan, ha, vni);
if (f)
rdst = first_remote_rcu(f);
if (rdst && vxlan_addr_any(&rdst->remote_ip)) {
@@ -1938,7 +1941,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
rcu_read_unlock();
reply = arp_create(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
- n->ha, sha);
+ ha, sha);
neigh_release(n);
@@ -1971,7 +1974,8 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
#if IS_ENABLED(CONFIG_IPV6)
static struct sk_buff *vxlan_na_create(struct sk_buff *request,
- struct neighbour *n, bool isrouter)
+ struct neighbour *n, u8 *ha,
+ bool isrouter)
{
struct net_device *dev = request->dev;
struct sk_buff *reply;
@@ -2019,7 +2023,7 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request,
/* Ethernet header */
ether_addr_copy(eth_hdr(reply)->h_dest, daddr);
- ether_addr_copy(eth_hdr(reply)->h_source, n->ha);
+ ether_addr_copy(eth_hdr(reply)->h_source, ha);
eth_hdr(reply)->h_proto = htons(ETH_P_IPV6);
reply->protocol = htons(ETH_P_IPV6);
@@ -2048,7 +2052,7 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request,
na->icmph.icmp6_override = 1;
na->icmph.icmp6_solicited = 1;
na->target = ns->target;
- ether_addr_copy(&na->opt[2], n->ha);
+ ether_addr_copy(&na->opt[2], ha);
na->opt[0] = ND_OPT_TARGET_LL_ADDR;
na->opt[1] = na_olen >> 3;
@@ -2091,6 +2095,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
if (n) {
struct vxlan_rdst *rdst = NULL;
+ u8 ha[ETH_ALEN] __aligned(2);
struct vxlan_fdb *f;
struct sk_buff *reply;
@@ -2099,7 +2104,8 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
goto out;
}
- f = vxlan_find_mac_tx(vxlan, n->ha, vni);
+ neigh_ha_snapshot(ha, n, n->dev);
+ f = vxlan_find_mac_tx(vxlan, ha, vni);
if (f)
rdst = first_remote_rcu(f);
if (rdst && vxlan_addr_any(&rdst->remote_ip)) {
@@ -2108,7 +2114,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
goto out;
}
- reply = vxlan_na_create(skb, n,
+ reply = vxlan_na_create(skb, n, ha,
!!(f ? f->flags & NTF_ROUTER : 0));
neigh_release(n);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 611/869] net: bridge: arp/nd proxy: fix reading neigh ha
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (609 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 610/869] vxlan: fix reading neigh ha Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 612/869] ip6mr: do not clone dst in ip6mr_cache_report() Greg Kroah-Hartman
` (258 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nikolay Aleksandrov, Petr Machata,
Ido Schimmel, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikolay Aleksandrov <razor@blackwall.org>
[ Upstream commit 57549ab9079122991dfa0f8248ca00e101e8e69b ]
Currently neigh ha address is read directly, but that can result in
torn/partial reads if the neigh is being updated. Use neigh_ha_snapshot
to take a stable snapshot of the address.
Fixes: 057658cb33fb ("bridge: suppress arp pkts on BR_NEIGH_SUPPRESS ports")
Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
Signed-off-by: Nikolay Aleksandrov <razor@blackwall.org>
Reviewed-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260818150756.890025-2-razor@blackwall.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bridge/br_arp_nd_proxy.c | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
index f2d6643d2c0a1..e1c6a54e9a0c7 100644
--- a/net/bridge/br_arp_nd_proxy.c
+++ b/net/bridge/br_arp_nd_proxy.c
@@ -191,13 +191,15 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,
n = neigh_lookup(&arp_tbl, &tip, vlandev);
if (n) {
struct net_bridge_fdb_entry *f;
+ u8 ha[ETH_ALEN] __aligned(2);
if (!(READ_ONCE(n->nud_state) & NUD_VALID)) {
neigh_release(n);
return;
}
- f = br_fdb_find_rcu(br, n->ha, vid);
+ neigh_ha_snapshot(ha, n, n->dev);
+ f = br_fdb_find_rcu(br, ha, vid);
if (f) {
const struct net_bridge_port *dst = READ_ONCE(f->dst);
bool replied = false;
@@ -207,10 +209,10 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,
br_is_neigh_suppress_enabled(dst, vid)) {
if (!vid)
br_arp_send(br, p, skb->dev, sip, tip,
- sha, n->ha, sha, 0, 0);
+ sha, ha, sha, 0, 0);
else
br_arp_send(br, p, skb->dev, sip, tip,
- sha, n->ha, sha,
+ sha, ha, sha,
skb->vlan_proto,
skb_vlan_tag_get(skb));
replied = true;
@@ -248,7 +250,7 @@ struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *msg)
}
static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
- struct sk_buff *request, struct neighbour *n,
+ struct sk_buff *request, struct neighbour *n, u8 *ha,
__be16 vlan_proto, u16 vlan_tci)
{
struct net_device *dev = request->dev;
@@ -306,7 +308,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
ipv6_eth_mc_map(&in6addr_linklocal_allnodes, eth_hdr(reply)->h_dest);
else
ether_addr_copy(eth_hdr(reply)->h_dest, daddr);
- ether_addr_copy(eth_hdr(reply)->h_source, n->ha);
+ ether_addr_copy(eth_hdr(reply)->h_source, ha);
eth_hdr(reply)->h_proto = htons(ETH_P_IPV6);
reply->protocol = htons(ETH_P_IPV6);
@@ -336,7 +338,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
na->icmph.icmp6_override = 1;
na->icmph.icmp6_solicited = dad ? 0 : 1;
na->target = ns->target;
- ether_addr_copy(&na->opt[2], n->ha);
+ ether_addr_copy(&na->opt[2], ha);
na->opt[0] = ND_OPT_TARGET_LL_ADDR;
na->opt[1] = na_olen >> 3;
@@ -365,7 +367,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
__vlan_hwaccel_put_tag(reply, vlan_proto, vlan_tci);
netdev_dbg(dev, "nd send dev %s dst %pI6 dst_hw %pM src %pI6 src_hw %pM\n",
- dev->name, &pip6->daddr, daddr, &pip6->saddr, n->ha);
+ dev->name, &pip6->daddr, daddr, &pip6->saddr, ha);
if (p) {
dev_queue_xmit(reply);
@@ -462,24 +464,26 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
n = neigh_lookup(ipv6_stub->nd_tbl, &msg->target, vlandev);
if (n) {
struct net_bridge_fdb_entry *f;
+ u8 ha[ETH_ALEN] __aligned(2);
if (!(READ_ONCE(n->nud_state) & NUD_VALID)) {
neigh_release(n);
return;
}
- f = br_fdb_find_rcu(br, n->ha, vid);
+ neigh_ha_snapshot(ha, n, n->dev);
+ f = br_fdb_find_rcu(br, ha, vid);
if (f) {
const struct net_bridge_port *dst = READ_ONCE(f->dst);
bool replied = false;
if (br_is_neigh_suppress_enabled(dst, vid)) {
if (vid != 0)
- br_nd_send(br, p, skb, n,
+ br_nd_send(br, p, skb, n, ha,
skb->vlan_proto,
skb_vlan_tag_get(skb));
else
- br_nd_send(br, p, skb, n, 0, 0);
+ br_nd_send(br, p, skb, n, ha, 0, 0);
replied = true;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 612/869] ip6mr: do not clone dst in ip6mr_cache_report()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (610 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 611/869] net: bridge: arp/nd proxy: " Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 613/869] ALSA: mtpav: shut down output timer before card teardown Greg Kroah-Hartman
` (257 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Zero Day Initiative, Eric Dumazet,
Hangbin Liu, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 235b42b5860189eb8c27c36435ad932cae65a734 ]
IPv6 input attaches a non-refcounted (NOREF) dst to skbs under RCU.
When an ingress multicast packet misses MFC lookup,
ip6mr_cache_unresolved() places the skb onto the unresolved queue,
escaping the receive-side RCU grace period.
If the underlying route is deleted and freed, and the MFC queue is later
resolved with a wrong parent interface, ip6_mr_forward() invokes
ip6mr_cache_report(..., MRT6MSG_WRONGMIF), which executes
dst_clone(skb_dst(pkt)) on the freed dst entry, triggering a slab
use-after-free.
Report packets queued to mroute6_sk (a raw socket) and netlink
notifications do not require an attached dst entry.
Fix this by:
1. Removing dst_clone() in ip6mr_cache_report() and ensuring report skbs
do not hold a dst.
2. Dropping skb_dst before queuing unresolved skbs in
ip6mr_cache_unresolved(), matching the fact that multicast
forwarding resolves outgoing routes anew via ip6_route_output().
Fixes: 67f415dd2906 ("ipv6: convert rx data path to not take refcnt on dst")
Reported-by: Zero Day Initiative <zdi-disclosures@trendmicro.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>
Link: https://patch.msgid.link/20260818172755.4083692-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv6/ip6mr.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index ac0120b75ff2b..d95b988be4afe 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -1128,7 +1128,6 @@ static int ip6mr_cache_report(const struct mr_table *mrt, struct sk_buff *pkt,
msg->im6_src = ipv6_hdr(pkt)->saddr;
msg->im6_dst = ipv6_hdr(pkt)->daddr;
- skb_dst_set(skb, dst_clone(skb_dst(pkt)));
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
@@ -1138,6 +1137,7 @@ static int ip6mr_cache_report(const struct mr_table *mrt, struct sk_buff *pkt,
return -EINVAL;
}
+ skb_dst_drop(skb);
mrt6msg_netlink_event(mrt, skb);
/* Deliver to user space multicast routing algorithms */
@@ -1217,6 +1217,7 @@ static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi,
skb->dev = dev;
skb->skb_iif = dev->ifindex;
}
+ skb_dst_drop(skb);
skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb);
err = 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 613/869] ALSA: mtpav: shut down output timer before card teardown
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (611 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 612/869] ip6mr: do not clone dst in ip6mr_cache_report() Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 614/869] virtio_net: Fix resize of the RX ring Greg Kroah-Hartman
` (256 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Runyu Xiao, Takashi Iwai,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <runyu.xiao@seu.edu.cn>
[ Upstream commit c73cb5b7c159246dd572277c668851a56e516019 ]
snd_mtpav_output_timer() rearms chip->timer while holding
chip->spinlock and accesses the card-private mtpav state.
snd_mtpav_free() currently takes the same lock and calls
timer_delete() when the timer is active. This only removes a
pending timer; it does not wait for a callback that is already
running and does not prevent the callback from rearming the timer.
A callback running on another CPU can therefore continue after
snd_mtpav_free() releases the lock and access the card-private
state while the card is being torn down. It can also rearm the
timer after timer_delete() has returned.
Call timer_shutdown_sync() without holding chip->spinlock. This
waits for any running callback to finish and prevents further
rearming before the card-private mtpav state is released.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
Link: https://patch.msgid.link/20260820112749.9195-1-runyu.xiao@seu.edu.cn
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/drivers/mtpav.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index 946184a2a7589..dc67bb3d46397 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -657,12 +657,8 @@ static int snd_mtpav_get_RAWMIDI(struct mtpav *mcard)
static void snd_mtpav_free(struct snd_card *card)
{
struct mtpav *crd = card->private_data;
- unsigned long flags;
- spin_lock_irqsave(&crd->spinlock, flags);
- if (crd->istimer > 0)
- snd_mtpav_remove_output_timer(crd);
- spin_unlock_irqrestore(&crd->spinlock, flags);
+ timer_shutdown_sync(&crd->timer);
}
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 614/869] virtio_net: Fix resize of the RX ring
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (612 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 613/869] ALSA: mtpav: shut down output timer before card teardown Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 615/869] dpll: fix NULL deref in dpll_device_ops() during teardown race Greg Kroah-Hartman
` (255 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Anton Protopopov, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anton Protopopov <a.s.protopopov@gmail.com>
[ Upstream commit d09c98a6da215bce2173a292e4b95c8de6ea5d51 ]
When a AF_XDP socket is attached, the virtnet_rx_resize
should resize the rq->xsk_buffs XSK buffer array. Otherwise,
when the size grows, the virtnet_rx_resume() causes a write
past the end of the array. This is easily reproducable with
ethtool -G ens3 rx 32
./xdpsock -i eth0 -q 0 -r -z &
ethtool -G eth0 rx 256
Fixes: e9f3962441c0 ("virtio_net: xsk: rx: support fill with xsk buffer")
Signed-off-by: Anton Protopopov <a.s.protopopov@gmail.com>
Link: https://patch.msgid.link/20260810120728.47445-1-a.s.protopopov@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/virtio_net.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 851defa105e04..2c62371666cd5 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -3220,17 +3220,31 @@ static void virtnet_rx_resume(struct virtnet_info *vi, struct receive_queue *rq)
static int virtnet_rx_resize(struct virtnet_info *vi,
struct receive_queue *rq, u32 ring_num)
{
+ unsigned int old_ring_num = virtqueue_get_vring_size(rq->vq);
+ struct xdp_buff **tmp_xsk_buffs = NULL;
int err, qindex;
qindex = rq - vi->rq;
+ if (rq->xsk_pool && ring_num > old_ring_num) {
+ tmp_xsk_buffs = kvzalloc_objs(*tmp_xsk_buffs, ring_num);
+ if (!tmp_xsk_buffs)
+ return -ENOMEM;
+ }
+
virtnet_rx_pause(vi, rq);
err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf, NULL);
+
+ /* virtqueue_resize may have changed the size even if err != 0 */
+ if (tmp_xsk_buffs && virtqueue_get_vring_size(rq->vq) > old_ring_num)
+ swap(rq->xsk_buffs, tmp_xsk_buffs);
+
if (err)
netdev_err(vi->dev, "resize rx fail: rx queue index: %d err: %d\n", qindex, err);
virtnet_rx_resume(vi, rq);
+ kvfree(tmp_xsk_buffs);
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 615/869] dpll: fix NULL deref in dpll_device_ops() during teardown race
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (613 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 614/869] virtio_net: Fix resize of the RX ring Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 616/869] bpf, xdp: move offload check into dev_xdp_install() Greg Kroah-Hartman
` (254 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Petr Oros, Ivan Vecera,
Vadim Fedorenko, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <poros@redhat.com>
[ Upstream commit 33f016b23a219fe034213849b51436b8e79df251 ]
When the last owner of a dpll device unregisters while a foreign driver
still holds a pin on it via dpll_pin_on_pin_register(), the dpll object
stays alive with an empty registration list. A pin notification queued
before the unregister (e.g. ice reacting to zl3073x_i2c removal) then
walks pin->dpll_refs into dpll_device_ops(), which trips the WARN_ON and
dereferences the missing registration. dpll_lock cannot help because the
notification work was queued before the unregistering driver took the
lock.
Treat the empty registration list as a legitimate transient state. Make
dpll_priv() and dpll_device_ops() return NULL in that case and make
every pin netlink path that resolves a device from a pin skip such
dplls. dpll_cmd_pin_get_one() picks a ref with a live registration and
returns -ENODEV when there is none, the pin dumpit skips such a pin
instead of aborting the dump, dpll_msg_add_pin_dplls() and the
frequency, esync, reference sync and phase adjust set paths skip dead
refs, and dpll_pin_parent_device_set() validates the parent with
dpll_device_get_by_id(). dpll_pin_register() is the last caller that
dereferenced the device ops without a check, so move its frequency
monitor validation under dpll_lock and tolerate a missing registration
there as well.
The empty registration list is equivalent to a cleared DPLL_REGISTERED
mark, both transitions happen under dpll_lock in dpll_device_register()
and dpll_device_unregister(). A pin notification for a pin whose dplls
are all gone is now dropped with -ENODEV instead of crashing, all
callers in the core ignore that return value.
WARNING: drivers/dpll/dpll_core.c:1092 at dpll_device_ops+0x24/0x40,
CPU#83: kworker/u576:3/23471
Modules linked in: ... ice ... zl3073x_i2c(-) ... zl3073x ...
Workqueue: ice_dpll_wq ice_dpll_pin_notify_work [ice]
RIP: 0010:dpll_device_ops+0x24/0x40
Call Trace:
<TASK>
dpll_cmd_pin_get_one+0x336/0x520
dpll_pin_event_send+0x82/0x140
dpll_pin_on_pin_unregister+0xbb/0x160
ice_dpll_pin_notify_work+0x1bc/0x1f0 [ice]
process_one_work+0x19e/0x370
worker_thread+0x1a6/0x310
kthread+0xe4/0x120
ret_from_fork+0x1a1/0x270
ret_from_fork_asm+0x1a/0x30
</TASK>
---[ end trace 0000000000000000 ]---
BUG: kernel NULL pointer dereference, address: 0000000000000010
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
Fixes: 9431063ad323 ("dpll: core: Add DPLL framework base functions")
Signed-off-by: Petr Oros <poros@redhat.com>
Tested-by: Ivan Vecera <ivecera@redhat.com>
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Link: https://patch.msgid.link/20260813140817.1051388-1-poros@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/dpll/dpll_core.c | 12 +++----
drivers/dpll/dpll_netlink.c | 68 +++++++++++++++++++++++++++++++++++--
2 files changed, 71 insertions(+), 9 deletions(-)
diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c
index 6fa6a0d8e430d..0a8db4dc25786 100644
--- a/drivers/dpll/dpll_core.c
+++ b/drivers/dpll/dpll_core.c
@@ -1009,12 +1009,8 @@ EXPORT_SYMBOL_GPL(dpll_pin_ref_sync_pair_add);
static struct dpll_device_registration *
dpll_device_registration_first(struct dpll_device *dpll)
{
- struct dpll_device_registration *reg;
-
- reg = list_first_entry_or_null((struct list_head *)&dpll->registration_list,
- struct dpll_device_registration, list);
- WARN_ON(!reg);
- return reg;
+ return list_first_entry_or_null((struct list_head *)&dpll->registration_list,
+ struct dpll_device_registration, list);
}
void *dpll_priv(struct dpll_device *dpll)
@@ -1022,6 +1018,8 @@ void *dpll_priv(struct dpll_device *dpll)
struct dpll_device_registration *reg;
reg = dpll_device_registration_first(dpll);
+ if (!reg)
+ return NULL;
return reg->priv;
}
@@ -1030,6 +1028,8 @@ const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll)
struct dpll_device_registration *reg;
reg = dpll_device_registration_first(dpll);
+ if (!reg)
+ return NULL;
return reg->ops;
}
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index 270ea8f7248a4..3939f03620396 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -66,6 +66,22 @@ static bool dpll_pin_available(struct dpll_pin *pin)
return false;
}
+static bool dpll_device_registered(struct dpll_device *dpll)
+{
+ return dpll_device_ops(dpll);
+}
+
+static struct dpll_pin_ref *dpll_pin_first_registered_ref(struct dpll_pin *pin)
+{
+ struct dpll_pin_ref *ref;
+ unsigned long i;
+
+ xa_for_each(&pin->dpll_refs, i, ref)
+ if (dpll_device_registered(ref->dpll))
+ return ref;
+ return NULL;
+}
+
/**
* dpll_msg_add_pin_handle - attach pin handle attribute to a given message
* @msg: pointer to sk_buff message to attach a pin handle
@@ -534,6 +550,8 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
int ret;
xa_for_each(&pin->dpll_refs, index, ref) {
+ if (!dpll_device_registered(ref->dpll))
+ continue;
attr = nla_nest_start(msg, DPLL_A_PIN_PARENT_DEVICE);
if (!attr)
return -EMSGSIZE;
@@ -571,7 +589,10 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
int ret;
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
- ASSERT_NOT_NULL(ref);
+ if (!ref || !dpll_device_registered(ref->dpll))
+ ref = dpll_pin_first_registered_ref(pin);
+ if (!ref)
+ return -ENODEV;
ret = dpll_msg_add_pin_handle(msg, pin);
if (ret)
@@ -817,6 +838,8 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
}
xa_for_each(&pin->dpll_refs, i, ref) {
+ if (!dpll_device_registered(ref->dpll))
+ continue;
ops = dpll_pin_ops(ref);
if (!ops->frequency_set || !ops->frequency_get) {
NL_SET_ERR_MSG(extack, "frequency set not supported by the device");
@@ -824,6 +847,10 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
}
}
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
+ if (!ref || !dpll_device_registered(ref->dpll)) {
+ NL_SET_ERR_MSG(extack, "pin owner dpll not found");
+ return -ENODEV;
+ }
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
@@ -836,6 +863,8 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
return 0;
xa_for_each(&pin->dpll_refs, i, ref) {
+ if (!dpll_device_registered(ref->dpll))
+ continue;
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
@@ -855,6 +884,8 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
xa_for_each(&pin->dpll_refs, i, ref) {
if (ref == failed)
break;
+ if (!dpll_device_registered(ref->dpll))
+ continue;
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
if (ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
@@ -878,6 +909,8 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
int ret;
xa_for_each(&pin->dpll_refs, i, ref) {
+ if (!dpll_device_registered(ref->dpll))
+ continue;
ops = dpll_pin_ops(ref);
if (!ops->esync_set || !ops->esync_get) {
NL_SET_ERR_MSG(extack,
@@ -886,6 +919,10 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
}
}
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
+ if (!ref || !dpll_device_registered(ref->dpll)) {
+ NL_SET_ERR_MSG(extack, "pin owner dpll not found");
+ return -ENODEV;
+ }
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->esync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
@@ -908,6 +945,8 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
xa_for_each(&pin->dpll_refs, i, ref) {
void *pin_dpll_priv;
+ if (!dpll_device_registered(ref->dpll))
+ continue;
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
@@ -931,6 +970,8 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
if (ref == failed)
break;
+ if (!dpll_device_registered(ref->dpll))
+ continue;
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
@@ -966,7 +1007,10 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
return -EINVAL;
}
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
- ASSERT_NOT_NULL(ref);
+ if (!ref || !dpll_device_registered(ref->dpll)) {
+ NL_SET_ERR_MSG(extack, "pin owner dpll not found");
+ return -ENODEV;
+ }
ops = dpll_pin_ops(ref);
if (!ops->ref_sync_set || !ops->ref_sync_get) {
NL_SET_ERR_MSG(extack, "reference sync not supported by this pin");
@@ -984,6 +1028,8 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
if (state == old_state)
return 0;
xa_for_each(&pin->dpll_refs, i, ref) {
+ if (!dpll_device_registered(ref->dpll))
+ continue;
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
@@ -1006,6 +1052,8 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
xa_for_each(&pin->dpll_refs, i, ref) {
if (ref == failed)
break;
+ if (!dpll_device_registered(ref->dpll))
+ continue;
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
if (ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
@@ -1185,6 +1233,8 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
}
xa_for_each(&pin->dpll_refs, i, ref) {
+ if (!dpll_device_registered(ref->dpll))
+ continue;
ops = dpll_pin_ops(ref);
if (!ops->phase_adjust_set || !ops->phase_adjust_get) {
NL_SET_ERR_MSG(extack, "phase adjust not supported");
@@ -1192,6 +1242,10 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
}
}
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
+ if (!ref || !dpll_device_registered(ref->dpll)) {
+ NL_SET_ERR_MSG(extack, "pin owner dpll not found");
+ return -ENODEV;
+ }
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
@@ -1205,6 +1259,8 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
return 0;
xa_for_each(&pin->dpll_refs, i, ref) {
+ if (!dpll_device_registered(ref->dpll))
+ continue;
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->phase_adjust_set(pin,
@@ -1227,6 +1283,8 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
xa_for_each(&pin->dpll_refs, i, ref) {
if (ref == failed)
break;
+ if (!dpll_device_registered(ref->dpll))
+ continue;
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
if (ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
@@ -1256,7 +1314,7 @@ dpll_pin_parent_device_set(struct dpll_pin *pin, struct nlattr *parent_nest,
return -EINVAL;
}
pdpll_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]);
- dpll = xa_load(&dpll_device_xa, pdpll_idx);
+ dpll = dpll_device_get_by_id(pdpll_idx);
if (!dpll) {
NL_SET_ERR_MSG(extack, "parent device not found");
return -EINVAL;
@@ -1546,6 +1604,10 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
ret = dpll_cmd_pin_get_one(skb, pin, cb->extack);
if (ret) {
genlmsg_cancel(skb, hdr);
+ if (ret == -ENODEV) {
+ ret = 0;
+ continue;
+ }
break;
}
genlmsg_end(skb, hdr);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 616/869] bpf, xdp: move offload check into dev_xdp_install()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (614 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 615/869] dpll: fix NULL deref in dpll_device_ops() during teardown race Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 617/869] NFSv4/flexfiles: fix NULL dereference for NFSv4.0 data servers Greg Kroah-Hartman
` (253 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jiayuan Chen, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <jiayuan.chen@linux.dev>
[ Upstream commit ad27ed7d2309419a129078d781504f486b1b469a ]
bpf_xdp_link_update() calls dev_xdp_install() directly and skips
dev_xdp_attach(), so the checks in dev_xdp_attach() do not run. A user can
make an XDP link with a normal program and then swap in an offloaded or
device-bound program with BPF_LINK_UPDATE, which puts it on the software
path.
dev_xdp_install() is the one place all three paths go through:
"ip link set xdp" and BPF_LINK_CREATE reach it via dev_xdp_attach(), and
BPF_LINK_UPDATE calls it directly. So move the program checks (offloaded,
bound to another device, device-bound in generic mode, native vs generic,
DEVMAP and CPUMAP) there, and keep only the netlink-flag check
(XDP_FLAGS_UPDATE_IF_NOEXIST) in dev_xdp_attach().
Fixes: 026a4c28e1db3 ("bpf, xdp: Implement LINK_UPDATE for BPF XDP link")
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/core/dev.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/net/core/dev.c b/net/core/dev.c
index 9888affc68df3..8f507292f8ba4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -9627,6 +9627,37 @@ static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode,
return -EBUSY;
}
+ if (prog) {
+ enum bpf_xdp_mode other_mode = mode == XDP_MODE_SKB
+ ? XDP_MODE_DRV : XDP_MODE_SKB;
+ bool offload = mode == XDP_MODE_HW;
+
+ if (!offload && dev_xdp_prog(dev, other_mode)) {
+ NL_SET_ERR_MSG(extack, "Native and generic XDP can't be active at the same time");
+ return -EEXIST;
+ }
+ if (!offload && bpf_prog_is_offloaded(prog->aux)) {
+ NL_SET_ERR_MSG(extack, "Using offloaded program without HW_MODE flag is not supported");
+ return -EINVAL;
+ }
+ if (bpf_prog_is_dev_bound(prog->aux) && !bpf_offload_dev_match(prog, dev)) {
+ NL_SET_ERR_MSG(extack, "Program bound to different device");
+ return -EINVAL;
+ }
+ if (bpf_prog_is_dev_bound(prog->aux) && mode == XDP_MODE_SKB) {
+ NL_SET_ERR_MSG(extack, "Can't attach device-bound programs in generic mode");
+ return -EINVAL;
+ }
+ if (prog->expected_attach_type == BPF_XDP_DEVMAP) {
+ NL_SET_ERR_MSG(extack, "BPF_XDP_DEVMAP programs can not be attached to a device");
+ return -EINVAL;
+ }
+ if (prog->expected_attach_type == BPF_XDP_CPUMAP) {
+ NL_SET_ERR_MSG(extack, "BPF_XDP_CPUMAP programs can not be attached to a device");
+ return -EINVAL;
+ }
+ }
+
memset(&xdp, 0, sizeof(xdp));
xdp.command = mode == XDP_MODE_HW ? XDP_SETUP_PROG_HW : XDP_SETUP_PROG;
xdp.extack = extack;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 617/869] NFSv4/flexfiles: fix NULL dereference for NFSv4.0 data servers
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (615 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 616/869] bpf, xdp: move offload check into dev_xdp_install() Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 618/869] ksmbd: scope session state changes to bound connections Greg Kroah-Hartman
` (252 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jeuk Kim, Trond Myklebust,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeuk Kim <jeuk20.kim@gmail.com>
[ Upstream commit 2b03ebbf8d5e8f6af4ecd6c65375232dd1ec32cc ]
flexfiles accepts NFSv4.0 data servers, but two NFSv4 code paths assume
the data server client has a session. Unlike NFSv4.1+, an NFSv4.0 client
has no session (clp->cl_session is NULL; it uses clp->cl_slot_tbl), so
I/O to a v4.0 flexfiles DS oopses:
- nfs4_init_ds_session() dereferences clp->cl_session->session_state
while seeding the DS lease. It also only seeds cl_lease_time when
NFS4_SESSION_INITING is set; without a session that never happens, so
cl_lease_time stays 0 and nfs4_renew_state() busy-loops, requeuing
every 5 seconds. Seed the lease whenever there is no session and
return before touching session state.
- ff_layout_async_handle_error_v4() dereferences
clp->cl_session->fc_slot_table on every DS I/O error. Fall back to the
v4.0 transport slot table (clp->cl_slot_tbl) when there is no session.
Fixes: a7878ca14008 ("nfs: flexfilelayout: remove v3-only data server limitation")
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfs/flexfilelayout/flexfilelayout.c | 3 ++-
fs/nfs/nfs4session.c | 16 +++++++++++-----
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
index 7de5575f4bee2..61705e7f0be7a 100644
--- a/fs/nfs/flexfilelayout/flexfilelayout.c
+++ b/fs/nfs/flexfilelayout/flexfilelayout.c
@@ -1154,7 +1154,8 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
struct pnfs_layout_hdr *lo = lseg->pls_layout;
struct inode *inode = lo->plh_inode;
struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx);
- struct nfs4_slot_table *tbl = &clp->cl_session->fc_slot_table;
+ struct nfs4_slot_table *tbl = nfs4_has_session(clp) ?
+ &clp->cl_session->fc_slot_table : clp->cl_slot_tbl;
switch (op_status) {
case NFS4_OK:
diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c
index 5db460476bf2a..c59e710eb7ccc 100644
--- a/fs/nfs/nfs4session.c
+++ b/fs/nfs/nfs4session.c
@@ -634,16 +634,22 @@ int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time)
int ret;
spin_lock(&clp->cl_lock);
- if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
- /*
- * Do not set NFS_CS_CHECK_LEASE_TIME instead set the
- * DS lease to be equal to the MDS lease.
- */
+ /*
+ * Do not set NFS_CS_CHECK_LEASE_TIME instead set the
+ * DS lease to be equal to the MDS lease.
+ *
+ * A v4.0 DS has no session, so seed the lease every time.
+ */
+ if (!session ||
+ test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
clp->cl_lease_time = lease_time;
clp->cl_last_renewal = jiffies;
}
spin_unlock(&clp->cl_lock);
+ if (!session)
+ return 0;
+
ret = nfs41_check_session_ready(clp);
if (ret)
return ret;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 618/869] ksmbd: scope session state changes to bound connections
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (616 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 617/869] NFSv4/flexfiles: fix NULL dereference for NFSv4.0 data servers Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 619/869] ksmbd: detach blocked lock requests before freeing Greg Kroah-Hartman
` (251 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Namjae Jeon, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit c50e628122aed077695669e25b842e778511a43d ]
ksmbd_all_conn_set_status() treats every connection whose transient
binding flag is set as belonging to the target SessionId. A logoff or
session replacement can consequently move an unrelated connection to
NEED_RECONNECT or NEED_SETUP.
Pass the target session itself and select connections using either the
connection-local session xarray or the session's permanent channel list.
Use the same association test while waiting for requests to drain.
Serialize session-wide status changes under request_lock and do not
overwrite EXITING or RELEASING. Protect the shutdown transition with the
same lock so a concurrent session update cannot revive a closing
connection.
Fixes: f5a544e3bab7 ("ksmbd: add support for SMB3 multichannel")
Fixes: abcc506a9a71 ("ksmbd: fix racy issue from smb2 close and logoff with multichannel")
Fixes: c444139cb747 ("ksmbd: rewrite stop_sessions() with restartable iteration")
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/connection.c | 37 ++++++++++++++++++++++++++-----
fs/smb/server/connection.h | 7 ++++--
fs/smb/server/mgmt/user_session.c | 8 +++----
fs/smb/server/smb2pdu.c | 6 ++---
4 files changed, 42 insertions(+), 16 deletions(-)
diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
index c5f9705825b87..898e1832ce05a 100644
--- a/fs/smb/server/connection.c
+++ b/fs/smb/server/connection.c
@@ -242,15 +242,37 @@ void ksmbd_conn_unlock(struct ksmbd_conn *conn)
mutex_unlock(&conn->srv_mutex);
}
-void ksmbd_all_conn_set_status(u64 sess_id, u32 status)
+static bool ksmbd_session_is_bound_to_conn(struct ksmbd_session *sess,
+ struct ksmbd_conn *conn)
+{
+ bool found;
+
+ rcu_read_lock();
+ found = xa_load(&conn->sessions, sess->id) == sess;
+ rcu_read_unlock();
+ if (found)
+ return true;
+
+ down_read(&sess->chann_lock);
+ found = xa_load(&sess->ksmbd_chann_list, (long)conn);
+ up_read(&sess->chann_lock);
+ return found;
+}
+
+void ksmbd_all_conn_set_status(struct ksmbd_session *sess, u32 status)
{
struct ksmbd_conn *conn;
int bkt;
down_read(&conn_list_lock);
hash_for_each(conn_list, bkt, conn, hlist) {
- if (conn->binding || xa_load(&conn->sessions, sess_id))
- WRITE_ONCE(conn->status, status);
+ if (ksmbd_session_is_bound_to_conn(sess, conn)) {
+ spin_lock(&conn->request_lock);
+ if (!ksmbd_conn_exiting(conn) &&
+ !ksmbd_conn_releasing(conn))
+ WRITE_ONCE(conn->status, status);
+ spin_unlock(&conn->request_lock);
+ }
}
up_read(&conn_list_lock);
}
@@ -276,7 +298,8 @@ void ksmbd_conn_wait_idle(struct ksmbd_conn *conn)
wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2);
}
-int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id)
+int ksmbd_conn_wait_idle_sess(struct ksmbd_conn *curr_conn,
+ struct ksmbd_session *sess)
{
struct ksmbd_conn *conn;
int rc, retry_count = 0, max_timeout = 120;
@@ -288,7 +311,7 @@ int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id)
down_read(&conn_list_lock);
hash_for_each(conn_list, bkt, conn, hlist) {
- if (conn->binding || xa_load(&conn->sessions, sess_id)) {
+ if (ksmbd_session_is_bound_to_conn(sess, conn)) {
rcount = (conn == curr_conn) ? 2 : 1;
if (atomic_read(&conn->req_running) >= rcount) {
rc = wait_event_timeout(conn->req_running_q,
@@ -609,8 +632,10 @@ static void stop_sessions(void)
* handler exited its receive loop for an unrelated
* reason).
*/
- if (READ_ONCE(conn->status) != KSMBD_SESS_RELEASING)
+ spin_lock(&conn->request_lock);
+ if (!ksmbd_conn_releasing(conn))
ksmbd_conn_set_exiting(conn);
+ spin_unlock(&conn->request_lock);
target = conn;
break;
}
diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h
index 96ef441330512..1ddc53d3a8ab1 100644
--- a/fs/smb/server/connection.h
+++ b/fs/smb/server/connection.h
@@ -20,6 +20,8 @@
#include "smb_common.h"
#include "ksmbd_work.h"
+struct ksmbd_session;
+
#define KSMBD_SOCKET_BACKLOG 16
enum {
@@ -161,7 +163,8 @@ extern struct rw_semaphore conn_list_lock;
bool ksmbd_conn_alive(struct ksmbd_conn *conn);
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn);
-int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id);
+int ksmbd_conn_wait_idle_sess(struct ksmbd_conn *curr_conn,
+ struct ksmbd_session *sess);
struct ksmbd_conn *ksmbd_conn_alloc(void);
void ksmbd_conn_free(struct ksmbd_conn *conn);
struct ksmbd_conn *ksmbd_conn_get(struct ksmbd_conn *conn);
@@ -266,5 +269,5 @@ static inline void ksmbd_conn_set_releasing(struct ksmbd_conn *conn)
WRITE_ONCE(conn->status, KSMBD_SESS_RELEASING);
}
-void ksmbd_all_conn_set_status(u64 sess_id, u32 status);
+void ksmbd_all_conn_set_status(struct ksmbd_session *sess, u32 status);
#endif /* __CONNECTION_H__ */
diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
index 2b605664ea3d8..0c65a862f8589 100644
--- a/fs/smb/server/mgmt/user_session.c
+++ b/fs/smb/server/mgmt/user_session.c
@@ -413,16 +413,16 @@ void destroy_previous_session(struct ksmbd_conn *conn,
memcmp(user->passkey, prev_user->passkey, user->passkey_sz))
goto out;
- ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_RECONNECT);
- err = ksmbd_conn_wait_idle_sess_id(conn, id);
+ ksmbd_all_conn_set_status(prev_sess, KSMBD_SESS_NEED_RECONNECT);
+ err = ksmbd_conn_wait_idle_sess(conn, prev_sess);
if (err) {
- ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP);
+ ksmbd_all_conn_set_status(prev_sess, KSMBD_SESS_NEED_SETUP);
goto out;
}
ksmbd_destroy_file_table(prev_sess);
prev_sess->state = SMB2_SESSION_EXPIRED;
- ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP);
+ ksmbd_all_conn_set_status(prev_sess, KSMBD_SESS_NEED_SETUP);
ksmbd_launch_ksmbd_durable_scavenger();
out:
up_write(&conn->session_lock);
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 892fcc06c1ab0..0785f921aec06 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2264,7 +2264,6 @@ int smb2_session_logoff(struct ksmbd_work *work)
struct ksmbd_session *sess = work->sess;
struct smb2_logoff_req *req;
struct smb2_logoff_rsp *rsp;
- u64 sess_id;
int err;
WORK_BUFFERS(work, req, rsp);
@@ -2278,8 +2277,7 @@ int smb2_session_logoff(struct ksmbd_work *work)
smb2_set_err_rsp(work);
return -ENOENT;
}
- sess_id = le64_to_cpu(req->hdr.SessionId);
- ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT);
+ ksmbd_all_conn_set_status(sess, KSMBD_SESS_NEED_RECONNECT);
ksmbd_conn_unlock(conn);
ksmbd_close_session_fds(work);
@@ -2296,7 +2294,7 @@ int smb2_session_logoff(struct ksmbd_work *work)
sess->state = SMB2_SESSION_EXPIRED;
up_write(&conn->session_lock);
- ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_SETUP);
+ ksmbd_all_conn_set_status(sess, KSMBD_SESS_NEED_SETUP);
rsp->StructureSize = cpu_to_le16(4);
err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp));
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 619/869] ksmbd: detach blocked lock requests before freeing
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (617 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 618/869] ksmbd: scope session state changes to bound connections Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 620/869] ksmbd: safely discard unregistered deferred locks Greg Kroah-Hartman
` (250 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kyenghwan Hwang, ChenXiaoSong,
Namjae Jeon, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 215e8816b1ac25176d911abb8704390413ccee4b ]
A file_lock retained by ksmbd for byte-range lock bookkeeping can still
be part of the VFS blocked-request graph. In particular, the VFS can
chain a new waiter below an already blocked request through
flc_blocked_requests. The ksmbd_file reference count does not cover that
graph.
Both __ksmbd_close_fd() and the cross-request unlock path free these
retained file_lock objects directly. If a dependent waiter is still
attached, locks_release_private() hits
BUG_ON(!list_empty(&flc->flc_blocked_requests)). The same lifetime
mismatch can leave a freed ksmbd_lock reachable through its request-local
llist.
Detach the file_lock from the blocked-request graph before freeing it in
the close, cross-request unlock, and rollback paths. locks_delete_block()
also wakes requests chained below the object. Remove llist when a
completed lock is published so a globally visible ksmbd_lock no longer
points into the submitting worker's stack.
Fixes: d63528eb0d43 ("ksmbd: free ksmbd_lock when file is closed")
Reported-by: Kyenghwan Hwang <obnred@gmail.com>
Tested-by: Kyenghwan Hwang <obnred@gmail.com>
Tested-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/smb2pdu.c | 14 ++++++++++----
fs/smb/server/vfs_cache.c | 8 +++++---
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 0785f921aec06..b2d4c30571d6c 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -7524,6 +7524,12 @@ static void smb2_remove_blocked_lock(void **argv)
locks_wake_up(flock);
}
+static void smb2_free_lock(struct file_lock *flock)
+{
+ ksmbd_vfs_posix_lock_unblock(flock);
+ locks_free_lock(flock);
+}
+
static inline bool lock_defer_pending(struct file_lock *fl)
{
/* check pending lock waiters */
@@ -7677,14 +7683,14 @@ int smb2_lock(struct ksmbd_work *work)
cmp_lock->end == smb_lock->end &&
!lock_defer_pending(cmp_lock->fl)) {
nolock = 0;
- list_del(&cmp_lock->flist);
- list_del(&cmp_lock->clist);
+ list_del_init(&cmp_lock->flist);
+ list_del_init(&cmp_lock->clist);
cmp_lock->conn = NULL;
spin_unlock(&conn->llist_lock);
up_read(&conn_list_lock);
ksmbd_conn_put(conn);
- locks_free_lock(cmp_lock->fl);
+ smb2_free_lock(cmp_lock->fl);
kfree(cmp_lock);
goto out_check_cl;
}
@@ -7882,7 +7888,7 @@ int smb2_lock(struct ksmbd_work *work)
spin_unlock(&conn->llist_lock);
ksmbd_conn_put(conn);
- locks_free_lock(smb_lock->fl);
+ smb2_free_lock(smb_lock->fl);
if (rlock)
locks_free_lock(rlock);
kfree(smb_lock);
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
index ce6e9886df8be..970b8f185aacd 100644
--- a/fs/smb/server/vfs_cache.c
+++ b/fs/smb/server/vfs_cache.c
@@ -388,8 +388,9 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
if (!IS_ERR_OR_NULL(filp))
fput(filp);
- /* because the reference count of fp is 0, it is guaranteed that
- * there are not accesses to fp->lock_list.
+ /*
+ * The zero fp reference count serializes access to fp->lock_list, but
+ * the VFS may still have blocked requests chained below these locks.
*/
list_for_each_entry_safe(smb_lock, tmp_lock, &fp->lock_list, flist) {
struct ksmbd_conn *conn = smb_lock->conn;
@@ -402,7 +403,8 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
ksmbd_conn_put(conn);
}
- list_del(&smb_lock->flist);
+ list_del_init(&smb_lock->flist);
+ ksmbd_vfs_posix_lock_unblock(smb_lock->fl);
locks_free_lock(smb_lock->fl);
kfree(smb_lock);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 620/869] ksmbd: safely discard unregistered deferred locks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (618 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 619/869] ksmbd: detach blocked lock requests before freeing Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 621/869] erofs: fix interlaced ztailpacking pclusters Greg Kroah-Hartman
` (249 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Namjae Jeon, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 054bcca4cd9f00719b01f7108b51a2168fb94f15 ]
When vfs_lock_file() defers a lock, smb2_lock() puts its ksmbd_lock on
rollback_list before allocating and registering the asynchronous work.
If either operation fails, rollback assumes that smb_lock->conn is
initialized and dereferences NULL. The deferred file_lock also remains
linked into the VFS blocked-lock state while it is freed.
Keep the lock off rollback_list until async setup succeeds. On setup
failures, explicitly unblock and wake the deferred lock before freeing it
and its ksmbd wrapper.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/smb2pdu.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index b2d4c30571d6c..951d3c4f861c4 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -7772,11 +7772,12 @@ int smb2_lock(struct ksmbd_work *work)
ksmbd_debug(SMB,
"would have to wait for getting lock\n");
- list_add(&smb_lock->llist, &rollback_list);
argv = kmalloc(sizeof(void *), KSMBD_DEFAULT_GFP);
if (!argv) {
err = -ENOMEM;
+ smb2_free_lock(flock);
+ kfree(smb_lock);
goto out;
}
argv[0] = flock;
@@ -7787,8 +7788,11 @@ int smb2_lock(struct ksmbd_work *work)
if (rc) {
kfree(argv);
err = -ENOMEM;
+ smb2_free_lock(flock);
+ kfree(smb_lock);
goto out;
}
+ list_add(&smb_lock->llist, &rollback_list);
spin_lock(&fp->f_lock);
list_add(&work->fp_entry, &fp->blocked_works);
spin_unlock(&fp->f_lock);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 621/869] erofs: fix interlaced ztailpacking pclusters
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (619 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 620/869] ksmbd: safely discard unregistered deferred locks Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 622/869] ksmbd: defer publishing granted locks to prevent UAF/double-free race Greg Kroah-Hartman
` (248 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Haiyang Huang, Chao Yu, Gao Xiang,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gao Xiang <xiang@kernel.org>
[ Upstream commit 862427ebb81d1f6abbf74d799790e1694b37b187 ]
On-disk sizes of interlaced pclusters should be block-aligned, and
ztailpacking interlaced pclusters should be invalid at all.
Currently, mkfs.erofs won't generate any interlaced pcluster with
ztailpacking enabled, so this doesn't affect any existing valid
filesystems.
However, crafted images can contain invalid interlaced ztailpacking
pclusters, resulting in an out-of-bounds read from a kmap'd page and
copying irrelevant kernel memory into userspace-visible page cache.
Reported-by: Haiyang Huang <huanghaiyang83@gmail.com>
Closes: https://lore.kernel.org/r/20260806065253.1083865-1-huanghaiyang83@gmail.com
Fixes: fdffc091e6f9 ("erofs: support interlaced uncompressed data for compressed files")
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Gao Xiang <xiang@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/erofs/decompressor.c | 1 +
fs/erofs/zmap.c | 8 +++++---
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
index 39695addce076..d965a3f3073b7 100644
--- a/fs/erofs/decompressor.c
+++ b/fs/erofs/decompressor.c
@@ -312,6 +312,7 @@ static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
return -EOPNOTSUPP;
if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) {
cur = bs - (rq->pageofs_out & (bs - 1));
+ DBG_BUGON(rq->pageofs_in & (bs - 1));
pi = (rq->pageofs_in + rq->inputsize - cur) & ~PAGE_MASK;
cur = min(cur, rq->outputsize);
if (cur && rq->out[0]) {
diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
index af1046908c626..eb14dda612a9e 100644
--- a/fs/erofs/zmap.c
+++ b/fs/erofs/zmap.c
@@ -477,9 +477,11 @@ static int z_erofs_do_map_blocks(struct inode *inode,
err = -EFSCORRUPTED;
goto unmap_out;
}
- afmt = vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER ?
- Z_EROFS_COMPRESSION_INTERLACED :
- Z_EROFS_COMPRESSION_SHIFTED;
+ if ((vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER) &&
+ !(map->m_flags & EROFS_MAP_META))
+ afmt = Z_EROFS_COMPRESSION_INTERLACED;
+ else
+ afmt = Z_EROFS_COMPRESSION_SHIFTED;
} else {
afmt = m.headtype == Z_EROFS_LCLUSTER_TYPE_HEAD2 ?
vi->z_algorithmtype[1] : vi->z_algorithmtype[0];
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 622/869] ksmbd: defer publishing granted locks to prevent UAF/double-free race
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (620 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 621/869] erofs: fix interlaced ztailpacking pclusters Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 623/869] ksmbd: serialize oplock close with pending break ownership Greg Kroah-Hartman
` (247 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Ilan Dudnik, Namjae Jeon,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilan Dudnik <ilan.dudnik@safebreach.com>
[ Upstream commit 29f74f0f2e6df3b393b7b66e810136d0c64e3c59 ]
In smb2_lock(), mid-batch granted locks are published to connection-wide
(conn->lock_list) and file-wide (fp->lock_list) lists immediately upon
vfs_lock_file() success, while also remaining tracked on the stack-local
rollback_list.
If a subsequent element in the same SMB2_LOCK request array fails
validation or execution, the thread jumps to out: and walks
rollback_list to undo previously granted locks. However, because the
granted lock was already published to conn->lock_list, a concurrent
UNLOCK request on the same connection can find the lock object and
kfree() it before the rollback loop executes.
When the granting thread subsequently walks rollback_list, it
dereferences and frees the already-freed ksmbd_lock structure, resulting
in a Use-After-Free and Double-Free (on both ksmbd_lock and struct
file_lock).
Fix this by deferring the publication of granted locks to
conn->lock_list and fp->lock_list until after the entire array of lock
elements has been processed without error. Mid-batch grants remain
tracked exclusively on the request-local rollback_list until the whole
batch succeeds, eliminating the race window.
Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Signed-off-by: Ilan Dudnik <ilan.dudnik@safebreach.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/smb2pdu.c | 32 +++++++++++++++-----------------
1 file changed, 15 insertions(+), 17 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 951d3c4f861c4..e46b58a768c5d 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -7825,16 +7825,10 @@ int smb2_lock(struct ksmbd_work *work)
rsp->hdr.Status =
STATUS_RANGE_NOT_LOCKED;
kfree(smb_lock);
- goto out2;
+ /* rollback_list may still hold earlier grants */
+ goto out;
} else if (!rc) {
list_add(&smb_lock->llist, &rollback_list);
- smb_lock->conn = ksmbd_conn_get(work->conn);
- spin_lock(&work->conn->llist_lock);
- list_add_tail(&smb_lock->clist,
- &work->conn->lock_list);
- list_add_tail(&smb_lock->flist,
- &fp->lock_list);
- spin_unlock(&work->conn->llist_lock);
ksmbd_debug(SMB, "successful in taking lock\n");
} else {
locks_free_lock(flock);
@@ -7856,6 +7850,19 @@ int smb2_lock(struct ksmbd_work *work)
if (err)
goto out;
+ /* publish only once the whole batch has committed */
+ if (!list_empty(&rollback_list)) {
+ spin_lock(&work->conn->llist_lock);
+ list_for_each_entry(smb_lock, &rollback_list, llist) {
+ smb_lock->conn = ksmbd_conn_get(work->conn);
+ list_add_tail(&smb_lock->clist,
+ &work->conn->lock_list);
+ list_add_tail(&smb_lock->flist,
+ &fp->lock_list);
+ }
+ spin_unlock(&work->conn->llist_lock);
+ }
+
ksmbd_fd_put(work, fp);
return 0;
@@ -7883,15 +7890,6 @@ int smb2_lock(struct ksmbd_work *work)
}
list_del(&smb_lock->llist);
- conn = smb_lock->conn;
- spin_lock(&conn->llist_lock);
- if (!list_empty(&smb_lock->flist))
- list_del(&smb_lock->flist);
- list_del(&smb_lock->clist);
- smb_lock->conn = NULL;
- spin_unlock(&conn->llist_lock);
- ksmbd_conn_put(conn);
-
smb2_free_lock(smb_lock->fl);
if (rlock)
locks_free_lock(rlock);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 623/869] ksmbd: serialize oplock close with pending break ownership
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (621 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 622/869] ksmbd: defer publishing granted locks to prevent UAF/double-free race Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 624/869] ksmbd: fix slab-out-of-bounds read in ksmbd_alloc_user() Greg Kroah-Hartman
` (246 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Yunseong Kim, Namjae Jeon,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit b0148dc5625dbfd50596ac63c7487c12e8a8ab03 ]
close may abort an in-flight oplock break while another breaker already
holds an opinfo reference. Releasing pending_break wakes that waiter, but
without serializing the close transition with bit acquisition it can become
a new break owner through the test_and_set_bit() fast path. It can then
overwrite OPLOCK_CLOSING with OPLOCK_ACK_WAIT and continue a break for
a dying opinfo.
Make OPLOCK_CLOSING terminal once the opinfo is removed from the inode
list. Serialize that transition, pending_break acquisition, and
OPLOCK_ACK_WAIT setup with an opinfo state lock. A breaker which loses
the race releases its ownership and returns -ENOENT. Explicitly wake
pending_break waiters during close so they can observe the terminal state.
Also prevent ACK and timeout paths from replacing OPLOCK_CLOSING with
OPLOCK_STATE_NONE.
Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Co-developed-by: Yunseong Kim <yunseong.kim@est.tech>
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/oplock.c | 81 ++++++++++++++++++++++++++++++++++-------
fs/smb/server/oplock.h | 1 +
fs/smb/server/smb2pdu.c | 12 ++++--
3 files changed, 77 insertions(+), 17 deletions(-)
diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
index 6183bd52ca9d1..08e3e4504b03f 100644
--- a/fs/smb/server/oplock.c
+++ b/fs/smb/server/oplock.c
@@ -56,6 +56,7 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
opinfo->conn = ksmbd_conn_get(work->conn);
opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
opinfo->op_state = OPLOCK_STATE_NONE;
+ spin_lock_init(&opinfo->state_lock);
opinfo->pending_break = 0;
opinfo->fid = id;
opinfo->Tid = Tid;
@@ -424,14 +425,23 @@ void close_id_del_oplock(struct ksmbd_file *fp)
opinfo_del(opinfo);
rcu_assign_pointer(fp->f_opinfo, NULL);
- if (opinfo->op_state == OPLOCK_ACK_WAIT) {
- opinfo->op_state = OPLOCK_CLOSING;
- wake_up_interruptible_all(&opinfo->oplock_q);
- if (opinfo->is_lease) {
- atomic_set(&opinfo->breaking_cnt, 0);
- wake_up_interruptible_all(&opinfo->oplock_brk);
- }
- }
+ spin_lock(&opinfo->state_lock);
+ if (opinfo->op_state == OPLOCK_ACK_WAIT && opinfo->is_lease)
+ atomic_set(&opinfo->breaking_cnt, 0);
+ /*
+ * An opinfo that has been removed from the inode list is terminal. Keep
+ * this transition and releasing pending_break under state_lock. a breaker
+ * takes the same lock before it acquires pending_break or sets ACK_WAIT.
+ */
+ opinfo->op_state = OPLOCK_CLOSING;
+ clear_bit_unlock(0, &opinfo->pending_break);
+ spin_unlock(&opinfo->state_lock);
+ wake_up_interruptible_all(&opinfo->oplock_q);
+ if (opinfo->is_lease)
+ wake_up_interruptible_all(&opinfo->oplock_brk);
+ /* memory barrier is needed for wake_up_bit() */
+ smp_mb__after_atomic();
+ wake_up_bit(&opinfo->pending_break, 0);
opinfo_count_dec(fp);
atomic_dec(&opinfo->refcount);
@@ -610,10 +620,16 @@ static void wait_for_break_ack(struct oplock_info *opinfo)
/* is this a timeout ? */
if (!rc) {
+ spin_lock(&opinfo->state_lock);
+ if (opinfo->op_state == OPLOCK_CLOSING) {
+ spin_unlock(&opinfo->state_lock);
+ return;
+ }
if (opinfo->is_lease)
opinfo->o_lease->state = SMB2_LEASE_NONE_LE;
opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
opinfo->op_state = OPLOCK_STATE_NONE;
+ spin_unlock(&opinfo->state_lock);
}
}
@@ -625,17 +641,46 @@ static void wake_up_oplock_break(struct oplock_info *opinfo)
wake_up_bit(&opinfo->pending_break, 0);
}
+static bool oplock_break_set_ack_wait(struct oplock_info *opinfo)
+{
+ bool ret = false;
+
+ spin_lock(&opinfo->state_lock);
+ if (opinfo->op_state != OPLOCK_CLOSING) {
+ opinfo->op_state = OPLOCK_ACK_WAIT;
+ ret = true;
+ }
+ spin_unlock(&opinfo->state_lock);
+
+ return ret;
+}
+
static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level)
{
- while (test_and_set_bit(0, &opinfo->pending_break)) {
+ for (;;) {
+ bool closing;
+
+ spin_lock(&opinfo->state_lock);
+ closing = opinfo->op_state == OPLOCK_CLOSING;
+ if (!closing && !test_and_set_bit(0, &opinfo->pending_break)) {
+ spin_unlock(&opinfo->state_lock);
+ break;
+ }
+ spin_unlock(&opinfo->state_lock);
+ if (closing)
+ return -ENOENT;
+
wait_on_bit(&opinfo->pending_break, 0, TASK_UNINTERRUPTIBLE);
/* Not immediately break to none. */
opinfo->open_trunc = 0;
- if (opinfo->op_state == OPLOCK_CLOSING)
+ spin_lock(&opinfo->state_lock);
+ closing = opinfo->op_state == OPLOCK_CLOSING;
+ spin_unlock(&opinfo->state_lock);
+ if (closing)
return -ENOENT;
- else if (opinfo->level <= req_op_level) {
+ if (opinfo->level <= req_op_level) {
if (opinfo->is_lease == false)
return 1;
@@ -1005,7 +1050,11 @@ static int oplock_break(struct oplock_info *brk_opinfo, struct ksmbd_inode *ci,
release_async_work(in_work);
}
- brk_opinfo->op_state = OPLOCK_ACK_WAIT;
+ if (!oplock_break_set_ack_wait(brk_opinfo)) {
+ atomic_dec_if_positive(&brk_opinfo->breaking_cnt);
+ wake_up_oplock_break(brk_opinfo);
+ return -ENOENT;
+ }
} else
atomic_dec(&brk_opinfo->breaking_cnt);
} else {
@@ -1014,8 +1063,12 @@ static int oplock_break(struct oplock_info *brk_opinfo, struct ksmbd_inode *ci,
return err < 0 ? err : 0;
if (brk_opinfo->level == SMB2_OPLOCK_LEVEL_BATCH ||
- brk_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE)
- brk_opinfo->op_state = OPLOCK_ACK_WAIT;
+ brk_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+ if (!oplock_break_set_ack_wait(brk_opinfo)) {
+ wake_up_oplock_break(brk_opinfo);
+ return -ENOENT;
+ }
+ }
}
if (brk_opinfo->is_lease)
diff --git a/fs/smb/server/oplock.h b/fs/smb/server/oplock.h
index 795a9119dad9a..6e8680c06db97 100644
--- a/fs/smb/server/oplock.h
+++ b/fs/smb/server/oplock.h
@@ -59,6 +59,7 @@ struct oplock_info {
struct ksmbd_file *o_fp;
int level;
int op_state;
+ spinlock_t state_lock;
unsigned long pending_break;
u64 fid;
atomic_t breaking_cnt;
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index e46b58a768c5d..6212e615aa0a1 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -8827,7 +8827,10 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
smb2_set_err_rsp(work);
out:
- opinfo->op_state = OPLOCK_STATE_NONE;
+ spin_lock(&opinfo->state_lock);
+ if (opinfo->op_state != OPLOCK_CLOSING)
+ opinfo->op_state = OPLOCK_STATE_NONE;
+ spin_unlock(&opinfo->state_lock);
wake_up_interruptible_all(&opinfo->oplock_q);
opinfo_put(opinfo);
ksmbd_fd_put(work, fp);
@@ -8913,9 +8916,12 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
if (ret)
goto err_out;
- opinfo->op_state = OPLOCK_STATE_NONE;
+ spin_lock(&opinfo->state_lock);
+ if (opinfo->op_state != OPLOCK_CLOSING)
+ opinfo->op_state = OPLOCK_STATE_NONE;
+ spin_unlock(&opinfo->state_lock);
wake_up_interruptible_all(&opinfo->oplock_q);
- atomic_dec(&opinfo->breaking_cnt);
+ atomic_dec_if_positive(&opinfo->breaking_cnt);
wake_up_interruptible_all(&opinfo->oplock_brk);
opinfo_put(opinfo);
return;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 624/869] ksmbd: fix slab-out-of-bounds read in ksmbd_alloc_user()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (622 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 623/869] ksmbd: serialize oplock close with pending break ownership Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 625/869] bpf: Check pointer type for all atomic RMW paths Greg Kroah-Hartman
` (245 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Yunseong Kim, Namjae Jeon,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yunseong Kim <yunseong.kim@est.tech>
[ Upstream commit 7405d0ba294306721843bc551611775e6edef516 ]
ksmbd_alloc_user() copies resp->hash_sz bytes out of the mountd IPC
login response with
user->passkey_sz = resp->hash_sz;
user->passkey = kmalloc(resp->hash_sz, KSMBD_DEFAULT_GFP);
if (user->passkey)
memcpy(user->passkey, resp->hash, resp->hash_sz);
resp->hash_sz is a __u16 supplied by the response, but resp->hash[] is
only KSMBD_REQ_MAX_HASH_SZ bytes. A malformed or malicious login
response can set hash_sz well beyond that (up to 65535), so the memcpy()
reads past the end of the response object. ipc_validate_msg() does not
bound hash_sz, so reject any response whose hash_sz exceeds the on-stack
hash[] buffer before allocating and copying.
[ 2030.238706] BUG: KASAN: slab-out-of-bounds in ksmbd_alloc_user+0x278/0x680
[ 2030.240549] Read of size 65535 at addr ffff888121bb6680 by task kworker/4:1/18611
[ 2030.242296]
[ 2030.242710] CPU: 4 UID: 0 PID: 18611 Comm: kworker/4:1 Not tainted 7.1.0-next-20260623-virtme #96 PREEMPT(lazy)
[ 2030.242732] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
[ 2030.242743] Workqueue: ksmbd-io handle_ksmbd_work
[ 2030.242763] Call Trace:
[ 2030.242769] <TASK>
[ 2030.242776] dump_stack_lvl+0xa2/0xd0
[ 2030.242794] print_address_description+0x77/0x200
[ 2030.242815] ? ksmbd_alloc_user+0x278/0x680
[ 2030.242831] print_report+0x58/0x70
[ 2030.242848] kasan_report+0x117/0x150
[ 2030.242869] ? ksmbd_alloc_user+0x278/0x680
[ 2030.242888] kasan_check_range+0x3c7/0x3f0
[ 2030.242908] ? ksmbd_alloc_user+0x278/0x680
[ 2030.242925] __asan_memcpy+0x29/0x70
[ 2030.242942] ksmbd_alloc_user+0x278/0x680
[ 2030.242960] ksmbd_login_user+0xc3/0x120
[ 2030.242978] ntlm_authenticate+0x5e6/0x1b00
[ 2030.243017] ? __pfx_ntlm_authenticate+0x10/0x10
[ 2030.243035] ? ksmbd_session_lookup+0x188/0x1d0
[ 2030.243054] ? __pfx_ksmbd_session_lookup+0x10/0x10
[ 2030.243090] ? __sanitizer_cov_trace_switch+0x7b/0x140
[ 2030.243108] smb2_sess_setup+0x1e4a/0x27b0
[ 2030.243126] ? copy_from_kernel_nofault+0x199/0x300
[ 2030.243156] ? __pfx_smb2_sess_setup+0x10/0x10
[ 2030.243173] ? get_smb2_cmd_val+0xe3/0x1c0
[ 2030.243208] handle_ksmbd_work+0x954/0x1280
[ 2030.243230] ? __pfx_handle_ksmbd_work+0x10/0x10
[ 2030.243249] ? process_scheduled_works+0xa07/0x1490
[ 2030.243270] ? process_scheduled_works+0xa07/0x1490
[ 2030.243291] process_scheduled_works+0xa70/0x1490
[ 2030.243320] ? __pfx_process_scheduled_works+0x10/0x10
[ 2030.243340] ? do_raw_spin_lock+0x130/0x300
[ 2030.243358] ? lock_is_held_type+0x7b/0x110
[ 2030.243388] worker_thread+0x932/0xe20
[ 2030.243415] kthread+0x38a/0x470
[ 2030.243431] ? __pfx_worker_thread+0x10/0x10
[ 2030.243451] ? __pfx_kthread+0x10/0x10
[ 2030.243467] ret_from_fork+0x484/0x910
[ 2030.243485] ? __pfx_ret_from_fork+0x10/0x10
[ 2030.243501] ? __switch_to+0xc77/0x12c0
[ 2030.243523] ? __pfx_kthread+0x10/0x10
[ 2030.243540] ret_from_fork_asm+0x1a/0x30
[ 2030.243564] </TASK>
[ 2030.243570]
[ 2030.290164] Allocated by task 19279:
[ 2030.290911] kasan_save_track+0x3e/0x80
[ 2030.292179] __kasan_kmalloc+0x72/0x90
[ 2030.293217] __kvmalloc_node_noprof+0x3ff/0x6b0
[ 2030.294467] handle_generic_event+0x59b/0x750
[ 2030.295345] genl_family_rcv_msg_doit+0x238/0x340
[ 2030.296553] genl_rcv_msg+0x606/0x7b0
[ 2030.297129] netlink_rcv_skb+0x22b/0x4a0
[ 2030.298500] genl_rcv+0x2d/0x40
[ 2030.299273] netlink_unicast+0x7ba/0x930
[ 2030.300019] netlink_sendmsg+0x8c3/0xb00
[ 2030.301073] __sock_sendmsg+0xec/0x140
[ 2030.301579] __sys_sendto+0x357/0x470
[ 2030.302255] __x64_sys_sendto+0xe3/0x100
[ 2030.303425] do_syscall_64+0x135/0x460
[ 2030.304763] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 2030.305594]
[ 2030.305819] The buggy address belongs to the object at ffff888121bb6640
[ 2030.305819] which belongs to the cache kmalloc-192 of size 192
[ 2030.309595] The buggy address is located 64 bytes inside of
[ 2030.309595] allocated 166-byte region [ffff888121bb6640, ffff888121bb66e6)
[ 2030.312484]
[ 2030.312719] The buggy address belongs to the physical page:
[ 2030.314315] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x121bb6
[ 2030.316481] head: order:1 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
[ 2030.318248] flags: 0x100000000000040(head|node=0|zone=2)
[ 2030.319662] page_type: f5(slab)
[ 2030.320242] raw: 0100000000000040 ffff8881000424c0 ffffea00047c1510 ffff888100040468
[ 2030.321911] raw: 0000000000000000 0000000000150015 00000000f5000000 0000000000000000
[ 2030.324413] head: 0100000000000040 ffff8881000424c0 ffffea00047c1510 ffff888100040468
[ 2030.326150] head: 0000000000000000 0000000000150015 00000000f5000000 0000000000000000
[ 2030.327960] head: 0100000000000001 ffffffffffffff81 00000000ffffffff 00000000ffffffff
[ 2030.329615] head: ffff888121bb7ab0 0000000000000000 00000000ffffffff 0000000000000000
[ 2030.331861] page dumped because: kasan: bad access detected
[ 2030.332946]
[ 2030.333502] Memory state around the buggy address:
[ 2030.334698] ffff888121bb6580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 2030.336475] ffff888121bb6600: fc fc fc fc fc fc fc fc 00 00 00 00 00 00 00 00
[ 2030.338143] >ffff888121bb6680: 00 00 00 00 00 00 00 00 00 00 00 00 06 fc fc fc
[ 2030.339116] ^
[ 2030.341315] ffff888121bb6700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 2030.342801] ffff888121bb6780: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb
[ 2030.344643] ==================================================================
Found with ksmbdzzer [2], a KSMBD fuzzer that drives libFuzzer with a
kcov-dataflow [1] coverage vector: it folds each instrumented
comparison/argument's runtime operand value together with its PC (the
default arm mixes them as pc⊕val) so that a new operand value at a known
site counts as new coverage.
[1] https://lwn.net/Articles/1077606/
[2] https://github.com/yskzalloc/kcov-dataflow
Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/mgmt/user_config.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/fs/smb/server/mgmt/user_config.c b/fs/smb/server/mgmt/user_config.c
index 53db14e91bfd8..0e5fcd6f95c15 100644
--- a/fs/smb/server/mgmt/user_config.c
+++ b/fs/smb/server/mgmt/user_config.c
@@ -37,6 +37,17 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp,
{
struct ksmbd_user *user;
+ /*
+ * resp->hash_sz is a __u16 taken from the mountd IPC login response but
+ * resp->hash[] is only KSMBD_REQ_MAX_HASH_SZ bytes. A malformed or
+ * malicious response can set hash_sz far beyond that (up to 65535),
+ * making the memcpy() below read past the response object
+ * (slab-out-of-bounds in ksmbd_alloc_user()). Reject any oversized
+ * hash rather than trust the length.
+ */
+ if (resp->hash_sz > sizeof(resp->hash))
+ return NULL;
+
user = kmalloc(sizeof(struct ksmbd_user), KSMBD_DEFAULT_GFP);
if (!user)
return NULL;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 625/869] bpf: Check pointer type for all atomic RMW paths
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (623 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 624/869] ksmbd: fix slab-out-of-bounds read in ksmbd_alloc_user() Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 626/869] apparmor: fix deadlock in complain-mode change_hat Greg Kroah-Hartman
` (244 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yiyang Chen, Eduard Zingerman,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
[ Upstream commit 4bc49ae344d65cfcef738f281ac575cf73ca2fc5 ]
Atomic RMW verification records an instruction pointer type only when the
current destination is PTR_TO_ARENA. A second path can therefore reach the
same instruction with an ordinary pointer without comparing it against the
saved arena type.
The post-verification fixup uses the saved type to rewrite the instruction
to BPF_PROBE_ATOMIC for every path. Record the actual destination type for
all atomic RMW paths so the existing mismatch check rejects incompatible
uses of one instruction.
Fixes: d503a04f8bc0 ("bpf: Add support for certain atomics in bpf_arena to x86 JIT")
Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260816-bpf-next-038-mixed-atomic-v1-v2-1-4644c1886dbc@mails.tsinghua.edu.cn
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 03d5e7db3df76..752bc2d57d2bf 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -7559,11 +7559,9 @@ static int check_atomic_rmw(struct bpf_verifier_env *env,
if (err)
return err;
- if (is_arena_reg(env, insn->dst_reg)) {
- err = save_aux_ptr_type(env, PTR_TO_ARENA, false);
- if (err)
- return err;
- }
+ err = save_aux_ptr_type(env, reg_state(env, insn->dst_reg)->type, false);
+ if (err)
+ return err;
/* Check whether we can write into the same memory. */
err = check_mem_access(env, env->insn_idx, insn->dst_reg, insn->off,
BPF_SIZE(insn->code), BPF_WRITE, -1, true, false);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 626/869] apparmor: fix deadlock in complain-mode change_hat
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (624 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 625/869] bpf: Check pointer type for all atomic RMW paths Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 627/869] blk-cgroup: delay freeing policy data after rcu grace period Greg Kroah-Hartman
` (243 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Martin Petricek, John Johansen,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Johansen <john.johansen@canonical.com>
[ Upstream commit 4ec11f14d1d6fdda787d991b142537be7841d395 ]
The use of change_hat when in complain mode can cause a deadlock
when the hat doesn't exist and a new learning profile is created
for the missing profile. This is because change_hat() has taken
the lock to search the hat list and creating the new learning
profile needs to take the lock to add it to the list.
>From the bug report:
Originally found in 7.0.0 in LTS ubuntu 26.04 with pam_apparmor + su
in complain mode set to change hats. Then verified in newest
available vanilla kernel I've compiled to see if still present:
7.2-rc7 vanilla -> affected
checked also some other kernels:
6.18.44 vanilla -> affected
6.12.95 with debian patches -> unaffected
On systems without bug (for example 6.12.95 debian) it just prints:
aa_change_hat rc=0
On systems with bug, the executable always hangs, prints nothing and
becomes unkillable. (And once stuck this way, it will cause any
further hat changes to also cause the changing process to get stuck)
Then in syslog you can find hint about cause:
kernel: INFO: task hat:3409 blocked for more than 483 seconds.
kernel: Not tainted 7.2.0-rc7 #1
kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
kernel: task:hat state:D stack:0 pid:3409 tgid:3409 ppid:2605 task_flags:0x400000 flags:0x00080800
kernel: Call Trace:
kernel: <TASK>
kernel: __schedule+0x48f/0xfe0
kernel: schedule+0x27/0xa0
kernel: schedule_preempt_disabled+0x15/0x30
kernel: __mutex_lock.constprop.0+0x569/0xa10
kernel: aa_new_learning_profile+0x15f/0x210
kernel: build_change_hat+0x19f/0x3b0
kernel: change_hat.isra.0+0x5dd/0xd60
kernel: aa_change_hat+0x2f3/0x710
kernel: aa_setprocattr_changehat+0x121/0x1f0
kernel: do_setattr+0x28c/0x340
kernel: apparmor_setselfattr+0x20/0x50
kernel: security_setselfattr+0xf6/0x110
kernel: __x64_sys_lsm_set_self_attr+0x53/0x90
kernel: do_syscall_64+0xdd/0x5e0
kernel: ? __mod_memcg_lruvec_state+0xfd/0x260
kernel: ? lruvec_stat_mod_folio+0x8d/0xd0
kernel: ? __folio_mod_stat+0x2d/0x90
kernel: ? map_anon_folio_pte_nopf+0xd1/0x1f0
kernel: ? do_anonymous_page+0x184/0xa10
kernel: ? __handle_mm_fault+0x805/0x870
kernel: ? count_memcg_events+0xef/0x230
kernel: ? handle_mm_fault+0x1f0/0x2f0
kernel: ? do_user_addr_fault+0x2bb/0x7b0
kernel: ? do_syscall_64+0x94/0x5e0
kernel: ? exc_page_fault+0x75/0x160
kernel: entry_SYSCALL_64_after_hwframe+0x76/0x7e
kernel: RIP: 0033:0x7f815e134c8d
kernel: RSP: 002b:00007fff6df94ea8 EFLAGS: 00000246 ORIG_RAX: 00000000000001cc
kernel: RAX: ffffffffffffffda RBX: 0000556d8c81d040 RCX: 00007f815e134c8d
kernel: RDX: 0000000000000046 RSI: 0000556d8c81d040 RDI: 0000000000000064
kernel: RBP: 00007fff6df94ef0 R08: 00007f815e212ac8 R09: 000000000000000c
kernel: R10: 0000000000000000 R11: 0000000000000246 R12: 0000556d8c81d010
kernel: R13: 0000000000000026 R14: 0000000000000046 R15: 0000000000000064
kernel: </TASK>
kernel: INFO: task hat:3409 is blocked on a mutex likely owned by task hat:3409.
To fix the issue, lift the locking out of the core of
aa_new_learning_profile(), introduce a wrapper function that takes the
lock where needed, and have build_change_hat() call the core function
that no longer takes the lock.
In addition fix 4 other issues introduced by commit
32e92764d6f8d ("apparmor: grab ns lock and refresh when looking up changehat child profiles")
- aa_get_profile_rcu() was replaced-by: aa_get_profile without the
accompanying rcu_dereference_protected()
- an extra aa_get_label(label) was introduced at the start of
change_hat() without an accompanying aa_put_label() causing a
reference count leak.
- a reference count leak was introduced in the label_is_stale(label)
case, where the newest profile would be leaked instead of the
label passed to the function.
- a potential UAF when the lookup walks up the tree with new_ns != ns
the new label reference is put, and then used for the next lookup.
The mutex_lock, will block replacement, and removal in the locked
ns. However there are two cases where putting the reference can
result in the label being freed even with the lock held.
1. the label does not have a list reference (possible for temporary
or special profiles) in which case the put can trigger the
cleanup.
2. the new label reference is in a different namespace, which does
not have a lock held on it. This extends case 1 to also include
replacement, and removal that could be occurring in the namespace
new is in.
Reported-by: Martin Petricek <mp@petricek.net>
Link: https://lists.ubuntu.com/archives/apparmor/2026-August/014907.html
Fixes: 32e92764d6f8d ("apparmor: grab ns lock and refresh when looking up changehat child profiles")
Signed-off-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
security/apparmor/domain.c | 25 +++++++++++++++++--------
security/apparmor/include/policy.h | 3 +++
security/apparmor/policy.c | 22 +++++++++++++++++-----
3 files changed, 37 insertions(+), 13 deletions(-)
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index ced513197ed5e..91879bda56b9a 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -1036,8 +1036,8 @@ static struct aa_label *build_change_hat(const struct cred *subj_cred,
if (!hat) {
error = -ENOENT;
if (COMPLAIN_MODE(profile)) {
- hat = aa_new_learning_profile(profile, true, name,
- GFP_KERNEL);
+ hat = __aa_new_learning_profile(profile, true, name,
+ GFP_KERNEL);
if (!hat) {
info = "failed null profile create";
error = -ENOMEM;
@@ -1075,6 +1075,7 @@ static struct aa_label *change_hat(const struct cred *subj_cred,
bool sibling = false;
const char *name, *info = NULL;
int i, error;
+ bool needput = false;
AA_BUG(!label);
AA_BUG(!hats);
@@ -1087,7 +1088,6 @@ static struct aa_label *change_hat(const struct cred *subj_cred,
* the profiles and label, we can rely on the namespaces being live
* and avoid incrementing their refcounts while grabbing the lock.
*/
- label = aa_get_label(label);
ns = labels_ns(label);
retry:
@@ -1095,15 +1095,19 @@ static struct aa_label *change_hat(const struct cred *subj_cred,
if (label_is_stale(label)) {
new = aa_get_newest_label(label);
new_ns = labels_ns(new);
+
+ if (needput)
+ /* aa_put_label() is safe to call when under lock */
+ aa_put_label(label);
+ label = new;
+ needput = true;
+ /* check if replaced with label in parent ns, and lock there */
if (new_ns != ns) {
- aa_put_label(new);
mutex_unlock(&ns->lock);
ns = new_ns;
- label = new;
+ /* retry will bottom out at the root of the tree */
goto retry;
}
- aa_put_label(label);
- label = new;
}
if (PROFILE_IS_HAT(labels_profile(label)))
@@ -1114,7 +1118,8 @@ static struct aa_label *change_hat(const struct cred *subj_cred,
name = hats[i];
label_for_each_in_ns(it, labels_ns(label), label, profile) {
if (sibling && PROFILE_IS_HAT(profile)) {
- root = aa_get_profile(profile->parent);
+ root = aa_get_profile(rcu_dereference_protected(profile->parent,
+ mutex_is_locked(&ns->lock)));
} else if (!sibling && !PROFILE_IS_HAT(profile)) {
root = aa_get_profile(profile);
} else { /* conflicting change type */
@@ -1175,6 +1180,8 @@ static struct aa_label *change_hat(const struct cred *subj_cred,
}
}
mutex_unlock(&ns->lock);
+ if (needput)
+ aa_put_label(label);
return ERR_PTR(error);
build:
@@ -1188,6 +1195,8 @@ static struct aa_label *change_hat(const struct cred *subj_cred,
goto fail;
} /* else if (IS_ERR) build_change_hat has logged error so return new */
mutex_unlock(&ns->lock);
+ if (needput)
+ aa_put_label(label);
return new;
}
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index dbd6af6034f19..e85824c90f430 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -258,6 +258,9 @@ struct aa_profile *aa_alloc_profile(const char *name, struct aa_proxy *proxy,
gfp_t gfp);
struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name,
gfp_t gfp);
+struct aa_profile *__aa_new_learning_profile(struct aa_profile *parent,
+ bool hat, const char *base,
+ gfp_t gfp);
struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat,
const char *base, gfp_t gfp);
void aa_free_profile(struct aa_profile *profile);
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index da39bd937c2a4..b3a602c9c23d7 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -667,7 +667,7 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name,
}
/**
- * aa_new_learning_profile - create or find a null-X learning profile
+ * __aa_new_learning_profile - create or find a null-X learning profile
* @parent: profile that caused this profile to be created (NOT NULL)
* @hat: true if the null- learning profile is a hat
* @base: name to base the null profile off of
@@ -684,14 +684,16 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name,
*
* Returns: new refcounted profile else NULL on failure
*/
-struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat,
- const char *base, gfp_t gfp)
+struct aa_profile *__aa_new_learning_profile(struct aa_profile *parent,
+ bool hat, const char *base,
+ gfp_t gfp)
{
struct aa_profile *p, *profile;
const char *bname;
char *name = NULL;
AA_BUG(!parent);
+ AA_BUG(!mutex_is_locked(&parent->ns->lock));
if (base) {
name = kmalloc(strlen(parent->base.hname) + 8 + strlen(base),
@@ -723,7 +725,6 @@ struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat,
if (hat)
profile->label.flags |= FLAG_HAT;
- mutex_lock_nested(&profile->ns->lock, profile->ns->level);
p = __find_child(&parent->base.profiles, bname);
if (p) {
aa_free_profile(profile);
@@ -731,7 +732,6 @@ struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat,
} else {
__add_profile(&parent->base.profiles, profile);
}
- mutex_unlock(&profile->ns->lock);
/* refcount released by caller */
out:
@@ -745,6 +745,18 @@ struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat,
return NULL;
}
+struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat,
+ const char *base, gfp_t gfp)
+{
+ struct aa_profile *profile;
+
+ mutex_lock_nested(&parent->ns->lock, parent->ns->level);
+ profile = __aa_new_learning_profile(parent, hat, base, gfp);
+ mutex_unlock(&parent->ns->lock);
+
+ return profile;
+}
+
/**
* replacement_allowed - test to see if replacement is allowed
* @profile: profile to test if it can be replaced (MAYBE NULL)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 627/869] blk-cgroup: delay freeing policy data after rcu grace period
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (625 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 626/869] apparmor: fix deadlock in complain-mode change_hat Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 628/869] blk-iocost: clear delay state when freeing policy data Greg Kroah-Hartman
` (242 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Yu Kuai, Jens Axboe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <yukuai@fygo.io>
[ Upstream commit 0af3fedb8c8ed3c07b4f76927bd7fc88f6f82efb ]
Currently blkcg_print_blkgs() must hold RCU to iterate blkgs from a
blkcg, and prfill() must hold queue_lock to prevent policy data from
being freed by policy deactivation. As a consequence, queue_lock has to
be nested under RCU from blkcg_print_blkgs().
Delay freeing policy data until after an RCU grace period so prfill() can
be protected by RCU alone.
Signed-off-by: Yu Kuai <yukuai@fygo.io>
Link: https://patch.msgid.link/e20e5d984b41a026d61851966bed35eb094c4bff.1780621988.git.yukuai@fygo.io
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Stable-dep-of: 97cb95d21488 ("blk-iocost: clear delay state when freeing policy data")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
block/bfq-cgroup.c | 9 ++++++++-
block/blk-cgroup.h | 2 ++
block/blk-iocost.c | 14 ++++++++++++--
block/blk-iolatency.c | 10 +++++++++-
block/blk-throttle.c | 13 +++++++++++--
5 files changed, 42 insertions(+), 6 deletions(-)
diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c
index 6a75fe1c7a5c0..2e7cfaac7b214 100644
--- a/block/bfq-cgroup.c
+++ b/block/bfq-cgroup.c
@@ -548,14 +548,21 @@ static void bfq_pd_init(struct blkg_policy_data *pd)
bfqg->rq_pos_tree = RB_ROOT;
}
-static void bfq_pd_free(struct blkg_policy_data *pd)
+static void bfqg_release(struct rcu_head *rcu)
{
+ struct blkg_policy_data *pd =
+ container_of(rcu, struct blkg_policy_data, rcu_head);
struct bfq_group *bfqg = pd_to_bfqg(pd);
bfqg_stats_exit(&bfqg->stats);
bfqg_put(bfqg);
}
+static void bfq_pd_free(struct blkg_policy_data *pd)
+{
+ call_rcu(&pd->rcu_head, bfqg_release);
+}
+
static void bfq_pd_reset_stats(struct blkg_policy_data *pd)
{
struct bfq_group *bfqg = pd_to_bfqg(pd);
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index 112bf11d0fadd..270e58e5f38af 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -140,6 +140,8 @@ struct blkg_policy_data {
struct blkcg_gq *blkg;
int plid;
bool online;
+
+ struct rcu_head rcu_head;
};
/*
diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index 61a347f504d73..b48f9c63ca063 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -3019,6 +3019,16 @@ static void ioc_pd_init(struct blkg_policy_data *pd)
spin_unlock_irqrestore(&ioc->lock, flags);
}
+static void iocg_release(struct rcu_head *rcu)
+{
+ struct blkg_policy_data *pd =
+ container_of(rcu, struct blkg_policy_data, rcu_head);
+ struct ioc_gq *iocg = pd_to_iocg(pd);
+
+ free_percpu(iocg->pcpu_stat);
+ kfree(iocg);
+}
+
static void ioc_pd_free(struct blkg_policy_data *pd)
{
struct ioc_gq *iocg = pd_to_iocg(pd);
@@ -3043,8 +3053,8 @@ static void ioc_pd_free(struct blkg_policy_data *pd)
hrtimer_cancel(&iocg->waitq_timer);
}
- free_percpu(iocg->pcpu_stat);
- kfree(iocg);
+
+ call_rcu(&pd->rcu_head, iocg_release);
}
static void ioc_pd_stat(struct blkg_policy_data *pd, struct seq_file *s)
diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c
index ebb522788d978..49141c7fbcaa2 100644
--- a/block/blk-iolatency.c
+++ b/block/blk-iolatency.c
@@ -1031,13 +1031,21 @@ static void iolatency_pd_offline(struct blkg_policy_data *pd)
iolatency_clear_scaling(blkg);
}
-static void iolatency_pd_free(struct blkg_policy_data *pd)
+static void iolat_release(struct rcu_head *rcu)
{
+ struct blkg_policy_data *pd =
+ container_of(rcu, struct blkg_policy_data, rcu_head);
struct iolatency_grp *iolat = pd_to_lat(pd);
+
free_percpu(iolat->stats);
kfree(iolat);
}
+static void iolatency_pd_free(struct blkg_policy_data *pd)
+{
+ call_rcu(&pd->rcu_head, iolat_release);
+}
+
static struct cftype iolatency_files[] = {
{
.name = "latency",
diff --git a/block/blk-throttle.c b/block/blk-throttle.c
index bdf363868ac03..7a29eeb7b6957 100644
--- a/block/blk-throttle.c
+++ b/block/blk-throttle.c
@@ -327,16 +327,25 @@ static void throtl_pd_online(struct blkg_policy_data *pd)
tg_update_has_rules(tg);
}
-static void throtl_pd_free(struct blkg_policy_data *pd)
+static void tg_release(struct rcu_head *rcu)
{
+ struct blkg_policy_data *pd =
+ container_of(rcu, struct blkg_policy_data, rcu_head);
struct throtl_grp *tg = pd_to_tg(pd);
- del_timer_sync(&tg->service_queue.pending_timer);
blkg_rwstat_exit(&tg->stat_bytes);
blkg_rwstat_exit(&tg->stat_ios);
kfree(tg);
}
+static void throtl_pd_free(struct blkg_policy_data *pd)
+{
+ struct throtl_grp *tg = pd_to_tg(pd);
+
+ del_timer_sync(&tg->service_queue.pending_timer);
+ call_rcu(&pd->rcu_head, tg_release);
+}
+
static struct throtl_grp *
throtl_rb_first(struct throtl_service_queue *parent_sq)
{
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 628/869] blk-iocost: clear delay state when freeing policy data
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (626 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 627/869] blk-cgroup: delay freeing policy data after rcu grace period Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 629/869] blk-iolatency: " Greg Kroah-Hartman
` (241 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Usama Arif, Tejun Heo, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Usama Arif <usama.arif@linux.dev>
[ Upstream commit 97cb95d2148835ae86ff916b145aef332d40439d ]
iocg_kick_delay() turns sufficiently large debt into an explicit
block-cgroup delay with blkcg_set_delay(), setting blkg->use_delay to
-1 and incrementing blkcg->congestion_count. Clearing it again depends
on iocg_kick_delay() running from the period timer, the waitq timer or
the issue path.
ioc_pd_free() removes the iocg from active_iocgs and cancels its waitq
timer, and no further bios can arrive, so once it has run nothing is
left which can reduce the debt and clear the delay. The blkcg stays
marked congested for the rest of its life.
blk_cgroup_congested() then returns true for every task in that cgroup
and its descendants: page_cache_sync_ra() cuts readahead to a single
page, page_cache_async_ra() skips it altogether, and
__folio_throttle_swaprate() takes swap_avail_lock and schedules a
throttle on anonymous folio allocation.
Clear it explicitly, after the list removal and the synchronous
hrtimer_cancel() so that neither timer processing nor an I/O path can
re-arm it. The free callback can also see policy data which was never
attached to a blkg, hence the pd->blkg check.
Fixes: 7caa47151ab2 ("blkcg: implement blk-iocost")
Signed-off-by: Usama Arif <usama.arif@linux.dev>
Acked-by: Tejun Heo <tj@kernel.org>
Link: https://patch.msgid.link/20260814165712.510132-3-usama.arif@linux.dev
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
block/blk-iocost.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index b48f9c63ca063..8b775dd95ba57 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -3032,6 +3032,7 @@ static void iocg_release(struct rcu_head *rcu)
static void ioc_pd_free(struct blkg_policy_data *pd)
{
struct ioc_gq *iocg = pd_to_iocg(pd);
+ struct blkcg_gq *blkg = pd_to_blkg(pd);
struct ioc *ioc = iocg->ioc;
unsigned long flags;
@@ -3054,6 +3055,12 @@ static void ioc_pd_free(struct blkg_policy_data *pd)
hrtimer_cancel(&iocg->waitq_timer);
}
+ /* off ->active_iocgs and timer gone, so nothing can re-arm the delay */
+ iocg->delay = 0;
+ iocg->indelay_since = 0;
+ if (blkg)
+ blkcg_clear_delay(blkg);
+
call_rcu(&pd->rcu_head, iocg_release);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 629/869] blk-iolatency: clear delay state when freeing policy data
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (627 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 628/869] blk-iocost: clear delay state when freeing policy data Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 630/869] ocfs2: validate DIO orphan slot during inode read Greg Kroah-Hartman
` (240 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Usama Arif, Tejun Heo, Jens Axboe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Usama Arif <usama.arif@linux.dev>
[ Upstream commit 8935bf22c0a0db517a7f72f7097300e05dd852f5 ]
io.latency can throttle a group which has no latency target of its own.
When a sibling misses its target, check_scale_change() scales down its
peers, and a peer that reaches queue depth one gets blkcg_use_delay()
called on it on every further scale-down, even with min_lat_nsec == 0.
iolatency_pd_offline() resets the target through
iolatency_set_min_lat_nsec(), which clears the delay only on a nonzero
to zero transition, so it never clears such a peer. Freeing the policy
data then leaves blkg->use_delay set and blkcg->congestion_count
elevated with nothing left that can drop it.
blk_cgroup_congested() then returns true for every task in that cgroup
and its descendants for as long as the cgroup lives: page_cache_sync_ra()
cuts readahead to a single page, page_cache_async_ra() skips it
altogether, and __folio_throttle_swaprate() takes swap_avail_lock and
schedules a throttle on anonymous folio allocation.
Clear the delay in iolatency_pd_free(). By then bio-held blkg
references have drained, or the queue is frozen for policy
deactivation, so check_scale_change() cannot re-arm it. The free
callback can also see policy data which was never attached to a blkg,
hence the pd->blkg check.
Fixes: d70675121546 ("block: introduce blk-iolatency io controller")
Signed-off-by: Usama Arif <usama.arif@linux.dev>
Acked-by: Tejun Heo <tj@kernel.org>
Link: https://patch.msgid.link/20260814165712.510132-2-usama.arif@linux.dev
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
block/blk-iolatency.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c
index 49141c7fbcaa2..6be1c5e020ac9 100644
--- a/block/blk-iolatency.c
+++ b/block/blk-iolatency.c
@@ -1043,6 +1043,15 @@ static void iolat_release(struct rcu_head *rcu)
static void iolatency_pd_free(struct blkg_policy_data *pd)
{
+ struct blkcg_gq *blkg = pd_to_blkg(pd);
+
+ /*
+ * Groups throttled as collateral have min_lat_nsec == 0, so
+ * iolatency_pd_offline() leaves their delay set. Drop it here, where
+ * no in-flight bio can re-arm it via check_scale_change().
+ */
+ if (blkg)
+ blkcg_clear_delay(blkg);
call_rcu(&pd->rcu_head, iolat_release);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 630/869] ocfs2: validate DIO orphan slot during inode read
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (628 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 629/869] blk-iolatency: " Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 631/869] ocfs2: validate " Greg Kroah-Hartman
` (239 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, ZhengYuan Huang, Joseph Qi,
Mark Fasheh, Joel Becker, Junxiao Bi, Changwei Ge, Jun Piao,
Heming Zhao, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhengYuan Huang <gality369@gmail.com>
[ Upstream commit bb88131c9831075b8dc08cdd375743e5d44c7ca2 ]
[BUG]
A corrupted append-DIO dinode (high byte at offset 0xa1
corrupted from 0 to 1) can carry an i_dio_orphaned_slot
outside the mounted filesystem slot range and trigger a
use-after-free error:
BUG: KASAN: slab-use-after-free in ocfs2_get_system_file_inode+0x780/0x820 fs/ocfs2/sysfile.c:102
Read of size 8 at addr ffff88800b767c00 by task kworker/u8:3/85
Call Trace:
...
ocfs2_get_system_file_inode+0x780/0x820 fs/ocfs2/sysfile.c:102
ocfs2_wipe_inode+0x292/0xf70 fs/ocfs2/inode.c:840
ocfs2_delete_inode fs/ocfs2/inode.c:1155 [inline]
ocfs2_evict_inode+0x6c9/0x1170 fs/ocfs2/inode.c:1295
evict+0x38e/0x8f0 fs/inode.c:810
iput_final fs/inode.c:1914 [inline]
iput fs/inode.c:1966 [inline]
iput+0x55b/0x8b0 fs/inode.c:1926
ocfs2_recover_orphans+0x610/0xe40 fs/ocfs2/journal.c:2374
ocfs2_complete_recovery+0x5af/0xd00 fs/ocfs2/journal.c:1373
...
[CAUSE]
ocfs2_del_inode_from_orphan() uses i_dio_orphaned_slot to index the
slot-local system inode cache. The dinode validator does not check
this active slot, so an out-of-range value produces an invalid cache
entry pointer that is dereferenced as an inode pointer.
[FIX]
Reject an active i_dio_orphaned_slot outside the slot range during
dinode validation, before DIO orphan recovery can consume it.
Link: https://lore.kernel.org/20260803030007.3993199-3-gality369@gmail.com
Fixes: 06ee5c75b575 ("ocfs2: add functions to add and remove inode in orphan dir")
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/inode.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index dd486c74ab9d1..4cb7d51d4e774 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -1466,6 +1466,14 @@ int ocfs2_validate_inode_block(struct super_block *sb,
goto bail;
}
+ if ((le32_to_cpu(di->i_flags) & OCFS2_DIO_ORPHANED_FL) &&
+ le16_to_cpu(di->i_dio_orphaned_slot) >= OCFS2_SB(sb)->max_slots) {
+ rc = ocfs2_error(sb, "Invalid dinode %llu: DIO orphaned slot %u\n",
+ (unsigned long long)bh->b_blocknr,
+ le16_to_cpu(di->i_dio_orphaned_slot));
+ goto bail;
+ }
+
/*
* Reject dinodes whose i_mode does not name one of the seven
* canonical POSIX file types. ocfs2_populate_inode() copies
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 631/869] ocfs2: validate orphan slot during inode read
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (629 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 630/869] ocfs2: validate DIO orphan slot during inode read Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 632/869] nvmet: fix max_qid race between configfs and controller allocation Greg Kroah-Hartman
` (238 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, ZhengYuan Huang, Joseph Qi,
Mark Fasheh, Joel Becker, Junxiao Bi, Changwei Ge, Jun Piao,
Heming Zhao, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhengYuan Huang <gality369@gmail.com>
[ Upstream commit b2d31acbd3b182755b019183fb46949ba5e39b9f ]
Patch series "ocfs2: validate active orphan slots during inode read".
OCFS2 trusts active ordinary and append-DIO orphan slots read from dinodes.
A corrupted slot can therefore index osb_orphan_wipes or the slot-local
system-inode cache outside their allocations before the corruption is
reported.
Patch 1 validates the ordinary orphan slot used by inode wipe processing.
Patch 2 validates the append-DIO orphan slot used by DIO completion and
orphan recovery. Both checks reject corrupt metadata at the existing inode
validation boundary.
This patch (of 2):
[BUG]
A corrupted dinode with OCFS2_ORPHANED_FL can carry an
i_orphaned_slot outside the mounted filesystem slot range.
ocfs2_wipe_inode() uses it to index osb_orphan_wipes before looking
up the orphan directory, causing an out-of-bounds memory access.
BUG: KASAN: slab-use-after-free in ocfs2_get_system_file_inode+0x780/0x820 fs/ocfs2/sysfile.c:102
Read of size 8 at addr ffff88800b767c00 by task kworker/u8:3/85
Call Trace:
...
ocfs2_get_system_file_inode+0x780/0x820 fs/ocfs2/sysfile.c:102
ocfs2_wipe_inode+0x292/0xf70 fs/ocfs2/inode.c:840
ocfs2_delete_inode fs/ocfs2/inode.c:1155 [inline]
ocfs2_evict_inode+0x6c9/0x1170 fs/ocfs2/inode.c:1295
evict+0x38e/0x8f0 fs/inode.c:810
iput_final fs/inode.c:1914 [inline]
iput fs/inode.c:1966 [inline]
iput+0x55b/0x8b0 fs/inode.c:1926
ocfs2_recover_orphans+0x610/0xe40 fs/ocfs2/journal.c:2374
ocfs2_complete_recovery+0x5af/0xd00 fs/ocfs2/journal.c:1373
...
[CAUSE]
ocfs2_validate_inode_block() validates i_suballoc_slot but leaves
the active ordinary orphan slot unchecked. Downstream consumers
assume that the value is smaller than osb->max_slots.
[FIX]
Reject an active i_orphaned_slot outside the slot range during
dinode validation, before the inode reaches orphan wipe processing.
Link: https://lore.kernel.org/20260803030007.3993199-1-gality369@gmail.com
Link: https://lore.kernel.org/20260803030007.3993199-2-gality369@gmail.com
Fixes: b4df6ed8db0c ("[PATCH] ocfs2: fix orphan recovery deadlock")
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/inode.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 4cb7d51d4e774..1330ea2473736 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -1474,6 +1474,14 @@ int ocfs2_validate_inode_block(struct super_block *sb,
goto bail;
}
+ if ((le32_to_cpu(di->i_flags) & OCFS2_ORPHANED_FL) &&
+ le16_to_cpu(di->i_orphaned_slot) >= OCFS2_SB(sb)->max_slots) {
+ rc = ocfs2_error(sb, "Invalid dinode %llu: orphaned slot %u\n",
+ (unsigned long long)bh->b_blocknr,
+ le16_to_cpu(di->i_orphaned_slot));
+ goto bail;
+ }
+
/*
* Reject dinodes whose i_mode does not name one of the seven
* canonical POSIX file types. ocfs2_populate_inode() copies
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 632/869] nvmet: fix max_qid race between configfs and controller allocation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (630 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 631/869] ocfs2: validate " Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 633/869] clocksource/drivers/samsung_pwm: Switch to raw_spinlock_t type Greg Kroah-Hartman
` (237 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+2626e846cd2585c9aa67,
Maurizio Lombardi, Keith Busch, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maurizio Lombardi <mlombard@redhat.com>
[ Upstream commit f1a8846e06388113dfdbb89dee005083fa9afdf9 ]
The function nvmet_subsys_attr_qid_max_store() can race against
nvmet_alloc_ctrl() when a subsystem's max_qid limit is modified.
Suppose max_qid is currently 64. If nvmet_alloc_ctrl() executes:
ctrl->sqs = kzalloc_objs(struct nvmet_sq *, subsys->max_qid + 1);
and at this exact point, a userspace process changes max_qid to 128,
nvmet_subsys_attr_qid_max_store() will set the new max_qid value. It
attempts to delete active controllers to force a reconnect, but the
new controller won't be deleted because it hasn't been added to the
subsys->ctrls list yet.
nvmet_alloc_ctrl() then proceeds and adds the new controller to the
subsys->ctrls list. Later, when nvmet_install_queue() is called, it
will see max_qid set to 128, but the memory allocated for sqs is only
sized for 64 entries. This results in a KASAN out-of-bounds warning
and potential memory corruptions.
Fix this by protecting the queue allocations and list insertion in
nvmet_alloc_ctrl() with down_read(&nvmet_config_sem). Because
nvmet_subsys_attr_qid_max_store() acquires down_write(&nvmet_config_sem)
to modify the attribute, this safely prevents the configfs writer from
modifying max_qid during controller creation.
Copy the max_qid from the subsystem to the controller's structure
during the allocation; ctrl->max_qid never changes as long as the
controller remains in LIVE state, so this will prevent similar race
conditions.
Fixes: 3e980f5995e0 ("nvmet: expose max queues to configfs")
Reported-by: syzbot+2626e846cd2585c9aa67@syzkaller.appspotmail.com
Signed-off-by: Maurizio Lombardi <mlombard@redhat.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/nvme/target/admin-cmd.c | 8 +++---
drivers/nvme/target/core.c | 41 ++++++++++++++++++-------------
drivers/nvme/target/fabrics-cmd.c | 2 +-
drivers/nvme/target/nvmet.h | 6 +++++
4 files changed, 35 insertions(+), 22 deletions(-)
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 0f1956bb6d3c9..72a5de1f8252d 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -828,7 +828,7 @@ u16 nvmet_set_feat_async_event(struct nvmet_req *req, u32 mask)
void nvmet_execute_set_features(struct nvmet_req *req)
{
- struct nvmet_subsys *subsys = nvmet_req_subsys(req);
+ struct nvmet_ctrl *ctrl = nvmet_req_ctrl(req);
u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10);
u32 cdw11 = le32_to_cpu(req->cmd->common.cdw11);
u16 status = 0;
@@ -847,7 +847,7 @@ void nvmet_execute_set_features(struct nvmet_req *req)
break;
}
nvmet_set_result(req,
- (subsys->max_qid - 1) | ((subsys->max_qid - 1) << 16));
+ (ctrl->max_qid - 1) | ((ctrl->max_qid - 1) << 16));
break;
case NVME_FEAT_KATO:
status = nvmet_set_feat_kato(req);
@@ -902,7 +902,7 @@ void nvmet_get_feat_async_event(struct nvmet_req *req)
void nvmet_execute_get_features(struct nvmet_req *req)
{
- struct nvmet_subsys *subsys = nvmet_req_subsys(req);
+ struct nvmet_ctrl *ctrl = nvmet_req_ctrl(req);
u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10);
u16 status = 0;
@@ -939,7 +939,7 @@ void nvmet_execute_get_features(struct nvmet_req *req)
break;
case NVME_FEAT_NUM_QUEUES:
nvmet_set_result(req,
- (subsys->max_qid-1) | ((subsys->max_qid-1) << 16));
+ (ctrl->max_qid-1) | ((ctrl->max_qid-1) << 16));
break;
case NVME_FEAT_KATO:
nvmet_get_feat_kato(req);
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 5950635d6f58d..fa011c16c9b1c 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -1479,21 +1479,6 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
if (!ctrl->changed_ns_list)
goto out_free_ctrl;
- ctrl->sqs = kcalloc(subsys->max_qid + 1,
- sizeof(struct nvmet_sq *),
- GFP_KERNEL);
- if (!ctrl->sqs)
- goto out_free_changed_ns_list;
-
- ret = ida_alloc_range(&cntlid_ida,
- subsys->cntlid_min, subsys->cntlid_max,
- GFP_KERNEL);
- if (ret < 0) {
- status = NVME_SC_CONNECT_CTRL_BUSY | NVME_STATUS_DNR;
- goto out_free_sqs;
- }
- ctrl->cntlid = ret;
-
/*
* Discovery controllers may use some arbitrary high value
* in order to cleanup stale discovery sessions
@@ -1507,13 +1492,33 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
ctrl->err_counter = 0;
spin_lock_init(&ctrl->error_lock);
- nvmet_start_keep_alive_timer(ctrl);
-
+ down_read(&nvmet_config_sem);
mutex_lock(&subsys->lock);
+
+ ctrl->max_qid = subsys->max_qid;
+
+ ctrl->sqs = kcalloc(ctrl->max_qid + 1,
+ sizeof(struct nvmet_sq *),
+ GFP_KERNEL);
+ if (!ctrl->sqs)
+ goto out_free_changed_ns_list;
+
+ ret = ida_alloc_range(&cntlid_ida,
+ subsys->cntlid_min, subsys->cntlid_max,
+ GFP_KERNEL);
+ if (ret < 0) {
+ status = NVME_SC_CONNECT_CTRL_BUSY | NVME_STATUS_DNR;
+ goto out_free_sqs;
+ }
+ ctrl->cntlid = ret;
+
list_add_tail(&ctrl->subsys_entry, &subsys->ctrls);
nvmet_setup_p2p_ns_map(ctrl, req);
nvmet_debugfs_ctrl_setup(ctrl);
mutex_unlock(&subsys->lock);
+ up_read(&nvmet_config_sem);
+
+ nvmet_start_keep_alive_timer(ctrl);
*ctrlp = ctrl;
return 0;
@@ -1521,6 +1526,8 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
out_free_sqs:
kfree(ctrl->sqs);
out_free_changed_ns_list:
+ mutex_unlock(&subsys->lock);
+ up_read(&nvmet_config_sem);
kfree(ctrl->changed_ns_list);
out_free_ctrl:
kfree(ctrl);
diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c
index a593003c1c20c..66d0dbf7ac733 100644
--- a/drivers/nvme/target/fabrics-cmd.c
+++ b/drivers/nvme/target/fabrics-cmd.c
@@ -350,7 +350,7 @@ static void nvmet_execute_io_connect(struct nvmet_req *req)
goto out;
}
- if (unlikely(qid > ctrl->subsys->max_qid)) {
+ if (unlikely(qid > ctrl->max_qid)) {
pr_warn("invalid queue id (%d)\n", qid);
status = NVME_SC_CONNECT_INVALID_PARAM | NVME_STATUS_DNR;
req->cqe->result.u32 = IPO_IATTR_CONNECT_SQE(qid);
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 25bba2d097626..408c3cda47436 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -204,6 +204,7 @@ struct nvmet_ctrl {
uuid_t hostid;
u16 cntlid;
+ u16 max_qid;
u32 kato;
struct nvmet_port *port;
@@ -642,6 +643,11 @@ static inline struct nvmet_subsys *nvmet_req_subsys(struct nvmet_req *req)
return req->sq->ctrl->subsys;
}
+static inline struct nvmet_ctrl *nvmet_req_ctrl(struct nvmet_req *req)
+{
+ return req->sq->ctrl;
+}
+
static inline bool nvmet_is_disc_subsys(struct nvmet_subsys *subsys)
{
return subsys->type != NVME_NQN_NVME;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 633/869] clocksource/drivers/samsung_pwm: Switch to raw_spinlock_t type
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (631 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 632/869] nvmet: fix max_qid race between configfs and controller allocation Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 634/869] bpf, s390: Clear fetch destination on faulting arena atomic Greg Kroah-Hartman
` (236 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Marek Szyprowski, Daniel Lezcano,
Krzysztof Kozlowski, Sebastian Andrzej Siewior,
Uwe Kleine-König, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marek Szyprowski <m.szyprowski@samsung.com>
[ Upstream commit 3b212f9d70805d91febae01d618868f4860e267c ]
Samsung PWM timer might be used as a clock source on some legacy systems.
When PREEMPT_RT is enabled on ARM, regular spinlock is converted to a
sleeping lock (mutex-based), which must not be used in atomic context
such as hard interrupt handlers. Switch the samsung_pwm_lock to the
raw_spinlock, which remains a true non-sleeping spinlock even
under PREEMPT_RT.
Fixes: 7aac482e6290 ("clocksource: samsung_pwm_timer: Make PWM spinlock global")
Fixes: f11899894c0a ("clocksource: add samsung pwm timer driver")
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@kernel.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Acked-by: Uwe Kleine-König <ukleinek@kernel.org>
Link: https://patch.msgid.link/20260713085653.1145015-1-m.szyprowski@samsung.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/clocksource/samsung_pwm_timer.c | 22 +++++++++++-----------
drivers/pwm/pwm-samsung.c | 22 +++++++++++-----------
include/clocksource/samsung_pwm.h | 2 +-
3 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c
index b9561e3f196c4..0544124cf5cea 100644
--- a/drivers/clocksource/samsung_pwm_timer.c
+++ b/drivers/clocksource/samsung_pwm_timer.c
@@ -56,7 +56,7 @@
#define TCON_AUTORELOAD(chan) \
((chan < 5) ? _TCON_AUTORELOAD(chan) : _TCON_AUTORELOAD4(chan))
-DEFINE_SPINLOCK(samsung_pwm_lock);
+DEFINE_RAW_SPINLOCK(samsung_pwm_lock);
EXPORT_SYMBOL(samsung_pwm_lock);
struct samsung_pwm_clocksource {
@@ -87,14 +87,14 @@ static void samsung_timer_set_prescale(unsigned int channel, u16 prescale)
if (channel >= 2)
shift = TCFG0_PRESCALER1_SHIFT;
- spin_lock_irqsave(&samsung_pwm_lock, flags);
+ raw_spin_lock_irqsave(&samsung_pwm_lock, flags);
reg = readl(pwm.base + REG_TCFG0);
reg &= ~(TCFG0_PRESCALER_MASK << shift);
reg |= (prescale - 1) << shift;
writel(reg, pwm.base + REG_TCFG0);
- spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+ raw_spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}
static void samsung_timer_set_divisor(unsigned int channel, u8 divisor)
@@ -106,14 +106,14 @@ static void samsung_timer_set_divisor(unsigned int channel, u8 divisor)
bits = (fls(divisor) - 1) - pwm.variant.div_base;
- spin_lock_irqsave(&samsung_pwm_lock, flags);
+ raw_spin_lock_irqsave(&samsung_pwm_lock, flags);
reg = readl(pwm.base + REG_TCFG1);
reg &= ~(TCFG1_MUX_MASK << shift);
reg |= bits << shift;
writel(reg, pwm.base + REG_TCFG1);
- spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+ raw_spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}
static void samsung_time_stop(unsigned int channel)
@@ -124,13 +124,13 @@ static void samsung_time_stop(unsigned int channel)
if (channel > 0)
++channel;
- spin_lock_irqsave(&samsung_pwm_lock, flags);
+ raw_spin_lock_irqsave(&samsung_pwm_lock, flags);
tcon = readl_relaxed(pwm.base + REG_TCON);
tcon &= ~TCON_START(channel);
writel_relaxed(tcon, pwm.base + REG_TCON);
- spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+ raw_spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}
static void samsung_time_setup(unsigned int channel, unsigned long tcnt)
@@ -142,7 +142,7 @@ static void samsung_time_setup(unsigned int channel, unsigned long tcnt)
if (tcon_chan > 0)
++tcon_chan;
- spin_lock_irqsave(&samsung_pwm_lock, flags);
+ raw_spin_lock_irqsave(&samsung_pwm_lock, flags);
tcon = readl_relaxed(pwm.base + REG_TCON);
@@ -153,7 +153,7 @@ static void samsung_time_setup(unsigned int channel, unsigned long tcnt)
writel_relaxed(tcnt, pwm.base + REG_TCMPB(channel));
writel_relaxed(tcon, pwm.base + REG_TCON);
- spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+ raw_spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}
static void samsung_time_start(unsigned int channel, bool periodic)
@@ -164,7 +164,7 @@ static void samsung_time_start(unsigned int channel, bool periodic)
if (channel > 0)
++channel;
- spin_lock_irqsave(&samsung_pwm_lock, flags);
+ raw_spin_lock_irqsave(&samsung_pwm_lock, flags);
tcon = readl_relaxed(pwm.base + REG_TCON);
@@ -178,7 +178,7 @@ static void samsung_time_start(unsigned int channel, bool periodic)
writel_relaxed(tcon, pwm.base + REG_TCON);
- spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+ raw_spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}
static int samsung_set_next_event(unsigned long cycles,
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index 951b38ff5f8ec..14fb460a45655 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -102,7 +102,7 @@ struct samsung_pwm_chip {
* IP. Should this change, both drivers will need to be modified to
* properly synchronize accesses to particular instances.
*/
-static DEFINE_SPINLOCK(samsung_pwm_lock);
+static DEFINE_RAW_SPINLOCK(samsung_pwm_lock);
#endif
static inline
@@ -141,14 +141,14 @@ static void pwm_samsung_set_divisor(struct samsung_pwm_chip *our_chip,
bits = (fls(divisor) - 1) - our_chip->variant.div_base;
- spin_lock_irqsave(&samsung_pwm_lock, flags);
+ raw_spin_lock_irqsave(&samsung_pwm_lock, flags);
reg = readl(our_chip->base + REG_TCFG1);
reg &= ~(TCFG1_MUX_MASK << shift);
reg |= bits << shift;
writel(reg, our_chip->base + REG_TCFG1);
- spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+ raw_spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}
static int pwm_samsung_is_tdiv(struct samsung_pwm_chip *our_chip, unsigned int chan)
@@ -249,7 +249,7 @@ static int pwm_samsung_enable(struct pwm_chip *chip, struct pwm_device *pwm)
unsigned long flags;
u32 tcon;
- spin_lock_irqsave(&samsung_pwm_lock, flags);
+ raw_spin_lock_irqsave(&samsung_pwm_lock, flags);
tcon = readl(our_chip->base + REG_TCON);
@@ -263,7 +263,7 @@ static int pwm_samsung_enable(struct pwm_chip *chip, struct pwm_device *pwm)
our_chip->disabled_mask &= ~BIT(pwm->hwpwm);
- spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+ raw_spin_unlock_irqrestore(&samsung_pwm_lock, flags);
return 0;
}
@@ -275,7 +275,7 @@ static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm)
unsigned long flags;
u32 tcon;
- spin_lock_irqsave(&samsung_pwm_lock, flags);
+ raw_spin_lock_irqsave(&samsung_pwm_lock, flags);
tcon = readl(our_chip->base + REG_TCON);
tcon &= ~TCON_AUTORELOAD(tcon_chan);
@@ -290,7 +290,7 @@ static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm)
our_chip->disabled_mask |= BIT(pwm->hwpwm);
- spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+ raw_spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}
static void pwm_samsung_manual_update(struct samsung_pwm_chip *our_chip,
@@ -298,11 +298,11 @@ static void pwm_samsung_manual_update(struct samsung_pwm_chip *our_chip,
{
unsigned long flags;
- spin_lock_irqsave(&samsung_pwm_lock, flags);
+ raw_spin_lock_irqsave(&samsung_pwm_lock, flags);
__pwm_samsung_manual_update(our_chip, pwm);
- spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+ raw_spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}
static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -390,7 +390,7 @@ static void pwm_samsung_set_invert(struct samsung_pwm_chip *our_chip,
unsigned long flags;
u32 tcon;
- spin_lock_irqsave(&samsung_pwm_lock, flags);
+ raw_spin_lock_irqsave(&samsung_pwm_lock, flags);
tcon = readl(our_chip->base + REG_TCON);
@@ -404,7 +404,7 @@ static void pwm_samsung_set_invert(struct samsung_pwm_chip *our_chip,
writel(tcon, our_chip->base + REG_TCON);
- spin_unlock_irqrestore(&samsung_pwm_lock, flags);
+ raw_spin_unlock_irqrestore(&samsung_pwm_lock, flags);
}
static int pwm_samsung_set_polarity(struct pwm_chip *chip,
diff --git a/include/clocksource/samsung_pwm.h b/include/clocksource/samsung_pwm.h
index 9b435caa95fef..36f6f246e5594 100644
--- a/include/clocksource/samsung_pwm.h
+++ b/include/clocksource/samsung_pwm.h
@@ -15,7 +15,7 @@
* spinlock is not shared between both drivers.
*/
#ifdef CONFIG_CLKSRC_SAMSUNG_PWM
-extern spinlock_t samsung_pwm_lock;
+extern raw_spinlock_t samsung_pwm_lock;
#endif
struct samsung_pwm_variant {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 634/869] bpf, s390: Clear fetch destination on faulting arena atomic
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (632 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 633/869] clocksource/drivers/samsung_pwm: Switch to raw_spinlock_t type Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 635/869] bpf: Compare iterator types during state pruning Greg Kroah-Hartman
` (235 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Daniel Borkmann, Ilya Leoshkevich,
Eduard Zingerman, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Borkmann <daniel@iogearbox.net>
[ Upstream commit cc3e12330599f097f0e1f792435686ddc276f26d ]
Same missing register clear as on riscv64. A RMW atomic on an arena pointer
is converted to BPF_PROBE_ATOMIC and gets an exception table entry, but
bpf_jit_probe_atomic_pre() only fills in the arena base and the probe
offset, leaving probe->reg at the -1 that bpf_jit_probe_init() set, which
bpf_jit_probe_post() writes into the entry and ex_handler_bpf() then reads
back as "there is nothing to clear".
That is right for a plain BPF_{ADD,AND,OR,XOR}, which only writes memory,
but an RMW carrying BPF_FETCH also reads the old value into a register:
src_reg for BPF_{ADD,AND,OR,XOR} | BPF_FETCH and BPF_XCHG, and r0 for
BPF_CMPXCHG. So on a fault over an unmapped arena page the program resumes
at the landing pad with whatever that register held before the atomic
instead of the 0 that every other BPF_PROBE_* access delivers.
Fill probe->reg in from bpf_atomic_load_reg(). Unlike x86-64 and arm64,
s390x does not report arena violations from its exception handler, so there
is no access direction to correct here, only the missing register clear.
Fixes: 2f9469484a3b ("s390/bpf: Support arena atomics")
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Ilya Leoshkevich <iii@linux.ibm.com>
Link: https://patch.msgid.link/20260811131600.506721-5-daniel@iogearbox.net
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/net/bpf_jit_comp.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index c3ad3cf86ca64..55419813c570b 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -782,6 +782,8 @@ static void bpf_jit_probe_atomic_pre(struct bpf_jit *jit,
struct bpf_insn *insn,
struct bpf_jit_probe *probe)
{
+ int load_reg;
+
if (BPF_MODE(insn->code) != BPF_PROBE_ATOMIC)
return;
@@ -791,6 +793,14 @@ static void bpf_jit_probe_atomic_pre(struct bpf_jit *jit,
EMIT4(0xb9080000, REG_W1, insn->dst_reg);
probe->arena_reg = REG_W1;
probe->prg = jit->prg;
+ /*
+ * A read-modify-write carrying BPF_FETCH reads the old value into
+ * src_reg, or into r0 for a BPF_CMPXCHG. Clear that register on
+ * fault, the remaining atomics only write memory.
+ */
+ load_reg = bpf_atomic_load_reg(insn);
+ if (load_reg >= 0)
+ probe->reg = reg2hex[load_reg];
}
static int bpf_jit_probe_post(struct bpf_jit *jit, struct bpf_prog *fp,
@@ -1653,6 +1663,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
if (load_probe.prg != -1) {
probe.prg = jit->prg;
probe.arena_reg = load_probe.arena_reg;
+ probe.reg = load_probe.reg;
}
loop_start = jit->prg;
/* 0: {csy|csg} %w0,%src,off(%arena) */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 635/869] bpf: Compare iterator types during state pruning
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (633 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 634/869] bpf, s390: Clear fetch destination on faulting arena atomic Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 636/869] apparmor: fix unconfined user namespace restriction forced stack Greg Kroah-Hartman
` (234 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ning Ding, Eduard Zingerman,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ning Ding <dingning04@gmail.com>
[ Upstream commit 83608e303b95d07afba1c15da0b5d9e513c2f15a ]
An iterator stack slot can be MEM_RCU or PTR_UNTRUSTED. These states
must not be equal, or the verifier can prune an unsafe path.
Compare the pointer type for STACK_ITER slots.
Fixes: dfab99df147b ("bpf: teach the verifier to enforce css_iter and task_iter in RCU CS")
Signed-off-by: Ning Ding <dingning04@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260811035955.132989-2-dingning04@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 752bc2d57d2bf..f0a10f6f09fb0 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -18053,7 +18053,8 @@ static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old,
* infinite loop check triggering, see
* iter_active_depths_differ()
*/
- if (old_reg->iter.btf != cur_reg->iter.btf ||
+ if (old_reg->type != cur_reg->type ||
+ old_reg->iter.btf != cur_reg->iter.btf ||
old_reg->iter.btf_id != cur_reg->iter.btf_id ||
old_reg->iter.state != cur_reg->iter.state ||
/* ignore {old_reg,cur_reg}->iter.depth, see above */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 636/869] apparmor: fix unconfined user namespace restriction forced stack
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (634 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 635/869] bpf: Compare iterator types during state pruning Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 637/869] amt: Dont support cross-netns setup Greg Kroah-Hartman
` (233 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, John Johansen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Johansen <john.johansen@canonical.com>
[ Upstream commit 08c2f7c8d4b1434cfae006f3daf4d1bce330b57b ]
If a task is already confined by a stack the unprivileged transition
restriction on unconfined is not correctly, applied. This results in
an escape if two transitions through an unconfined profile can be
executed.
Fix this by pushing the check into the per profile label build. The
check will always be done against unconfined and result in a stack of
just the unconfined component when necessary.
Fixes: 2d9da9b188b8 ("apparmor: allow restricting unprivileged change_profile")
Signed-off-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
security/apparmor/domain.c | 80 +++++++++++++++++++++++++-------------
1 file changed, 54 insertions(+), 26 deletions(-)
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 91879bda56b9a..8685c10e6754c 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -812,6 +812,52 @@ static int profile_onexec(const struct cred *subj_cred,
/* ensure none ns domain transitions are correctly applied with onexec */
+static bool is_profile_priv_restricted_to_stack(const struct cred *subj_cred,
+ struct aa_profile *profile)
+{
+ if (profile_unconfined(profile) && profile == profile->ns->unconfined &&
+ aa_unprivileged_unconfined_restricted &&
+ /* cap_capable returns false (0) if true, hence true here means
+ * doesn't have capability and the stack will be restricted
+ */
+ cap_capable(current_cred(), &init_user_ns, CAP_MAC_OVERRIDE,
+ CAP_OPT_NOAUDIT))
+ return true;
+ return false;
+}
+
+static const char *stack_msg = "change_profile unprivileged unconfined converted to stacking";
+
+static struct aa_label *priv_restricted_transition(const struct cred *subj_cred,
+ struct aa_profile *profile,
+ const char *op, u32 request,
+ const char *name,
+ struct aa_label *transition,
+ gfp_t gfp)
+{
+ if (!is_profile_priv_restricted_to_stack(subj_cred, profile))
+ return aa_get_newest_label(transition);
+
+ /* transition allowed but only via stack */
+ struct aa_label *target = aa_label_merge(&profile->label,
+ transition, gfp);
+ if (!target)
+ return ERR_PTR(-ENOMEM);
+
+ /* doing this here is less than optimal but good enough until the
+ * fs mediation rework lands
+ */
+ struct aa_perms perms = {
+ .allow = request,
+ .audit = request,
+ };
+ aa_audit_file(subj_cred, profile, &perms, op,
+ request, name, NULL, target,
+ subj_cred->euid, stack_msg, 0);
+
+ return target;
+}
+
static struct aa_label *handle_onexec(const struct cred *subj_cred,
struct aa_label *label,
struct aa_label *onexec, bool stack,
@@ -835,7 +881,10 @@ static struct aa_label *handle_onexec(const struct cred *subj_cred,
if (error)
return ERR_PTR(error);
new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
- aa_get_newest_label(onexec),
+ priv_restricted_transition(subj_cred, profile,
+ OP_CHANGE_ONEXEC, AA_MAY_ONEXEC,
+ bprm->filename, onexec,
+ GFP_KERNEL),
profile_transition(subj_cred, profile, bprm,
buffer,
cond, unsafe));
@@ -1354,8 +1403,6 @@ static int change_profile_perms_wrapper(const char *op, const char *name,
return error;
}
-static const char *stack_msg = "change_profile unprivileged unconfined converted to stacking";
-
/**
* aa_change_profile - perform a one-way profile transition
* @fqname: name of profile may include namespace (NOT NULL)
@@ -1415,28 +1462,6 @@ int aa_change_profile(const char *fqname, int flags)
op = OP_CHANGE_PROFILE;
}
- /* This should move to a per profile test. Requires pushing build
- * into callback
- */
- if (!stack && unconfined(label) &&
- label == &labels_ns(label)->unconfined->label &&
- aa_unprivileged_unconfined_restricted &&
- /* TODO: refactor so this check is a fn */
- cap_capable(current_cred(), &init_user_ns, CAP_MAC_OVERRIDE,
- CAP_OPT_NOAUDIT)) {
- /* regardless of the request in this case apparmor
- * stacks against unconfined so admin set policy can't be
- * by-passed
- */
- stack = true;
- perms.audit = request;
- (void) fn_for_each_in_ns(label, profile,
- aa_audit_file(subj_cred, profile, &perms, op,
- request, auditname, NULL, target,
- GLOBAL_ROOT_UID, stack_msg, 0));
- perms.audit = 0;
- }
-
if (*fqname == '&') {
stack = true;
/* don't have label_parse() do stacking */
@@ -1507,7 +1532,10 @@ int aa_change_profile(const char *fqname, int flags)
/* stacking is always a subset, so only check the nonstack case */
if (!stack) {
new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
- aa_get_label(target),
+ priv_restricted_transition(subj_cred, profile,
+ op, request,
+ auditname, target,
+ GFP_KERNEL),
aa_get_label(&profile->label));
if (IS_ERR_OR_NULL(new))
goto build_fail;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 637/869] amt: Dont support cross-netns setup.
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (635 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 636/869] apparmor: fix unconfined user namespace restriction forced stack Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 638/869] NFS: Return a delegation the client fails to record Greg Kroah-Hartman
` (232 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kuniyuki Iwashima, Taehee Yoo,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit e99ecc3046ea5f5c6b5e1f8b4ef854c6c6998e06 ]
When a lower device is unregistered, amt_device_event() tries
to unregister its upper AMT device, but it has two problems.
1. amt_lookup_upper_dev() looks up an upper device in the
lower device's netns only
2. amt_device_event() unregisters a single upper device only
If AMT device is created on a lower device in another netns,
removing the lower device triggers the splat below and gets
stuck until all upper devices are removed. [0]
The cross-netns setup seems unintentional considering 1. and
the following points:
* amt_link_setup() sets dev->netns_immutable to true
* skb_scrub_packet() is not called in the fast path
* iproute2 binary fails to find cross-netns lower device via
link-netns:
# ip -n ns1 link add amt0 link-netns ns2 type amt dev veth1
Cannot find device "veth1"
Instead of supporting it properly and preparing for per-netns
netdev unreg, let's forbid cross-netns setup.
Note that the problem 2. needs a separate fix.
[0]:
WARNING: net/core/dev.c:12518 at unregister_netdevice_many_notify+0x1cce/0x2250, CPU#48: ip/2031
Modules linked in:
CPU: 48 UID: 0 PID: 2031 Comm: ip Not tainted 7.2.0-rc5+ #27 PREEMPT(full)
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
RIP: 0010:unregister_netdevice_many_notify (net/core/dev.c:12518)
Code: 89 ef e8 d5 52 ae fe e9 d0 f4 ff ff 48 8d 3d f9 3b 9c 02 48 c7 c6 c0 0b 63 84 ba ab 1f 00 00 67 48 0f b9 3a e9 65 ff ff ff 90 <0f> 0b 90 eb 81 48 8d 3d f6 3b 9c 02 48 c7 c6 c0 0b 63 84 ba e2 1f
RSP: 0018:ffffc90004abf160 EFLAGS: 00010212
RAX: ffff888104d38260 RBX: ffff88800b0911b8 RCX: dffffc0000000000
RDX: 0000000000000000 RSI: 0000000000000008 RDI: ffffffff85b9f880
RBP: ffffc90004abf2d0 R08: ffffffff85b9f887 R09: 1ffffffff0b73f10
R10: dffffc0000000000 R11: fffffbfff0b73f11 R12: ffff88800b091d08
R13: ffff88800b091178 R14: dffffc0000000000 R15: ffff88800b091000
FS: 00007f555b86c600(0000) GS:ffff8881942a0000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000562107d489c0 CR3: 0000000109a40002 CR4: 0000000000372ef0
Call Trace:
<TASK>
rtnl_dellink (net/core/rtnetlink.c:3632 net/core/rtnetlink.c:3674)
rtnetlink_rcv_msg (net/core/rtnetlink.c:7112)
netlink_rcv_skb (net/netlink/af_netlink.c:2556)
netlink_unicast (net/netlink/af_netlink.c:1319)
netlink_sendmsg (net/netlink/af_netlink.c:1900)
____sys_sendmsg (net/socket.c:775)
__sys_sendmsg (net/socket.c:2738)
do_syscall_64 (arch/x86/entry/syscall_64.c:63)
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
...
unregister_netdevice: waiting for veth0 to become free. Usage count = 7
ref_tracker: netdev@ffff88800d7496d8 has 3/3 users at
__netdev_adjacent_dev_insert (./include/linux/netdevice.h:4525 ./include/linux/netdevice.h:4554 net/core/dev.c:8791)
__netdev_upper_dev_link (net/core/dev.c:8879 net/core/dev.c:8963)
netdev_upper_dev_link (net/core/dev.c:9009)
amt_newlink (drivers/net/amt.c:3321)
Fixes: b9022b53adad ("amt: add control plane of amt interface")
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Taehee Yoo <ap420073@gmail.com>
Link: https://patch.msgid.link/20260807020326.2519445-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/amt.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index ac87ea8478077..bf890f90f51e2 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -3195,6 +3195,9 @@ static int amt_newlink(struct net *net, struct net_device *dev,
struct amt_dev *amt = netdev_priv(dev);
int err = -EINVAL;
+ if (!net_eq(net, dev_net(dev)))
+ return err;
+
amt->net = net;
amt->mode = nla_get_u32(data[IFLA_AMT_MODE]);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 638/869] NFS: Return a delegation the client fails to record
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (636 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 637/869] amt: Dont support cross-netns setup Greg Kroah-Hartman
@ 2026-10-17 15:57 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 639/869] iommu/vt-d: Flush context cache with correct SID when tearing down aliases Greg Kroah-Hartman
` (231 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:57 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Chuck Lever, Trond Myklebust,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <cel@kernel.org>
[ Upstream commit 220af23d863995091f0edeb1e6aa0945b3db8b37 ]
When an NFS server grants a delegation in an OPEN reply,
nfs_inode_set_delegation() records it on the client. However, three
of its error flows return without sending DELEGRETURN.
A delegation can be relinquished only by DELEGRETURN (RFC 8881
Section 20.2.4), so dropping one silently leaves the server believing
the client still holds it. If the server happens to recall that
delegation, the client answers CB_RECALL with NFS4ERR_BADHANDLE
because it has no record of the stateid. The server revokes the
delegation and moves it onto its cl_revoked list, because the client
never sends the FREE_STATEID that would drain it. Every subsequent
SEQUENCE reply then carries SEQ4_STATUS_RECALLABLE_STATE_REVOKED,
and the client's state manager loops issuing TEST_STATEID across its
delegations without ever clearing the condition.
The window is easy to reach now that a server offers a write
delegation on any write OPEN: a delegation recalled for one opener
races a re-open that the server answers with a fresh write
delegation.
Instead of dropping it, hand the delegation back during these error
flows.
Fixes: ade04647dd56 ("NFSv4: Ensure we honour NFS_DELEGATION_RETURNING in nfs_inode_set_delegation()")
Signed-off-by: Chuck Lever <cel@kernel.org>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfs/delegation.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index c1bbc358833dd..14a5f3cc3ef50 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -455,11 +455,14 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_delegation *delegation, *old_delegation;
struct nfs_delegation *freeme = NULL;
+ bool orphaned = false;
int status = 0;
delegation = kmalloc(sizeof(*delegation), GFP_KERNEL_ACCOUNT);
- if (delegation == NULL)
+ if (delegation == NULL) {
+ nfs4_proc_delegreturn(inode, cred, stateid, NULL, 0);
return -ENOMEM;
+ }
nfs4_stateid_copy(&delegation->stateid, stateid);
refcount_set(&delegation->refcount, 1);
delegation->type = type;
@@ -507,12 +510,16 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
goto out;
}
if (test_and_set_bit(NFS_DELEGATION_RETURNING,
- &old_delegation->flags))
+ &old_delegation->flags)) {
+ orphaned = true;
goto out;
+ }
}
freeme = nfs_detach_delegation_locked(nfsi, old_delegation, clp);
- if (freeme == NULL)
+ if (freeme == NULL) {
+ orphaned = true;
goto out;
+ }
add_new:
/*
* If we didn't revalidate the change attribute before setting
@@ -544,8 +551,11 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
nfs_update_delegated_mtime(inode);
out:
spin_unlock(&clp->cl_lock);
- if (delegation != NULL)
+ if (delegation != NULL) {
+ if (orphaned)
+ nfs_do_return_delegation(inode, delegation, 0);
__nfs_free_delegation(delegation);
+ }
if (freeme != NULL) {
nfs_do_return_delegation(inode, freeme, 0);
nfs_free_delegation(freeme);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 639/869] iommu/vt-d: Flush context cache with correct SID when tearing down aliases
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (637 preceding siblings ...)
2026-10-17 15:57 ` [PATCH 6.12 638/869] NFS: Return a delegation the client fails to record Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 640/869] bpf: Fix mmap_lock leak in irq_work path Greg Kroah-Hartman
` (230 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Lu Baolu, Samiullah Khawaja,
Joerg Roedel, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lu Baolu <baolu.lu@linux.intel.com>
[ Upstream commit c54e4ae971b98e8d650400137d332cee56c03f55 ]
domain_context_clear_one() and device_pasid_table_teardown() are both
invoked once per DMA alias of a device. Each function locates the context
entry using the bus/devfn pair provided by the pci_for_each_dma_alias()
callback, then calls intel_context_flush_no_pasid(), which constructs a
device-selective context-cache invalidation from info->bus and
info->devfn (that is, always the requester ID of the device itself).
As a result, for every alias other than the device’s own RID, the context
entry that was just cleared in memory is never invalidated in the context
cache. Hardware may continue using that stale cached entry. In the
scalable-mode teardown path, intel_pasid_free_table() can then free the
PASID directory still referenced by that stale entry, allowing the IOMMU
to walk freed memory.
Fix this by passing the source ID of the entry being torn down to
intel_context_flush_no_pasid(), instead of deriving it from @info.
Fixes: f90584f4beb84 ("iommu/vt-d: Add helper to flush caches for context change")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260602233426.357499-1-baolu.lu%40linux.intel.com
Assisted-by: Claude:claude-opus-5
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Samiullah Khawaja <skhawaja@google.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/iommu/intel/iommu.c | 4 ++--
drivers/iommu/intel/iommu.h | 2 +-
drivers/iommu/intel/pasid.c | 9 ++++++---
3 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 9da974068b828..94fd053816802 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -1921,7 +1921,7 @@ static void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8
context_clear_present(context);
__iommu_flush_cache(iommu, context, sizeof(*context));
spin_unlock(&iommu->lock);
- intel_context_flush_no_pasid(info, context, did);
+ intel_context_flush_no_pasid(info, context, did, PCI_DEVID(bus, devfn));
context_clear_entry(context);
__iommu_flush_cache(iommu, context, sizeof(*context));
}
@@ -4164,7 +4164,7 @@ static int context_flip_pri(struct device_domain_info *info, bool enable)
if (!ecap_coherent(iommu->ecap))
clflush_cache_range(context, sizeof(*context));
- intel_context_flush_no_pasid(info, context, did);
+ intel_context_flush_no_pasid(info, context, did, PCI_DEVID(bus, devfn));
spin_unlock(&iommu->lock);
return 0;
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index b8d09b00f3945..f94d739c2291e 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -1297,7 +1297,7 @@ void cache_tag_flush_range_np(struct dmar_domain *domain, unsigned long start,
unsigned long end);
void intel_context_flush_no_pasid(struct device_domain_info *info,
- struct context_entry *context, u16 did);
+ struct context_entry *context, u16 did, u16 sid);
int intel_iommu_enable_prq(struct intel_iommu *iommu);
int intel_iommu_finish_prq(struct intel_iommu *iommu);
diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
index 93e9b9243d5fd..dbf1e775fd806 100644
--- a/drivers/iommu/intel/pasid.c
+++ b/drivers/iommu/intel/pasid.c
@@ -717,7 +717,7 @@ static void device_pasid_table_teardown(struct device *dev, u8 bus, u8 devfn)
context_clear_present(context);
__iommu_flush_cache(iommu, context, sizeof(*context));
spin_unlock(&iommu->lock);
- intel_context_flush_no_pasid(info, context, did);
+ intel_context_flush_no_pasid(info, context, did, PCI_DEVID(bus, devfn));
context_clear_entry(context);
__iommu_flush_cache(iommu, context, sizeof(*context));
}
@@ -919,9 +919,12 @@ static void __context_flush_dev_iotlb(struct device_domain_info *info)
* This helper can only be used when IOMMU is working in the legacy mode or
* IOMMU is in scalable mode but all PASID table entries of the device are
* non-present.
+ *
+ * @sid identifies the context entry that was modified, which may be a DMA
+ * alias of @info->dev rather than its own requester ID.
*/
void intel_context_flush_no_pasid(struct device_domain_info *info,
- struct context_entry *context, u16 did)
+ struct context_entry *context, u16 did, u16 sid)
{
struct intel_iommu *iommu = info->iommu;
@@ -931,7 +934,7 @@ void intel_context_flush_no_pasid(struct device_domain_info *info,
* when operating in scalable mode. Therefore the @did value doesn't
* matter in scalable mode.
*/
- iommu->flush.flush_context(iommu, did, PCI_DEVID(info->bus, info->devfn),
+ iommu->flush.flush_context(iommu, did, sid,
DMA_CCMD_MASK_NOBIT, DMA_CCMD_DEVICE_INVL);
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 640/869] bpf: Fix mmap_lock leak in irq_work path
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (638 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 639/869] iommu/vt-d: Flush context cache with correct SID when tearing down aliases Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 641/869] Bluetooth: ISO: fix race of kfree vs kref_get_unless_zero Greg Kroah-Hartman
` (229 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+cdd6c0925e12b0af60cc,
sashiko-bot, Sanghyun Park, Andrii Nakryiko, Daniel Borkmann,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanghyun Park <sanghyun.park.cnu@gmail.com>
[ Upstream commit fa9dcacdcdf487f0ffef64bf67622f1caed509f1 ]
stack_map_get_build_id_offset() introduced a per-CPU irq_work to defer
mmap_read_unlock() from NMI context, and bpf_find_vma() later reused the
same mmap_unlock_work. Both callers only check whether the work is busy
before taking mmap_lock, so a nested caller can reuse the slot before the
first caller queues it. Two read locks may then be acquired while only one
deferred unlock runs, leaking a read lock and blocking exit_mmap().
Reserve the per-CPU slot before mmap_read_trylock(). Use the same wrapper
in stackmap and bpf_find_vma() so both callers release the reservation on
trylock failure. Keep rejecting the slot while the irq_work remains busy.
Release it after the irq_work callback unlocks the mm.
Fixes: eac9153f2b58 ("bpf/stackmap: Fix deadlock with rq_lock in bpf_get_stack()")
Reported-by: syzbot+cdd6c0925e12b0af60cc@syzkaller.appspotmail.com
Reported-by: sashiko-bot@kernel.org
Signed-off-by: Sanghyun Park <sanghyun.park.cnu@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Closes: https://syzkaller.appspot.com/bug?extid=cdd6c0925e12b0af60cc
Closes: https://lore.kernel.org/r/20260630033745.B80201F000E9@smtp.kernel.org
Link: https://lore.kernel.org/bpf/20260805031425.2157475-2-sanghyun.park.cnu@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/mmap_unlock_work.h | 51 ++++++++++++++++++++---------------
kernel/bpf/stackmap.c | 33 +++++++++++++----------
kernel/bpf/task_iter.c | 14 +++++++---
3 files changed, 58 insertions(+), 40 deletions(-)
diff --git a/kernel/bpf/mmap_unlock_work.h b/kernel/bpf/mmap_unlock_work.h
index 5d18d7d85bef9..1834db20b8612 100644
--- a/kernel/bpf/mmap_unlock_work.h
+++ b/kernel/bpf/mmap_unlock_work.h
@@ -4,12 +4,15 @@
#ifndef __MMAP_UNLOCK_WORK_H__
#define __MMAP_UNLOCK_WORK_H__
+#include <linux/atomic.h>
+#include <linux/err.h>
#include <linux/irq_work.h>
/* irq_work to run mmap_read_unlock() in irq_work */
struct mmap_unlock_irq_work {
struct irq_work irq_work;
struct mm_struct *mm;
+ atomic_t active;
};
DECLARE_PER_CPU(struct mmap_unlock_irq_work, mmap_unlock_work);
@@ -18,32 +21,36 @@ DECLARE_PER_CPU(struct mmap_unlock_irq_work, mmap_unlock_work);
* We cannot do mmap_read_unlock() when the irq is disabled, because of
* risk to deadlock with rq_lock. To look up vma when the irqs are
* disabled, we need to run mmap_read_unlock() in irq_work. We use a
- * percpu variable to do the irq_work. If the irq_work is already used
- * by another lookup, we fall over.
+ * percpu variable to do the irq_work. The active flag reserves the slot
+ * before mmap_read_trylock() and until the irq_work callback consumes mm.
*/
-static inline bool bpf_mmap_unlock_get_irq_work(struct mmap_unlock_irq_work **work_ptr)
+static inline struct mmap_unlock_irq_work *bpf_mmap_unlock_guard_get(void)
{
- struct mmap_unlock_irq_work *work = NULL;
- bool irq_work_busy = false;
+ struct mmap_unlock_irq_work *work;
- if (irqs_disabled()) {
- if (!IS_ENABLED(CONFIG_PREEMPT_RT)) {
- work = this_cpu_ptr(&mmap_unlock_work);
- if (irq_work_is_busy(&work->irq_work)) {
- /* cannot queue more up_read, fallback */
- irq_work_busy = true;
- }
- } else {
- /*
- * PREEMPT_RT does not allow to trylock mmap sem in
- * interrupt disabled context. Force the fallback code.
- */
- irq_work_busy = true;
- }
- }
+ if (!irqs_disabled())
+ return NULL;
+
+ /*
+ * PREEMPT_RT does not allow to trylock mmap sem in interrupt
+ * disabled context. Force the fallback code.
+ */
+ if (IS_ENABLED(CONFIG_PREEMPT_RT))
+ return ERR_PTR(-EBUSY);
+
+ work = this_cpu_ptr(&mmap_unlock_work);
+ if (irq_work_is_busy(&work->irq_work) ||
+ atomic_cmpxchg_acquire(&work->active, 0, 1))
+ return ERR_PTR(-EBUSY);
- *work_ptr = work;
- return irq_work_busy;
+ return work;
+}
+
+static inline void
+bpf_mmap_unlock_guard_put(struct mmap_unlock_irq_work *work)
+{
+ if (work)
+ atomic_set_release(&work->active, 0);
}
static inline void bpf_mmap_unlock_mm(struct mmap_unlock_irq_work *work, struct mm_struct *mm)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index d0c7c5713dc45..ebab2f0374b88 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -166,23 +166,20 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
u32 trace_nr, bool user, bool may_fault)
{
int i;
- struct mmap_unlock_irq_work *work = NULL;
- bool irq_work_busy = bpf_mmap_unlock_get_irq_work(&work);
+ struct mmap_unlock_irq_work *work;
struct vm_area_struct *vma, *prev_vma = NULL;
const char *prev_build_id;
- /* If the irq_work is in use, fall back to report ips. Same
- * fallback is used for kernel stack (!user) on a stackmap with
- * build_id.
- */
- if (!user || !current || !current->mm || irq_work_busy ||
- !mmap_read_trylock(current->mm)) {
- /* cannot access current->mm, fall back to ips */
- for (i = 0; i < trace_nr; i++) {
- id_offs[i].status = BPF_STACK_BUILD_ID_IP;
- memset(id_offs[i].build_id, 0, BUILD_ID_SIZE_MAX);
- }
- return;
+ if (!user || !current || !current->mm)
+ goto fallback;
+
+ work = bpf_mmap_unlock_guard_get();
+ if (IS_ERR(work))
+ goto fallback;
+
+ if (!mmap_read_trylock(current->mm)) {
+ bpf_mmap_unlock_guard_put(work);
+ goto fallback;
}
for (i = 0; i < trace_nr; i++) {
@@ -207,6 +204,14 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
prev_build_id = id_offs[i].build_id;
}
bpf_mmap_unlock_mm(work, current->mm);
+ return;
+
+fallback:
+ /* cannot access current->mm, fall back to ips */
+ for (i = 0; i < trace_nr; i++) {
+ id_offs[i].status = BPF_STACK_BUILD_ID_IP;
+ memset(id_offs[i].build_id, 0, BUILD_ID_SIZE_MAX);
+ }
}
static struct perf_callchain_entry *
diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
index f3a7a96a77d7d..1b36cbc3d25c0 100644
--- a/kernel/bpf/task_iter.c
+++ b/kernel/bpf/task_iter.c
@@ -757,9 +757,8 @@ static struct bpf_iter_reg task_vma_reg_info = {
BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
bpf_callback_t, callback_fn, void *, callback_ctx, u64, flags)
{
- struct mmap_unlock_irq_work *work = NULL;
+ struct mmap_unlock_irq_work *work;
struct vm_area_struct *vma;
- bool irq_work_busy = false;
bool __maybe_unused mmput_needed = false;
struct mm_struct *mm;
int ret = -ENOENT;
@@ -796,9 +795,14 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start,
if (!mm)
return -ENOENT;
- irq_work_busy = bpf_mmap_unlock_get_irq_work(&work);
+ work = bpf_mmap_unlock_guard_get();
+ if (IS_ERR(work)) {
+ ret = PTR_ERR(work);
+ goto out;
+ }
- if (irq_work_busy || !mmap_read_trylock(mm)) {
+ if (!mmap_read_trylock(mm)) {
+ bpf_mmap_unlock_guard_put(work);
ret = -EBUSY;
goto out;
}
@@ -1195,6 +1199,8 @@ static void do_mmap_read_unlock(struct irq_work *entry)
work = container_of(entry, struct mmap_unlock_irq_work, irq_work);
mmap_read_unlock_non_owner(work->mm);
+ work->mm = NULL;
+ bpf_mmap_unlock_guard_put(work);
}
static int __init task_iter_init(void)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 641/869] Bluetooth: ISO: fix race of kfree vs kref_get_unless_zero
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (639 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 640/869] bpf: Fix mmap_lock leak in irq_work path Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 642/869] Bluetooth: L2CAP: use proto_lock for l2cap_data to fix l2cap_disconn_ind Greg Kroah-Hartman
` (228 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pauli Virtanen,
Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <pav@iki.fi>
[ Upstream commit af24e338bf5dafb80f42baa9a0b9e9b57b1c5d9c ]
hci_conn::iso_data is accessed and modified without lock or RCU.
This leads to a race
[Task hdev->workqueue] [Task 2]
iso_recv iso_conn_put(conn)
conn = LOAD hcon->iso_data iso_conn_free(conn)
iso_conn_hold_unless_zero(conn) hcon->iso_data = NULL
kfree(conn)
kref_get_unless_zero(&conn->ref) /* UAF */
and also to races in iso_conn_add() vs. iso_conn_free().
Fix by adding spinlock hci_conn::proto_lock and using it to guard
hci_conn::iso_data.
Fixes: dc26097bdb86 ("Bluetooth: ISO: Use kref to track lifetime of iso_conn")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Stable-dep-of: 2b66c83ff175 ("Bluetooth: L2CAP: use proto_lock for l2cap_data to fix l2cap_disconn_ind")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/bluetooth/hci_core.h | 2 ++
net/bluetooth/hci_conn.c | 2 ++
2 files changed, 4 insertions(+)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 763f003ac29e3..f846865db0ca4 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -751,6 +751,8 @@ struct hci_conn {
struct dentry *debugfs;
struct hci_dev *hdev;
+
+ spinlock_t proto_lock; /* lock guarding protocol data */
void *l2cap_data;
void *sco_data;
void *iso_data;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 48d28c79e2992..602b5be7eccc8 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1052,6 +1052,8 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
INIT_DELAYED_WORK(&conn->idle_work, hci_conn_idle);
INIT_DELAYED_WORK(&conn->le_conn_timeout, le_conn_timeout);
+ spin_lock_init(&conn->proto_lock);
+
atomic_set(&conn->refcnt, 0);
hci_dev_hold(hdev);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 642/869] Bluetooth: L2CAP: use proto_lock for l2cap_data to fix l2cap_disconn_ind
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (640 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 641/869] Bluetooth: ISO: fix race of kfree vs kref_get_unless_zero Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 643/869] btrfs: qgroup: fix a wrong length calculation in qgroup_free_reserved_data() Greg Kroah-Hartman
` (227 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+9c40ad7c6ed7165e46e8,
Pauli Virtanen, Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <pav@iki.fi>
[ Upstream commit 2b66c83ff1751d6bd3201b3017206262ab46dc05 ]
hci_conn::l2cap_data is accessed without locks in l2cap_disconn_ind via
hci_conn_timeout (disc_work) -> hci_proto_disconn_ind ->
l2cap_disconn_ind. This is UAF if the l2cap_conn is deleted
concurrently.
disc_work is disabled sync in hci_conn_del(), so we cannot take
hci_dev_lock in disc_work.
Fix by using proto_lock to guard l2cap_data, in addition to hdev->lock
which is held in other access paths.
Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del")
Reported-by: syzbot+9c40ad7c6ed7165e46e8@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9c40ad7c6ed7165e46e8
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/l2cap_core.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 12d39f1e822b3..61914f280d6fa 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1843,7 +1843,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
hci_chan_del(conn->hchan);
conn->hchan = NULL;
+ spin_lock(&hcon->proto_lock);
hcon->l2cap_data = NULL;
+ spin_unlock(&hcon->proto_lock);
+
mutex_unlock(&conn->lock);
l2cap_conn_put(conn);
}
@@ -7167,8 +7170,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
}
kref_init(&conn->ref);
- hcon->l2cap_data = conn;
- conn->hcon = hci_conn_get(hcon);
conn->hchan = hchan;
BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
@@ -7197,6 +7198,11 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
+ spin_lock(&hcon->proto_lock);
+ conn->hcon = hci_conn_get(hcon);
+ hcon->l2cap_data = conn;
+ spin_unlock(&hcon->proto_lock);
+
return conn;
}
@@ -7585,13 +7591,18 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
int l2cap_disconn_ind(struct hci_conn *hcon)
{
- struct l2cap_conn *conn = hcon->l2cap_data;
+ struct l2cap_conn *conn;
+ int ret = HCI_ERROR_REMOTE_USER_TERM;
BT_DBG("hcon %p", hcon);
- if (!conn)
- return HCI_ERROR_REMOTE_USER_TERM;
- return conn->disc_reason;
+ spin_lock(&hcon->proto_lock);
+ conn = hcon->l2cap_data;
+ if (conn)
+ ret = conn->disc_reason;
+ spin_unlock(&hcon->proto_lock);
+
+ return ret;
}
static void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 643/869] btrfs: qgroup: fix a wrong length calculation in qgroup_free_reserved_data()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (641 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 642/869] Bluetooth: L2CAP: use proto_lock for l2cap_data to fix l2cap_disconn_ind Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 644/869] btrfs: zoned: dont clobber the extent buffer when zeroing it out Greg Kroah-Hartman
` (226 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Filipe Manana, Qu Wenruo,
David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <wqu@suse.com>
[ Upstream commit 9102b179512e11644fb0489ae62010a09afa199c ]
In that function, we round down the start position and round up the
ending position.
But during the calculation of @len, we use "round_up(start + len,
sectorsize)", which is the rounded up end position, not the rounded up
length.
Which results a much larger length, and later we are still using
"start + len", which is completely incorrect.
Fix it by declaring a local @aligned_start and @aligned_len and use them
instead.
Fixes: bc42bda22345 ("btrfs: qgroup: Fix qgroup reserved space underflow by only freeing reserved ranges")
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/qgroup.c | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 5b158eb25d181..57552c414b43a 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -4371,12 +4371,13 @@ static int qgroup_free_reserved_data(struct btrfs_inode *inode,
struct ulist_node *unode;
struct ulist_iterator uiter;
struct extent_changeset changeset;
+ const u32 sectorsize = root->fs_info->sectorsize;
+ const u64 aligned_start = round_down(start, sectorsize);
+ const u64 aligned_len = round_up(start + len, sectorsize) - aligned_start;
u64 freed = 0;
int ret;
extent_changeset_init(&changeset);
- len = round_up(start + len, root->fs_info->sectorsize);
- start = round_down(start, root->fs_info->sectorsize);
ULIST_ITER_INIT(&uiter);
while ((unode = ulist_next(&reserved->range_changed, &uiter))) {
@@ -4388,12 +4389,15 @@ static int qgroup_free_reserved_data(struct btrfs_inode *inode,
extent_changeset_release(&changeset);
- /* Only free range in range [start, start + len) */
- if (range_start >= start + len ||
- range_start + range_len <= start)
+ /*
+ * Only free the range within
+ * [aligned_start, aligned_start + aligned_len).
+ */
+ if (range_start >= aligned_start + aligned_len ||
+ range_start + range_len <= aligned_start)
continue;
- free_start = max(range_start, start);
- free_len = min(start + len, range_start + range_len) -
+ free_start = max(range_start, aligned_start);
+ free_len = min(aligned_start + aligned_len, range_start + range_len) -
free_start;
/*
* TODO: To also modify reserved->ranges_reserved to reflect
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 644/869] btrfs: zoned: dont clobber the extent buffer when zeroing it out
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (642 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 643/869] btrfs: qgroup: fix a wrong length calculation in qgroup_free_reserved_data() Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 645/869] btrfs: check if root is readonly when setting posix acl Greg Kroah-Hartman
` (225 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Boris Burkov, Johannes Thumshirn,
David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
[ Upstream commit db4b9eefc8ee0bcaeee4d5e6a7313905f6a2fe7c ]
On a zoned filesystem a freed-but-still-dirty tree block is written out
as zeros (EXTENT_BUFFER_ZONED_ZEROOUT) only to keep the zone write
pointer advancing. btree_csum_one_bio() implemented this by memzeroing
the extent buffer's own folios before submission.
That destroys the in-memory buffer while it may still be referenced. In
particular btrfs_free_tree_block() can run on it afterwards and reads
the header to add a delayed reference; once the header has been zeroed
it frees bytenr 0 and corrupts the extent tree (the
btrfs_header_bytenr(buf) != 0 ASSERT in btrfs_free_tree_block(), or an
"unable to find ref" abort). It is flaky and reproduces under fsstress,
e.g. generic/461 and generic/013.
Write the zeros to disk from the shared zero page instead and leave the
extent buffer content untouched, so any later reference - including the
delayed reference from btrfs_free_tree_block() - still sees a valid
header. end_bbio_meta_write() now clears writeback on the buffer's own
folios, as the bio no longer carries them.
Fixes: aa6313e6ff2b ("btrfs: zoned: don't clear dirty flag of extent buffer")
Assisted-by: LLM (debugging, commit message)
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/disk-io.c | 13 +++++-----
fs/btrfs/extent_io.c | 58 +++++++++++++++++++++++++++++++++++---------
2 files changed, 53 insertions(+), 18 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 74af70897bcb0..d1f245ef1911f 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -272,14 +272,15 @@ blk_status_t btree_csum_one_bio(struct btrfs_bio *bbio)
return BLK_STS_IOERR;
/*
- * If an extent_buffer is marked as EXTENT_BUFFER_ZONED_ZEROOUT, don't
- * checksum it but zero-out its content. This is done to preserve
- * ordering of I/O without unnecessarily writing out data.
+ * An extent_buffer marked EXTENT_BUFFER_ZONED_ZEROOUT is written out as
+ * zeros to preserve ordering of I/O without persisting the now
+ * unnecessary block. The bio is fed from the shared zero page (see
+ * write_one_eb()), so there is nothing to checksum here. Crucially, the
+ * buffer's own content is left intact: it may still be referenced, e.g.
+ * btrfs_free_tree_block() reads its header to add a delayed reference.
*/
- if (test_bit(EXTENT_BUFFER_ZONED_ZEROOUT, &eb->bflags)) {
- memzero_extent_buffer(eb, 0, eb->len);
+ if (test_bit(EXTENT_BUFFER_ZONED_ZEROOUT, &eb->bflags))
return BLK_STS_OK;
- }
if (WARN_ON_ONCE(found_start != eb->start))
return BLK_STS_IOERR;
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 8753ce416c5c6..dbb81c58a2e3c 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1839,18 +1839,21 @@ static void end_bbio_meta_write(struct btrfs_bio *bbio)
struct extent_buffer *eb = bbio->private;
struct btrfs_fs_info *fs_info = eb->fs_info;
bool uptodate = !bbio->bio.bi_status;
- struct folio_iter fi;
u32 bio_offset = 0;
if (!uptodate)
set_btree_ioerr(eb);
- bio_for_each_folio_all(fi, &bbio->bio) {
- u64 start = eb->start + bio_offset;
- struct folio *folio = fi.folio;
- u32 len = fi.length;
+ /*
+ * Clear writeback on the buffer's own folios. The bio may carry the
+ * shared zero page instead (EXTENT_BUFFER_ZONED_ZEROOUT), so iterate
+ * the extent buffer folios rather than the bio folios.
+ */
+ for (int i = 0; i < num_extent_folios(eb); i++) {
+ u32 len = min(eb->len - bio_offset, (u32)eb->folio_size);
- btrfs_folio_clear_writeback(fs_info, folio, start, len);
+ btrfs_folio_clear_writeback(fs_info, eb->folios[i],
+ eb->start + bio_offset, len);
bio_offset += len;
}
@@ -1895,7 +1898,8 @@ static noinline_for_stack void write_one_eb(struct extent_buffer *eb,
struct btrfs_fs_info *fs_info = eb->fs_info;
struct btrfs_bio *bbio;
- prepare_eb_write(eb);
+ if (!test_bit(EXTENT_BUFFER_ZONED_ZEROOUT, &eb->bflags))
+ prepare_eb_write(eb);
bbio = btrfs_bio_alloc(INLINE_EXTENT_BUFFER_PAGES,
REQ_OP_WRITE | REQ_META | wbc_to_write_flags(wbc),
@@ -1916,9 +1920,23 @@ static noinline_for_stack void write_one_eb(struct extent_buffer *eb,
folio_clear_dirty_for_io(folio);
wbc->nr_to_write--;
}
- ret = bio_add_folio(&bbio->bio, folio, eb->len,
- eb->start - folio_pos(folio));
- ASSERT(ret);
+ if (test_bit(EXTENT_BUFFER_ZONED_ZEROOUT, &eb->bflags)) {
+ u32 off = 0;
+
+ while (off < eb->len) {
+ u32 add = min_t(u32, PAGE_SIZE, eb->len - off);
+
+ ret = bio_add_folio(&bbio->bio,
+ page_folio(ZERO_PAGE(0)),
+ add, 0);
+ ASSERT(ret);
+ off += add;
+ }
+ } else {
+ ret = bio_add_folio(&bbio->bio, folio, eb->len,
+ eb->start - folio_pos(folio));
+ ASSERT(ret);
+ }
wbc_account_cgroup_owner(wbc, folio, eb->len);
folio_unlock(folio);
} else {
@@ -1931,8 +1949,24 @@ static noinline_for_stack void write_one_eb(struct extent_buffer *eb,
folio_lock(folio);
folio_clear_dirty_for_io(folio);
folio_start_writeback(folio);
- ret = bio_add_folio(&bbio->bio, folio, eb->folio_size, 0);
- ASSERT(ret);
+ if (test_bit(EXTENT_BUFFER_ZONED_ZEROOUT, &eb->bflags)) {
+ u32 off = 0;
+
+ while (off < eb->folio_size) {
+ u32 add = min_t(u32, PAGE_SIZE,
+ eb->folio_size - off);
+
+ ret = bio_add_folio(&bbio->bio,
+ page_folio(ZERO_PAGE(0)),
+ add, 0);
+ ASSERT(ret);
+ off += add;
+ }
+ } else {
+ ret = bio_add_folio(&bbio->bio, folio,
+ eb->folio_size, 0);
+ ASSERT(ret);
+ }
wbc_account_cgroup_owner(wbc, folio, eb->folio_size);
wbc->nr_to_write -= folio_nr_pages(folio);
folio_unlock(folio);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 645/869] btrfs: check if root is readonly when setting posix acl
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (643 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 644/869] btrfs: zoned: dont clobber the extent buffer when zeroing it out Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 646/869] btrfs: always wait for ordered extents to avoid OE races Greg Kroah-Hartman
` (224 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johannes Thumshirn, Filipe Manana,
Sun YangKai, David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sun YangKai <sunyangkai@fnnas.com>
[ Upstream commit 01c2f41fc441f75b3f9326443372faceb1cb6638 ]
For a filesystem which has btrfs read-only property set to true, all
write operations including acl and xattr should be denied. However, acl
can still be set even if btrfs ro property is true.
This happens because no function on the set_acl code path checks the root
is readonly or not. It was checked in btrfs_setxattr_trans() but got
removed in commit 353c2ea735e4 ("btrfs: remove redundant readonly root
check in btrfs_setxattr_trans")
That commit didn't check if all the callers properly check the root's
read-only flag. A previous fix is commit b51111271b03 ("btrfs: check if
root is readonly while setting security xattr").
Always check if the root is read-only before performing the set acl
operation.
Fixes: 353c2ea735e4 ("btrfs: remove redundant readonly root check in btrfs_setxattr_trans")
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Sun YangKai <sunyangkai@fnnas.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/acl.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index e0ba00d64ea0b..d1c67faacc187 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -14,6 +14,7 @@
#include "ctree.h"
#include "xattr.h"
#include "acl.h"
+#include "btrfs_inode.h"
struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
{
@@ -116,6 +117,9 @@ int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
struct inode *inode = d_inode(dentry);
umode_t old_mode = inode->i_mode;
+ if (btrfs_root_readonly(BTRFS_I(inode)->root))
+ return -EROFS;
+
if (type == ACL_TYPE_ACCESS && acl) {
ret = posix_acl_update_mode(idmap, inode,
&inode->i_mode, &acl);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 646/869] btrfs: always wait for ordered extents to avoid OE races
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (644 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 645/869] btrfs: check if root is readonly when setting posix acl Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 647/869] btrfs: defrag: fix deadlock between defrag and delalloc space reservation Greg Kroah-Hartman
` (223 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+ba2afde329fc27e3f22e,
Filipe Manana, Qu Wenruo, David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <wqu@suse.com>
[ Upstream commit ec78575dde998c21be7e0cb2503b5620f34b6255 ]
[BUG]
Syzbot reported a bug that there can be conflicting OEs for the same
range:
BTRFS critical (device loop4): panic in insert_ordered_extent:264: overlapping ordered extents, existing oe file_offset 16384 num_bytes 430080 flags 0x1089, new oe file_offset 16384 num_bytes 430080 flags 0x80 (errno=-17 Object alrea[ 179.162726][ T6897] BTRFS critical (device loop4): panic in insert_ordered_extent:264: overlapping ordered extents, existing oe file_offset 16384 num_bytes 430080 flags 0x1089, new oe file_offset 16384 num_bytes 430080 flags 0x80 (errno=-17 Object already exists)
------------[ cut here ]------------
kernel BUG at fs/btrfs/ordered-data.c:264!
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/09/2026
RIP: 0010:btrfs_alloc_ordered_extent+0x943/0xad0
Call Trace:
<TASK>
cow_file_range+0x744/0x12a0
fallback_to_cow+0x5ea/0xa00
run_delalloc_nocow+0x110c/0x17a0
btrfs_run_delalloc_range+0xbe4/0x1c20
writepage_delalloc+0x104d/0x1ba0
btrfs_writepages+0x1667/0x28b0
do_writepages+0x338/0x560
filemap_fdatawrite_range+0x1f2/0x300
btrfs_fdatawrite_range+0x54/0xf0
btrfs_direct_write+0x6a0/0xc30
btrfs_do_write_iter+0x329/0x790
do_iter_readv_writev+0x624/0x8d0
vfs_writev+0x34c/0x990
__se_sys_pwritev2+0x17a/0x2a0
do_syscall_64+0x174/0x580
entry_SYSCALL_64_after_hwframe+0x77/0x7f
</TASK>
---[ end trace 0000000000000000 ]---
[CAUSE]
Since commit ff66fe666233 ("btrfs: fix incorrect buffered IO fallback
for append direct writes"), if the direct IO finished short, we will
revert the isize back to the original one, so that append writes can be
respected during the buffered fallback.
Normally we rely on lock_and_cleanup_extent_if_need() function during
buffered writeback to wait for any existing ordered extents.
But that ordered extent waiting only happens if the start_pos is inside
the isize.
Since we have reverted the isize during failed direct IO, we will not
wait for any ordered extents.
This means we can have a race where the direct IO OE is still in the
tree, finished but not yet removed, then we're inserting the OE for the
buffered write, causing the above crash.
[FIX]
Make the OE wait to be unconditional, to handle the reverted isize
situation.
And since lock_and_cleanup_extent_if_need() now either lock the
extents or return -EAGAIN, also remove the branches that handles
no-extent-locked cases, and rename it to remove the "_if_need" suffix.
The following micro benchmark shows the runtime difference for
btrfs_buffered_write(), doing `xfs_io -f -c "pwrite 0 1m"` workload,
all values are the average runtime in nano seconds.
function runtime | before | after
-----------------------------------+-------------+---------------
lock_and_cleanup_extent_if_need() | 58.2 | 183.0
btrfs_buffered_write() | 2115.6 | 2973.3
The overall runtime of btrfs_buffered_write() is still pretty
tiny (still less than 3 micro seconds), I'd say the extra cost is still
acceptable.
An alternative to fix this problem is to wait ordered extents during
iomap_end() where the isize revert is done.
But that solution will break nowait requirement, as if a nowait direct
IO finished short, we have to wait for the OEs unconditionally or the
next append buffered IO can still hit the same problem.
So here we have to move the wait cost to buffered write, but at least
the code is slightly more streamline.
Reported-by: syzbot+ba2afde329fc27e3f22e@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=ba2afde329fc27e3f22e
Fixes: ff66fe666233 ("btrfs: fix incorrect buffered IO fallback for append direct writes")
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/file.c | 101 ++++++++++++++++++++----------------------------
1 file changed, 41 insertions(+), 60 deletions(-)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 5627e2f7dd64a..c885c9a221094 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -969,70 +969,64 @@ static noinline int prepare_pages(struct inode *inode, struct page **pages,
/*
* This function locks the extent and properly waits for data=ordered extents
- * to finish before allowing the pages to be modified if need.
+ * to finish before allowing the pages to be modified.
*
* The return value:
- * 1 - the extent is locked
- * 0 - the extent is not locked, and everything is OK
+ * 0 - the extent is locked
* -EAGAIN - need re-prepare the pages
* the other < 0 number - Something wrong happens
*/
static noinline int
-lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages,
- size_t num_pages, loff_t pos,
- size_t write_bytes,
- u64 *lockstart, u64 *lockend, bool nowait,
- struct extent_state **cached_state)
+lock_and_cleanup_extent(struct btrfs_inode *inode, struct page **pages,
+ size_t num_pages, loff_t pos,
+ size_t write_bytes,
+ u64 *lockstart, u64 *lockend, bool nowait,
+ struct extent_state **cached_state)
{
struct btrfs_fs_info *fs_info = inode->root->fs_info;
+ struct btrfs_ordered_extent *ordered;
u64 start_pos;
u64 last_pos;
int i;
- int ret = 0;
start_pos = round_down(pos, fs_info->sectorsize);
last_pos = round_up(pos + write_bytes, fs_info->sectorsize) - 1;
- if (start_pos < inode->vfs_inode.i_size) {
- struct btrfs_ordered_extent *ordered;
-
- if (nowait) {
- if (!btrfs_try_lock_extent(&inode->io_tree, start_pos, last_pos,
- cached_state)) {
- for (i = 0; i < num_pages; i++) {
- unlock_page(pages[i]);
- put_page(pages[i]);
- pages[i] = NULL;
- }
-
- return -EAGAIN;
- }
- } else {
- btrfs_lock_extent(&inode->io_tree, start_pos, last_pos, cached_state);
- }
-
- ordered = btrfs_lookup_ordered_range(inode, start_pos,
- last_pos - start_pos + 1);
- if (ordered &&
- ordered->file_offset + ordered->num_bytes > start_pos &&
- ordered->file_offset <= last_pos) {
- btrfs_unlock_extent(&inode->io_tree, start_pos, last_pos,
- cached_state);
+ if (nowait) {
+ if (!btrfs_try_lock_extent(&inode->io_tree, start_pos, last_pos,
+ cached_state)) {
for (i = 0; i < num_pages; i++) {
unlock_page(pages[i]);
put_page(pages[i]);
+ pages[i] = NULL;
}
- btrfs_start_ordered_extent(ordered);
- btrfs_put_ordered_extent(ordered);
+
return -EAGAIN;
}
- if (ordered)
- btrfs_put_ordered_extent(ordered);
+ } else {
+ btrfs_lock_extent(&inode->io_tree, start_pos, last_pos, cached_state);
+ }
- *lockstart = start_pos;
- *lockend = last_pos;
- ret = 1;
+ ordered = btrfs_lookup_ordered_range(inode, start_pos,
+ last_pos - start_pos + 1);
+ if (ordered &&
+ ordered->file_offset + ordered->num_bytes > start_pos &&
+ ordered->file_offset <= last_pos) {
+ btrfs_unlock_extent(&inode->io_tree, start_pos, last_pos,
+ cached_state);
+ for (i = 0; i < num_pages; i++) {
+ unlock_page(pages[i]);
+ put_page(pages[i]);
+ }
+ btrfs_start_ordered_extent(ordered);
+ btrfs_put_ordered_extent(ordered);
+ return -EAGAIN;
}
+ if (ordered)
+ btrfs_put_ordered_extent(ordered);
+
+ *lockstart = start_pos;
+ *lockend = last_pos;
/*
* We should be called after prepare_pages() which should have locked
@@ -1041,7 +1035,7 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages,
for (i = 0; i < num_pages; i++)
WARN_ON(!PageLocked(pages[i]));
- return ret;
+ return 0;
}
/*
@@ -1242,7 +1236,6 @@ ssize_t btrfs_buffered_write(struct kiocb *iocb, struct iov_iter *i)
size_t copied;
size_t dirty_sectors;
size_t num_sectors;
- int extents_locked;
/*
* Fault pages before locking them in prepare_pages
@@ -1326,17 +1319,15 @@ ssize_t btrfs_buffered_write(struct kiocb *iocb, struct iov_iter *i)
break;
}
- extents_locked = lock_and_cleanup_extent_if_need(
- BTRFS_I(inode), pages,
+ ret = lock_and_cleanup_extent(BTRFS_I(inode), pages,
num_pages, pos, write_bytes, &lockstart,
&lockend, nowait, &cached_state);
- if (extents_locked < 0) {
- if (!nowait && extents_locked == -EAGAIN)
+ if (ret < 0) {
+ if (!nowait)
goto again;
btrfs_delalloc_release_extents(BTRFS_I(inode),
reserve_bytes);
- ret = extents_locked;
break;
}
@@ -1389,18 +1380,8 @@ ssize_t btrfs_buffered_write(struct kiocb *iocb, struct iov_iter *i)
dirty_pages, pos, copied,
&cached_state, only_release_metadata);
- /*
- * If we have not locked the extent range, because the range's
- * start offset is >= i_size, we might still have a non-NULL
- * cached extent state, acquired while marking the extent range
- * as delalloc through btrfs_dirty_pages(). Therefore free any
- * possible cached extent state to avoid a memory leak.
- */
- if (extents_locked)
- btrfs_unlock_extent(&BTRFS_I(inode)->io_tree, lockstart,
- lockend, &cached_state);
- else
- free_extent_state(cached_state);
+ btrfs_unlock_extent(&BTRFS_I(inode)->io_tree, lockstart,
+ lockend, &cached_state);
btrfs_delalloc_release_extents(BTRFS_I(inode), reserve_bytes);
if (ret) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 647/869] btrfs: defrag: fix deadlock between defrag and delalloc space reservation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (645 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 646/869] btrfs: always wait for ordered extents to avoid OE races Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 648/869] scsi: sd: Move the sd_config_discard() function definition Greg Kroah-Hartman
` (222 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Qu Wenruo, Filipe Manana,
David Sterba, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Filipe Manana <fdmanana@suse.com>
[ Upstream commit ba02eab28041f9a4bbe9fc90c7249644fef6de0f ]
While running fsstress with autodefrag and flushoncommit, hit a deadlock
due to the fact that defrag reserves delalloc space while it's holding
dirty and locked folios, besides the extent range lock. The stack traces
are the following:
[958.624] task:kworker/u50:3 state:D stack:0 pid:20365 tgid:20365 ppid:2 task_flags:0x4208060 flags:0x00080000
[958.626] Workqueue: events_unbound btrfs_async_reclaim_metadata_space [btrfs]
[958.627] Call Trace:
[958.628] <TASK>
[958.628] __schedule+0x4be/0x10f0
[958.629] ? preempt_count_add+0x69/0xa0
[958.630] schedule+0x26/0xd0
[958.631] wait_current_trans+0x102/0x160 [btrfs]
[958.632] ? __pfx_autoremove_wake_function+0x10/0x10
[958.633] start_transaction+0x374/0x900 [btrfs]
[958.634] btrfs_commit_current_transaction+0x1d/0x70 [btrfs]
[958.635] flush_space+0xca/0x5e0 [btrfs]
[958.636] ? _raw_spin_unlock+0x15/0x30
[958.637] ? btrfs_reduce_alloc_profile+0x8c/0x190 [btrfs]
[958.639] ? _raw_spin_unlock+0x15/0x30
[958.640] ? calc_available_free_space.isra.0+0x6f/0x110 [btrfs]
[958.641] do_async_reclaim_metadata_space+0x84/0x190 [btrfs]
[958.642] btrfs_async_reclaim_metadata_space+0x64/0x80 [btrfs]
[958.644] process_one_work+0x19d/0x3a0
[958.644] worker_thread+0x1c4/0x330
[958.645] ? __pfx_worker_thread+0x10/0x10
[958.646] kthread+0xfc/0x130
[958.647] ? __pfx_kthread+0x10/0x10
[958.648] ret_from_fork+0x1f7/0x2c0
[958.648] ? __pfx_kthread+0x10/0x10
[958.649] ret_from_fork_asm+0x1a/0x30
[958.650] </TASK>
[958.651] task:kworker/u49:7 state:D stack:0 pid:52990 tgid:52990 ppid:2 task_flags:0x4208060 flags:0x00080000
[958.653] Workqueue: writeback wb_workfn (flush-btrfs-334)
[958.655] Call Trace:
[958.655] <TASK>
[958.656] __schedule+0x4be/0x10f0
[958.657] ? __blk_flush_plug+0xe9/0x140
[958.658] schedule+0x26/0xd0
[958.658] io_schedule+0x42/0x70
[958.659] folio_wait_bit_common+0x12b/0x330
[958.660] ? folio_wait_bit_common+0x100/0x330
[958.662] ? __pfx_wake_page_function+0x10/0x10
[958.663] extent_write_cache_pages+0x599/0x830 [btrfs]
[958.664] ? acpi_fwnode_get_reference_args+0x1fa/0x270
[958.665] btrfs_writepages+0x77/0x130 [btrfs]
[958.666] ? __pfx_end_bbio_data_write+0x10/0x10 [btrfs]
[958.667] do_writepages+0xc6/0x160
[958.668] __writeback_single_inode+0x42/0x310
[958.669] writeback_sb_inodes+0x231/0x570
[958.670] wb_writeback+0x8a/0x340
[958.671] wb_workfn+0xbf/0x450
[958.672] ? finish_task_switch.isra.0+0xc1/0x350
[958.673] process_one_work+0x19d/0x3a0
[958.673] worker_thread+0x1c4/0x330
[958.674] ? __pfx_worker_thread+0x10/0x10
[958.675] kthread+0xfc/0x130
[958.676] ? __pfx_kthread+0x10/0x10
[958.676] ret_from_fork+0x1f7/0x2c0
[958.677] ? __pfx_kthread+0x10/0x10
[958.678] ret_from_fork_asm+0x1a/0x30
[958.679] </TASK>
[958.679] task:btrfs-cleaner state:D stack:0 pid:296750 tgid:296750 ppid:2 task_flags:0x208040 flags:0x00080000
[958.681] Call Trace:
[958.682] <TASK>
[958.682] __schedule+0x4be/0x10f0
[958.683] schedule+0x26/0xd0
[958.684] handle_reserve_ticket+0x1b9/0x2c0 [btrfs]
[958.685] ? __pfx_autoremove_wake_function+0x10/0x10
[958.686] reserve_bytes+0x283/0x4c0 [btrfs]
[958.687] btrfs_reserve_metadata_bytes+0x18/0xb0 [btrfs]
[958.688] btrfs_delalloc_reserve_metadata+0x121/0x320 [btrfs]
[958.690] btrfs_delalloc_reserve_space+0x46/0xb0 [btrfs]
[958.691] btrfs_defrag_file+0x903/0x1110 [btrfs]
[958.692] btrfs_run_defrag_inodes+0x334/0x430 [btrfs]
[958.694] cleaner_kthread+0x97/0x1c0 [btrfs]
[958.694] ? __pfx_cleaner_kthread+0x10/0x10 [btrfs]
[958.696] kthread+0xfc/0x130
[958.696] ? __pfx_kthread+0x10/0x10
[958.697] ret_from_fork+0x1f7/0x2c0
[958.698] ? __pfx_kthread+0x10/0x10
[958.699] ret_from_fork_asm+0x1a/0x30
[958.700] </TASK>
[958.716] task:fsstress state:D stack:0 pid:296769 tgid:296769 ppid:296768 task_flags:0x400140 flags:0x00080000
[958.718] Call Trace:
[958.719] <TASK>
[958.719] __schedule+0x4be/0x10f0
[958.720] ? preempt_count_add+0x69/0xa0
[958.721] schedule+0x26/0xd0
[958.722] wb_wait_for_completion+0x79/0xc0
[958.723] ? __pfx_autoremove_wake_function+0x10/0x10
[958.724] __writeback_inodes_sb_nr+0xc5/0xf0
[958.725] try_to_writeback_inodes_sb+0x55/0x70
[958.726] btrfs_commit_transaction+0x19d/0xeb0 [btrfs]
[958.727] ? start_transaction+0x343/0x900 [btrfs]
[958.728] btrfs_mksubvol+0x28b/0x4e0 [btrfs]
[958.729] btrfs_mksnapshot+0x74/0xa0 [btrfs]
[958.730] __btrfs_ioctl_snap_create+0x194/0x210 [btrfs]
[958.732] btrfs_ioctl_snap_create_v2+0xef/0x150 [btrfs]
[958.733] btrfs_ioctl+0x7ec/0x2a70 [btrfs]
[958.734] ? __virt_addr_valid+0xe4/0x180
[958.735] ? __check_object_size+0x1cd/0x1f0
[958.736] ? kmem_cache_free+0x146/0x380
[958.737] ? _raw_spin_unlock+0x15/0x30
[958.738] ? do_sys_openat2+0x83/0xd0
[958.739] __x64_sys_ioctl+0x92/0xe0
[958.740] do_syscall_64+0x60/0x590
[958.741] ? clear_bhb_loop+0x60/0xb0
[958.742] entry_SYSCALL_64_after_hwframe+0x76/0x7e
[958.743] RIP: 0033:0x7f4431e108db
[958.744] RSP: 002b:00007ffcd147db20 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[958.746] RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007f4431e108db
[958.747] RDX: 00007ffcd147eb90 RSI: 0000000050009417 RDI: 0000000000000005
[958.749] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
[958.751] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffcd147fbf0
[958.752] R13: 00007ffcd147eb90 R14: 0000000000000005 R15: 0000000000000003
[958.754] </TASK>
What happens is the following:
1) The cleaner kthread is running autodefrag, and in defrag_one_range()
it acquired all the folios for the range and locked them.
Then it locked the extent range in the inode's iotree.
It got two subranges from defrag_collect_targets(), the first one
with folio A and the second one with folio B.
After it defragged the first subrange, folio A remains locked and
dirty - it's only unlocked when defrag_one_range() returns.
When it attempts to defrag the second subrange (containing folio B),
btrfs_delalloc_reserve_space() creates a space reservation ticket,
due to lack of free metadata space and blocks waiting for the async
metadata reclaim task to free space and wake it up;
2) The async reclaim metadata task attempts to commit the current
transaction, but it blocks because there is another task that
started the commit first;
3) A task creating a snapshot is committing the transaction and
because the fs was mounted with flushoncommit, it calls
try_to_writeback_inodes_sb(), which spawns a task to flush
delalloc and waits for it to complete;
4) The task flushing delalloc (kworker/u49:7), finds that folio A for
the inode being defragged is dirty, so it tries to lock it...
But it blocks because folio A is locked by the defrag task (the
cleaner kthread) which is blocked waiting for the reservation
ticket to be served, but the async reclaim metadata task is
blocked waiting for the transaction commit, which in turn is
blocked waiting for the delalloc flush task, which is trying to
lock folio A, resulting in a deadlock.
The same type of problem can happen if the async reclaim task starts to
flush delalloc, as that requires both locking the folio and the extent
range in the inode's io tree, and in this case we don't need the fs to
be mounted with flushoncommit. This type of problem has ocurred several
times in the past with reflinks for example, where we had a dirty folio
while holding the extent range locked and then starting a transaction
blocked waiting for the async reclaim task due to lack of free metadata
space.
So fix this by reserving delalloc space before locking folios and locking
the extent range in the inode's iotree. We can not simply unlock the
folios for each subrange given by defrag_collect_targets() after we defrag
it because the same folio may be present too in the next subrange (due to
large folios).
Fixes: 22b398eeeed4 ("btrfs: defrag: introduce helper to defrag a contiguous prepared range")
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/defrag.c | 50 +++++++++++++++++++++++++++++++----------------
1 file changed, 33 insertions(+), 17 deletions(-)
diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c
index d8e8b87c8bc7f..727a016b2025b 100644
--- a/fs/btrfs/defrag.c
+++ b/fs/btrfs/defrag.c
@@ -1153,26 +1153,21 @@ static_assert(PAGE_ALIGNED(CLUSTER_SIZE));
*
* - Extent bits are locked
*/
-static int defrag_one_locked_target(struct btrfs_inode *inode,
- struct defrag_target_range *target,
- struct folio **folios, int nr_pages,
- struct extent_state **cached_state)
+static void defrag_one_locked_target(struct btrfs_inode *inode,
+ struct defrag_target_range *target,
+ struct folio **folios, int nr_pages,
+ struct extent_state **cached_state)
{
struct btrfs_fs_info *fs_info = inode->root->fs_info;
- struct extent_changeset *data_reserved = NULL;
const u64 start = target->start;
const u64 len = target->len;
unsigned long last_index = (start + len - 1) >> PAGE_SHIFT;
unsigned long start_index = start >> PAGE_SHIFT;
unsigned long first_index = folios[0]->index;
- int ret = 0;
int i;
ASSERT(last_index - first_index + 1 <= nr_pages);
- ret = btrfs_delalloc_reserve_space(inode, &data_reserved, start, len);
- if (ret < 0)
- return ret;
clear_extent_bit(&inode->io_tree, start, start + len - 1,
EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING |
EXTENT_DEFRAG, cached_state);
@@ -1184,10 +1179,6 @@ static int defrag_one_locked_target(struct btrfs_inode *inode,
folio_clear_checked(folios[i]);
btrfs_folio_clamp_set_dirty(fs_info, folios[i], start, len);
}
- btrfs_delalloc_release_extents(inode, len);
- extent_changeset_free(data_reserved);
-
- return ret;
}
static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
@@ -1203,6 +1194,8 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
u64 last_index = (start + len - 1) >> PAGE_SHIFT;
u64 start_index = start >> PAGE_SHIFT;
unsigned int nr_pages = last_index - start_index + 1;
+ struct extent_changeset *data_reserved = NULL;
+ u64 last_defrag_end = start;
int ret = 0;
int i;
@@ -1213,6 +1206,22 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
if (!folios)
return -ENOMEM;
+ /*
+ * Reserve delalloc space before locking the range and before locking
+ * and dirtying any folios - otherwise we could deadlock, for example
+ * after defrag of one range we dirty folios and keep them locked when
+ * we move to the next range, so reserving delalloc space right before
+ * each range could trigger flushing of delalloc and deadlock on the
+ * extent lock or trigger a transaction commit with flushoncommit, which
+ * can either deadlock on the lock of a folio made dirty in the previous
+ * range or the extent lock.
+ */
+ ret = btrfs_delalloc_reserve_space(inode, &data_reserved, start, len);
+ if (ret < 0) {
+ kfree(folios);
+ return ret;
+ }
+
/* Prepare all pages */
for (i = 0; i < nr_pages; i++) {
folios[i] = defrag_prepare_one_folio(inode, start_index + i);
@@ -1243,10 +1252,11 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
goto btrfs_unlock_extent;
list_for_each_entry(entry, &target_list, list) {
- ret = defrag_one_locked_target(inode, entry, folios, nr_pages,
- &cached_state);
- if (ret < 0)
- break;
+ defrag_one_locked_target(inode, entry, folios, nr_pages, &cached_state);
+ if (entry->start > last_defrag_end)
+ btrfs_delalloc_release_space(inode, data_reserved, last_defrag_end,
+ entry->start - last_defrag_end, true);
+ last_defrag_end = entry->start + entry->len;
}
list_for_each_entry_safe(entry, tmp, &target_list, list) {
@@ -1263,6 +1273,12 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
folio_put(folios[i]);
}
kfree(folios);
+ btrfs_delalloc_release_extents(inode, len);
+ if (last_defrag_end < start + len)
+ btrfs_delalloc_release_space(inode, data_reserved, last_defrag_end,
+ start + len - last_defrag_end, true);
+ extent_changeset_free(data_reserved);
+
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 648/869] scsi: sd: Move the sd_config_discard() function definition
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (646 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 647/869] btrfs: defrag: fix deadlock between defrag and delalloc space reservation Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 649/869] scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails Greg Kroah-Hartman
` (221 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Damien Le Moal, Himanshu Madhani,
Johannes Thumshirn, Bart Van Assche, Martin K. Petersen,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bart Van Assche <bvanassche@acm.org>
[ Upstream commit c0daf4836114fcbdf64bf817cab00b75ce712945 ]
Move the sd_config_discard() function definition such that its
forward declaration can be removed.
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Link: https://patch.msgid.link/20260114175054.4118163-3-bvanassche@acm.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Stable-dep-of: bb31844d88b7 ("scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/scsi/sd.c | 114 ++++++++++++++++++++++++++----------------------------
1 file changed, 56 insertions(+), 58 deletions(-)
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -102,8 +102,6 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC);
#define SD_MINORS 16
-static void sd_config_discard(struct scsi_disk *sdkp, struct queue_limits *lim,
- unsigned int mode);
static void sd_config_write_same(struct scsi_disk *sdkp,
struct queue_limits *lim);
static int sd_revalidate_disk(struct gendisk *);
@@ -121,6 +119,62 @@ static const char *sd_cache_types[] = {
"write back, no read (daft)"
};
+static void sd_disable_discard(struct scsi_disk *sdkp)
+{
+ sdkp->provisioning_mode = SD_LBP_DISABLE;
+ blk_queue_disable_discard(sdkp->disk->queue);
+}
+
+static void sd_config_discard(struct scsi_disk *sdkp, struct queue_limits *lim,
+ unsigned int mode)
+{
+ unsigned int logical_block_size = sdkp->device->sector_size;
+ unsigned int max_blocks = 0;
+
+ lim->discard_alignment = sdkp->unmap_alignment * logical_block_size;
+ lim->discard_granularity = max(sdkp->physical_block_size,
+ sdkp->unmap_granularity * logical_block_size);
+ sdkp->provisioning_mode = mode;
+
+ switch (mode) {
+
+ case SD_LBP_FULL:
+ case SD_LBP_DISABLE:
+ break;
+
+ case SD_LBP_UNMAP:
+ max_blocks = min_not_zero(sdkp->max_unmap_blocks,
+ (u32)SD_MAX_WS16_BLOCKS);
+ break;
+
+ case SD_LBP_WS16:
+ if (sdkp->device->unmap_limit_for_ws)
+ max_blocks = sdkp->max_unmap_blocks;
+ else
+ max_blocks = sdkp->max_ws_blocks;
+
+ max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS16_BLOCKS);
+ break;
+
+ case SD_LBP_WS10:
+ if (sdkp->device->unmap_limit_for_ws)
+ max_blocks = sdkp->max_unmap_blocks;
+ else
+ max_blocks = sdkp->max_ws_blocks;
+
+ max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS10_BLOCKS);
+ break;
+
+ case SD_LBP_ZERO:
+ max_blocks = min_not_zero(sdkp->max_ws_blocks,
+ (u32)SD_MAX_WS10_BLOCKS);
+ break;
+ }
+
+ lim->max_hw_discard_sectors = max_blocks *
+ (logical_block_size >> SECTOR_SHIFT);
+}
+
static void sd_set_flush_flag(struct scsi_disk *sdkp,
struct queue_limits *lim)
{
@@ -836,62 +890,6 @@ static unsigned char sd_setup_protect_cm
return protect;
}
-static void sd_disable_discard(struct scsi_disk *sdkp)
-{
- sdkp->provisioning_mode = SD_LBP_DISABLE;
- blk_queue_disable_discard(sdkp->disk->queue);
-}
-
-static void sd_config_discard(struct scsi_disk *sdkp, struct queue_limits *lim,
- unsigned int mode)
-{
- unsigned int logical_block_size = sdkp->device->sector_size;
- unsigned int max_blocks = 0;
-
- lim->discard_alignment = sdkp->unmap_alignment * logical_block_size;
- lim->discard_granularity = max(sdkp->physical_block_size,
- sdkp->unmap_granularity * logical_block_size);
- sdkp->provisioning_mode = mode;
-
- switch (mode) {
-
- case SD_LBP_FULL:
- case SD_LBP_DISABLE:
- break;
-
- case SD_LBP_UNMAP:
- max_blocks = min_not_zero(sdkp->max_unmap_blocks,
- (u32)SD_MAX_WS16_BLOCKS);
- break;
-
- case SD_LBP_WS16:
- if (sdkp->device->unmap_limit_for_ws)
- max_blocks = sdkp->max_unmap_blocks;
- else
- max_blocks = sdkp->max_ws_blocks;
-
- max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS16_BLOCKS);
- break;
-
- case SD_LBP_WS10:
- if (sdkp->device->unmap_limit_for_ws)
- max_blocks = sdkp->max_unmap_blocks;
- else
- max_blocks = sdkp->max_ws_blocks;
-
- max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS10_BLOCKS);
- break;
-
- case SD_LBP_ZERO:
- max_blocks = min_not_zero(sdkp->max_ws_blocks,
- (u32)SD_MAX_WS10_BLOCKS);
- break;
- }
-
- lim->max_hw_discard_sectors = max_blocks *
- (logical_block_size >> SECTOR_SHIFT);
-}
-
static void *sd_set_special_bvec(struct request *rq, unsigned int data_len)
{
struct page *page;
^ permalink raw reply [flat|nested] 872+ messages in thread
* [PATCH 6.12 649/869] scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (647 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 648/869] scsi: sd: Move the sd_config_discard() function definition Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 650/869] coresight: etm4x: missing cscfg_csdev_disable_active_config() in perf enable Greg Kroah-Hartman
` (220 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Damien Le Moal, Yang Xiuwei,
John Garry, Martin K. Petersen (Oracle), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Xiuwei <yangxiuwei@kylinos.cn>
[ Upstream commit bb31844d88b77138b67aa20c3600203baff40140 ]
sd_set_special_bvec() allocates a special payload page for UNMAP and
WRITE SAME commands. If scsi_alloc_sgtables() fails afterward in
sd_setup_unmap_cmnd() or sd_setup_write_same{10,16}_cmnd(), the SCSI
midlayer does not call uninit_command() because RQF_DONTPREP is not set
yet, leaking the page.
Call sd_uninit_command() on error, and clear RQF_SPECIAL_PAYLOAD after
freeing the page.
Fixes: 81d926e8b552 ("sd: split sd_setup_discard_cmnd")
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
Reviewed-by: John Garry <john.g.garry@oracle.com>
Link: https://patch.msgid.link/20260707030333.22245-3-yangxiuwei@kylinos.cn
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/scsi/sd.c | 37 ++++++++++++++++++++++++++-----------
1 file changed, 26 insertions(+), 11 deletions(-)
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -890,6 +890,17 @@ static unsigned char sd_setup_protect_cm
return protect;
}
+static void sd_uninit_command(struct scsi_cmnd *cmd)
+{
+ struct request *rq = scsi_cmd_to_rq(cmd);
+
+ if (!(rq->rq_flags & RQF_SPECIAL_PAYLOAD))
+ return;
+
+ mempool_free(rq->special_vec.bv_page, sd_page_pool);
+ rq->rq_flags &= ~RQF_SPECIAL_PAYLOAD;
+}
+
static void *sd_set_special_bvec(struct request *rq, unsigned int data_len)
{
struct page *page;
@@ -912,6 +923,7 @@ static blk_status_t sd_setup_unmap_cmnd(
u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq));
unsigned int data_len = 24;
char *buf;
+ blk_status_t ret;
buf = sd_set_special_bvec(rq, data_len);
if (!buf)
@@ -930,7 +942,10 @@ static blk_status_t sd_setup_unmap_cmnd(
cmd->transfersize = data_len;
rq->timeout = SD_TIMEOUT;
- return scsi_alloc_sgtables(cmd);
+ ret = scsi_alloc_sgtables(cmd);
+ if (ret != BLK_STS_OK)
+ sd_uninit_command(cmd);
+ return ret;
}
static void sd_config_atomic(struct scsi_disk *sdkp, struct queue_limits *lim)
@@ -1000,6 +1015,7 @@ static blk_status_t sd_setup_write_same1
u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq));
u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq));
u32 data_len = sdp->sector_size;
+ blk_status_t ret;
if (!sd_set_special_bvec(rq, data_len))
return BLK_STS_RESOURCE;
@@ -1015,7 +1031,10 @@ static blk_status_t sd_setup_write_same1
cmd->transfersize = data_len;
rq->timeout = unmap ? SD_TIMEOUT : SD_WRITE_SAME_TIMEOUT;
- return scsi_alloc_sgtables(cmd);
+ ret = scsi_alloc_sgtables(cmd);
+ if (ret != BLK_STS_OK)
+ sd_uninit_command(cmd);
+ return ret;
}
static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd,
@@ -1027,6 +1046,7 @@ static blk_status_t sd_setup_write_same1
u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq));
u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq));
u32 data_len = sdp->sector_size;
+ blk_status_t ret;
if (!sd_set_special_bvec(rq, data_len))
return BLK_STS_RESOURCE;
@@ -1042,7 +1062,10 @@ static blk_status_t sd_setup_write_same1
cmd->transfersize = data_len;
rq->timeout = unmap ? SD_TIMEOUT : SD_WRITE_SAME_TIMEOUT;
- return scsi_alloc_sgtables(cmd);
+ ret = scsi_alloc_sgtables(cmd);
+ if (ret != BLK_STS_OK)
+ sd_uninit_command(cmd);
+ return ret;
}
static blk_status_t sd_setup_write_zeroes_cmnd(struct scsi_cmnd *cmd)
@@ -1466,14 +1489,6 @@ static blk_status_t sd_init_command(stru
}
}
-static void sd_uninit_command(struct scsi_cmnd *SCpnt)
-{
- struct request *rq = scsi_cmd_to_rq(SCpnt);
-
- if (rq->rq_flags & RQF_SPECIAL_PAYLOAD)
- mempool_free(rq->special_vec.bv_page, sd_page_pool);
-}
-
static bool sd_need_revalidate(struct gendisk *disk, struct scsi_disk *sdkp)
{
if (sdkp->device->removable || sdkp->write_prot) {
^ permalink raw reply [flat|nested] 872+ messages in thread
* [PATCH 6.12 650/869] coresight: etm4x: missing cscfg_csdev_disable_active_config() in perf enable
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (648 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 649/869] scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 651/869] drm/amd/display: disable replay when crc source is enabled Greg Kroah-Hartman
` (219 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Leo Yan, Yeoreum Yun,
Suzuki K Poulose, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yeoreum Yun <yeoreum.yun@arm.com>
[ Upstream commit 0a47f0be6557b4a851addd430383a4dc7ee08752 ]
In the perf enable path, there are missing cases where
cscfg_csdev_disable_active_config() is not called:
- Branch broadcast is selected but not supported by the hardware
- etm4_enable_hw() fails
This can lead to a leak of config_desc->active_cnt.
Fix this by properly calling cscfg_csdev_disable_active_config()
in these error paths.
Fixes: 810ac401db1f ("coresight: etm4x: Add complex configuration handlers to etmv4")
Suggested-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20260725113645.57519-6-yeoreum.yun@arm.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../coresight/coresight-etm4x-core.c | 46 +++++++++++--------
1 file changed, 28 insertions(+), 18 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index e69ee4ccc2658..9127bc0255528 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -698,8 +698,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
struct etmv4_config *config = &drvdata->config;
struct perf_event_attr *attr = &event->attr;
- unsigned long cfg_hash;
- int preset, cc_threshold;
+ int cc_threshold;
/* Clear configuration from previous run */
memset(config, 0, sizeof(struct etmv4_config));
@@ -774,20 +773,6 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
/* bit[12], Return stack enable bit */
config->cfg |= TRCCONFIGR_RS;
- /*
- * Set any selected configuration and preset.
- *
- * This extracts the values of PMU_FORMAT_ATTR(configid) and PMU_FORMAT_ATTR(preset)
- * in the perf attributes defined in coresight-etm-perf.c.
- * configid uses bits 63:32 of attr->config2, preset uses bits 3:0 of attr->config.
- * A zero configid means no configuration active, preset = 0 means no preset selected.
- */
- if (attr->config2 & GENMASK_ULL(63, 32)) {
- cfg_hash = (u32)(attr->config2 >> 32);
- preset = attr->config & 0xF;
- ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
- }
-
/* branch broadcast - enable if selected and supported */
if (attr->config & BIT(ETM_OPT_BRANCH_BROADCAST)) {
if (!drvdata->trcbb) {
@@ -810,8 +795,10 @@ static int etm4_enable_perf(struct coresight_device *csdev,
struct perf_event *event,
struct coresight_trace_id_map *id_map)
{
- int ret = 0, trace_id;
+ int ret = 0, trace_id, preset;
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ struct perf_event_attr *attr = &event->attr;
+ unsigned long cfg_hash = 0;
if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) {
ret = -EINVAL;
@@ -823,6 +810,22 @@ static int etm4_enable_perf(struct coresight_device *csdev,
if (ret)
goto out;
+ /*
+ * Set any selected configuration and preset.
+ *
+ * This extracts the values of PMU_FORMAT_ATTR(configid) and PMU_FORMAT_ATTR(preset)
+ * in the perf attributes defined in coresight-etm-perf.c.
+ * configid uses bits 63:32 of attr->config2, preset uses bits 3:0 of attr->config.
+ * A zero configid means no configuration active, preset = 0 means no preset selected.
+ */
+ if (attr->config2 & GENMASK_ULL(63, 32)) {
+ cfg_hash = (u32)(attr->config2 >> 32);
+ preset = attr->config & 0xF;
+ ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
+ if (ret)
+ goto out;
+ }
+
/*
* perf allocates cpu ids as part of _setup_aux() - device needs to use
* the allocated ID. This reads the current version without allocation.
@@ -836,13 +839,20 @@ static int etm4_enable_perf(struct coresight_device *csdev,
dev_err(&drvdata->csdev->dev, "Failed to set trace ID for %s on CPU%d\n",
dev_name(&drvdata->csdev->dev), drvdata->cpu);
ret = -EINVAL;
- goto out;
+ goto err_cfg;
}
drvdata->trcid = (u8)trace_id;
/* And enable it */
ret = etm4_enable_hw(drvdata);
+ if (ret)
+ goto err_cfg;
+
+ return 0;
+err_cfg:
+ if (cfg_hash)
+ cscfg_csdev_disable_active_config(csdev);
out:
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 651/869] drm/amd/display: disable replay when crc source is enabled
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (649 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 650/869] coresight: etm4x: missing cscfg_csdev_disable_active_config() in perf enable Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 652/869] drm/amd/display: Resize MST HDCP per-connector arrays to 32 Greg Kroah-Hartman
` (218 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, ChiaHsuan (Tom) Chung, Ray Wu,
Matthew Stewart, Dan Wheeler, Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ray Wu <ray.wu@amd.com>
[ Upstream commit a036db3953140d5c2816b056aa3e73b8e98d9bc0 ]
[Why]
IGT CRC tests fail on replay panels due to invalid CRC values
captured when replay is active.
[How]
- Disable replay when CRC source is enabled; set flag to
prevent unexpected re-enable
- Reset flag when CRC source is disabled to allow replay
Reviewed-by: ChiaHsuan (Tom) Chung <chiahsuan.chung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
Signed-off-by: Matthew Stewart <matthew.stewart2@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Stable-dep-of: 261e0fe4e2c9 ("drm/amd/display: Resize MST HDCP per-connector arrays to 32")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 +
.../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 25 ++++++++++++++++---
.../amd/display/amdgpu_dm/amdgpu_dm_replay.c | 7 ++++++
3 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 9682c190e9524..e447ab49cf3ca 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -732,6 +732,7 @@ struct amdgpu_dm_connector {
int sr_skip_count;
bool disallow_edp_enter_psr;
+ bool disallow_edp_enter_replay;
/* Record progress status of mst*/
uint8_t mst_status;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 41812081418e3..b4a769216d609 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -31,6 +31,7 @@
#include "dc.h"
#include "amdgpu_securedisplay.h"
#include "amdgpu_dm_psr.h"
+#include "amdgpu_dm_replay.h"
static const char *const pipe_crc_sources[] = {
"none",
@@ -216,6 +217,7 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
{
struct amdgpu_device *adev = drm_to_adev(crtc->dev);
struct dc_stream_state *stream_state = dm_crtc_state->stream;
+ struct amdgpu_dm_connector *aconnector = NULL;
bool enable = amdgpu_dm_is_valid_crc_source(source);
int ret = 0;
@@ -223,11 +225,22 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
if (!stream_state)
return -EINVAL;
+ /* Get connector from stream */
+ aconnector = (struct amdgpu_dm_connector *)stream_state->dm_stream_context;
+
mutex_lock(&adev->dm.dc_lock);
- /* For PSR1, check that the panel has exited PSR */
- if (stream_state->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1)
- amdgpu_dm_psr_wait_disable(stream_state);
+
+ if (enable) {
+ /* For PSR1, check that the panel has exited PSR */
+ if (stream_state->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1)
+ amdgpu_dm_psr_wait_disable(stream_state);
+
+ /* Set flag to disallow enter replay when CRC source is enabled */
+ if (aconnector)
+ aconnector->disallow_edp_enter_replay = true;
+ amdgpu_dm_replay_disable(stream_state);
+ }
/* Enable or disable CRTC CRC generation */
if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) {
@@ -250,6 +263,12 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
DYN_EXPANSION_AUTO);
}
+ if (!enable) {
+ /* Clear flag to allow enter replay when CRC source is disabled */
+ if (aconnector)
+ aconnector->disallow_edp_enter_replay = false;
+ }
+
unlock:
mutex_unlock(&adev->dm.dc_lock);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c
index 41f07f13a7b57..7db927dcfe8d2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c
@@ -153,10 +153,17 @@ bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait)
{
bool replay_active = true;
struct dc_link *link = NULL;
+ struct amdgpu_dm_connector *aconnector = NULL;
if (stream == NULL)
return false;
+ /* Check if replay is disabled by connector flag */
+ aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
+ if (!aconnector || aconnector->disallow_edp_enter_replay) {
+ return false;
+ }
+
link = stream->link;
if (link) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 652/869] drm/amd/display: Resize MST HDCP per-connector arrays to 32
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (650 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 651/869] drm/amd/display: disable replay when crc source is enabled Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 653/869] bpf: Factor callchain_store function from __bpf_get_stack Greg Kroah-Hartman
` (217 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alex Hung, Harry Wentland, Roman Li,
Dan Wheeler, Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <harry.wentland@amd.com>
[ Upstream commit 261e0fe4e2c99f687114b64b10b98db964b475f4 ]
AMDGPU_DM_MAX_DISPLAY_INDEX is 31. It suggest a maximum number of
32 connectors. But the way it's used is like MAX_DISPLAY_COUNT.
Hence we're off by one with DRM core, which supports a max of 32
connectors.
Rename AMDGPU_DM_MAX_DISPLAY_INDEX to AMDGPU_DM_MAX_DISPLAY_COUNT
to match its actual use, and increase the size to 32 to match the
originally intended size.
Fixes: 82986fd631fa ("drm/amd/display: save restore hdcp state when display is unplugged from mst hub")
Assisted-by: Copilot:claude-opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Roman Li <roman.li@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 2 +-
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 10 +++++-----
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h | 8 ++++----
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index e447ab49cf3ca..db707c2311be2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -44,7 +44,7 @@
* in amdgpu_dm_kms.h file
*/
-#define AMDGPU_DM_MAX_DISPLAY_INDEX 31
+#define AMDGPU_DM_MAX_DISPLAY_COUNT 32
#define AMDGPU_DM_MAX_CRTC 6
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
index 10ba4d7bf6325..930310aff1d66 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
@@ -256,7 +256,7 @@ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_inde
cancel_delayed_work(&hdcp_w->property_validate_dwork);
- for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) {
+ for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_COUNT; conn_index++) {
hdcp_w->encryption_status[conn_index] =
MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
if (hdcp_w->aconnector[conn_index]) {
@@ -303,7 +303,7 @@ static void event_property_update(struct work_struct *work)
struct drm_connector *connector;
struct drm_connector_state *conn_state;
- for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) {
+ for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_COUNT; conn_index++) {
aconnector = hdcp_work->aconnector[conn_index];
if (!aconnector)
@@ -372,7 +372,7 @@ static void event_property_validate(struct work_struct *work)
guard(mutex)(&hdcp_work->mutex);
- for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX;
+ for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_COUNT;
conn_index++) {
aconnector = hdcp_work->aconnector[conn_index];
@@ -749,10 +749,10 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev,
memset(hdcp_work[i].aconnector, 0,
sizeof(struct amdgpu_dm_connector *) *
- AMDGPU_DM_MAX_DISPLAY_INDEX);
+ AMDGPU_DM_MAX_DISPLAY_COUNT);
memset(hdcp_work[i].encryption_status, 0,
sizeof(enum mod_hdcp_encryption_status) *
- AMDGPU_DM_MAX_DISPLAY_INDEX);
+ AMDGPU_DM_MAX_DISPLAY_COUNT);
}
cp_psp->funcs.update_stream_config = update_config;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
index 69b445b011c8c..d18c4cc7d69f3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
@@ -43,7 +43,7 @@ struct hdcp_workqueue {
struct delayed_work callback_dwork;
struct delayed_work watchdog_timer_dwork;
struct delayed_work property_validate_dwork;
- struct amdgpu_dm_connector *aconnector[AMDGPU_DM_MAX_DISPLAY_INDEX];
+ struct amdgpu_dm_connector *aconnector[AMDGPU_DM_MAX_DISPLAY_COUNT];
struct mutex mutex;
struct mod_hdcp hdcp;
@@ -51,7 +51,7 @@ struct hdcp_workqueue {
struct mod_hdcp_display display;
struct mod_hdcp_link link;
- enum mod_hdcp_encryption_status encryption_status[AMDGPU_DM_MAX_DISPLAY_INDEX];
+ enum mod_hdcp_encryption_status encryption_status[AMDGPU_DM_MAX_DISPLAY_COUNT];
/* when display is unplugged from mst hub, connctor will be
* destroyed within dm_dp_mst_connector_destroy. connector
* hdcp perperties, like type, undesired, desired, enabled,
@@ -61,9 +61,9 @@ struct hdcp_workqueue {
* will be retrieved from hdcp_work within dm_dp_mst_get_modes
*/
/* un-desired, desired, enabled */
- unsigned int content_protection[AMDGPU_DM_MAX_DISPLAY_INDEX];
+ unsigned int content_protection[AMDGPU_DM_MAX_DISPLAY_COUNT];
/* hdcp1.x, hdcp2.x */
- unsigned int hdcp_content_type[AMDGPU_DM_MAX_DISPLAY_INDEX];
+ unsigned int hdcp_content_type[AMDGPU_DM_MAX_DISPLAY_COUNT];
uint8_t max_link;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 653/869] bpf: Factor callchain_store function from __bpf_get_stack
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (651 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 652/869] drm/amd/display: Resize MST HDCP per-connector arrays to 32 Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 654/869] bpf: Factor callchain_finalize " Greg Kroah-Hartman
` (216 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jiri Olsa, Andrii Nakryiko,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Olsa <jolsa@kernel.org>
[ Upstream commit cbb99938e7935c9f62c891573a4b09690e5e22de ]
The new callchain_store function stores trace entries buffer into
user supplied buffer. It covers both just-ip and buildid data.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260803210149.296496-7-jolsa@kernel.org
Stable-dep-of: f5d242825ca4 ("bpf: Clear buf on error in __bpf_get_task_stack")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/stackmap.c | 39 +++++++++++++++++++++++++--------------
1 file changed, 25 insertions(+), 14 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index ebab2f0374b88..db6d6bfecbad4 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -488,6 +488,29 @@ const struct bpf_func_proto bpf_get_stackid_proto_pe = {
.arg3_type = ARG_ANYTHING,
};
+static u32 callchain_store(struct perf_callchain_entry *trace, void *buf,
+ u32 elem_size, u64 flags)
+{
+ bool user_build_id = flags & BPF_F_USER_BUILD_ID;
+ u32 skip = flags & BPF_F_SKIP_FIELD_MASK;
+ u32 trace_nr, copy_len;
+ u64 *ips;
+
+ trace_nr = trace->nr - skip;
+ copy_len = trace_nr * elem_size;
+
+ ips = trace->ip + skip;
+ if (user_build_id) {
+ struct bpf_stack_build_id *id_offs = buf;
+
+ for (u32 i = 0; i < trace_nr; i++)
+ id_offs[i].ip = ips[i];
+ } else {
+ memcpy(buf, ips, copy_len);
+ }
+ return trace_nr;
+}
+
static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
struct perf_callchain_entry *trace_in,
void *buf, u32 size, u64 flags, bool may_fault)
@@ -500,7 +523,6 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
struct perf_callchain_entry *trace;
bool kernel = !user;
int err = -EINVAL;
- u64 *ips;
if (unlikely(flags & ~(BPF_F_SKIP_FIELD_MASK | BPF_F_USER_STACK |
BPF_F_USER_BUILD_ID)))
@@ -547,21 +569,10 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
goto err_fault;
}
- trace_nr = trace->nr - skip;
+ trace_nr = callchain_store(trace, buf, elem_size, flags);
copy_len = trace_nr * elem_size;
- ips = trace->ip + skip;
- if (user_build_id) {
- struct bpf_stack_build_id *id_offs = buf;
- u32 i;
-
- for (i = 0; i < trace_nr; i++)
- id_offs[i].ip = ips[i];
- } else {
- memcpy(buf, ips, copy_len);
- }
-
- /* trace/ips should not be dereferenced after this point */
+ /* trace should not be dereferenced after this point */
if (may_fault)
rcu_read_unlock();
preempt_enable();
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 654/869] bpf: Factor callchain_finalize function from __bpf_get_stack
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (652 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 653/869] bpf: Factor callchain_store function from __bpf_get_stack Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 655/869] bpf: Remove trace_in argument " Greg Kroah-Hartman
` (215 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jiri Olsa, Andrii Nakryiko,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Olsa <jolsa@kernel.org>
[ Upstream commit 014fbe5902dccdaef69114abdcdb15e3dbe55e34 ]
The new callchain_finalize function calls the build-id retrieval
(if needed) and zeroes the buffer. This makes things easier for
preemption fix in following change.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260803210149.296496-8-jolsa@kernel.org
Stable-dep-of: f5d242825ca4 ("bpf: Clear buf on error in __bpf_get_task_stack")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/stackmap.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index db6d6bfecbad4..7818b124d9d6e 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -511,16 +511,31 @@ static u32 callchain_store(struct perf_callchain_entry *trace, void *buf,
return trace_nr;
}
+static long callchain_finalize(void *buf, u32 size, u32 trace_nr, u32 elem_size,
+ u64 flags, bool may_fault)
+{
+ bool user_build_id = flags & BPF_F_USER_BUILD_ID;
+ bool user = flags & BPF_F_USER_STACK;
+ u32 copy_len = trace_nr * elem_size;
+
+ if (user_build_id)
+ stack_map_get_build_id_offset(buf, trace_nr, user, may_fault);
+
+ if (size > copy_len)
+ memset(buf + copy_len, 0, size - copy_len);
+ return copy_len;
+}
+
static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
struct perf_callchain_entry *trace_in,
void *buf, u32 size, u64 flags, bool may_fault)
{
- u32 trace_nr, copy_len, elem_size, max_depth;
bool user_build_id = flags & BPF_F_USER_BUILD_ID;
bool crosstask = task && task != current;
u32 skip = flags & BPF_F_SKIP_FIELD_MASK;
bool user = flags & BPF_F_USER_STACK;
struct perf_callchain_entry *trace;
+ u32 trace_nr, elem_size, max_depth;
bool kernel = !user;
int err = -EINVAL;
@@ -570,19 +585,13 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
}
trace_nr = callchain_store(trace, buf, elem_size, flags);
- copy_len = trace_nr * elem_size;
/* trace should not be dereferenced after this point */
if (may_fault)
rcu_read_unlock();
preempt_enable();
- if (user_build_id)
- stack_map_get_build_id_offset(buf, trace_nr, user, may_fault);
-
- if (size > copy_len)
- memset(buf + copy_len, 0, size - copy_len);
- return copy_len;
+ return callchain_finalize(buf, size, trace_nr, elem_size, flags, may_fault);
err_fault:
err = -EFAULT;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 655/869] bpf: Remove trace_in argument from __bpf_get_stack
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (653 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 654/869] bpf: Factor callchain_finalize " Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 656/869] bpf: Clear buf on error in __bpf_get_task_stack Greg Kroah-Hartman
` (214 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jiri Olsa, Andrii Nakryiko,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Olsa <jolsa@kernel.org>
[ Upstream commit 58cfc2201d964163fe9c4a703136eb64db799f08 ]
Now with the new callchain_* helper functions we can process trace_in
case directly in bpf_get_stack_pe function and remove it from
__bpf_get_stack which makes things easier for preemption fix in
following change.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260803210149.296496-9-jolsa@kernel.org
Stable-dep-of: f5d242825ca4 ("bpf: Clear buf on error in __bpf_get_task_stack")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/stackmap.c | 49 ++++++++++++++++++++++++++++++-------------
1 file changed, 35 insertions(+), 14 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 7818b124d9d6e..49f724e63e38a 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -527,7 +527,6 @@ static long callchain_finalize(void *buf, u32 size, u32 trace_nr, u32 elem_size,
}
static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
- struct perf_callchain_entry *trace_in,
void *buf, u32 size, u64 flags, bool may_fault)
{
bool user_build_id = flags & BPF_F_USER_BUILD_ID;
@@ -567,10 +566,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
if (may_fault)
rcu_read_lock(); /* need RCU for perf's callchain below */
- if (trace_in) {
- trace = trace_in;
- trace->nr = min_t(u32, trace->nr, max_depth);
- } else if (kernel && task) {
+ if (kernel && task) {
trace = get_callchain_entry_for_task(task, max_depth);
} else {
trace = get_perf_callchain(regs, kernel, user, max_depth,
@@ -603,7 +599,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
BPF_CALL_4(bpf_get_stack, struct pt_regs *, regs, void *, buf, u32, size,
u64, flags)
{
- return __bpf_get_stack(regs, NULL, NULL, buf, size, flags, false /* !may_fault */);
+ return __bpf_get_stack(regs, NULL, buf, size, flags, false /* !may_fault */);
}
const struct bpf_func_proto bpf_get_stack_proto = {
@@ -619,7 +615,7 @@ const struct bpf_func_proto bpf_get_stack_proto = {
BPF_CALL_4(bpf_get_stack_sleepable, struct pt_regs *, regs, void *, buf, u32, size,
u64, flags)
{
- return __bpf_get_stack(regs, NULL, NULL, buf, size, flags, true /* may_fault */);
+ return __bpf_get_stack(regs, NULL, buf, size, flags, true /* may_fault */);
}
const struct bpf_func_proto bpf_get_stack_sleepable_proto = {
@@ -644,7 +640,7 @@ static long __bpf_get_task_stack(struct task_struct *task, void *buf, u32 size,
regs = task_pt_regs(task);
if (regs)
- res = __bpf_get_stack(regs, task, NULL, buf, size, flags, may_fault);
+ res = __bpf_get_stack(regs, task, buf, size, flags, may_fault);
put_task_stack(task);
return res;
@@ -685,6 +681,32 @@ const struct bpf_func_proto bpf_get_task_stack_sleepable_proto = {
.arg4_type = ARG_ANYTHING,
};
+static int __bpf_get_stack_pe(struct perf_callchain_entry *trace, void *buf, u32 size,
+ u64 flags)
+{
+ bool user_build_id = flags & BPF_F_USER_BUILD_ID;
+ u64 skip = flags & BPF_F_SKIP_FIELD_MASK;
+ bool user = flags & BPF_F_USER_STACK;
+ u32 elem_size, max_depth, nr_trace;
+ bool kernel = !user;
+
+ if (kernel && user_build_id)
+ return -EINVAL;
+
+ elem_size = user_build_id ? sizeof(struct bpf_stack_build_id) : sizeof(u64);
+ if (unlikely(size % elem_size))
+ return -EINVAL;
+
+ max_depth = stack_map_calculate_max_depth(size, elem_size, flags);
+ trace->nr = min_t(u32, trace->nr, max_depth);
+
+ if (trace->nr < skip)
+ return -EFAULT;
+
+ nr_trace = callchain_store(trace, buf, elem_size, flags);
+ return callchain_finalize(buf, size, nr_trace, elem_size, flags, false /* !may_fault */);
+}
+
BPF_CALL_4(bpf_get_stack_pe, struct bpf_perf_event_data_kern *, ctx,
void *, buf, u32, size, u64, flags)
{
@@ -696,7 +718,7 @@ BPF_CALL_4(bpf_get_stack_pe, struct bpf_perf_event_data_kern *, ctx,
__u64 nr_kernel;
if (!(event->attr.sample_type & PERF_SAMPLE_CALLCHAIN))
- return __bpf_get_stack(regs, NULL, NULL, buf, size, flags, false /* !may_fault */);
+ return __bpf_get_stack(regs, NULL, buf, size, flags, false /* !may_fault */);
if (unlikely(flags & ~(BPF_F_SKIP_FIELD_MASK | BPF_F_USER_STACK |
BPF_F_USER_BUILD_ID)))
@@ -716,7 +738,7 @@ BPF_CALL_4(bpf_get_stack_pe, struct bpf_perf_event_data_kern *, ctx,
__u64 nr = trace->nr;
trace->nr = nr_kernel;
- err = __bpf_get_stack(regs, NULL, trace, buf, size, flags, false /* !may_fault */);
+ err = __bpf_get_stack_pe(trace, buf, size, flags);
/* restore nr */
trace->nr = nr;
@@ -726,14 +748,13 @@ BPF_CALL_4(bpf_get_stack_pe, struct bpf_perf_event_data_kern *, ctx,
skip += nr_kernel;
if (skip > BPF_F_SKIP_FIELD_MASK)
goto clear;
-
flags = (flags & ~BPF_F_SKIP_FIELD_MASK) | skip;
- err = __bpf_get_stack(regs, NULL, trace, buf, size, flags, false /* !may_fault */);
+ err = __bpf_get_stack_pe(trace, buf, size, flags);
}
- return err;
clear:
- memset(buf, 0, size);
+ if (err < 0)
+ memset(buf, 0, size);
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 656/869] bpf: Clear buf on error in __bpf_get_task_stack
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (654 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 655/869] bpf: Remove trace_in argument " Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 657/869] ocfs2/heartbeat: fix slot mapping rollback leaks on error paths Greg Kroah-Hartman
` (213 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Jiri Olsa, Andrii Nakryiko,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Olsa <jolsa@kernel.org>
[ Upstream commit f5d242825ca417bb6afe35fde6e8880f97ca43fb ]
Both bpf_get_task_stack and bpf_get_task_stack_sleepable helpers that
use __bpf_get_task_stack have buf defined as ARG_PTR_TO_UNINIT_MEM
argument and we should initialize the buf on every return path.
Adding missing buf memset for __bpf_get_task_stack fail paths. This
provides deterministic buffer contents, which is useful when the buffer
is used directly as a map key.
Fixes: 06ab134ce8ec ("bpf: Refcount task stack in bpf_get_task_stack")
Fixes: b992f01e6615 ("bpf: Guard against accessing NULL pt_regs in bpf_get_task_stack()")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260803210149.296496-10-jolsa@kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/stackmap.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 49f724e63e38a..a43b2d8b13e04 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -635,14 +635,17 @@ static long __bpf_get_task_stack(struct task_struct *task, void *buf, u32 size,
struct pt_regs *regs;
long res = -EINVAL;
- if (!try_get_task_stack(task))
+ if (!try_get_task_stack(task)) {
+ memset(buf, 0, size);
return -EFAULT;
+ }
regs = task_pt_regs(task);
if (regs)
res = __bpf_get_stack(regs, task, buf, size, flags, may_fault);
+ else
+ memset(buf, 0, size);
put_task_stack(task);
-
return res;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 657/869] ocfs2/heartbeat: fix slot mapping rollback leaks on error paths
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (655 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 656/869] bpf: Clear buf on error in __bpf_get_task_stack Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 658/869] ocfs2: o2hb: quiesce negotiate handlers and timeout work Greg Kroah-Hartman
` (212 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yufan Chen, Joseph Qi, Mark Fasheh,
Joel Becker, Junxiao Bi, Changwei Ge, Jun Piao, Heming Zhao,
Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yufan Chen <ericterminal@gmail.com>
[ Upstream commit 5686459423d03d192134166f0ec45f98bb2d5d57 ]
o2hb_map_slot_data() allocates hr_tmp_block, hr_slots, hr_slot_data, and
pages in stages. If a later allocation fails, the current code returns
without unwinding the earlier allocations.
o2hb_region_dev_store() also leaves slot mapping resources behind when
setup aborts, and it keeps hr_aborted_start/hr_node_deleted set across
retries. That leaves stale state behind after a failed start.
Factor the slot cleanup into o2hb_unmap_slot_data(), use it from both
o2hb_map_slot_data() and o2hb_region_release(), and call it from the
dev_store() rollback after stopping a started heartbeat thread. While
freeing pages, clear each hr_slot_data entry as it is released, and reset
the start state before each new setup attempt.
This closes the slot mapping leak on allocation/setup failure paths and
keeps failed setup attempts retryable.
Link: https://lkml.kernel.org/r/20260330153428.19586-1-yufan.chen@linux.dev
Signed-off-by: Yufan Chen <ericterminal@gmail.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Stable-dep-of: 011291b70ba4 ("ocfs2: o2hb: quiesce negotiate handlers and timeout work")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/cluster/heartbeat.c | 83 ++++++++++++++++++++++++------------
1 file changed, 56 insertions(+), 27 deletions(-)
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index 6170e202e56e3..806da7f2d37cc 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -1531,33 +1531,45 @@ static struct o2hb_region *to_o2hb_region(struct config_item *item)
return item ? container_of(item, struct o2hb_region, hr_item) : NULL;
}
-/* drop_item only drops its ref after killing the thread, nothing should
- * be using the region anymore. this has to clean up any state that
- * attributes might have built up. */
-static void o2hb_region_release(struct config_item *item)
+static void o2hb_unmap_slot_data(struct o2hb_region *reg)
{
int i;
struct page *page;
- struct o2hb_region *reg = to_o2hb_region(item);
-
- mlog(ML_HEARTBEAT, "hb region release (%pg)\n", reg_bdev(reg));
-
- kfree(reg->hr_tmp_block);
if (reg->hr_slot_data) {
for (i = 0; i < reg->hr_num_pages; i++) {
page = reg->hr_slot_data[i];
- if (page)
+ if (page) {
__free_page(page);
+ reg->hr_slot_data[i] = NULL;
+ }
}
kfree(reg->hr_slot_data);
+ reg->hr_slot_data = NULL;
}
+ kfree(reg->hr_slots);
+ reg->hr_slots = NULL;
+
+ kfree(reg->hr_tmp_block);
+ reg->hr_tmp_block = NULL;
+}
+
+/* drop_item only drops its ref after killing the thread, nothing should
+ * be using the region anymore. this has to clean up any state that
+ * attributes might have built up.
+ */
+static void o2hb_region_release(struct config_item *item)
+{
+ struct o2hb_region *reg = to_o2hb_region(item);
+
+ mlog(ML_HEARTBEAT, "hb region release (%pg)\n", reg_bdev(reg));
+
+ o2hb_unmap_slot_data(reg);
+
if (reg->hr_bdev_file)
fput(reg->hr_bdev_file);
- kfree(reg->hr_slots);
-
debugfs_remove_recursive(reg->hr_debug_dir);
kfree(reg->hr_db_livenodes);
kfree(reg->hr_db_regnum);
@@ -1708,6 +1720,7 @@ static void o2hb_init_region_params(struct o2hb_region *reg)
static int o2hb_map_slot_data(struct o2hb_region *reg)
{
int i, j;
+ int ret = -ENOMEM;
unsigned int last_slot;
unsigned int spp = reg->hr_slots_per_page;
struct page *page;
@@ -1715,15 +1728,15 @@ static int o2hb_map_slot_data(struct o2hb_region *reg)
struct o2hb_disk_slot *slot;
reg->hr_tmp_block = kmalloc(reg->hr_block_bytes, GFP_KERNEL);
- if (reg->hr_tmp_block == NULL)
- return -ENOMEM;
+ if (!reg->hr_tmp_block)
+ goto out;
reg->hr_slots = kcalloc(reg->hr_blocks,
sizeof(struct o2hb_disk_slot), GFP_KERNEL);
- if (reg->hr_slots == NULL)
- return -ENOMEM;
+ if (!reg->hr_slots)
+ goto out;
- for(i = 0; i < reg->hr_blocks; i++) {
+ for (i = 0; i < reg->hr_blocks; i++) {
slot = ®->hr_slots[i];
slot->ds_node_num = i;
INIT_LIST_HEAD(&slot->ds_live_item);
@@ -1738,12 +1751,12 @@ static int o2hb_map_slot_data(struct o2hb_region *reg)
reg->hr_slot_data = kcalloc(reg->hr_num_pages, sizeof(struct page *),
GFP_KERNEL);
if (!reg->hr_slot_data)
- return -ENOMEM;
+ goto out;
- for(i = 0; i < reg->hr_num_pages; i++) {
+ for (i = 0; i < reg->hr_num_pages; i++) {
page = alloc_page(GFP_KERNEL);
if (!page)
- return -ENOMEM;
+ goto out;
reg->hr_slot_data[i] = page;
@@ -1763,6 +1776,10 @@ static int o2hb_map_slot_data(struct o2hb_region *reg)
}
return 0;
+
+out:
+ o2hb_unmap_slot_data(reg);
+ return ret;
}
/* Read in all the slots available and populate the tracking
@@ -1854,9 +1871,11 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
"blocksize %u incorrect for device, expected %d",
reg->hr_block_bytes, sectsize);
ret = -EINVAL;
- goto out3;
+ goto out;
}
+ reg->hr_aborted_start = 0;
+ reg->hr_node_deleted = 0;
o2hb_init_region_params(reg);
/* Generation of zero is invalid */
@@ -1868,13 +1887,13 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
ret = o2hb_map_slot_data(reg);
if (ret) {
mlog_errno(ret);
- goto out3;
+ goto out;
}
ret = o2hb_populate_slot_data(reg);
if (ret) {
mlog_errno(ret);
- goto out3;
+ goto out;
}
INIT_DELAYED_WORK(®->hr_write_timeout_work, o2hb_write_timeout);
@@ -1905,7 +1924,7 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
if (IS_ERR(hb_task)) {
ret = PTR_ERR(hb_task);
mlog_errno(ret);
- goto out3;
+ goto out;
}
spin_lock(&o2hb_live_lock);
@@ -1922,12 +1941,12 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
if (reg->hr_aborted_start) {
ret = -EIO;
- goto out3;
+ goto out;
}
if (reg->hr_node_deleted) {
ret = -EINVAL;
- goto out3;
+ goto out;
}
/* Ok, we were woken. Make sure it wasn't by drop_item() */
@@ -1946,8 +1965,18 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
printk(KERN_NOTICE "o2hb: Heartbeat started on region %s (%pg)\n",
config_item_name(®->hr_item), reg_bdev(reg));
-out3:
+out:
if (ret < 0) {
+ spin_lock(&o2hb_live_lock);
+ hb_task = reg->hr_task;
+ reg->hr_task = NULL;
+ spin_unlock(&o2hb_live_lock);
+
+ if (hb_task)
+ kthread_stop(hb_task);
+
+ o2hb_unmap_slot_data(reg);
+
fput(reg->hr_bdev_file);
reg->hr_bdev_file = NULL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 658/869] ocfs2: o2hb: quiesce negotiate handlers and timeout work
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (656 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 657/869] ocfs2/heartbeat: fix slot mapping rollback leaks on error paths Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 659/869] ARM: 9481/2: breakpoint: CFI breakpoints only on demand Greg Kroah-Hartman
` (211 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Cen Zhang, Joseph Qi, Mark Fasheh,
Joel Becker, Junxiao Bi, Changwei Ge, Jun Piao, Heming Zhao,
Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <zzzccc427@gmail.com>
[ Upstream commit 011291b70ba4832e136b7b581825b2bc0f525bf6 ]
Heartbeat regions publish struct o2hb_region as the private data for the
NEGO_TIMEOUT and NEGO_APPROVE o2net handlers as soon as make_item()
creates the configfs region. The approve handler can call
o2hb_arm_timeout(), so a peer can touch the region timeout work before
dev_store() has finished building the heartbeat runtime, or after teardown
has started to shut that runtime back down.
The final configfs put also has to keep reg alive until the last in-flight
o2net callback drops its handler reference.
o2net_unregister_handler_list() blocks future handler lookups, but it does
not wait for sc_rx_work that already passed o2net_handler_get(). That
drain needs to cover local listener teardown as well, where the o2net
ordered workqueue may already be inside destroy_workqueue().
Fix the lifetime rule in both directions. Initialize the region delayed
works before publishing reg through the o2net handler table, keep new or
stopping regions non-armable with hr_stopping, and quiesce both delayed
works on failed-start and teardown paths even when no heartbeat thread is
left to call o2hb_disarm_timeout(). Then unregister handlers before
tearing down handler-visible region state and make the drain wait for the
active or destroying o2net ordered workqueue before release frees reg.
The buggy scenario involves two paths, with each column showing the order
within that path:
region lifecycle: late negotiate callback:
1. make_item() registers the 1. o2net_process_message() gets a
region handlers before heartbeat handler for reg.
dev_store() has built a 2. The callback runs after the lookup
runnable heartbeat context. lock is dropped and dereferences reg.
2. A failed start or rmdir 3. An approve or timeout path tries to
stops the heartbeat thread, queue reg's delayed work, or release
quiesces existing work, and races the callback body after handler
drops the final configfs ref. unregister.
3. region_release() must drain 4. The callback or delayed work can
handler-visible o2net rx work outlive reg unless lifecycle code
before freeing reg. keeps the region non-armable and
drains the active-or-destroying
o2net workqueue.
Validation reproduced this kernel report:
KASAN slab-use-after-free in __run_timers+0x22c/0x5b0
Write of size 8
Call trace:
dump_stack_lvl+0x66/0xa0
print_report+0xce/0x630
__run_timers+0x22c/0x5b0
kasan_report+0xe0/0x110
_raw_spin_unlock_irqrestore+0x27/0x60
try_to_wake_up+0x191/0xf70
timer_expire_remote+0xae/0xf0
run_timer_softirq+0x19b/0x1a0
handle_softirqs+0x156/0x660
__irq_exit_rcu+0xc4/0x160
irq_exit_rcu+0xe/0x20
sysvec_apic_timer_interrupt+0x6c/0x80
asm_sysvec_apic_timer_interrupt+0x1a/0x20
Allocated by task stack:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0xaa/0xb0
o2hb_heartbeat_group_make_item+0x3c/0x600
Link: https://lore.kernel.org/20260624095310.763763-3-zzzccc427@gmail.com
Fixes: 34069b886f95 ("ocfs2: o2hb: add NEGO_TIMEOUT message")
Fixes: e76f8237a2f7 ("ocfs2: o2hb: add NEGOTIATE_APPROVE message")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Assisted-by: Codex:gpt-5.5
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/cluster/heartbeat.c | 56 ++++++++++++++++---
fs/ocfs2/cluster/tcp.c | 105 ++++++++++++++++++++++++++++++-----
fs/ocfs2/cluster/tcp.h | 1 +
3 files changed, 139 insertions(+), 23 deletions(-)
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index 806da7f2d37cc..9a21b720eeffb 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -14,6 +14,7 @@
#include <linux/file.h>
#include <linux/kthread.h>
#include <linux/configfs.h>
+#include <linux/mutex.h>
#include <linux/random.h>
#include <linux/crc32.h>
#include <linux/time.h>
@@ -265,6 +266,9 @@ struct o2hb_region {
/* Message key for negotiate timeout message. */
unsigned int hr_key;
struct list_head hr_handler_list;
+ /* Serializes timeout arming against failed-start and teardown. */
+ struct mutex hr_arming_mutex;
+ bool hr_stopping;
/* last hb status, 0 for success, other value for error. */
int hr_last_hb_status;
@@ -329,9 +333,14 @@ static void o2hb_write_timeout(struct work_struct *work)
static void o2hb_arm_timeout(struct o2hb_region *reg)
{
+ mutex_lock(®->hr_arming_mutex);
+
+ if (reg->hr_stopping)
+ goto out_unlock;
+
/* Arm writeout only after thread reaches steady state */
if (atomic_read(®->hr_steady_iterations) != 0)
- return;
+ goto out_unlock;
mlog(ML_HEARTBEAT, "Queue write timeout for %u ms\n",
O2HB_MAX_WRITE_TIMEOUT_MS);
@@ -350,6 +359,18 @@ static void o2hb_arm_timeout(struct o2hb_region *reg)
schedule_delayed_work(®->hr_nego_timeout_work,
msecs_to_jiffies(O2HB_NEGO_TIMEOUT_MS));
bitmap_zero(reg->hr_nego_node_bitmap, O2NM_MAX_NODES);
+
+out_unlock:
+ mutex_unlock(®->hr_arming_mutex);
+}
+
+static void o2hb_queue_nego_timeout(struct o2hb_region *reg,
+ unsigned long delay)
+{
+ mutex_lock(®->hr_arming_mutex);
+ if (!reg->hr_stopping)
+ schedule_delayed_work(®->hr_nego_timeout_work, delay);
+ mutex_unlock(®->hr_arming_mutex);
}
static void o2hb_disarm_timeout(struct o2hb_region *reg)
@@ -358,6 +379,19 @@ static void o2hb_disarm_timeout(struct o2hb_region *reg)
cancel_delayed_work_sync(®->hr_nego_timeout_work);
}
+static void o2hb_set_region_stopping(struct o2hb_region *reg, bool stopping)
+{
+ mutex_lock(®->hr_arming_mutex);
+ reg->hr_stopping = stopping;
+ mutex_unlock(®->hr_arming_mutex);
+}
+
+static void o2hb_quiesce_timeout(struct o2hb_region *reg)
+{
+ o2hb_set_region_stopping(reg, true);
+ o2hb_disarm_timeout(reg);
+}
+
static int o2hb_send_nego_msg(int key, int type, u8 target, u8 node_num)
{
struct o2hb_nego_msg msg;
@@ -407,8 +441,7 @@ static void o2hb_nego_timeout(struct work_struct *work)
/* check negotiate bitmap every second to do timeout
* approve decision.
*/
- schedule_delayed_work(®->hr_nego_timeout_work,
- msecs_to_jiffies(1000));
+ o2hb_queue_nego_timeout(reg, msecs_to_jiffies(1000));
return;
}
@@ -1565,6 +1598,8 @@ static void o2hb_region_release(struct config_item *item)
mlog(ML_HEARTBEAT, "hb region release (%pg)\n", reg_bdev(reg));
+ o2hb_quiesce_timeout(reg);
+ o2net_unregister_and_flush_handler_list(®->hr_handler_list);
o2hb_unmap_slot_data(reg);
if (reg->hr_bdev_file)
@@ -1580,7 +1615,6 @@ static void o2hb_region_release(struct config_item *item)
list_del(®->hr_all_item);
spin_unlock(&o2hb_live_lock);
- o2net_unregister_handler_list(®->hr_handler_list);
kfree(reg);
}
@@ -1896,9 +1930,6 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
goto out;
}
- INIT_DELAYED_WORK(®->hr_write_timeout_work, o2hb_write_timeout);
- INIT_DELAYED_WORK(®->hr_nego_timeout_work, o2hb_nego_timeout);
-
/*
* A node is considered live after it has beat LIVE_THRESHOLD
* times. We're not steady until we've given them a chance
@@ -1918,6 +1949,7 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
atomic_set(®->hr_steady_iterations, live_threshold);
/* unsteady_iterations is triple the steady_iterations */
atomic_set(®->hr_unsteady_iterations, (live_threshold * 3));
+ o2hb_set_region_stopping(reg, false);
hb_task = kthread_run(o2hb_thread, reg, "o2hb-%s",
reg->hr_item.ci_name);
@@ -1967,6 +1999,8 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
out:
if (ret < 0) {
+ o2hb_quiesce_timeout(reg);
+
spin_lock(&o2hb_live_lock);
hb_task = reg->hr_task;
reg->hr_task = NULL;
@@ -2108,6 +2142,10 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g
*/
reg->hr_key = crc32_le(reg->hr_region_num + O2NM_MAX_REGIONS,
name, strlen(name));
+ mutex_init(®->hr_arming_mutex);
+ reg->hr_stopping = true;
+ INIT_DELAYED_WORK(®->hr_write_timeout_work, o2hb_write_timeout);
+ INIT_DELAYED_WORK(®->hr_nego_timeout_work, o2hb_nego_timeout);
INIT_LIST_HEAD(®->hr_handler_list);
ret = o2net_register_handler(O2HB_NEGO_TIMEOUT_MSG, reg->hr_key,
sizeof(struct o2hb_nego_msg),
@@ -2128,7 +2166,7 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g
return ®->hr_item;
unregister_handler:
- o2net_unregister_handler_list(®->hr_handler_list);
+ o2net_unregister_and_flush_handler_list(®->hr_handler_list);
remove_item:
spin_lock(&o2hb_live_lock);
list_del(®->hr_all_item);
@@ -2147,6 +2185,8 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group,
struct o2hb_region *reg = to_o2hb_region(item);
int quorum_region = 0;
+ o2hb_quiesce_timeout(reg);
+
/* stop the thread when the user removes the region dir */
spin_lock(&o2hb_live_lock);
hb_task = reg->hr_task;
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 15b726a3a1fc7..dd4fb83d9cd8b 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -38,6 +38,8 @@
*/
#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
#include <linux/sched/mm.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
@@ -101,10 +103,15 @@ static struct socket *o2net_listen_sock;
* o2net_wq. teardown detaches the callbacks before destroying the workqueue.
* quorum work is queued as sock containers are shutdown.. stop_listening
* tears down all the node's sock containers, preventing future shutdowns
- * and queued quroum work, before canceling delayed quorum work and
- * destroying the work queue.
+ * and queued quorum work, before canceling delayed quorum work and
+ * destroying the work queue. Handler teardown can also race local listener
+ * shutdown, so keep a waitable destroying pointer until the old ordered
+ * queue has finished draining.
*/
static struct workqueue_struct *o2net_wq;
+static struct workqueue_struct *o2net_wq_destroying;
+static DEFINE_MUTEX(o2net_wq_mutex);
+static DECLARE_COMPLETION(o2net_wq_destroyed);
/* Heartbeat callbacks stay registered across local-node off/on. */
static bool o2net_listening;
static struct work_struct o2net_listen_work;
@@ -886,6 +893,27 @@ void o2net_unregister_handler_list(struct list_head *list)
}
EXPORT_SYMBOL_GPL(o2net_unregister_handler_list);
+static void o2net_flush_wq(void)
+{
+ mutex_lock(&o2net_wq_mutex);
+ if (o2net_wq_destroying) {
+ mutex_unlock(&o2net_wq_mutex);
+ wait_for_completion(&o2net_wq_destroyed);
+ return;
+ }
+
+ if (o2net_wq)
+ flush_workqueue(o2net_wq);
+ mutex_unlock(&o2net_wq_mutex);
+}
+
+void o2net_unregister_and_flush_handler_list(struct list_head *list)
+{
+ o2net_unregister_handler_list(list);
+ o2net_flush_wq();
+}
+EXPORT_SYMBOL_GPL(o2net_unregister_and_flush_handler_list);
+
static struct o2net_msg_handler *o2net_handler_get(u32 msg_type, u32 key)
{
struct o2net_msg_handler *nmh;
@@ -1716,12 +1744,10 @@ void o2net_disconnect_node(struct o2nm_node *node)
o2net_set_nn_state(nn, NULL, 0, -ENOTCONN);
spin_unlock(&nn->nn_lock);
- if (o2net_wq) {
- cancel_delayed_work(&nn->nn_connect_expired);
- cancel_delayed_work(&nn->nn_connect_work);
- cancel_delayed_work(&nn->nn_still_up);
- flush_workqueue(o2net_wq);
- }
+ cancel_delayed_work(&nn->nn_connect_expired);
+ cancel_delayed_work(&nn->nn_connect_work);
+ cancel_delayed_work(&nn->nn_still_up);
+ o2net_flush_wq();
}
static void o2net_hb_node_down_cb(struct o2nm_node *node, int node_num,
@@ -2066,6 +2092,36 @@ static int o2net_open_listening_sock(__be32 addr, __be16 port)
return ret;
}
+static void o2net_destroy_wq(void)
+{
+ struct workqueue_struct *wq;
+
+ mutex_lock(&o2net_wq_mutex);
+ if (o2net_wq_destroying) {
+ mutex_unlock(&o2net_wq_mutex);
+ wait_for_completion(&o2net_wq_destroyed);
+ return;
+ }
+
+ wq = o2net_wq;
+ if (!wq) {
+ mutex_unlock(&o2net_wq_mutex);
+ return;
+ }
+
+ reinit_completion(&o2net_wq_destroyed);
+ o2net_wq_destroying = wq;
+ mutex_unlock(&o2net_wq_mutex);
+
+ destroy_workqueue(wq);
+
+ mutex_lock(&o2net_wq_mutex);
+ o2net_wq = NULL;
+ o2net_wq_destroying = NULL;
+ complete_all(&o2net_wq_destroyed);
+ mutex_unlock(&o2net_wq_mutex);
+}
+
/*
* called from node manager when we should bring up our network listening
* socket. node manager handles all the serialization to only call this
@@ -2076,24 +2132,44 @@ static int o2net_open_listening_sock(__be32 addr, __be16 port)
int o2net_start_listening(struct o2nm_node *node)
{
int ret = 0;
+ struct workqueue_struct *wq;
if (WARN_ON_ONCE(READ_ONCE(o2net_listening)))
return -EBUSY;
- BUG_ON(o2net_wq != NULL);
+
+ mutex_lock(&o2net_wq_mutex);
+ if (o2net_wq_destroying) {
+ mutex_unlock(&o2net_wq_mutex);
+ return -EBUSY;
+ }
+ if (WARN_ON_ONCE(o2net_wq)) {
+ mutex_unlock(&o2net_wq_mutex);
+ return -EBUSY;
+ }
+ mutex_unlock(&o2net_wq_mutex);
+
BUG_ON(o2net_listen_sock != NULL);
mlog(ML_KTHREAD, "starting o2net thread...\n");
- o2net_wq = alloc_ordered_workqueue("o2net", WQ_MEM_RECLAIM);
- if (o2net_wq == NULL) {
+ wq = alloc_ordered_workqueue("o2net", WQ_MEM_RECLAIM);
+ if (!wq) {
mlog(ML_ERROR, "unable to launch o2net thread\n");
return -ENOMEM; /* ? */
}
+ mutex_lock(&o2net_wq_mutex);
+ if (unlikely(o2net_wq_destroying || o2net_wq)) {
+ mutex_unlock(&o2net_wq_mutex);
+ destroy_workqueue(wq);
+ return -EBUSY;
+ }
+ o2net_wq = wq;
+ mutex_unlock(&o2net_wq_mutex);
+
ret = o2net_open_listening_sock(node->nd_ipv4_address,
node->nd_ipv4_port);
if (ret) {
- destroy_workqueue(o2net_wq);
- o2net_wq = NULL;
+ o2net_destroy_wq();
} else
o2quo_conn_up(node->nd_num);
@@ -2129,8 +2205,7 @@ void o2net_stop_listening(struct o2nm_node *node)
/* finish all work and tear down the work queue */
mlog(ML_KTHREAD, "waiting for o2net thread to exit....\n");
- destroy_workqueue(o2net_wq);
- o2net_wq = NULL;
+ o2net_destroy_wq();
sock_release(o2net_listen_sock);
o2net_listen_sock = NULL;
diff --git a/fs/ocfs2/cluster/tcp.h b/fs/ocfs2/cluster/tcp.h
index 2e86d42b5faf9..a11bcee289479 100644
--- a/fs/ocfs2/cluster/tcp.h
+++ b/fs/ocfs2/cluster/tcp.h
@@ -89,6 +89,7 @@ int o2net_register_handler(u32 msg_type, u32 key, u32 max_len,
o2net_post_msg_handler_func *post_func,
struct list_head *unreg_list);
void o2net_unregister_handler_list(struct list_head *list);
+void o2net_unregister_and_flush_handler_list(struct list_head *list);
void o2net_fill_node_map(unsigned long *map, unsigned bytes);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 659/869] ARM: 9481/2: breakpoint: CFI breakpoints only on demand
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (657 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 658/869] ocfs2: o2hb: quiesce negotiate handlers and timeout work Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 660/869] thermal: hwmon: Remove hwmon class device along with its parent Greg Kroah-Hartman
` (210 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, slipher, Mark Rutland, Linus Walleij,
Russell King, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <linusw@kernel.org>
[ Upstream commit 8ed9bff906cf8036531d1559f10e82733a52b41f ]
This removes the stub hw_breakpoint_cfi_handler() from ARM, making
it not steal breakpoint type 0x03 (ARM_ENTRY_CFI_BREAKPOINT) unless
CFI is actively used in the kernel.
When not instrumenting with CFI, or when a breakpoint is issued in
userspace, we fall through to return 1 from hw_breakpoint_pending()
"unhandled fault" so userspace can make use of this breakpoint.
Tested with LKDTM and this command line:
echo CFI_FORWARD_PROTO > /sys/kernel/debug/provoke-crash/DIRECT
still works as expected.
Closes: https://lore.kernel.org/lkml/kJqktbpLphg_Pk5I5SPptgTLjl3E3eq5mN5UzCslyFj7Q1Irp-wDid4mj5eQVd2iZtRGXgeZd8goq195EkXdjyt864YMc8mVb2B9NGH91NQ=@protonmail.com/
Fixes: c3f89986fde7 ("ARM: 9391/2: hw_breakpoint: Handle CFI breakpoints")
Reported-by: slipher <slipher@protonmail.com>
Suggested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm/kernel/hw_breakpoint.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index a12efd0f43e81..6819d4c1f3521 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -929,10 +929,6 @@ static void hw_breakpoint_cfi_handler(struct pt_regs *regs)
break;
}
}
-#else
-static void hw_breakpoint_cfi_handler(struct pt_regs *regs)
-{
-}
#endif
/*
@@ -964,9 +960,14 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
case ARM_ENTRY_SYNC_WATCHPOINT:
watchpoint_handler(addr, fsr, regs);
break;
+#ifdef CONFIG_CFI
case ARM_ENTRY_CFI_BREAKPOINT:
- hw_breakpoint_cfi_handler(regs);
+ if (user_mode(regs))
+ ret = 1; /* Don't handle userspace BKPT */
+ else
+ hw_breakpoint_cfi_handler(regs);
break;
+#endif
default:
ret = 1; /* Unhandled fault. */
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 660/869] thermal: hwmon: Remove hwmon class device along with its parent
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (658 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 659/869] ARM: 9481/2: breakpoint: CFI breakpoints only on demand Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 661/869] ocfs2: validate inline xattrs during inode block validation Greg Kroah-Hartman
` (209 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rafael J. Wysocki, Lukasz Luba,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
[ Upstream commit 2b57e24d34b2dfc43c81942bb359d6315bf302fb ]
The current code creates one hwmon device per thermal zone type and that
device is registered under the first thermal zone of the given type.
That turns out to be problematic when the thermal zone holding the
hwmon device is removed.
For example, say that there are two ACPI thermal zones on a system
/sys/devices/virtual/thermal/thermal_zone0/
/sys/devices/virtual/thermal/thermal_zone1/
The current code registers a hwmon class device for thermal_zone0 only:
/sys/devices/virtual/thermal/thermal_zone0/hwmon0/
because the type is "acpitz" for both of them, but it adds a sysfs
attribute that belongs to thermal_zone1 under it:
/sys/devices/virtual/thermal/thermal_zone0/hwmon0/temp2_input
There is also
/sys/devices/virtual/thermal/thermal_zone0/hwmon0/temp1_input
which belongs to thermal_zone0.
When thermal_zone0 is removed, say because the ACPI thermal driver is
unbound from the underlying platform device, thermal_remove_hwmon_sysfs()
skips the removal of hwmon0 because of the temp2_input attribute
belonging to thermal_zone1 which effectively prevents thermal_zone0
removal from making progress.
Address this by making thermal_remove_hwmon_sysfs() remove the entire
hwmon class device interface for the given thermal zone type when the
thermal zone device holding it is removed.
To prevent races with thermal_add_hwmon_sysfs() that may interfere
with this, carry out the entire addition and removal of hwmon sysfs
interfaces for thermal zones under thermal_hwmon_list_lock.
Also adjust the layout of the labels in thermal_add_hwmon_sysfs() to
the current kernel coding style to align with the new "unlock" label.
Link: https://lore.kernel.org/linux-pm/20260402021828.16556-1-liujia6264@gmail.com/
Fixes: f6b6b52ef7a5 ("thermal_hwmon: Pass the originating device down to hwmon_device_register_with_info")
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
Link: https://patch.msgid.link/5094738.GXAFRqVoOG@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/thermal/thermal_hwmon.c | 87 +++++++++++++--------------------
1 file changed, 34 insertions(+), 53 deletions(-)
diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c
index 3162a1a8cbb60..fcbad98d3e1b1 100644
--- a/drivers/thermal/thermal_hwmon.c
+++ b/drivers/thermal/thermal_hwmon.c
@@ -98,34 +98,12 @@ thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
struct thermal_hwmon_device *hwmon;
char type[THERMAL_NAME_LENGTH];
- mutex_lock(&thermal_hwmon_list_lock);
list_for_each_entry(hwmon, &thermal_hwmon_list, node) {
strcpy(type, tz->type);
strreplace(type, '-', '_');
- if (!strcmp(hwmon->type, type)) {
- mutex_unlock(&thermal_hwmon_list_lock);
+ if (!strcmp(hwmon->type, type))
return hwmon;
- }
}
- mutex_unlock(&thermal_hwmon_list_lock);
-
- return NULL;
-}
-
-/* Find the temperature input matching a given thermal zone */
-static struct thermal_hwmon_temp *
-thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
- const struct thermal_zone_device *tz)
-{
- struct thermal_hwmon_temp *temp;
-
- mutex_lock(&thermal_hwmon_list_lock);
- list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
- if (temp->tz == tz) {
- mutex_unlock(&thermal_hwmon_list_lock);
- return temp;
- }
- mutex_unlock(&thermal_hwmon_list_lock);
return NULL;
}
@@ -141,7 +119,9 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
struct thermal_hwmon_device *hwmon;
struct thermal_hwmon_temp *temp;
int new_hwmon_device = 1;
- int result;
+ int result = 0;
+
+ mutex_lock(&thermal_hwmon_list_lock);
hwmon = thermal_hwmon_lookup_by_type(tz);
if (hwmon) {
@@ -150,8 +130,10 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
}
hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL);
- if (!hwmon)
- return -ENOMEM;
+ if (!hwmon) {
+ result = -ENOMEM;
+ goto unlock;
+ }
INIT_LIST_HEAD(&hwmon->tz_list);
strscpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
@@ -199,24 +181,24 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
temp->temp_crit_present = true;
}
- mutex_lock(&thermal_hwmon_list_lock);
if (new_hwmon_device)
list_add_tail(&hwmon->node, &thermal_hwmon_list);
list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
- mutex_unlock(&thermal_hwmon_list_lock);
- return 0;
+ goto unlock;
- unregister_input:
+unregister_input:
device_remove_file(hwmon->device, &temp->temp_input.attr);
- free_temp_mem:
+free_temp_mem:
kfree(temp);
- unregister_name:
+unregister_name:
if (new_hwmon_device)
hwmon_device_unregister(hwmon->device);
- free_mem:
+free_mem:
if (new_hwmon_device)
kfree(hwmon);
+unlock:
+ mutex_unlock(&thermal_hwmon_list_lock);
return result;
}
@@ -224,8 +206,11 @@ EXPORT_SYMBOL_GPL(thermal_add_hwmon_sysfs);
void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
{
+ struct thermal_hwmon_temp *temp, *entry;
struct thermal_hwmon_device *hwmon;
- struct thermal_hwmon_temp *temp;
+ bool unregister;
+
+ guard(mutex)(&thermal_hwmon_list_lock);
hwmon = thermal_hwmon_lookup_by_type(tz);
if (unlikely(!hwmon)) {
@@ -234,29 +219,25 @@ void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
return;
}
- temp = thermal_hwmon_lookup_temp(hwmon, tz);
- if (unlikely(!temp)) {
- /* Should never happen... */
- dev_dbg(&tz->device, "temperature input lookup failed!\n");
- return;
- }
+ unregister = hwmon->device->parent == &tz->device;
- device_remove_file(hwmon->device, &temp->temp_input.attr);
- if (temp->temp_crit_present)
- device_remove_file(hwmon->device, &temp->temp_crit.attr);
+ list_for_each_entry_safe_reverse(temp, entry, &hwmon->tz_list, hwmon_node) {
+ if (!unregister && temp->tz != tz)
+ continue;
- mutex_lock(&thermal_hwmon_list_lock);
- list_del(&temp->hwmon_node);
- kfree(temp);
- if (!list_empty(&hwmon->tz_list)) {
- mutex_unlock(&thermal_hwmon_list_lock);
- return;
+ device_remove_file(hwmon->device, &temp->temp_input.attr);
+ if (temp->temp_crit_present)
+ device_remove_file(hwmon->device, &temp->temp_crit.attr);
+
+ list_del(&temp->hwmon_node);
+ kfree(temp);
}
- list_del(&hwmon->node);
- mutex_unlock(&thermal_hwmon_list_lock);
- hwmon_device_unregister(hwmon->device);
- kfree(hwmon);
+ if (unregister) {
+ list_del(&hwmon->node);
+ hwmon_device_unregister(hwmon->device);
+ kfree(hwmon);
+ }
}
EXPORT_SYMBOL_GPL(thermal_remove_hwmon_sysfs);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 661/869] ocfs2: validate inline xattrs during inode block validation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (659 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 660/869] thermal: hwmon: Remove hwmon class device along with its parent Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 662/869] ublk: check import_ubuf() return value Greg Kroah-Hartman
` (208 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Cen Zhang, Joseph Qi, Changwei Ge,
Heming Zhao, Joel Becker, Jun Piao, Junxiao Bi, Mark Fasheh,
Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <zzzccc427@gmail.com>
[ Upstream commit 8914a3330b72378136c2c02d6328a826f6abdad7 ]
Patch series "ocfs2: validate xattr entry bounds", v7.
This series validates OCFS2 xattr entry name/value bounds when xattr
metadata is read and validated, before getxattr() or listxattr() can walk
out-of-range entry arrays or offsets from corrupted metadata.
This patch (of 2):
ocfs2_validate_inode_block() verifies a dinode before OCFS2 users walk
metadata from it, but inline xattr metadata is still checked only in
operation-specific consumers. The existing ibody lookup helper validates
inline header placement and entry count, but inode block validation does
not reject entry name/value bounds.
Add a flat xattr entry validator and call it from inode block validation
for inline xattrs. Keep the operation paths on their existing
header/count lookup checks; the full entry bounds check now runs when the
inode block is validated at read time.
Reject corrupted inline xattr metadata before ocfs2_xattr_ibody_get() or
listxattr() can walk past the inline storage.
Validation reproduced this kernel report:
BUG: KASAN: use-after-free in ocfs2_xattr_find_entry+0x5a/0x170
Read of size 2 at addr ffff8881242a2000 by task python3/529
Call Trace:
dump_stack_lvl+0x66/0xa0
print_report+0xce/0x630
kasan_report+0xe0/0x110
ocfs2_xattr_find_entry+0x5a/0x170
ocfs2_xattr_get_nolock+0x20a/0x820
ocfs2_xattr_get+0x10c/0x1e0
__vfs_getxattr+0xe2/0x130
vfs_getxattr+0x185/0x1b0
Link: https://lore.kernel.org/20260705025311.3429854-1-zzzccc427@gmail.com
Link: https://lore.kernel.org/20260705025311.3429854-2-zzzccc427@gmail.com
Fixes: cf1d6c763fbc ("ocfs2: Add extended attribute support")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Assisted-by: Codex:gpt-5.5
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Mark Fasheh <mark@fasheh.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/inode.c | 4 ++
fs/ocfs2/xattr.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++
fs/ocfs2/xattr.h | 2 +
3 files changed, 124 insertions(+)
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 1330ea2473736..eb8de681376bd 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -1562,6 +1562,10 @@ int ocfs2_validate_inode_block(struct super_block *sb,
goto bail;
}
+ rc = ocfs2_validate_inode_xattr(sb, bh->b_blocknr, di);
+ if (rc)
+ goto bail;
+
if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) {
struct ocfs2_inline_data *data = &di->id2.i_data;
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index 3cc679e5f1a1a..1cad9a386705e 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -953,6 +953,124 @@ static int ocfs2_xattr_list_entries(struct inode *inode,
return result;
}
+static int ocfs2_validate_xattr_entries_flat(struct super_block *sb, u64 blkno,
+ struct ocfs2_xattr_header *xh,
+ size_t region_size)
+{
+ u16 xattr_count = le16_to_cpu(xh->xh_count);
+ size_t entries_limit = region_size;
+ size_t nv_limit = region_size;
+ size_t max_entries;
+ int i;
+
+ if (region_size < sizeof(*xh))
+ return ocfs2_error(sb,
+ "Invalid xattr in block %llu: region size %zu is too small\n",
+ (unsigned long long)blkno, region_size);
+
+ max_entries = (entries_limit - sizeof(*xh)) /
+ sizeof(struct ocfs2_xattr_entry);
+
+ if (xattr_count > max_entries)
+ return ocfs2_error(sb,
+ "Invalid xattr in block %llu: entry count %u exceeds maximum %zu\n",
+ (unsigned long long)blkno,
+ xattr_count, max_entries);
+
+ for (i = 0; i < xattr_count; i++) {
+ struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
+ size_t name_offset = le16_to_cpu(xe->xe_name_offset);
+ size_t value_offset;
+
+ if (name_offset > nv_limit ||
+ xe->xe_name_len > nv_limit - name_offset)
+ return ocfs2_error(sb,
+ "Invalid xattr in block %llu: entry %d name is out of bounds\n",
+ (unsigned long long)blkno, i);
+
+ value_offset = name_offset + OCFS2_XATTR_SIZE(xe->xe_name_len);
+ if (value_offset > nv_limit)
+ return ocfs2_error(sb,
+ "Invalid xattr in block %llu: entry %d value starts out of bounds\n",
+ (unsigned long long)blkno, i);
+
+ if (ocfs2_xattr_is_local(xe)) {
+ if (le64_to_cpu(xe->xe_value_size) >
+ nv_limit - value_offset)
+ return ocfs2_error(sb,
+ "Invalid xattr in block %llu: entry %d value is out of bounds\n",
+ (unsigned long long)blkno,
+ i);
+ } else if (sizeof(struct ocfs2_xattr_value_root) >
+ nv_limit - value_offset) {
+ return ocfs2_error(sb,
+ "Invalid xattr in block %llu: entry %d value root is out of bounds\n",
+ (unsigned long long)blkno, i);
+ }
+ }
+
+ return 0;
+}
+
+static int ocfs2_xattr_ibody_lookup_header_raw(struct super_block *sb,
+ u64 blkno,
+ struct ocfs2_dinode *di,
+ struct ocfs2_xattr_header **header,
+ u16 *inline_size_ret)
+{
+ struct ocfs2_xattr_header *xh;
+ u16 xattr_count;
+ size_t max_entries;
+ u16 inline_size = le16_to_cpu(di->i_xattr_inline_size);
+
+ if (inline_size > sb->s_blocksize ||
+ inline_size < sizeof(struct ocfs2_xattr_header)) {
+ ocfs2_error(sb,
+ "Invalid inode %llu: xattr inline size %u\n",
+ (unsigned long long)blkno, inline_size);
+ return -EFSCORRUPTED;
+ }
+
+ xh = (struct ocfs2_xattr_header *)
+ ((void *)di + sb->s_blocksize - inline_size);
+
+ xattr_count = le16_to_cpu(xh->xh_count);
+ max_entries = (inline_size - sizeof(struct ocfs2_xattr_header)) /
+ sizeof(struct ocfs2_xattr_entry);
+
+ if (xattr_count > max_entries) {
+ ocfs2_error(sb,
+ "xattr entry count %u exceeds maximum %zu in inode %llu\n",
+ xattr_count, max_entries,
+ (unsigned long long)blkno);
+ return -EFSCORRUPTED;
+ }
+
+ *header = xh;
+ if (inline_size_ret)
+ *inline_size_ret = inline_size;
+
+ return 0;
+}
+
+int ocfs2_validate_inode_xattr(struct super_block *sb, u64 blkno,
+ struct ocfs2_dinode *di)
+{
+ struct ocfs2_xattr_header *xh;
+ u16 inline_size;
+ int ret;
+
+ if (!(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL))
+ return 0;
+
+ ret = ocfs2_xattr_ibody_lookup_header_raw(sb, blkno, di, &xh,
+ &inline_size);
+ if (ret)
+ return ret;
+
+ return ocfs2_validate_xattr_entries_flat(sb, blkno, xh, inline_size);
+}
+
int ocfs2_has_inline_xattr_value_outside(struct inode *inode,
struct ocfs2_dinode *di)
{
diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h
index aeba323e14b3c..887cc1a18b1af 100644
--- a/fs/ocfs2/xattr.h
+++ b/fs/ocfs2/xattr.h
@@ -43,6 +43,8 @@ int ocfs2_xattr_set_handle(handle_t *, struct inode *, struct buffer_head *,
struct ocfs2_alloc_context *);
int ocfs2_has_inline_xattr_value_outside(struct inode *inode,
struct ocfs2_dinode *di);
+int ocfs2_validate_inode_xattr(struct super_block *sb, u64 blkno,
+ struct ocfs2_dinode *di);
int ocfs2_xattr_remove(struct inode *, struct buffer_head *);
int ocfs2_init_security_get(struct inode *, struct inode *,
const struct qstr *,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 662/869] ublk: check import_ubuf() return value
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (660 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 661/869] ocfs2: validate inline xattrs during inode block validation Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 663/869] blk-cgroup: fix race between policy activation and blkg destruction Greg Kroah-Hartman
` (207 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ming Lei, Caleb Sander Mateos,
Jens Axboe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Caleb Sander Mateos <csander@purestorage.com>
[ Upstream commit 3831568792af75b6523fa93bb91560e29189cf55 ]
import_ubuf() can fail if the address range (provided by the userspace
ublk server) is outside the allowed user address space. Return that 0
bytes were copied if import_ubuf() fails rather than passing an
uninitialized struct iov_iter to ublk_copy_user_pages().
Fixes: 981f95a571e3 ("ublk: cleanup ublk_copy_user_pages")
Reported-by: Ming Lei <tom.leiming@gmail.com>
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Link: https://patch.msgid.link/20260729171041.45061-2-csander@purestorage.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/block/ublk_drv.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index bd0b2046981e4..7fd286d8aadb2 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -915,7 +915,10 @@ static int ublk_map_io(const struct ublk_queue *ubq, const struct request *req,
struct iov_iter iter;
const int dir = ITER_DEST;
- import_ubuf(dir, u64_to_user_ptr(io->addr), rq_bytes, &iter);
+ if (import_ubuf(dir, u64_to_user_ptr(io->addr), rq_bytes,
+ &iter) < 0)
+ return 0;
+
return ublk_copy_user_pages(req, 0, &iter, dir);
}
return rq_bytes;
@@ -936,7 +939,10 @@ static int ublk_unmap_io(const struct ublk_queue *ubq,
WARN_ON_ONCE(io->res > rq_bytes);
- import_ubuf(dir, u64_to_user_ptr(io->addr), io->res, &iter);
+ if (import_ubuf(dir, u64_to_user_ptr(io->addr), io->res,
+ &iter) < 0)
+ return 0;
+
return ublk_copy_user_pages(req, 0, &iter, dir);
}
return rq_bytes;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 663/869] blk-cgroup: fix race between policy activation and blkg destruction
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (661 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 662/869] ublk: check import_ubuf() return value Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 664/869] HID: steam: Reject short reads Greg Kroah-Hartman
` (206 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Zheng Qixing, Tang Yizhou, Yu Kuai,
Tao Cui, Nilay Shroff, Jens Axboe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zheng Qixing <zhengqixing@huawei.com>
[ Upstream commit 5313d4d41739b0cb63000747c97bb1217ac45f3e ]
When switching an IO scheduler on a block device, blkcg_activate_policy()
allocates blkg_policy_data (pd) for all blkgs attached to the queue.
However, blkcg_activate_policy() may race with concurrent blkcg deletion,
leading to use-after-free and memory leak issues.
The use-after-free occurs in the following race:
T1 (blkcg_activate_policy):
- Successfully allocates pd for blkg1 (loop0->queue, blkcgA)
- Fails to allocate pd for blkg2 (loop0->queue, blkcgB)
- Enters the enomem rollback path to release blkg1 resources
T2 (blkcg deletion):
- blkcgA is deleted concurrently
- blkg1 is freed via blkg_free_workfn()
- blkg1->pd is freed
T1 (continued):
- Rollback path accesses blkg1->pd->online after pd is freed
- Triggers use-after-free
In addition, blkg_free_workfn() frees pd before removing the blkg from
q->blkg_list. This allows blkcg_activate_policy() to allocate a new pd
for a blkg that is being destroyed, leaving the newly allocated pd
unreachable when the blkg is finally freed.
Fix these races by extending blkcg_mutex coverage to serialize
blkcg_activate_policy() rollback and blkg destruction, ensuring pd
lifecycle is synchronized with blkg list visibility.
Fixes: f1c006f1c685 ("blk-cgroup: synchronize pd_free_fn() from blkg_free_workfn() and blkcg_deactivate_policy()")
Signed-off-by: Zheng Qixing <zhengqixing@huawei.com>
Reviewed-by: Tang Yizhou <yizhou.tang@shopee.com>
Signed-off-by: Yu Kuai <yukuai@fygo.io>
Reviewed-by: Tao Cui <cuitao@kylinos.cn>
Reviewed-by: Nilay Shroff <nilay@linux.ibm.com>
Link: https://patch.msgid.link/20260802112525.3933753-3-yukuai@kernel.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
block/blk-cgroup.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index cc882dc2db7f6..06de4024a9a25 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -1561,6 +1561,8 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
if (queue_is_mq(q))
blk_mq_freeze_queue(q);
+
+ mutex_lock(&q->blkcg_mutex);
retry:
spin_lock_irq(&q->queue_lock);
@@ -1625,6 +1627,7 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
spin_unlock_irq(&q->queue_lock);
out:
+ mutex_unlock(&q->blkcg_mutex);
if (queue_is_mq(q))
blk_mq_unfreeze_queue(q);
if (pinned_blkg)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 664/869] HID: steam: Reject short reads
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (662 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 663/869] blk-cgroup: fix race between policy activation and blkg destruction Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 665/869] HID: logitech-hidpp: Fix FF device cleanup on init failure Greg Kroah-Hartman
` (205 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+75f3f9bff8c510602d36,
Vicki Pfau, Jiri Kosina, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vicki Pfau <vi@endrift.com>
[ Upstream commit 33ff7b49c38b39b1f3d27db508ac0720fb25c08a ]
Steam Controller FEATURE reports encode the size of the message in the
message itself. Previously we were trusting that the size reported matched
the size we actually read, leading to a potential issue with short reads.
Instead, we should actually verify the length of the read.
Fixes: c164d6abf384 ("HID: add driver for Valve Steam Controller")
Reported-by: syzbot+75f3f9bff8c510602d36@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=75f3f9bff8c510602d36
Signed-off-by: Vicki Pfau <vi@endrift.com>
Link: https://syzkaller.appspot.com/bug?extid=75f3f9bff8c510602d36
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/hid-steam.c | 33 ++++++++++++++++++++++++++++++---
1 file changed, 30 insertions(+), 3 deletions(-)
diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
index 0f826acfbf275..4283219275a3d 100644
--- a/drivers/hid/hid-steam.c
+++ b/drivers/hid/hid-steam.c
@@ -324,6 +324,13 @@ static int steam_recv_report(struct steam_device *steam,
u8 *buf;
int ret;
+ /*
+ * All reports start with a two byte header.
+ * We must read at least two bytes to get a sensible output.
+ */
+ if (size < 2)
+ return -EINVAL;
+
r = steam->hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0];
if (!r) {
hid_err(steam->hdev, "No HID_FEATURE_REPORT submitted - nothing to read\n");
@@ -346,10 +353,30 @@ static int steam_recv_report(struct steam_device *steam,
ret = hid_hw_raw_request(steam->hdev, 0x00,
buf, hid_report_len(r) + 1,
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
- if (ret > 0)
- memcpy(data, buf + 1, min(size, ret - 1));
+ if (ret > 0) {
+ /* Remove the report ID from the return buffer */
+ ret--;
+ size = min(size, ret);
+ memcpy(data, buf + 1, size);
+ }
kfree(buf);
- return ret;
+
+ if (ret < 0) {
+ hid_err(steam->hdev, "%s: error %d\n", __func__, ret);
+ return ret;
+ }
+
+ if (ret < 2) {
+ hid_err(steam->hdev, "%s: reply too short\n", __func__);
+ return -EPROTO;
+ }
+ if (ret < data[1] + 2) {
+ hid_err(steam->hdev, "%s: expected %u bytes, read %i\n",
+ __func__, data[1] + 2, ret);
+ return -EPROTO;
+ }
+ hid_dbg(steam->hdev, "Received report %*ph\n", size, data);
+ return size;
}
static int steam_send_report(struct steam_device *steam,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 665/869] HID: logitech-hidpp: Fix FF device cleanup on init failure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (663 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 664/869] HID: steam: Reject short reads Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 666/869] tty: skip cdev_del() when no cdev is registered Greg Kroah-Hartman
` (204 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Haoxiang Li, Bastien Nocera,
Jiri Kosina, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <haoxiang_li2024@163.com>
[ Upstream commit dd5be4d9ce2dfc4d4a4527ef7d31d21a78e3cdac ]
hidpp_ff_init() creates the input force-feedback device with
input_ff_create(), then allocates the HID++ FF private data,
effect ID array, and workqueue.
If any of those allocations fail after input_ff_create() succeeds,
the function returns an error without destroying the FF device.
Add an unwind path that frees the private allocations made by
hidpp_ff_init() and calls input_ff_destroy() for failures after
input_ff_create() succeeds.
Fixes: ff21a635dd1a ("HID: logitech-hidpp: Force feedback support for the Logitech G920")
Signed-off-by: Haoxiang Li <haoxiang_li2024@163.com>
Reviewed-by: Bastien Nocera <hadess@hadess.net>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/hid-logitech-hidpp.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 9926ab6e808eb..c84bd26faea96 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -2878,18 +2878,19 @@ static int hidpp_ff_init(struct hidpp_device *hidpp,
* ownership to FF core
*/
data = kmemdup(data, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
+ if (!data) {
+ error = -ENOMEM;
+ goto err_destroy_ff;
+ }
data->effect_ids = kcalloc(num_slots, sizeof(int), GFP_KERNEL);
if (!data->effect_ids) {
- kfree(data);
- return -ENOMEM;
+ error = -ENOMEM;
+ goto err_free_data;
}
data->wq = create_singlethread_workqueue("hidpp-ff-sendqueue");
if (!data->wq) {
- kfree(data->effect_ids);
- kfree(data);
- return -ENOMEM;
+ error = -ENOMEM;
+ goto err_free_effect_ids;
}
data->hidpp = hidpp;
@@ -2919,6 +2920,14 @@ static int hidpp_ff_init(struct hidpp_device *hidpp,
version);
return 0;
+
+err_free_effect_ids:
+ kfree(data->effect_ids);
+err_free_data:
+ kfree(data);
+err_destroy_ff:
+ input_ff_destroy(dev);
+ return error;
}
/* ************************************************************************** */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 666/869] tty: skip cdev_del() when no cdev is registered
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (664 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 665/869] HID: logitech-hidpp: Fix FF device cleanup on init failure Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 667/869] serial: core: clear freed pointers on uart_register_driver() failure Greg Kroah-Hartman
` (203 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Karl Mehltretter, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <kmehltretter@gmail.com>
[ Upstream commit c3b5623fd97648f2747444aa8932ae604662df93 ]
TTY device registration can fail before a cdev is allocated.
Serial core keeps the port so setserial can still use it, and later
removal passes the NULL cdev slot to cdev_del(), causing a NULL-pointer
dereference.
Only delete the cdev when the slot is not NULL.
Fixes: a3a10ce3429e ("Avoid usb reset crashes by making tty_io cdevs truly dynamic")
Fixes: da4c279942b0 ("serial: enable serdev support")
Assisted-by: Claude:claude-fable-5
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Link: https://patch.msgid.link/20260731181844.11330-4-kmehltretter@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/tty/tty_io.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 07e1e901dea59..dd2e2508df4c4 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3341,7 +3341,7 @@ EXPORT_SYMBOL_GPL(tty_register_device_attr);
void tty_unregister_device(struct tty_driver *driver, unsigned index)
{
device_destroy(&tty_class, MKDEV(driver->major, driver->minor_start) + index);
- if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
+ if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) && driver->cdevs[index]) {
cdev_del(driver->cdevs[index]);
driver->cdevs[index] = NULL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 667/869] serial: core: clear freed pointers on uart_register_driver() failure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (665 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 666/869] tty: skip cdev_del() when no cdev is registered Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 668/869] serial: core: do fallible allocations before the console can be registered Greg Kroah-Hartman
` (202 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Karl Mehltretter, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <kmehltretter@gmail.com>
[ Upstream commit 61a2fb25551be0375bc16ef2a70c987dfca26183 ]
uart_register_driver() leaves drv->state pointing to freed memory when
tty_alloc_driver() fails. If tty_register_driver() fails, drv->tty_driver
also retains a pointer after its reference is dropped.
Drivers that use drv->state as an "already registered" flag can then skip
registration on the next probe and pass the freed state to
uart_add_one_port().
This issue was found with failslab on QEMU's raspi1ap board by
failing registration and binding the PL011 port again.
Clear both pointers on their failure paths, as uart_unregister_driver()
already does.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Fixes: 9e845abfc8a8 ("serial: fix NULL pointer dereference")
Assisted-by: Claude:claude-fable-5
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Link: https://patch.msgid.link/20260731181844.11330-3-kmehltretter@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/tty/serial/serial_core.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 816f83141afd3..2da161227200a 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2861,8 +2861,10 @@ int uart_register_driver(struct uart_driver *drv)
for (i = 0; i < drv->nr; i++)
tty_port_destroy(&drv->state[i].port);
tty_driver_kref_put(normal);
+ drv->tty_driver = NULL;
out_kfree:
kfree(drv->state);
+ drv->state = NULL;
out:
return retval;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 668/869] serial: core: do fallible allocations before the console can be registered
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (666 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 667/869] serial: core: clear freed pointers on uart_register_driver() failure Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 669/869] wifi: cfg80211: stop PMSR before P2P and NAN teardown Greg Kroah-Hartman
` (201 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Sashiko, Karl Mehltretter,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <kmehltretter@gmail.com>
[ Upstream commit 1a0e4fbce5d9c1bc179a35a2fd9ed142664299e3 ]
serial_core_add_one_port() allocates uport->tty_groups after
uart_configure_port(), which may register the console. If the allocation
fails, the driver unwinds the port while its console remains registered.
The earlier uport->name allocation has a related failure path that leaves
state->uart_port linked to a port being freed.
Failslab reproduced a NULL dereference in PL011 console output and a KASAN
use-after-free in i.MX console output after failed binds.
Allocate the name and tty_groups before linking the port and configuring
it. Reserve space for the optional driver attribute group because
config_port() may populate uport->attr_group during configuration.
Fixes: 266dcff03eed ("Serial: allow port drivers to have a default attribute group")
Fixes: f7048b15900f ("tty: serial_core: Add name field to uart_port struct")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260719070454.D6FA21F000E9@smtp.kernel.org/
Assisted-by: Claude:claude-fable-5
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Link: https://patch.msgid.link/20260731181844.11330-2-kmehltretter@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/tty/serial/serial_core.c | 37 ++++++++++++++++----------------
1 file changed, 19 insertions(+), 18 deletions(-)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 2da161227200a..230df69c9f932 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -3144,7 +3144,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
struct tty_port *port;
int ret = 0;
struct device *tty_dev;
- int num_groups;
if (uport->line >= drv->nr)
return -EINVAL;
@@ -3158,6 +3157,25 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
goto out;
}
+ uport->name = kasprintf(GFP_KERNEL, "%s%u", drv->dev_name,
+ drv->tty_driver->name_base + uport->line);
+ if (!uport->name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * uart_configure_port() may set uport->attr_group and register the
+ * console. Allocate room for both groups and a NULL terminator first.
+ */
+ uport->tty_groups = kcalloc(3, sizeof(*uport->tty_groups), GFP_KERNEL);
+ if (!uport->tty_groups) {
+ kfree(uport->name);
+ ret = -ENOMEM;
+ goto out;
+ }
+ uport->tty_groups[0] = &tty_dev_attr_group;
+
/* Link the port to the driver state table and vice versa */
atomic_set(&state->refcount, 1);
init_waitqueue_head(&state->remove_wait);
@@ -3174,12 +3192,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
state->pm_state = UART_PM_STATE_UNDEFINED;
uart_port_set_cons(uport, drv->cons);
uport->minor = drv->tty_driver->minor_start + uport->line;
- uport->name = kasprintf(GFP_KERNEL, "%s%u", drv->dev_name,
- drv->tty_driver->name_base + uport->line);
- if (!uport->name) {
- ret = -ENOMEM;
- goto out;
- }
if (uport->cons && uport->dev)
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
@@ -3189,17 +3201,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
port->console = uart_console(uport);
- num_groups = 2;
- if (uport->attr_group)
- num_groups++;
-
- uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups),
- GFP_KERNEL);
- if (!uport->tty_groups) {
- ret = -ENOMEM;
- goto out;
- }
- uport->tty_groups[0] = &tty_dev_attr_group;
if (uport->attr_group)
uport->tty_groups[1] = uport->attr_group;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 669/869] wifi: cfg80211: stop PMSR before P2P and NAN teardown
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (667 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 668/869] serial: core: do fallible allocations before the console can be registered Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 670/869] wifi: brcmfmac: fix P2P action frame handling without device vif Greg Kroah-Hartman
` (200 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Zhao Li, Johannes Berg, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <enderaoelyther@gmail.com>
[ Upstream commit 6c5fc504d0d6934132637aa3db4b9b58148eaa78 ]
PMSR request teardown must abort active measurements while the
wireless_dev is still present in the driver. cfg80211_leave_locked() and
cfg80211_stop_pd() already do this before invoking the driver's stop
callback, but cfg80211_stop_p2p_device() and cfg80211_stop_nan() do not.
Those helpers are also called directly by nl80211, rfkill shutdown, and
wireless_dev unregister paths. If one of these paths stops a P2P device
or NAN interface with a pending request, it removes the mac80211
subinterface from the driver first. Subsequent request cleanup cannot
reach the lower driver's abort callback, but cfg80211 frees the request
regardless. Driver state can then retain a stale request and use it when
it later reports a result.
Call cfg80211_pmsr_wdev_down() before stopping the P2P device or NAN
interface. This keeps lower-driver request state and cfg80211 request
ownership in sync for all of the helpers' callers.
Fixes: 9bb7e0f24e7e ("cfg80211: add peer measurement with FTM initiator API")
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Zhao Li <enderaoelyther@gmail.com>
Link: https://patch.msgid.link/20260731071103.73563-1-enderaoelyther@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/wireless/core.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/wireless/core.c b/net/wireless/core.c
index e4b7917455fb4..c485cd6fbc825 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -237,6 +237,7 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
if (!wdev_running(wdev))
return;
+ cfg80211_pmsr_wdev_down(wdev);
rdev_stop_p2p_device(rdev, wdev);
wdev->is_running = false;
@@ -262,6 +263,8 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
if (!wdev_running(wdev))
return;
+ cfg80211_pmsr_wdev_down(wdev);
+
rdev_stop_nan(rdev, wdev);
wdev->is_running = false;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 670/869] wifi: brcmfmac: fix P2P action frame handling without device vif
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (668 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 669/869] wifi: cfg80211: stop PMSR before P2P and NAN teardown Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 671/869] wifi: nl80211: check link is beaconing for color change Greg Kroah-Hartman
` (199 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jason Huang, Arend van Spriel,
Johannes Berg, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason Huang <jason.huang2@infineon.com>
[ Upstream commit 1b1edb9ebed49099bdc924cef49a9aea8b552199 ]
Some P2P action frame paths assume the P2P device vif is always
available. That is not true when userspace sends non-P2P public action
frames through the primary interface, or when action-frame abort runs
after the P2P device vif has not been created.
Fall back to the primary vif when aborting an action frame without a P2P
device vif, and guard P2P device saved IE access before using it for
peer channel search.
Fixes: 30fb1b272909 ("brcmfmac: use actframe_abort to cancel ongoing action frame")
Fixes: 6eda4e2c5425 ("brcmfmac: Add tx p2p off-channel support.")
Signed-off-by: Jason Huang <jason.huang2@infineon.com>
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Link: https://patch.msgid.link/20260722082608.412472-1-Jason.Huang2@infineon.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index ef08b4163c937..c5fa6f61634a7 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -1281,6 +1281,9 @@ static s32 brcmf_p2p_abort_action_frame(struct brcmf_cfg80211_info *cfg)
brcmf_dbg(TRACE, "Enter\n");
vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ if (!vif)
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+
err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe_abort", &int_val,
sizeof(s32));
if (err)
@@ -1817,6 +1820,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_if *ifp,
/* validate channel and p2p ies */
if (config_af_params.search_channel &&
IS_P2P_SOCIAL_CHANNEL(le32_to_cpu(af_params->channel)) &&
+ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif &&
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->saved_ie.probe_req_ie_len) {
afx_hdl = &p2p->afx_hdl;
afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 671/869] wifi: nl80211: check link is beaconing for color change
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (669 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 670/869] wifi: brcmfmac: fix P2P action frame handling without device vif Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 672/869] wifi: nl80211: clean up color-change beacon data on errors Greg Kroah-Hartman
` (198 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Miriam Rachel Korenblit,
Johannes Berg, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Berg <johannes.berg@intel.com>
[ Upstream commit 55308cee9c2196f39cd1ce8ee6c1fed9e12a00d4 ]
When trying to do a color change, validate that the link is
beaconing first, to avoid calling the driver with an invalid
link.
Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260415145348.beb59ea5fbf7.I128a956a3e610bb6a5c9cad941d7d5b59b735a5e@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Stable-dep-of: 927ee844c47a ("wifi: nl80211: clean up color-change beacon data on errors")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/wireless/nl80211.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index dddd15f2d6b57..49ee160f3b3b2 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -16171,6 +16171,10 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
params.count = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT]);
params.color = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR]);
+ params.link_id = nl80211_link_id(info->attrs);
+ if (!wdev->links[params.link_id].ap.beacon_interval)
+ return -EINVAL;
+
err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_next,
info->extack);
if (err)
@@ -16236,7 +16240,6 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
params.counter_offset_presp = offset;
}
- params.link_id = nl80211_link_id(info->attrs);
err = rdev_color_change(rdev, dev, ¶ms);
out:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 672/869] wifi: nl80211: clean up color-change beacon data on errors
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (670 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 671/869] wifi: nl80211: check link is beaconing for color change Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 673/869] arm64: ptrace: Keep orig_x0 in-sync with x0 on syscall entry Greg Kroah-Hartman
` (197 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Zhao Li, Johannes Berg, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <enderaoelyther@gmail.com>
[ Upstream commit 927ee844c47ac2aef22c8f7a35f098ff576b398b ]
nl80211_color_change() calls nl80211_parse_beacon() for the beacon_next
template, which can allocate params.beacon_next.mbssid_ies and .rnr_ies.
A parsing failure returned directly instead of using the out: cleanup,
leaking any allocations completed before the error.
Allocate the nested attribute table before parsing beacon_next. Its
allocation failure can then return before beacon data exists, while a
later parsing failure uses out: to release the parsed data.
Fixes: dc1e3cb8da8b ("nl80211: MBSSID and EMA support in AP mode")
Assisted-by: Codex:gpt-5
Assisted-by: Claude:opus-4.8
Assisted-by: Kimi:K3
Signed-off-by: Zhao Li <enderaoelyther@gmail.com>
Link: https://patch.msgid.link/20260731120244.82628-1-enderaoelyther@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/wireless/nl80211.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 49ee160f3b3b2..c5df80b547077 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -16175,15 +16175,15 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
if (!wdev->links[params.link_id].ap.beacon_interval)
return -EINVAL;
- err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_next,
- info->extack);
- if (err)
- return err;
-
tb = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*tb), GFP_KERNEL);
if (!tb)
return -ENOMEM;
+ err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_next,
+ info->extack);
+ if (err)
+ goto out;
+
err = nla_parse_nested(tb, NL80211_ATTR_MAX,
info->attrs[NL80211_ATTR_COLOR_CHANGE_ELEMS],
nl80211_policy, info->extack);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 673/869] arm64: ptrace: Keep orig_x0 in-sync with x0 on syscall entry
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (671 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 672/869] wifi: nl80211: clean up color-change beacon data on errors Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 674/869] wifi: mt76: mt7996: do not attach hif2 WED when the main WED attach failed Greg Kroah-Hartman
` (196 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kees Cook, Jinjie Ruan, Mark Rutland,
Yiqi Sun, Will Deacon, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Will Deacon <will@kernel.org>
[ Upstream commit 88b839ce497ccb1ff92f7ae742c78dd2937ba572 ]
Commit e057b9477232 ("arm64: syscall: Ensure saved x0 is kept in-sync
with tracer updates") attempted to resolve a long-standing issue with
syscall entry tracing, where a tracer is able to manipulate the first
syscall argument without being subjected to seccomp or audit checking.
Unfortunately, that fix was incomplete [1], as it failed to update
'orig_x0' between a tracer updating x0 during a seccomp ptrace exit
(SECCOMP_RET_TRACE) and the seccomp filter being re-evaluated.
Rather than add hooks to the core seccomp code, instead move the
synchronisation code into the ptrace GPR and syscall setting code so
that 'orig_x0' is kept up to date with x0 whenever we're stopped on the
syscall entry path.
Cc: Kees Cook <kees@kernel.org>
Cc: Jinjie Ruan <ruanjinjie@huawei.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Link: https://sashiko.dev/#/patchset/20260716120640.6590-1-will@kernel.org [1]
Reported-by: Yiqi Sun <sunyiqixm@gmail.com>
Link: https://lore.kernel.org/all/20260529065444.1336608-1-sunyiqixm@gmail.com/
Fixes: e057b9477232 ("arm64: syscall: Ensure saved x0 is kept in-sync with tracer updates")
Fixes: a5cd110cb836 ("arm64/ptrace: run seccomp after ptrace")
Tested-by: Jinjie Ruan <ruanjinjie@huawei.com>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm64/kernel/ptrace.c | 50 ++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index ff1fe2d398692..fd3bf1c9f8528 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -559,6 +559,42 @@ static int gpr_get(struct task_struct *target,
return membuf_write(&to, uregs, sizeof(*uregs));
}
+static void update_syscall_orig_x0_after_ptrace(struct task_struct *target)
+{
+ struct pt_regs *regs = task_pt_regs(target);
+ struct kernel_siginfo *info = target->last_siginfo;
+
+ /*
+ * Skip the update for NO_SYSCALL (set either by the user or the
+ * tracer), as regs[0] holds the return value (see the comment in
+ * el0_svc_common()) and can be unwound using syscall_rollback().
+ */
+ if (regs->syscallno == NO_SYSCALL)
+ return;
+
+ /* We should only be called when target is in a ptrace stop */
+ if (WARN_ON_ONCE(!info))
+ return;
+
+ /*
+ * For compat tasks, orig_r0 is provided directly through GPR index
+ * 17.
+ */
+ if (is_compat_thread(task_thread_info(target)))
+ return;
+
+ /*
+ * Don't update orig_x0 for a syscall-exit-stop, as x0 now contains the
+ * return value of the system call.
+ */
+ if ((info->si_code & ~0x80) == SIGTRAP &&
+ target->ptrace_message == PTRACE_EVENTMSG_SYSCALL_EXIT) {
+ return;
+ }
+
+ regs->orig_x0 = regs->regs[0];
+}
+
static int gpr_set(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
@@ -574,6 +610,14 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
return -EINVAL;
task_pt_regs(target)->user_regs = newregs;
+
+ /*
+ * Keep orig_x0 authoritative so that seccomp (via
+ * syscall_get_arguments()), audit and the restart path all see the same
+ * first argument the syscall is dispatched with, even if it has been
+ * updated by a tracer.
+ */
+ update_syscall_orig_x0_after_ptrace(target);
return 0;
}
@@ -752,6 +796,12 @@ static int system_call_set(struct task_struct *target,
return ret;
task_pt_regs(target)->syscallno = syscallno;
+
+ /*
+ * Re-sync orig_x0 in case the syscall number has been changed
+ * from NO_SYSCALL.
+ */
+ update_syscall_orig_x0_after_ptrace(target);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 674/869] wifi: mt76: mt7996: do not attach hif2 WED when the main WED attach failed
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (672 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 673/869] arm64: ptrace: Keep orig_x0 in-sync with x0 on syscall entry Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 675/869] bpf: Reject >8 byte return values on return-reading trampoline paths Greg Kroah-Hartman
` (195 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Felix Fietkau, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <nbd@nbd.name>
[ Upstream commit 7c1924332e986019c6bcddf55c843361cccac73f ]
If the WED attach for the primary PCIe function fails, the probe path
still attached wed_hif2 for the secondary function, leaving the device
in an inconsistent half-WED configuration that crashes later. The hif2
call also re-enabled hwrro_mode, which the failed primary attach had
just turned off.
Skip the hif2 WED setup when the primary WED device is not active.
Fixes: 83eafc9251d6 ("wifi: mt76: mt7996: add wed tx support")
Link: https://patch.msgid.link/20260727150434.1778520-6-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mt7996/mmio.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
index 11e9c71e9b17a..ba1667ac1d367 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
@@ -312,6 +312,9 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
if (!wed_enable)
return 0;
+ if (hif2 && !mtk_wed_device_active(&dev->mt76.mmio.wed))
+ return 0;
+
dev->has_rro = true;
hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 675/869] bpf: Reject >8 byte return values on return-reading trampoline paths
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (673 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 674/869] wifi: mt76: mt7996: do not attach hif2 WED when the main WED attach failed Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 676/869] drm/msm: dont tear down KMS twice when KMS init fails Greg Kroah-Hartman
` (194 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yonghong Song, Eduard Zingerman,
Leon Hwang, Kumar Kartikeya Dwivedi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yonghong Song <yonghong.song@linux.dev>
[ Upstream commit c48796aa6c392cde93946e5d5a9a1f1b1cf72feb ]
btf_distill_func_proto() builds the function model used for the
fentry/fexit/fmod_ret/fsession trampolines and struct_ops. It has
accepted a 16-byte __int128 return value since the trampoline was
introduced: __get_type_size() returns the integer's type size, and the
return-type check only rejected ret < 0.
But the BPF trampoline preserves only 8 bytes of the return value (RAX on
x86, i.e. R0). For an attach type that reads the target's return value the
second half (RDX / R3) is neither saved nor restored, so a program
attached to a function returning a 16-byte value corrupts the value seen
by the real caller and itself observes only half of it. struct_ops
trampolines have the same limitation.
This affects the attach types that read the target's return value: fexit,
fmod_ret and fsession (plus the _multi variants of fexit and fsession),
and struct_ops. fentry/fentry_multi run before the target returns and are
unaffected.
Reject a >8 byte return value for these attach types in
bpf_check_attach_target() and bpf_check_attach_btf_id_multi(), and for
struct_ops in bpf_struct_ops_desc_init().
Fixes: fec56f5890d9 ("bpf: Introduce BPF trampoline")
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
Reviewed-by: Eduard Zingerman <eddyz87@gmail.com>
Acked-by: Leon Hwang <leon.hwang@linux.dev>
Link: https://lore.kernel.org/bpf/20260729050159.2585809-1-yonghong.song@linux.dev
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/bpf_struct_ops.c | 12 ++++++++++++
kernel/bpf/verifier.c | 19 +++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
index 2285b27ce68c7..582128fbc1d0c 100644
--- a/kernel/bpf/bpf_struct_ops.c
+++ b/kernel/bpf/bpf_struct_ops.c
@@ -422,6 +422,18 @@ int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
goto errout;
}
+ /*
+ * A >8 byte return value is passed back in a register pair,
+ * which the struct_ops trampoline does not preserve (only
+ * 8 bytes of the return value are saved and restored).
+ */
+ if (st_ops->func_models[i].ret_size > 8) {
+ pr_warn("func ptr %s in struct %s has a >8 byte return value, which is not supported\n",
+ mname, st_ops->name);
+ err = -EOPNOTSUPP;
+ goto errout;
+ }
+
stub_func_addr = *(void **)(st_ops->cfi_stubs + moff);
err = prepare_arg_info(btf, st_ops->name, mname,
func_proto, stub_func_addr,
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index f0a10f6f09fb0..a5abb59a925bc 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -22419,6 +22419,17 @@ static int check_non_sleepable_error_inject(u32 btf_id)
return btf_id_set_contains(&btf_non_sleepable_error_inject, btf_id);
}
+static bool attach_uses_trampoline_retval(enum bpf_attach_type type)
+{
+ switch (type) {
+ case BPF_MODIFY_RETURN:
+ case BPF_TRACE_FEXIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
int bpf_check_attach_target(struct bpf_verifier_log *log,
const struct bpf_prog *prog,
const struct bpf_prog *tgt_prog,
@@ -22653,6 +22664,14 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
if (ret < 0)
return ret;
+ if (tgt_info->fmodel.ret_size > 8 &&
+ attach_uses_trampoline_retval(prog->expected_attach_type)) {
+ bpf_log(log,
+ "Attach to function %s with a >8 byte return value is not supported for this attach type\n",
+ tname);
+ return -EOPNOTSUPP;
+ }
+
if (tgt_prog) {
if (subprog == 0)
addr = (long) tgt_prog->bpf_func;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 676/869] drm/msm: dont tear down KMS twice when KMS init fails
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (674 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 675/869] bpf: Reject >8 byte return values on return-reading trampoline paths Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 677/869] wifi: mt76: cancel reset and rc work on device unregister Greg Kroah-Hartman
` (193 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dmitry Baryshkov, Konrad Dybcio,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
[ Upstream commit 93c125e4ea98fb25f927ba5a334d85845127d667 ]
When priv->kms_init() (mdp4_kms_init() / mdp5_kms_init()) fails partway
through, both display drivers already tear their KMS state down via
mdp4_destroy() / mdp5_kms_destroy() before returning the error. The
common error path in msm_drm_init() then runs msm_drm_uninit() ->
msm_drm_kms_uninit(), which tries to destroy the very same KMS a second
time, which causes a use-after-free crash.
Bring MDP4/MDP5 in line with the DPU driver whose dpu_kms_init() doesn't
perform error cleanup on the failure. Let the common path own the
cleanup, instead of freeing the KMS from their error paths.
The crash trace for the reference:
__lock_acquire from lock_acquire (kernel/locking/lockdep.c:5906 kernel/locking/lockdep.c:5863)
lock_acquire from touch_wq_lockdep_map (kernel/workqueue.c:4094 (discriminator 1))
touch_wq_lockdep_map from __flush_workqueue (kernel/workqueue.c:4136)
__flush_workqueue from msm_drm_kms_uninit (drivers/gpu/drm/msm/msm_kms.c:243 (discriminator 33))
msm_drm_kms_uninit from msm_drm_uninit (drivers/gpu/drm/msm/msm_drv.c:93)
msm_drm_uninit from msm_drm_init (drivers/gpu/drm/msm/msm_drv.c:184)
msm_drm_init from try_to_bring_up_aggregate_device (drivers/base/component.c:249 drivers/base/component.c:227)
try_to_bring_up_aggregate_device from __component_add (drivers/base/component.c:269 drivers/base/component.c:748)
__component_add from dsi_host_attach (drivers/gpu/drm/msm/dsi/dsi_host.c:1739)
dsi_host_attach from mipi_dsi_attach (drivers/gpu/drm/drm_mipi_dsi.c:383)
mipi_dsi_attach from sharp_nt_panel_probe (drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c:247)
Fixes: 506efcba3129 ("drm/msm: carve out KMS code from msm_drv.c")
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Patchwork: https://patchwork.freedesktop.org/patch/742068/
Link: https://lore.kernel.org/r/20260723-msm-fix-crash-v1-1-78fb4721c2d9@oss.qualcomm.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c | 24 +++++++++---------------
drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 11 +++--------
2 files changed, 12 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
index 6e4e74f9d63d6..83efedb810edd 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
@@ -391,7 +391,7 @@ static int mdp4_kms_init(struct drm_device *dev)
ret = mdp_kms_init(&mdp4_kms->base, &kms_funcs);
if (ret) {
DRM_DEV_ERROR(dev->dev, "failed to init kms\n");
- goto fail;
+ return ret;
}
kms = priv->kms;
@@ -402,7 +402,7 @@ static int mdp4_kms_init(struct drm_device *dev)
ret = regulator_enable(mdp4_kms->vdd);
if (ret) {
DRM_DEV_ERROR(dev->dev, "failed to enable regulator vdd: %d\n", ret);
- goto fail;
+ return ret;
}
}
@@ -414,7 +414,7 @@ static int mdp4_kms_init(struct drm_device *dev)
DRM_DEV_ERROR(dev->dev, "unexpected MDP version: v%d.%d\n",
major, minor);
ret = -ENXIO;
- goto fail;
+ return ret;
}
mdp4_kms->rev = minor;
@@ -423,7 +423,7 @@ static int mdp4_kms_init(struct drm_device *dev)
if (!mdp4_kms->lut_clk) {
DRM_DEV_ERROR(dev->dev, "failed to get lut_clk\n");
ret = -ENODEV;
- goto fail;
+ return ret;
}
clk_set_rate(mdp4_kms->lut_clk, max_clk);
}
@@ -445,7 +445,7 @@ static int mdp4_kms_init(struct drm_device *dev)
mmu = msm_iommu_new(&pdev->dev, 0);
if (IS_ERR(mmu)) {
ret = PTR_ERR(mmu);
- goto fail;
+ return ret;
} else if (!mmu) {
DRM_DEV_INFO(dev->dev, "no iommu, fallback to phys "
"contig buffers for scanout\n");
@@ -458,7 +458,7 @@ static int mdp4_kms_init(struct drm_device *dev)
if (!IS_ERR(mmu))
mmu->funcs->destroy(mmu);
ret = PTR_ERR(aspace);
- goto fail;
+ return ret;
}
kms->aspace = aspace;
@@ -467,7 +467,7 @@ static int mdp4_kms_init(struct drm_device *dev)
ret = modeset_init(mdp4_kms);
if (ret) {
DRM_DEV_ERROR(dev->dev, "modeset_init failed: %d\n", ret);
- goto fail;
+ return ret;
}
mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC | MSM_BO_SCANOUT);
@@ -475,14 +475,14 @@ static int mdp4_kms_init(struct drm_device *dev)
ret = PTR_ERR(mdp4_kms->blank_cursor_bo);
DRM_DEV_ERROR(dev->dev, "could not allocate blank-cursor bo: %d\n", ret);
mdp4_kms->blank_cursor_bo = NULL;
- goto fail;
+ return ret;
}
ret = msm_gem_get_and_pin_iova(mdp4_kms->blank_cursor_bo, kms->aspace,
&mdp4_kms->blank_cursor_iova);
if (ret) {
DRM_DEV_ERROR(dev->dev, "could not pin blank-cursor bo: %d\n", ret);
- goto fail;
+ return ret;
}
dev->mode_config.min_width = 0;
@@ -491,12 +491,6 @@ static int mdp4_kms_init(struct drm_device *dev)
dev->mode_config.max_height = 2048;
return 0;
-
-fail:
- if (kms)
- mdp4_destroy(kms);
-
- return ret;
}
static const struct dev_pm_ops mdp4_pm_ops = {
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
index 374704cce6563..9e4c4531ff52b 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
@@ -514,7 +514,7 @@ static int mdp5_kms_init(struct drm_device *dev)
ret = mdp_kms_init(&mdp5_kms->base, &kms_funcs);
if (ret) {
DRM_DEV_ERROR(&pdev->dev, "failed to init kms\n");
- goto fail;
+ return ret;
}
config = mdp5_cfg_get_config(mdp5_kms->cfg);
@@ -537,7 +537,7 @@ static int mdp5_kms_init(struct drm_device *dev)
aspace = msm_kms_init_aspace(mdp5_kms->dev);
if (IS_ERR(aspace)) {
ret = PTR_ERR(aspace);
- goto fail;
+ return ret;
}
kms->aspace = aspace;
@@ -547,7 +547,7 @@ static int mdp5_kms_init(struct drm_device *dev)
ret = modeset_init(mdp5_kms);
if (ret) {
DRM_DEV_ERROR(&pdev->dev, "modeset_init failed: %d\n", ret);
- goto fail;
+ return ret;
}
dev->mode_config.min_width = 0;
@@ -559,11 +559,6 @@ static int mdp5_kms_init(struct drm_device *dev)
dev->vblank_disable_immediate = true;
return 0;
-fail:
- if (kms)
- mdp5_kms_destroy(kms);
-
- return ret;
}
static void mdp5_destroy(struct mdp5_kms *mdp5_kms)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 677/869] wifi: mt76: cancel reset and rc work on device unregister
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (675 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 676/869] drm/msm: dont tear down KMS twice when KMS init fails Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 678/869] wifi: mt76: mt7996: hold dev->mt76.mutex while disabling tx worker in SER Greg Kroah-Hartman
` (192 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Felix Fietkau, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <nbd@nbd.name>
[ Upstream commit e995d3dccc9d980af13a60ad37409ed1561f9eeb ]
Both drivers cancelled dump_work on unregister but left reset_work and
rc_work to be flushed only by destroy_workqueue() in mt76_free_device(),
which runs after the hw is unregistered and the hardware stopped. A
reset_work that fires in that window calls ieee80211_restart_hw() and
re-arms mac_work on an unregistered hw, and rc_work touches station state
being torn down. Cancel both up front, alongside dump_work.
Fixes: e57b7901469f ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets")
Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Link: https://patch.msgid.link/20260724124813.3961474-10-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mt7915/init.c | 2 ++
drivers/net/wireless/mediatek/mt76/mt7996/init.c | 2 ++
2 files changed, 4 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index 9b0f326c231c8..cd18540dc98ae 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -1288,6 +1288,8 @@ int mt7915_register_device(struct mt7915_dev *dev)
void mt7915_unregister_device(struct mt7915_dev *dev)
{
cancel_work_sync(&dev->dump_work);
+ cancel_work_sync(&dev->reset_work);
+ cancel_work_sync(&dev->rc_work);
mt7915_unregister_ext_phy(dev);
mt7915_coredump_unregister(dev);
mt7915_unregister_thermal(&dev->phy);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index d3d63f07d7b05..6da42d9411656 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -1405,6 +1405,8 @@ void mt7996_unregister_device(struct mt7996_dev *dev)
{
cancel_work_sync(&dev->dump_work);
cancel_work_sync(&dev->wed_rro.work);
+ cancel_work_sync(&dev->reset_work);
+ cancel_work_sync(&dev->rc_work);
mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
mt7996_unregister_thermal(&dev->phy);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 678/869] wifi: mt76: mt7996: hold dev->mt76.mutex while disabling tx worker in SER
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (676 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 677/869] wifi: mt76: cancel reset and rc work on device unregister Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 679/869] wifi: ath12k: fix overreads in ath12k_wmi_process_csa_switch_count_event() Greg Kroah-Hartman
` (191 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Felix Fietkau, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Fietkau <nbd@nbd.name>
[ Upstream commit 6190db312b8230813f529f014b26247c6d9800d0 ]
mt7996_mac_reset_work() parked the tx worker and disabled the RX/TX NAPIs
before taking dev->mt76.mutex. mt76_worker_disable()/_enable() are plain
kthread park/unpark, not refcounted, and __mt76_set_channel() toggles the
same worker and the MT76_RESET bit under the mutex. An L1 SER racing a
channel switch could therefore have the worker unparked and MT76_RESET
cleared while the reset path resets the DMA rings, corrupting descriptors
or tokens. Take the mutex before disabling the worker, as mt7915 does.
Fixes: 27015b6fbcca ("wifi: mt76: mt7996: enable full system reset support")
Link: https://patch.msgid.link/20260724124813.3961474-5-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 24e0346ea3d88..89d8a22e967c3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -1916,6 +1916,9 @@ void mt7996_mac_reset_work(struct work_struct *work)
set_bit(MT76_RESET, &phy3->mt76->state);
cancel_delayed_work_sync(&phy3->mt76->mac_work);
}
+
+ mutex_lock(&dev->mt76.mutex);
+
mt76_worker_disable(&dev->mt76.tx_worker);
mt76_for_each_q_rx(&dev->mt76, i) {
if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
@@ -1926,8 +1929,6 @@ void mt7996_mac_reset_work(struct work_struct *work)
}
napi_disable(&dev->mt76.tx_napi);
- mutex_lock(&dev->mt76.mutex);
-
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 679/869] wifi: ath12k: fix overreads in ath12k_wmi_process_csa_switch_count_event()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (677 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 678/869] wifi: mt76: mt7996: hold dev->mt76.mutex while disabling tx worker in SER Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 680/869] drm/i915: rename range_overflows_end() to range_end_overflows() Greg Kroah-Hartman
` (190 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rameshkumar Sundaram, Baochen Qiang,
Jeff Johnson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
[ Upstream commit 878654eb78c6aa0ff585baf1376567c775ca28ec ]
There is no policy entry for WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT, so
the parse infrastructure does not enforce a minimum length for the event
struct. Additionally, the num_vdevs field is taken directly from firmware
and used as a loop bound over the vdev_ids array without checking that it
fits within the TLV payload. Either condition can cause an out-of-bounds
read.
Add a TLV policy entry for WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT so
the parse infrastructure enforces a minimum length for the fixed-size event
struct. Add a helper ath12k_wmi_tlv_data_len() to recover the payload
length of a parsed TLV from the header preceding its data pointer. Use it
in ath12k_wmi_process_csa_switch_count_event() to bound num_vdevs before
the loop.
Compile tested only.
Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
Assisted-by: Claude:claude-sonnet-4-6
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Link: https://patch.msgid.link/20260724-ath12k_wmi_process_csa_switch_count_event-cleanup-v2-1-02a45d7246c0@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/ath/ath12k/wmi.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 598a69f9e6df0..ca359eecb42a9 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -171,6 +171,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
.min_len = sizeof(struct ath12k_wmi_p2p_noa_info) },
[WMI_TAG_P2P_NOA_EVENT] = {
.min_len = sizeof(struct wmi_p2p_noa_event) },
+ [WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT] = {
+ .min_len = sizeof(struct ath12k_wmi_pdev_csa_event) },
};
static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len)
@@ -384,6 +386,13 @@ ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab,
return tb;
}
+static u32 ath12k_wmi_tlv_data_len(const void *data)
+{
+ const struct wmi_tlv *tlv = (const struct wmi_tlv *)data - 1;
+
+ return le32_get_bits(tlv->header, WMI_TLV_LEN);
+}
+
static int ath12k_wmi_cmd_send_nowait(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb,
u32 cmd_id)
{
@@ -6735,6 +6744,8 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab,
const struct ath12k_wmi_pdev_csa_event *ev,
const u32 *vdev_ids)
{
+ u32 vdev_ids_len = ath12k_wmi_tlv_data_len(vdev_ids);
+ u32 num_vdevs = le32_to_cpu(ev->num_vdevs);
int i;
struct ath12k_vif *arvif;
@@ -6742,8 +6753,14 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab,
if (ev->current_switch_count)
return;
+ if (num_vdevs > vdev_ids_len / sizeof(*vdev_ids)) {
+ ath12k_warn(ab, "csa switch count num_vdevs %u exceeds tlv array length %u\n",
+ num_vdevs, vdev_ids_len);
+ return;
+ }
+
rcu_read_lock();
- for (i = 0; i < le32_to_cpu(ev->num_vdevs); i++) {
+ for (i = 0; i < num_vdevs; i++) {
arvif = ath12k_mac_get_arvif_by_vdev_id(ab, vdev_ids[i]);
if (!arvif) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 680/869] drm/i915: rename range_overflows_end() to range_end_overflows()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (678 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 679/869] wifi: ath12k: fix overreads in ath12k_wmi_process_csa_switch_count_event() Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 681/869] drm/i915: document range_overflows() and range_end_overflows() macros Greg Kroah-Hartman
` (189 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kees Cook, Gustavo A. R. Silva,
linux-hardening, Jouni Högander, Jani Nikula, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <jani.nikula@intel.com>
[ Upstream commit 1e4c85167cf672312a178b2af0b058add77e448b ]
Rename range_overflows_end() to range_end_overflows(), along with the _t
variant.
It's all rather subjective, but I think range_end_overflows() reads
better.
Cc: Kees Cook <kees@kernel.org>
Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
Cc: linux-hardening@vger.kernel.org
Reviewed-by: Jouni Högander <jouni.hogander@intel.com>
Link: https://lore.kernel.org/r/20250829174601.2163064-1-jani.nikula@intel.com
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Stable-dep-of: 985f5e12f3cd ("drm/panthor: Add vm_bind region with kbo range overlap check")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/i915/display/intel_fbc.c | 4 ++--
drivers/gpu/drm/i915/gt/intel_rc6.c | 2 +-
drivers/gpu/drm/i915/i915_utils.h | 6 +++---
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c
index 7cb1a9cfa20f4..809b477f907e3 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.c
+++ b/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -378,11 +378,11 @@ static void i8xx_fbc_program_cfb(struct intel_fbc *fbc)
struct drm_i915_private *i915 = to_i915(display->drm);
drm_WARN_ON(display->drm,
- range_overflows_end_t(u64, i915_gem_stolen_area_address(i915),
+ range_end_overflows_t(u64, i915_gem_stolen_area_address(i915),
i915_gem_stolen_node_offset(&fbc->compressed_fb),
U32_MAX));
drm_WARN_ON(display->drm,
- range_overflows_end_t(u64, i915_gem_stolen_area_address(i915),
+ range_end_overflows_t(u64, i915_gem_stolen_area_address(i915),
i915_gem_stolen_node_offset(&fbc->compressed_llb),
U32_MAX));
intel_de_write(i915, FBC_CFB_BASE,
diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c
index 9ca42589da4da..bf38cc5fe8729 100644
--- a/drivers/gpu/drm/i915/gt/intel_rc6.c
+++ b/drivers/gpu/drm/i915/gt/intel_rc6.c
@@ -341,7 +341,7 @@ static int vlv_rc6_init(struct intel_rc6 *rc6)
return PTR_ERR(pctx);
}
- GEM_BUG_ON(range_overflows_end_t(u64,
+ GEM_BUG_ON(range_end_overflows_t(u64,
i915->dsm.stolen.start,
pctx->stolen->start,
U32_MAX));
diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
index 71bdc89bd6215..61e561d6996d6 100644
--- a/drivers/gpu/drm/i915/i915_utils.h
+++ b/drivers/gpu/drm/i915/i915_utils.h
@@ -81,7 +81,7 @@ bool i915_error_injected(void);
#define range_overflows_t(type, start, size, max) \
range_overflows((type)(start), (type)(size), (type)(max))
-#define range_overflows_end(start, size, max) ({ \
+#define range_end_overflows(start, size, max) ({ \
typeof(start) start__ = (start); \
typeof(size) size__ = (size); \
typeof(max) max__ = (max); \
@@ -90,8 +90,8 @@ bool i915_error_injected(void);
start__ > max__ || size__ > max__ - start__; \
})
-#define range_overflows_end_t(type, start, size, max) \
- range_overflows_end((type)(start), (type)(size), (type)(max))
+#define range_end_overflows_t(type, start, size, max) \
+ range_end_overflows((type)(start), (type)(size), (type)(max))
#define ptr_mask_bits(ptr, n) ({ \
unsigned long __v = (unsigned long)(ptr); \
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 681/869] drm/i915: document range_overflows() and range_end_overflows() macros
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (679 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 680/869] drm/i915: rename range_overflows_end() to range_end_overflows() Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 682/869] overflow: add range_overflows() and range_end_overflows() Greg Kroah-Hartman
` (188 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kees Cook, Gustavo A. R. Silva,
linux-hardening, Jouni Högander, Jani Nikula, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <jani.nikula@intel.com>
[ Upstream commit 59bf37add1d2223d699d1855354277b7330765e4 ]
Document the macros in preparation for making them more generally
available.
Cc: Kees Cook <kees@kernel.org>
Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
Cc: linux-hardening@vger.kernel.org
Reviewed-by: Jouni Högander <jouni.hogander@intel.com>
Link: https://lore.kernel.org/r/20250829174601.2163064-2-jani.nikula@intel.com
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Stable-dep-of: 985f5e12f3cd ("drm/panthor: Add vm_bind region with kbo range overlap check")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/i915/i915_utils.h | 46 +++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
index 61e561d6996d6..a53d8a59ce19a 100644
--- a/drivers/gpu/drm/i915/i915_utils.h
+++ b/drivers/gpu/drm/i915/i915_utils.h
@@ -69,6 +69,18 @@ bool i915_error_injected(void);
drm_err(&(i915)->drm, fmt, ##__VA_ARGS__); \
})
+/**
+ * range_overflows() - Check if a range is out of bounds
+ * @start: Start of the range.
+ * @size: Size of the range.
+ * @max: Exclusive upper boundary.
+ *
+ * A strict check to determine if the range [@start, @start + @size) is
+ * invalid with respect to the allowable range [0, @max). Any range
+ * starting at or beyond @max is considered an overflow, even if @size is 0.
+ *
+ * Returns: true if the range is out of bounds.
+ */
#define range_overflows(start, size, max) ({ \
typeof(start) start__ = (start); \
typeof(size) size__ = (size); \
@@ -78,9 +90,32 @@ bool i915_error_injected(void);
start__ >= max__ || size__ > max__ - start__; \
})
+/**
+ * range_overflows_t() - Check if a range is out of bounds
+ * @type: Data type to use.
+ * @start: Start of the range.
+ * @size: Size of the range.
+ * @max: Exclusive upper boundary.
+ *
+ * Same as range_overflows() but forcing the parameters to @type.
+ *
+ * Returns: true if the range is out of bounds.
+ */
#define range_overflows_t(type, start, size, max) \
range_overflows((type)(start), (type)(size), (type)(max))
+/**
+ * range_end_overflows() - Check if a range's endpoint is out of bounds
+ * @start: Start of the range.
+ * @size: Size of the range.
+ * @max: Exclusive upper boundary.
+ *
+ * Checks only if the endpoint of a range (@start + @size) exceeds @max.
+ * Unlike range_overflows(), a zero-sized range at the boundary (@start == @max)
+ * is not considered an overflow. Useful for iterator-style checks.
+ *
+ * Returns: true if the endpoint exceeds the boundary.
+ */
#define range_end_overflows(start, size, max) ({ \
typeof(start) start__ = (start); \
typeof(size) size__ = (size); \
@@ -90,6 +125,17 @@ bool i915_error_injected(void);
start__ > max__ || size__ > max__ - start__; \
})
+/**
+ * range_end_overflows_t() - Check if a range's endpoint is out of bounds
+ * @type: Data type to use.
+ * @start: Start of the range.
+ * @size: Size of the range.
+ * @max: Exclusive upper boundary.
+ *
+ * Same as range_end_overflows() but forcing the parameters to @type.
+ *
+ * Returns: true if the endpoint exceeds the boundary.
+ */
#define range_end_overflows_t(type, start, size, max) \
range_end_overflows((type)(start), (type)(size), (type)(max))
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 682/869] overflow: add range_overflows() and range_end_overflows()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (680 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 681/869] drm/i915: document range_overflows() and range_end_overflows() macros Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 683/869] drm/panthor: Add vm_bind region with kbo range overlap check Greg Kroah-Hartman
` (187 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kees Cook, Gustavo A. R. Silva,
linux-hardening, Jouni Högander, Thomas Zimmermann,
Jani Nikula, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jani Nikula <jani.nikula@intel.com>
[ Upstream commit 5f3cec21f6d57336a2cbfa9ee428ac66c77a7211 ]
Move the range_overflows() and range_end_overflows() along with the _t
variants over from drm/i915 and drm/buddy to overflow.h.
Cc: Kees Cook <kees@kernel.org>
Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
Cc: linux-hardening@vger.kernel.org
Reviewed-by: Kees Cook <kees@kernel.org>
Reviewed-by: Jouni Högander <jouni.hogander@intel.com>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://lore.kernel.org/r/20250829174601.2163064-3-jani.nikula@intel.com
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Stable-dep-of: 985f5e12f3cd ("drm/panthor: Add vm_bind region with kbo range overlap check")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/i915/i915_utils.h | 70 -------------------------------
include/linux/gpu_buddy.h | 9 ----
include/linux/overflow.h | 70 +++++++++++++++++++++++++++++++
3 files changed, 70 insertions(+), 79 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
index a53d8a59ce19a..e9b8ec51f6ab4 100644
--- a/drivers/gpu/drm/i915/i915_utils.h
+++ b/drivers/gpu/drm/i915/i915_utils.h
@@ -69,76 +69,6 @@ bool i915_error_injected(void);
drm_err(&(i915)->drm, fmt, ##__VA_ARGS__); \
})
-/**
- * range_overflows() - Check if a range is out of bounds
- * @start: Start of the range.
- * @size: Size of the range.
- * @max: Exclusive upper boundary.
- *
- * A strict check to determine if the range [@start, @start + @size) is
- * invalid with respect to the allowable range [0, @max). Any range
- * starting at or beyond @max is considered an overflow, even if @size is 0.
- *
- * Returns: true if the range is out of bounds.
- */
-#define range_overflows(start, size, max) ({ \
- typeof(start) start__ = (start); \
- typeof(size) size__ = (size); \
- typeof(max) max__ = (max); \
- (void)(&start__ == &size__); \
- (void)(&start__ == &max__); \
- start__ >= max__ || size__ > max__ - start__; \
-})
-
-/**
- * range_overflows_t() - Check if a range is out of bounds
- * @type: Data type to use.
- * @start: Start of the range.
- * @size: Size of the range.
- * @max: Exclusive upper boundary.
- *
- * Same as range_overflows() but forcing the parameters to @type.
- *
- * Returns: true if the range is out of bounds.
- */
-#define range_overflows_t(type, start, size, max) \
- range_overflows((type)(start), (type)(size), (type)(max))
-
-/**
- * range_end_overflows() - Check if a range's endpoint is out of bounds
- * @start: Start of the range.
- * @size: Size of the range.
- * @max: Exclusive upper boundary.
- *
- * Checks only if the endpoint of a range (@start + @size) exceeds @max.
- * Unlike range_overflows(), a zero-sized range at the boundary (@start == @max)
- * is not considered an overflow. Useful for iterator-style checks.
- *
- * Returns: true if the endpoint exceeds the boundary.
- */
-#define range_end_overflows(start, size, max) ({ \
- typeof(start) start__ = (start); \
- typeof(size) size__ = (size); \
- typeof(max) max__ = (max); \
- (void)(&start__ == &size__); \
- (void)(&start__ == &max__); \
- start__ > max__ || size__ > max__ - start__; \
-})
-
-/**
- * range_end_overflows_t() - Check if a range's endpoint is out of bounds
- * @type: Data type to use.
- * @start: Start of the range.
- * @size: Size of the range.
- * @max: Exclusive upper boundary.
- *
- * Same as range_end_overflows() but forcing the parameters to @type.
- *
- * Returns: true if the endpoint exceeds the boundary.
- */
-#define range_end_overflows_t(type, start, size, max) \
- range_end_overflows((type)(start), (type)(size), (type)(max))
-
#define ptr_mask_bits(ptr, n) ({ \
unsigned long __v = (unsigned long)(ptr); \
(typeof(ptr))(__v & -BIT(n)); \
diff --git a/include/linux/gpu_buddy.h b/include/linux/gpu_buddy.h
index 2d45ce054f263..db0a23405ec9d 100644
--- a/include/linux/gpu_buddy.h
+++ b/include/linux/gpu_buddy.h
@@ -14,15 +14,6 @@
#include <drm/drm_print.h>
-#define range_overflows(start, size, max) ({ \
- typeof(start) start__ = (start); \
- typeof(size) size__ = (size); \
- typeof(max) max__ = (max); \
- (void)(&start__ == &size__); \
- (void)(&start__ == &max__); \
- start__ >= max__ || size__ > max__ - start__; \
-})
-
#define GPU_BUDDY_RANGE_ALLOCATION BIT(0)
#define GPU_BUDDY_TOPDOWN_ALLOCATION BIT(1)
#define GPU_BUDDY_CONTIGUOUS_ALLOCATION BIT(2)
diff --git a/include/linux/overflow.h b/include/linux/overflow.h
index 89e9d60498835..456b3b09e3e9c 100644
--- a/include/linux/overflow.h
+++ b/include/linux/overflow.h
@@ -238,6 +238,76 @@ static inline bool __must_check __must_check_overflow(bool overflow)
__overflows_type_constexpr(n, T), \
__overflows_type(n, T))
+/**
+ * range_overflows() - Check if a range is out of bounds
+ * @start: Start of the range.
+ * @size: Size of the range.
+ * @max: Exclusive upper boundary.
+ *
+ * A strict check to determine if the range [@start, @start + @size) is
+ * invalid with respect to the allowable range [0, @max). Any range
+ * starting at or beyond @max is considered an overflow, even if @size is 0.
+ *
+ * Returns: true if the range is out of bounds.
+ */
+#define range_overflows(start, size, max) ({ \
+ typeof(start) start__ = (start); \
+ typeof(size) size__ = (size); \
+ typeof(max) max__ = (max); \
+ (void)(&start__ == &size__); \
+ (void)(&start__ == &max__); \
+ start__ >= max__ || size__ > max__ - start__; \
+})
+
+/**
+ * range_overflows_t() - Check if a range is out of bounds
+ * @type: Data type to use.
+ * @start: Start of the range.
+ * @size: Size of the range.
+ * @max: Exclusive upper boundary.
+ *
+ * Same as range_overflows() but forcing the parameters to @type.
+ *
+ * Returns: true if the range is out of bounds.
+ */
+#define range_overflows_t(type, start, size, max) \
+ range_overflows((type)(start), (type)(size), (type)(max))
+
+/**
+ * range_end_overflows() - Check if a range's endpoint is out of bounds
+ * @start: Start of the range.
+ * @size: Size of the range.
+ * @max: Exclusive upper boundary.
+ *
+ * Checks only if the endpoint of a range (@start + @size) exceeds @max.
+ * Unlike range_overflows(), a zero-sized range at the boundary (@start == @max)
+ * is not considered an overflow. Useful for iterator-style checks.
+ *
+ * Returns: true if the endpoint exceeds the boundary.
+ */
+#define range_end_overflows(start, size, max) ({ \
+ typeof(start) start__ = (start); \
+ typeof(size) size__ = (size); \
+ typeof(max) max__ = (max); \
+ (void)(&start__ == &size__); \
+ (void)(&start__ == &max__); \
+ start__ > max__ || size__ > max__ - start__; \
+})
+
+/**
+ * range_end_overflows_t() - Check if a range's endpoint is out of bounds
+ * @type: Data type to use.
+ * @start: Start of the range.
+ * @size: Size of the range.
+ * @max: Exclusive upper boundary.
+ *
+ * Same as range_end_overflows() but forcing the parameters to @type.
+ *
+ * Returns: true if the endpoint exceeds the boundary.
+ */
+#define range_end_overflows_t(type, start, size, max) \
+ range_end_overflows((type)(start), (type)(size), (type)(max))
+
/**
* castable_to_type - like __same_type(), but also allows for casted literals
*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 683/869] drm/panthor: Add vm_bind region with kbo range overlap check
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (681 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 682/869] overflow: add range_overflows() and range_end_overflows() Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 684/869] RDMA/cxgb4: Fix dereg_skb leak and double free in write_tpt_entry() Greg Kroah-Hartman
` (186 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Boris Brezillon, Adrián Larumbe,
Steven Price, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrián Larumbe <adrian.larumbe@collabora.com>
[ Upstream commit 985f5e12f3cdf43030e13c2bbd154913133b5c3f ]
When a VM is created, caller has to specify the range of the address space
carve-out set aside for mapping kernel BO's. That means vm_bind mappings of
UM-exposed BO's should not intersect with that region, but at the moment
we're not checking this.
At first, I thought of giving these values to drm_gpuvm_init() through its
reserve_{offset, range} arguments, but it turns out that is meant for VM
address spans that are not managed through the usual drm_gpuvm split/merge
circuit, so storing the end of the user VA range at VM creation time and
doing a quick check in the vm_bind ioctl path was the simplest workaround.
The new check also makes sure vm_bind range doesn't overflow the size of a
64-bit unsigned integer. That was already being done further down the call
stack inside drm_gpuvm_sm_map -> drm_gpuvm_range_valid, but it's best to
fail early in the driver before GPUVM functions are invoked so that we
won't waste time allocating vm_bind context resources.
Fixes: 12cf826bf1dd ("drm/panthor: Support sparse mappings")
Fixes: 647810ec2476 ("drm/panthor: Add the MMU/VM logical block")
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Link: https://patch.msgid.link/20260720-vm_bind_checks-v6-1-c2c7dbe93a73@collabora.com
Signed-off-by: Steven Price <steven.price@arm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/panthor/panthor_mmu.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index 9b6afc9c1da13..3cad487c1b727 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -311,6 +311,9 @@ struct panthor_vm {
u64 end;
} kernel_auto_va;
+ /** @user_va_range: Upper boundary of VAs VM users can map objects against. */
+ u64 user_va_range;
+
/** @as: Address space related fields. */
struct {
/**
@@ -2323,6 +2326,8 @@ panthor_vm_create(struct panthor_device *ptdev, bool for_mcu,
va_range = full_va_range;
}
+ vm->user_va_range = kernel_va_start;
+
mutex_init(&vm->mm_lock);
drm_mm_init(&vm->mm, kernel_va_start, kernel_va_size);
vm->kernel_auto_va.start = auto_kernel_va_start;
@@ -2412,6 +2417,10 @@ panthor_vm_bind_prepare_op_ctx(struct drm_file *file,
if (!IS_ALIGNED(op->va | op->size | op->bo_offset, vm_pgsz))
return -EINVAL;
+ /* We don't allow mappings that overlap with kbo's reserved range */
+ if (range_overflows(op->va, op->size, vm->user_va_range))
+ return -EINVAL;
+
switch (op->flags & DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) {
case DRM_PANTHOR_VM_BIND_OP_TYPE_MAP:
gem = drm_gem_object_lookup(file, op->bo_handle);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 684/869] RDMA/cxgb4: Fix dereg_skb leak and double free in write_tpt_entry()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (682 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 683/869] drm/panthor: Add vm_bind region with kbo range overlap check Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 685/869] PCI: Make pci_match_one_device() match on ID instead of device Greg Kroah-Hartman
` (185 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Leon Romanovsky, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <leonro@nvidia.com>
[ Upstream commit 373f3716a2de7adc739269ebb4d87e5bf4dc180c ]
When the device is in the fatal error state, write_tpt_entry() returns -EIO
before handing the caller's preallocated skb to the transmit path; its
allocation-failure returns do the same. c4iw_dereg_mr() ignores the error
and frees mhp, leaking mhp->dereg_skb. c4iw_get_dma_mr() instead frees the
skb a second time after dereg_mem() already consumed it, a double free.
Make write_tpt_entry() the sole owner of a non-NULL skb, freeing it on
every return preceding handoff to c4iw_ofld_send(): fatal error, tpt and
stag allocation failure. c4iw_ofld_send() consumes the skb on success and
error alike, so drop the redundant kfree_skb() in c4iw_get_dma_mr() after
dereg_mem().
Fixes: 0f8ab0b6e91b ("RDMA/iw_cxgb4: Low resource fixes for Memory registration")
Link: https://patch.msgid.link/20260726-leaked-mhp-dereg-skb-in-c4iw-dereg-m-v1-1-ebd6df364d53@nvidia.com
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/hw/cxgb4/mem.c | 46 ++++++++++++-------------------
1 file changed, 17 insertions(+), 29 deletions(-)
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index 9c24789bbb54b..9ed43d23c1835 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -199,7 +199,8 @@ static int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len,
daddr = dma_map_single(&rdev->lldi.pdev->dev, data, len, DMA_TO_DEVICE);
if (dma_mapping_error(&rdev->lldi.pdev->dev, daddr))
- return -1;
+ return _c4iw_write_mem_inline(rdev, addr, len, data, skb,
+ wr_waitp);
save = daddr;
while (remain > inline_threshold) {
@@ -235,30 +236,12 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
void *data, struct sk_buff *skb,
struct c4iw_wr_wait *wr_waitp)
{
- int ret;
-
- if (!rdev->lldi.ulptx_memwrite_dsgl || !use_dsgl) {
- ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
- wr_waitp);
- goto out;
- }
-
- if (len <= inline_threshold) {
- ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
+ if (!rdev->lldi.ulptx_memwrite_dsgl || !use_dsgl ||
+ len <= inline_threshold)
+ return _c4iw_write_mem_inline(rdev, addr, len, data, skb,
wr_waitp);
- goto out;
- }
-
- ret = _c4iw_write_mem_dma(rdev, addr, len, data, skb, wr_waitp);
- if (ret) {
- pr_warn_ratelimited("%s: dma map failure (non fatal)\n",
- pci_name(rdev->lldi.pdev));
- ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
- wr_waitp);
- }
-out:
- return ret;
+ return _c4iw_write_mem_dma(rdev, addr, len, data, skb, wr_waitp);
}
/*
@@ -280,12 +263,16 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
bool stag_idx_allocated = false;
static atomic_t key;
- if (c4iw_fatal_error(rdev))
+ if (c4iw_fatal_error(rdev)) {
+ kfree_skb(skb);
return -EIO;
+ }
tpt = kmalloc(sizeof(*tpt), GFP_KERNEL);
- if (!tpt)
+ if (!tpt) {
+ kfree_skb(skb);
return -ENOMEM;
+ }
stag_state = stag_state > 0;
stag_idx = (*stag) >> 8;
@@ -297,6 +284,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
rdev->stats.stag.fail++;
mutex_unlock(&rdev->stats.lock);
kfree(tpt);
+ kfree_skb(skb);
return -ENOMEM;
}
mutex_lock(&rdev->stats.lock);
@@ -471,8 +459,10 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc)
FW_RI_STAG_NSMR, mhp->attr.perms,
mhp->attr.mw_bind_enable, 0, 0, ~0ULL, 0, 0, 0,
NULL, mhp->wr_waitp);
- if (ret)
- goto err_free_skb;
+ if (ret) {
+ kfree_skb(mhp->dereg_skb);
+ goto err_free_wr_wait;
+ }
ret = finish_mem_reg(mhp, stag);
if (ret)
@@ -481,8 +471,6 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc)
err_dereg_mem:
dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
-err_free_skb:
- kfree_skb(mhp->dereg_skb);
err_free_wr_wait:
c4iw_put_wr_wait(mhp->wr_waitp);
err_free_mhp:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 685/869] PCI: Make pci_match_one_device() match on ID instead of device
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (683 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 684/869] RDMA/cxgb4: Fix dereg_skb leak and double free in write_tpt_entry() Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 686/869] PCI: Fix dyn_id add TOCTOU Greg Kroah-Hartman
` (184 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Gary Guo, Bjorn Helgaas,
Danilo Krummrich, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gary Guo <gary@garyguo.net>
[ Upstream commit c967b365d7b51c2297d9be5df39ac3e20638faf4 ]
PCI dynamic ID needs to match IDs against a new ID to see if it already
exists. Existing APIs can only match IDs against devices, so the dynamic ID
insertion code creates a temporary device only for matching purposes.
Rename pci_match_one_device() to pci_match_one_id() so it can be used for
this purpose instead; add a pci_id_from_device() helper to make it easy to
convert users.
Similarly, convert pci_match_id() to do_pci_match_id(). But keep the
existing API because there are many users.
Signed-off-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Link: https://patch.msgid.link/20260723-pci_id_fix-v4-7-3580726844e1@garyguo.net
Stable-dep-of: 3ffc4c9690c3 ("PCI: Fix UAF when probe runs concurrent to dyn ID removal")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pci/pci-driver.c | 38 +++++++++++++++++++++++++----------
drivers/pci/pci.h | 43 +++++++++++++++++++++++++++++-----------
drivers/pci/search.c | 8 +++++---
3 files changed, 64 insertions(+), 25 deletions(-)
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 0eb246a07c87a..943162501c8e4 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -90,6 +90,27 @@ static void pci_free_dynids(struct pci_driver *drv)
spin_unlock(&drv->dynids.lock);
}
+/**
+ * do_pci_match_id - See if a PCI ID matches a given pci_id table
+ * @ids: array of PCI device ID structures to search in
+ * @dev_id: the actual PCI device ID structure to match against.
+ *
+ * Return: the matching pci_device_id structure or %NULL if there is no match.
+ */
+static const struct pci_device_id *
+do_pci_match_id(const struct pci_device_id *ids,
+ const struct pci_device_id *dev_id)
+{
+ if (ids) {
+ while (ids->vendor || ids->subvendor || ids->class_mask) {
+ if (pci_match_one_id(ids, dev_id))
+ return ids;
+ ids++;
+ }
+ }
+ return NULL;
+}
+
/**
* pci_match_id - See if a PCI device matches a given pci_id table
* @ids: array of PCI device ID structures to search in
@@ -105,14 +126,9 @@ static void pci_free_dynids(struct pci_driver *drv)
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
struct pci_dev *dev)
{
- if (ids) {
- while (ids->vendor || ids->subvendor || ids->class_mask) {
- if (pci_match_one_device(ids, dev))
- return ids;
- ids++;
- }
- }
- return NULL;
+ struct pci_device_id dev_id = pci_id_from_device(dev);
+
+ return do_pci_match_id(ids, &dev_id);
}
EXPORT_SYMBOL(pci_match_id);
@@ -138,6 +154,7 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
{
struct pci_dynid *dynid;
const struct pci_device_id *found_id = NULL, *ids;
+ struct pci_device_id dev_id;
int ret;
/* When driver_override is set, only bind to the matching driver */
@@ -145,10 +162,11 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
if (ret == 0)
return NULL;
+ dev_id = pci_id_from_device(dev);
/* Look at the dynamic ids first, before the static ones */
spin_lock(&drv->dynids.lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
- if (pci_match_one_device(&dynid->id, dev)) {
+ if (pci_match_one_id(&dynid->id, &dev_id)) {
found_id = &dynid->id;
break;
}
@@ -158,7 +176,7 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
if (found_id)
return found_id;
- for (ids = drv->id_table; (found_id = pci_match_id(ids, dev));
+ for (ids = drv->id_table; (found_id = do_pci_match_id(ids, &dev_id));
ids = found_id + 1) {
/*
* The match table is split based on driver_override.
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 7b3d45f243264..f60d0eb600645 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -289,21 +289,40 @@ extern unsigned long pci_hotplug_mmio_pref_size;
extern unsigned long pci_hotplug_bus_size;
/**
- * pci_match_one_device - Tell if a PCI device structure has a matching
- * PCI device id structure
- * @id: single PCI device id structure to match
- * @dev: the PCI device structure to match against
+ * pci_id_from_device - Obtain a pci_device_id from a PCI device
+ * @dev: the PCI device
*
- * Returns the matching pci_device_id structure or %NULL if there is no match.
+ * Return: a pci_device_id filled.
*/
-static inline const struct pci_device_id *
-pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
+static inline struct pci_device_id pci_id_from_device(const struct pci_dev *dev)
{
- if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
- (id->device == PCI_ANY_ID || id->device == dev->device) &&
- (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) &&
- (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) &&
- !((id->class ^ dev->class) & id->class_mask))
+ return (struct pci_device_id) {
+ .vendor = dev->vendor,
+ .device = dev->device,
+ .subvendor = dev->subsystem_vendor,
+ .subdevice = dev->subsystem_device,
+ .class = dev->class,
+ };
+}
+
+/**
+ * pci_match_one_id - Tell if a PCI device ID matches a needle PCI device ID
+ * @id: single PCI device id structure to match against (needle)
+ * @dev_id: the actual ID from the PCI device
+ *
+ * ID can be retrieved from device using pci_id_from_device().
+ *
+ * Return: the matching pci_device_id structure or %NULL if there is no match.
+ */
+static inline const struct pci_device_id *
+pci_match_one_id(const struct pci_device_id *id,
+ const struct pci_device_id *dev_id)
+{
+ if ((id->vendor == PCI_ANY_ID || id->vendor == dev_id->vendor) &&
+ (id->device == PCI_ANY_ID || id->device == dev_id->device) &&
+ (id->subvendor == PCI_ANY_ID || id->subvendor == dev_id->subvendor) &&
+ (id->subdevice == PCI_ANY_ID || id->subdevice == dev_id->subdevice) &&
+ !((id->class ^ dev_id->class) & id->class_mask))
return id;
return NULL;
}
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 53840634fbfc2..705ab725321a8 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -243,8 +243,10 @@ static int match_pci_dev_by_id(struct device *dev, const void *data)
{
struct pci_dev *pdev = to_pci_dev(dev);
const struct pci_device_id *id = data;
+ struct pci_device_id dev_id;
- if (pci_match_one_device(id, pdev))
+ dev_id = pci_id_from_device(pdev);
+ if (pci_match_one_id(id, &dev_id))
return 1;
return 0;
}
@@ -368,9 +370,9 @@ EXPORT_SYMBOL(pci_get_class);
* @class: search for a PCI device with this base class code
* @from: Previous PCI device found in search, or %NULL for new search.
*
- * Iterates through the list of known PCI devices. If a PCI device is found
+ * Iterate through the list of known PCI devices. If a PCI device is found
* with a matching base class code, the reference count to the device is
- * incremented. See pci_match_one_device() to figure out how does this works.
+ * incremented. See pci_match_one_id() to figure out how this works.
* A new search is initiated by passing %NULL as the @from argument.
* Otherwise if @from is not %NULL, searches continue from next device on the
* global list. The reference count for @from is always decremented if it is
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 686/869] PCI: Fix dyn_id add TOCTOU
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (684 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 685/869] PCI: Make pci_match_one_device() match on ID instead of device Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 687/869] PCI: Fix UAF when probe runs concurrent to dyn ID removal Greg Kroah-Hartman
` (183 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Gary Guo, Bjorn Helgaas,
Danilo Krummrich, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gary Guo <gary@garyguo.net>
[ Upstream commit 04fde70f782b6ce984f9f80c2023786caea28287 ]
Currently there is a TOCTOU issue in new_id_store() as the dyn ID insertion
in pci_add_dynid() and the pci_match_device() are in separate critical
sections.
Fix this by moving the existing ID check to inside pci_add_dynid() and only
check against the static ID table outside the critical section.
Fixes: 3853f9123c18 ("PCI: Avoid duplicate IDs in driver dynamic IDs list")
Signed-off-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Link: https://patch.msgid.link/20260723-pci_id_fix-v4-8-3580726844e1@garyguo.net
Stable-dep-of: 3ffc4c9690c3 ("PCI: Fix UAF when probe runs concurrent to dyn ID removal")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pci/pci-driver.c | 142 ++++++++++++++++++++-------------------
1 file changed, 73 insertions(+), 69 deletions(-)
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 943162501c8e4..d684106184c0b 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -29,6 +29,47 @@ struct pci_dynid {
struct pci_device_id id;
};
+/**
+ * do_pci_add_dynid - Add a new PCI device ID to this driver and re-probe
+ * @drv: target PCI driver
+ * @id: ID to be added
+ * @check_dup: whether to check if matching ID is already present
+ *
+ * Add a new dynamic PCI device ID to this driver and causes the driver to
+ * probe for all devices again. @drv must have been registered prior to calling
+ * this function.
+ *
+ * Context: Does GFP_KERNEL allocation.
+ *
+ * Return: 0 on success, -errno on failure.
+ */
+static int do_pci_add_dynid(struct pci_driver *drv,
+ const struct pci_device_id *id,
+ bool check_dup)
+{
+ struct pci_dynid *dynid, *existing_dynid;
+
+ dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
+ if (!dynid)
+ return -ENOMEM;
+
+ dynid->id = *id;
+
+ scoped_guard(spinlock, &drv->dynids.lock) {
+ if (check_dup) {
+ list_for_each_entry(existing_dynid, &drv->dynids.list, node) {
+ if (pci_match_one_id(&existing_dynid->id, id)) {
+ kfree(dynid);
+ return -EEXIST;
+ }
+ }
+ }
+ list_add_tail(&dynid->node, &drv->dynids.list);
+ }
+
+ return driver_attach(&drv->driver);
+}
+
/**
* pci_add_dynid - add a new PCI device ID to this driver and re-probe devices
* @drv: target pci driver
@@ -56,25 +97,17 @@ int pci_add_dynid(struct pci_driver *drv,
unsigned int class, unsigned int class_mask,
unsigned long driver_data)
{
- struct pci_dynid *dynid;
-
- dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
- if (!dynid)
- return -ENOMEM;
-
- dynid->id.vendor = vendor;
- dynid->id.device = device;
- dynid->id.subvendor = subvendor;
- dynid->id.subdevice = subdevice;
- dynid->id.class = class;
- dynid->id.class_mask = class_mask;
- dynid->id.driver_data = driver_data;
-
- spin_lock(&drv->dynids.lock);
- list_add_tail(&dynid->node, &drv->dynids.list);
- spin_unlock(&drv->dynids.lock);
-
- return driver_attach(&drv->driver);
+ struct pci_device_id id = {
+ .vendor = vendor,
+ .device = device,
+ .subvendor = subvendor,
+ .subdevice = subdevice,
+ .class = class,
+ .class_mask = class_mask,
+ .driver_data = driver_data,
+ };
+
+ return do_pci_add_dynid(drv, &id, false);
}
EXPORT_SYMBOL_GPL(pci_add_dynid);
@@ -94,16 +127,20 @@ static void pci_free_dynids(struct pci_driver *drv)
* do_pci_match_id - See if a PCI ID matches a given pci_id table
* @ids: array of PCI device ID structures to search in
* @dev_id: the actual PCI device ID structure to match against.
+ * @include_override_only: also match against device ID entries marked as
+ * override only.
*
* Return: the matching pci_device_id structure or %NULL if there is no match.
*/
static const struct pci_device_id *
do_pci_match_id(const struct pci_device_id *ids,
- const struct pci_device_id *dev_id)
+ const struct pci_device_id *dev_id,
+ bool include_override_only)
{
if (ids) {
while (ids->vendor || ids->subvendor || ids->class_mask) {
- if (pci_match_one_id(ids, dev_id))
+ if ((!ids->override_only || include_override_only) &&
+ pci_match_one_id(ids, dev_id))
return ids;
ids++;
}
@@ -128,7 +165,7 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
{
struct pci_device_id dev_id = pci_id_from_device(dev);
- return do_pci_match_id(ids, &dev_id);
+ return do_pci_match_id(ids, &dev_id, true);
}
EXPORT_SYMBOL(pci_match_id);
@@ -153,7 +190,7 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
struct pci_dev *dev)
{
struct pci_dynid *dynid;
- const struct pci_device_id *found_id = NULL, *ids;
+ const struct pci_device_id *found_id = NULL;
struct pci_device_id dev_id;
int ret;
@@ -176,20 +213,9 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
if (found_id)
return found_id;
- for (ids = drv->id_table; (found_id = do_pci_match_id(ids, &dev_id));
- ids = found_id + 1) {
- /*
- * The match table is split based on driver_override.
- * In case override_only was set, enforce driver_override
- * matching.
- */
- if (found_id->override_only) {
- if (ret > 0)
- return found_id;
- } else {
- return found_id;
- }
- }
+ found_id = do_pci_match_id(drv->id_table, &dev_id, ret > 0);
+ if (found_id)
+ return found_id;
/* driver_override will always match, send a dummy id */
if (ret > 0)
@@ -197,11 +223,6 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
return NULL;
}
-static void _pci_free_device(struct device *dev)
-{
- kfree(to_pci_dev(dev));
-}
-
/**
* new_id_store - sysfs frontend to pci_add_dynid()
* @driver: target device driver
@@ -215,38 +236,22 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf,
{
struct pci_driver *pdrv = to_pci_driver(driver);
const struct pci_device_id *ids = pdrv->id_table;
- u32 vendor, device, subvendor = PCI_ANY_ID,
- subdevice = PCI_ANY_ID, class = 0, class_mask = 0;
- unsigned long driver_data = 0;
+ struct pci_device_id id = {
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID
+ };
int fields;
int retval = 0;
fields = sscanf(buf, "%x %x %x %x %x %x %lx",
- &vendor, &device, &subvendor, &subdevice,
- &class, &class_mask, &driver_data);
+ &id.vendor, &id.device, &id.subvendor, &id.subdevice,
+ &id.class, &id.class_mask, &id.driver_data);
if (fields < 2)
return -EINVAL;
if (fields != 7) {
- struct pci_dev *pdev = kzalloc(sizeof(*pdev), GFP_KERNEL);
- if (!pdev)
- return -ENOMEM;
-
- pdev->vendor = vendor;
- pdev->device = device;
- pdev->subsystem_vendor = subvendor;
- pdev->subsystem_device = subdevice;
- pdev->class = class;
- pdev->dev.release = _pci_free_device;
-
- device_initialize(&pdev->dev);
- if (pci_match_device(pdrv, pdev))
- retval = -EEXIST;
-
- put_device(&pdev->dev);
-
- if (retval)
- return retval;
+ if (do_pci_match_id(pdrv->id_table, &id, false))
+ return -EEXIST;
}
/* Only accept driver_data values that match an existing id_table
@@ -254,7 +259,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf,
if (ids) {
retval = -EINVAL;
while (ids->vendor || ids->subvendor || ids->class_mask) {
- if (driver_data == ids->driver_data) {
+ if (id.driver_data == ids->driver_data) {
retval = 0;
break;
}
@@ -264,8 +269,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf,
return retval;
}
- retval = pci_add_dynid(pdrv, vendor, device, subvendor, subdevice,
- class, class_mask, driver_data);
+ retval = do_pci_add_dynid(pdrv, &id, fields != 7);
if (retval)
return retval;
return count;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 687/869] PCI: Fix UAF when probe runs concurrent to dyn ID removal
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (685 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 686/869] PCI: Fix dyn_id add TOCTOU Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 688/869] clk: mediatek: pllfh: Fix IO remapping leak in register_pllfhs error path Greg Kroah-Hartman
` (182 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Gary Guo, Bjorn Helgaas,
Danilo Krummrich, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gary Guo <gary@garyguo.net>
[ Upstream commit 3ffc4c9690c33ee28cdb3d0182b12f9c623e3acc ]
Dynamic IDs are only guaranteed to be valid when dynids.lock is held,
as remove_id_store() can free the node. Thus, make a copy in
pci_match_device(). Also, clarify that the id parameter is only valid
during probe.
Fixes: 0994375e9614 ("PCI: add remove_id sysfs entry")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://lore.kernel.org/all/20260619170503.518F61F00A3A@smtp.kernel.org/
Signed-off-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Link: https://patch.msgid.link/20260723-pci_id_fix-v4-9-3580726844e1@garyguo.net
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pci/pci-driver.c | 28 +++++++++++++++-------------
include/linux/pci.h | 1 +
2 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index d684106184c0b..f74299cb10e3e 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -180,6 +180,7 @@ static const struct pci_device_id pci_device_id_any = {
* pci_match_device - See if a device matches a driver's list of IDs
* @drv: the PCI driver to match against
* @dev: the PCI device structure to match against
+ * @id_copy: place to store copy of pci_device_id for dynamic ID
*
* Used by a driver to check whether a PCI device is in its list of
* supported devices or in the dynids list, which may have been augmented
@@ -187,9 +188,9 @@ static const struct pci_device_id pci_device_id_any = {
* structure or %NULL if there is no match.
*/
static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
- struct pci_dev *dev)
+ struct pci_dev *dev,
+ struct pci_device_id *id_copy)
{
- struct pci_dynid *dynid;
const struct pci_device_id *found_id = NULL;
struct pci_device_id dev_id;
int ret;
@@ -201,17 +202,16 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
dev_id = pci_id_from_device(dev);
/* Look at the dynamic ids first, before the static ones */
- spin_lock(&drv->dynids.lock);
- list_for_each_entry(dynid, &drv->dynids.list, node) {
- if (pci_match_one_id(&dynid->id, &dev_id)) {
- found_id = &dynid->id;
- break;
+ scoped_guard(spinlock, &drv->dynids.lock) {
+ struct pci_dynid *dynid;
+
+ list_for_each_entry(dynid, &drv->dynids.list, node) {
+ if (pci_match_one_id(&dynid->id, &dev_id)) {
+ *id_copy = dynid->id;
+ return id_copy;
+ }
}
}
- spin_unlock(&drv->dynids.lock);
-
- if (found_id)
- return found_id;
found_id = do_pci_match_id(drv->id_table, &dev_id, ret > 0);
if (found_id)
@@ -438,12 +438,13 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
{
const struct pci_device_id *id;
+ struct pci_device_id id_copy;
int error = 0;
if (drv->probe) {
error = -ENODEV;
- id = pci_match_device(drv, pci_dev);
+ id = pci_match_device(drv, pci_dev, &id_copy);
if (id)
error = pci_call_probe(drv, pci_dev, id);
}
@@ -1537,12 +1538,13 @@ static int pci_bus_match(struct device *dev, const struct device_driver *drv)
struct pci_dev *pci_dev = to_pci_dev(dev);
struct pci_driver *pci_drv;
const struct pci_device_id *found_id;
+ struct pci_device_id id_copy;
if (!pci_dev->match_driver)
return 0;
pci_drv = (struct pci_driver *)to_pci_driver(drv);
- found_id = pci_match_device(pci_drv, pci_dev);
+ found_id = pci_match_device(pci_drv, pci_dev, &id_copy);
if (found_id)
return 1;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index ee27f1ba01b8e..f3051fb5a5e84 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -929,6 +929,7 @@ struct module;
* function returns zero when the driver chooses to
* take "ownership" of the device or an error code
* (negative number) otherwise.
+ * The pci_device_id parameter is only valid during probe.
* The probe function always gets called from process
* context, so it can sleep.
* @remove: The remove() function gets called whenever a device
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 688/869] clk: mediatek: pllfh: Fix IO remapping leak in register_pllfhs error path
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (686 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 687/869] PCI: Fix UAF when probe runs concurrent to dyn ID removal Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 689/869] iommu/tegra241-cmdqv: Fix VINTF0 leak on the init-failure path Greg Kroah-Hartman
` (181 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Louis-Alexis Eyraud, Brian Masney,
AngeloGioacchino Del Regno, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
[ Upstream commit 540d91480bcb1b28a62d7023aa70947ea44c55b9 ]
When mtk_clk_register_pllfhs function fails to register a PLL, it
unregisters all PLLs and cleans up itself in its error path before
returning, so the function callers don't need to do it.
But contrary to mtk_clk_unregister_pllfhs function, that does almost
the same sequence, it does not free the IO memory mapped on fhctl node,
leading to a leak.
Fix this leak by factorizing the cleanup sequence in a new private
function and use it both mtk_clk_register_pllfhs and
mtk_clk_unregister_pllfhs functions.
Also, change the loop index start value to avoid the -1 operation on
index at each loop.
Fixes: d7964de8a8ea ("clk: mediatek: Add new clock driver to handle FHCTL hardware")
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
Reviewed-by: Brian Masney <bmasney@redhat.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Brian Masney <bmasney@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/clk/mediatek/clk-pllfh.c | 98 ++++++++++++++++----------------
1 file changed, 49 insertions(+), 49 deletions(-)
diff --git a/drivers/clk/mediatek/clk-pllfh.c b/drivers/clk/mediatek/clk-pllfh.c
index 094ec8a26d668..1e97daeb45e43 100644
--- a/drivers/clk/mediatek/clk-pllfh.c
+++ b/drivers/clk/mediatek/clk-pllfh.c
@@ -194,12 +194,56 @@ static void mtk_clk_unregister_pllfh(struct clk_hw *hw)
kfree(fh);
}
+static void mtk_clk_cleanup_pllfhs(void __iomem *iomem_base,
+ const struct mtk_pll_data *plls, int num_plls,
+ void __iomem *iomem_fhctl_base,
+ struct mtk_pllfh_data *pllfhs, int num_fhs,
+ struct clk_hw_onecell_data *clk_data)
+{
+ void __iomem *base = iomem_base;
+ void __iomem *fhctl_base = iomem_fhctl_base;
+ int i;
+
+ for (i = num_plls - 1; i >= 0; i--) {
+ const struct mtk_pll_data *pll = &plls[i];
+ struct mtk_pllfh_data *pllfh;
+ bool use_fhctl;
+
+ if (IS_ERR_OR_NULL(clk_data->hws[pll->id]))
+ continue;
+
+ pllfh = get_pllfh_by_id(pllfhs, num_fhs, pll->id);
+ use_fhctl = fhctl_is_supported_and_enabled(pllfh);
+
+ if (!base)
+ base = mtk_clk_pll_get_base(clk_data->hws[pll->id],
+ pll);
+
+ if (use_fhctl) {
+ if (!fhctl_base)
+ fhctl_base = pllfh->state.base;
+ mtk_clk_unregister_pllfh(clk_data->hws[pll->id]);
+ } else {
+ mtk_clk_unregister_pll(clk_data->hws[pll->id]);
+ }
+
+ clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
+ }
+
+ if (fhctl_base)
+ iounmap(fhctl_base);
+
+ if (base)
+ iounmap(base);
+}
+
+
int mtk_clk_register_pllfhs(struct device_node *node,
const struct mtk_pll_data *plls, int num_plls,
struct mtk_pllfh_data *pllfhs, int num_fhs,
struct clk_hw_onecell_data *clk_data)
{
- void __iomem *base;
+ void __iomem *base, *fhctl_base = NULL;
int i;
struct clk_hw *hw;
@@ -235,24 +279,8 @@ int mtk_clk_register_pllfhs(struct device_node *node,
return 0;
err:
- while (--i >= 0) {
- const struct mtk_pll_data *pll = &plls[i];
- struct mtk_pllfh_data *pllfh;
- bool use_fhctl;
-
- pllfh = get_pllfh_by_id(pllfhs, num_fhs, pll->id);
- use_fhctl = fhctl_is_supported_and_enabled(pllfh);
-
- if (use_fhctl)
- mtk_clk_unregister_pllfh(clk_data->hws[pll->id]);
- else
- mtk_clk_unregister_pll(clk_data->hws[pll->id]);
-
- clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
- }
-
- iounmap(base);
-
+ mtk_clk_cleanup_pllfhs(base, plls, i, fhctl_base, pllfhs, num_fhs,
+ clk_data);
return PTR_ERR(hw);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_pllfhs);
@@ -261,38 +289,10 @@ void mtk_clk_unregister_pllfhs(const struct mtk_pll_data *plls, int num_plls,
struct mtk_pllfh_data *pllfhs, int num_fhs,
struct clk_hw_onecell_data *clk_data)
{
- void __iomem *base = NULL, *fhctl_base = NULL;
- int i;
-
if (!clk_data)
return;
- for (i = num_plls; i > 0; i--) {
- const struct mtk_pll_data *pll = &plls[i - 1];
- struct mtk_pllfh_data *pllfh;
- bool use_fhctl;
-
- if (IS_ERR_OR_NULL(clk_data->hws[pll->id]))
- continue;
-
- pllfh = get_pllfh_by_id(pllfhs, num_fhs, pll->id);
- use_fhctl = fhctl_is_supported_and_enabled(pllfh);
-
- if (use_fhctl) {
- fhctl_base = pllfh->state.base;
- mtk_clk_unregister_pllfh(clk_data->hws[pll->id]);
- } else {
- base = mtk_clk_pll_get_base(clk_data->hws[pll->id],
- pll);
- mtk_clk_unregister_pll(clk_data->hws[pll->id]);
- }
-
- clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
- }
-
- if (fhctl_base)
- iounmap(fhctl_base);
-
- iounmap(base);
+ mtk_clk_cleanup_pllfhs(NULL, plls, num_plls, NULL, pllfhs,
+ num_fhs, clk_data);
}
EXPORT_SYMBOL_GPL(mtk_clk_unregister_pllfhs);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 689/869] iommu/tegra241-cmdqv: Fix VINTF0 leak on the init-failure path
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (687 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 688/869] clk: mediatek: pllfh: Fix IO remapping leak in register_pllfhs error path Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 690/869] iommu/tegra241-cmdqv: Dont fall back to a freed smmu after devm_krealloc() Greg Kroah-Hartman
` (180 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Nicolin Chen, Will Deacon,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <nicolinc@nvidia.com>
[ Upstream commit f40f3144477314b489e4bc209c06cb51679fe82b ]
tegra241_cmdqv_init_structures() allocates VINTF0 with kzalloc_obj(), inits
it, and preallocates its logical VCMDQs. Two of its error paths leak.
When tegra241_cmdqv_init_vintf() fails it returns before VINTF0 reaches the
cmdqv->vintfs[] array, so the devres unwind on probe failure cannot reach
it; free it directly there.
A later VCMDQ preallocation failure instead leaves VINTF0 published, and so
this time the unwind does reach tegra241_cmdqv_remove_vintf(), which then
frees it from vintf->hyp_own. But tegra241_vintf_hw_init() sets that flag
only afterward, from a HW read-back, so the still-uninited VINTF0 reads as
guest-owned and leaks, with mutex_destroy() and ida_destroy() run on fields
it never set up.
Decide ownership from vintf->idx instead, the index assigned when its id is
allocated: idx 0 is the kernel-owned VINTF0, while idx >= 1 marks a guest
VINTF. So the in-kernel free decision in tegra241_cmdqv_remove_vintf() and
tegra241_vintf_free_lvcmdq() now keys on idx too, and hyp_own stays a pure
HW-readback state.
Fixes: 918eb5c856f6 ("iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
index 2c7b668c84234..335928aa0ef59 100644
--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
+++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
@@ -778,6 +778,12 @@ static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
ret = tegra241_cmdqv_init_vintf(cmdqv, 0, vintf);
if (ret) {
dev_err(cmdqv->dev, "failed to init vintf0: %d\n", ret);
+ /*
+ * tegra241_cmdqv_init_vintf() failed to publish the vintf0 to
+ * cmdqv->vintfs[], so the probe unwind path that goes through
+ * cmdqv->vintfs[] would miss it. Free it here.
+ */
+ kfree(vintf);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 690/869] iommu/tegra241-cmdqv: Dont fall back to a freed smmu after devm_krealloc()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (688 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 689/869] iommu/tegra241-cmdqv: Fix VINTF0 leak on the init-failure path Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 691/869] scsi: ufs: core: Convert string descriptor format macros to enum Greg Kroah-Hartman
` (179 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Nicolin Chen, Will Deacon,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <nicolinc@nvidia.com>
[ Upstream commit d4d05f55e9da646ec03adfa77260eb46f4163749 ]
__tegra241_cmdqv_probe() uses devm_krealloc() to grow @smmu into the larger
tegra241_cmdqv, which frees the original @smmu once it relocates. A failure
after that returned NULL, and the caller then dereferenced the freed @smmu
on its fallback path.
Return an int and take @smmu by reference instead, then update *smmu to the
reallocated pointer after devm_krealloc() succeeds, so the caller and its
fallback path both use the live @smmu rather than the freed original.
Fixes: 918eb5c856f6 ("iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 54 +++++++++++--------
1 file changed, 32 insertions(+), 22 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
index 335928aa0ef59..3207fa9836063 100644
--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
+++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c
@@ -805,16 +805,22 @@ static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu)
static struct dentry *cmdqv_debugfs_dir;
#endif
-static struct arm_smmu_device *
-__tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
- int irq)
+/*
+ * Probe the CMDQV and reallocate @smmu into the larger cmdqv->smmu.
+ *
+ * devm_krealloc() may relocate and free the original @smmu, so update *smmu to
+ * the new pointer once it succeeds. The error paths after it do the same, so a
+ * caller falling back keeps a live @smmu instead of the freed original.
+ */
+static int __tegra241_cmdqv_probe(struct arm_smmu_device **smmu,
+ struct resource *res, int irq)
{
static const struct arm_smmu_impl_ops init_ops = {
.init_structures = tegra241_cmdqv_init_structures,
.device_remove = tegra241_cmdqv_remove,
};
- struct tegra241_cmdqv *cmdqv = NULL;
- struct arm_smmu_device *new_smmu;
+ struct device *dev = (*smmu)->dev;
+ struct tegra241_cmdqv *cmdqv;
void __iomem *base;
u32 regval;
int ret;
@@ -823,25 +829,28 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
base = ioremap(res->start, resource_size(res));
if (!base) {
- dev_err(smmu->dev, "failed to ioremap\n");
- return NULL;
+ dev_err(dev, "failed to ioremap\n");
+ return -ENOMEM;
}
regval = readl(base + TEGRA241_CMDQV_CONFIG);
if (disable_cmdqv) {
- dev_info(smmu->dev, "Detected disable_cmdqv=true\n");
+ dev_info(dev, "Detected disable_cmdqv=true\n");
writel(regval & ~CMDQV_EN, base + TEGRA241_CMDQV_CONFIG);
+ ret = -ENODEV;
goto iounmap;
}
- cmdqv = devm_krealloc(smmu->dev, smmu, sizeof(*cmdqv), GFP_KERNEL);
- if (!cmdqv)
+ cmdqv = devm_krealloc(dev, *smmu, sizeof(*cmdqv), GFP_KERNEL);
+ if (!cmdqv) {
+ ret = -ENOMEM;
goto iounmap;
- new_smmu = &cmdqv->smmu;
+ }
+ *smmu = &cmdqv->smmu;
cmdqv->irq = irq;
cmdqv->base = base;
- cmdqv->dev = smmu->impl_dev;
+ cmdqv->dev = (*smmu)->impl_dev;
regval = readl_relaxed(REG_CMDQV(cmdqv, PARAM));
cmdqv->num_vintfs = 1 << FIELD_GET(CMDQV_NUM_VINTF_LOG2, regval);
@@ -850,8 +859,10 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
cmdqv->vintfs =
kcalloc(cmdqv->num_vintfs, sizeof(*cmdqv->vintfs), GFP_KERNEL);
- if (!cmdqv->vintfs)
+ if (!cmdqv->vintfs) {
+ ret = -ENOMEM;
goto iounmap;
+ }
ida_init(&cmdqv->vintf_ids);
@@ -880,38 +891,37 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,
#endif
/* Provide init-level ops only, until tegra241_cmdqv_init_structures */
- new_smmu->impl_ops = &init_ops;
+ cmdqv->smmu.impl_ops = &init_ops;
- return new_smmu;
+ return 0;
free_vintfs:
ida_destroy(&cmdqv->vintf_ids);
kfree(cmdqv->vintfs);
iounmap:
iounmap(base);
- return NULL;
+ return ret;
}
struct arm_smmu_device *tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
{
- struct arm_smmu_device *new_smmu;
struct resource *res = NULL;
- int irq;
+ int irq, ret;
if (!smmu->dev->of_node)
res = tegra241_cmdqv_find_acpi_resource(smmu->impl_dev, &irq);
if (!res)
goto out_fallback;
- new_smmu = __tegra241_cmdqv_probe(smmu, res, irq);
+ ret = __tegra241_cmdqv_probe(&smmu, res, irq);
kfree(res);
- if (new_smmu)
- return new_smmu;
+ if (!ret)
+ return smmu;
out_fallback:
dev_info(smmu->impl_dev, "Falling back to standard SMMU CMDQ\n");
smmu->options &= ~ARM_SMMU_OPT_TEGRA241_CMDQV;
put_device(smmu->impl_dev);
- return ERR_PTR(-ENODEV);
+ return smmu;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 691/869] scsi: ufs: core: Convert string descriptor format macros to enum
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (689 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 690/869] iommu/tegra241-cmdqv: Dont fall back to a freed smmu after devm_krealloc() Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 692/869] scsi: ufs: core: Validate string descriptors Greg Kroah-Hartman
` (178 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bart Van Assche, Avri Altman,
Bean Huo, Martin K. Petersen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bean Huo <beanhuo@micron.com>
[ Upstream commit 0d9a7085ec24983b5b8a4971c0eb6c756c75f1bf ]
Convert SD_ASCII_STD and SD_RAW from boolean macros to enum values for
improved code readability. This makes ufshcd_read_string_desc() calls
self-documenting by using explicit enum values instead of true/false.
Move the ufshcd_read_string_desc() declaration from include/ufs/ufshcd.h
to drivers/ufs/core/ufshcd-priv.h since this function is not exported.
Co-developed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Suggested-by: Avri Altman <Avri.Altman@sandisk.com>
Signed-off-by: Bean Huo <beanhuo@micron.com>
Link: https://patch.msgid.link/20251107230518.4060231-2-beanhuo@iokpp.de
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Stable-dep-of: d96e83d028d7 ("scsi: ufs: core: Validate string descriptors")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ufs/core/ufshcd-priv.h | 14 ++++++++++----
drivers/ufs/core/ufshcd.c | 8 +++-----
include/ufs/ufshcd.h | 4 ----
3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h
index 786f20ef22386..8a799d9758f5f 100644
--- a/drivers/ufs/core/ufshcd-priv.h
+++ b/drivers/ufs/core/ufshcd-priv.h
@@ -78,11 +78,17 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag);
void ufshcd_release_scsi_cmd(struct ufs_hba *hba,
struct ufshcd_lrb *lrbp);
-#define SD_ASCII_STD true
-#define SD_RAW false
-int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index,
- u8 **buf, bool ascii);
+/**
+ * enum ufs_descr_fmt - UFS string descriptor format
+ * @SD_RAW: Raw UTF-16 format
+ * @SD_ASCII_STD: Convert to null-terminated ASCII string
+ */
+enum ufs_descr_fmt {
+ SD_RAW = 0,
+ SD_ASCII_STD = 1,
+};
+int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, u8 **buf, enum ufs_descr_fmt fmt);
int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd);
int ufshcd_send_bsg_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd);
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index c28c07602a58d..6c94300783e1d 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -3738,16 +3738,14 @@ static inline char ufshcd_remove_non_printable(u8 ch)
* @desc_index: descriptor index
* @buf: pointer to buffer where descriptor would be read,
* the caller should free the memory.
- * @ascii: if true convert from unicode to ascii characters
- * null terminated string.
+ * @fmt: if %SD_ASCII_STD, convert from UTF-16 to ASCII
*
* Return:
* * string size on success.
* * -ENOMEM: on allocation failure
* * -EINVAL: on a wrong parameter
*/
-int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index,
- u8 **buf, bool ascii)
+int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, u8 **buf, enum ufs_descr_fmt fmt)
{
struct uc_string_id *uc_str;
u8 *str;
@@ -3776,7 +3774,7 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index,
goto out;
}
- if (ascii) {
+ if (fmt == SD_ASCII_STD) {
ssize_t ascii_len;
int i;
/* remove header and divide by 2 to move from UTF16 to UTF8 */
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index 175ce70758bbc..70dcc13d136d6 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -1440,10 +1440,6 @@ static inline int ufshcd_disable_host_tx_lcc(struct ufs_hba *hba)
void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
void ufshcd_fixup_dev_quirks(struct ufs_hba *hba,
const struct ufs_dev_quirk *fixups);
-#define SD_ASCII_STD true
-#define SD_RAW false
-int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index,
- u8 **buf, bool ascii);
void ufshcd_hold(struct ufs_hba *hba);
void ufshcd_release(struct ufs_hba *hba);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 692/869] scsi: ufs: core: Validate string descriptors
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (690 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 691/869] scsi: ufs: core: Convert string descriptor format macros to enum Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 693/869] pinctrl: mediatek: use devm_gpiochip_add_data() for GPIO chip Greg Kroah-Hartman
` (177 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Li Qiang, Peter Wang,
Bart Van Assche, Martin K. Petersen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Qiang <liqiang01@kylinos.cn>
[ Upstream commit d96e83d028d7d8762e424e49c671d49ac2ecf14f ]
The string descriptor length includes a two-byte header while the UTF-16
payload starts after it. utf16s_to_utf8s() expects a count of UTF-16 code
units, not bytes. Passing the payload byte count can make it read beyond
the descriptor buffer.
Validate that the payload has an even byte count, pass a code-unit count to
the converter, and allocate sufficient UTF-8 output space.
The raw string buffer starts after the descriptor header but its size is
bLength. Copying bLength bytes from that pointer can read beyond the
response buffer.
Allocate a zeroed bLength-sized buffer and copy only the UTF-16
payload. This preserves the raw buffer size consumed by the RPMB device-ID
ABI while avoiding the overread.
Fixes: 4b828fe156a6 ("scsi: ufs: revamp string descriptor reading")
Fixes: d794b499f948 ("scsi: ufs: core: fix incorrect buffer duplication in ufshcd_read_string_desc()")
Signed-off-by: Li Qiang <liqiang01@kylinos.cn>
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Link: https://patch.msgid.link/20260717153914.26321-2-liqiang01@kylinos.cn
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ufs/core/ufshcd.c | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 6c94300783e1d..20cd42d00e362 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -3749,7 +3749,7 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, u8 **buf, enum u
{
struct uc_string_id *uc_str;
u8 *str;
- int ret;
+ int ret, uc_len;
if (!buf)
return -EINVAL;
@@ -3774,11 +3774,19 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, u8 **buf, enum u
goto out;
}
+ uc_len = uc_str->len - QUERY_DESC_HDR_SIZE;
+ if (uc_len % sizeof(*uc_str->uc)) {
+ dev_err(hba->dev, "String Desc has an odd UTF-16 payload length\n");
+ str = NULL;
+ ret = -EINVAL;
+ goto out;
+ }
+
if (fmt == SD_ASCII_STD) {
ssize_t ascii_len;
int i;
- /* remove header and divide by 2 to move from UTF16 to UTF8 */
- ascii_len = (uc_str->len - QUERY_DESC_HDR_SIZE) / 2 + 1;
+ /* Allow up to three UTF-8 bytes per UTF-16 code unit plus a NUL. */
+ ascii_len = uc_len / sizeof(*uc_str->uc) * 3 + 1;
str = kzalloc(ascii_len, GFP_KERNEL);
if (!str) {
ret = -ENOMEM;
@@ -3790,7 +3798,7 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, u8 **buf, enum u
* we need to convert to utf-8 so it can be displayed
*/
ret = utf16s_to_utf8s(uc_str->uc,
- uc_str->len - QUERY_DESC_HDR_SIZE,
+ uc_len / sizeof(*uc_str->uc),
UTF16_BIG_ENDIAN, str, ascii_len - 1);
/* replace non-printable or non-ASCII characters with spaces */
@@ -3800,11 +3808,17 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, u8 **buf, enum u
str[ret++] = '\0';
} else {
- str = kmemdup(uc_str->uc, uc_str->len, GFP_KERNEL);
+ /*
+ * Keep the bLength-sized raw output for the RPMB device ID ABI.
+ * The two bytes beyond the UTF-16 payload are explicitly zeroed
+ * instead of being read past the descriptor buffer.
+ */
+ str = kzalloc(uc_str->len, GFP_KERNEL);
if (!str) {
ret = -ENOMEM;
goto out;
}
+ memcpy(str, uc_str->uc, uc_len);
ret = uc_str->len;
}
out:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 693/869] pinctrl: mediatek: use devm_gpiochip_add_data() for GPIO chip
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (691 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 692/869] scsi: ufs: core: Validate string descriptors Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 694/869] bpf: Fix WARNING in bpf_tracing_link_release Greg Kroah-Hartman
` (176 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Justin Yeh, Chen-Yu Tsai,
Linus Walleij, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Justin Yeh <justin.yeh@mediatek.com>
[ Upstream commit 9c650317ba553d297f3fc5f0ae40ec53d86f9dab ]
The gpio_chip is allocated with device-managed memory but registered with
the non-managed gpiochip_add_data(). This was harmless while the drivers
were built-in, but once they can be built as modules and unbound/rmmod'd,
devm frees the gpio_chip's memory while it is still registered, causing a
use-after-free.
Register it with devm_gpiochip_add_data() so it shares the same
device-managed lifecycle, which also lets the manual gpiochip_remove()
error paths go away.
Fixes: a6df410d420a ("pinctrl: mediatek: Add Pinctrl/GPIO driver for mt8135.")
Fixes: 805250982bb5 ("pinctrl: mediatek: add pinctrl-paris that implements the vendor dt-bindings")
Fixes: e78d57b2f87c ("pinctrl: mediatek: add pinctrl-moore that implements the generic pinctrl dt-bindings")
Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pinctrl/mediatek/pinctrl-moore.c | 6 ++----
drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 14 ++++----------
drivers/pinctrl/mediatek/pinctrl-paris.c | 2 +-
3 files changed, 7 insertions(+), 15 deletions(-)
diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.c b/drivers/pinctrl/mediatek/pinctrl-moore.c
index aad4891223d3e..f24df94c49185 100644
--- a/drivers/pinctrl/mediatek/pinctrl-moore.c
+++ b/drivers/pinctrl/mediatek/pinctrl-moore.c
@@ -573,7 +573,7 @@ static int mtk_build_gpiochip(struct mtk_pinctrl *hw)
chip->base = -1;
chip->ngpio = hw->soc->npins;
- ret = gpiochip_add_data(chip, hw);
+ ret = devm_gpiochip_add_data(hw->dev, chip, hw);
if (ret < 0)
return ret;
@@ -587,10 +587,8 @@ static int mtk_build_gpiochip(struct mtk_pinctrl *hw)
if (!of_property_present(hw->dev->of_node, "gpio-ranges")) {
ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0,
chip->ngpio);
- if (ret < 0) {
- gpiochip_remove(chip);
+ if (ret < 0)
return ret;
- }
}
return 0;
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index efc9b07e62658..cee2dffd57e7a 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -1118,30 +1118,24 @@ int mtk_pctrl_init(struct platform_device *pdev,
pctl->chip->parent = &pdev->dev;
pctl->chip->base = -1;
- ret = gpiochip_add_data(pctl->chip, pctl);
+ ret = devm_gpiochip_add_data(&pdev->dev, pctl->chip, pctl);
if (ret)
return -EINVAL;
/* Register the GPIO to pin mappings. */
ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev),
0, 0, pctl->devdata->npins);
- if (ret) {
- ret = -EINVAL;
- goto chip_error;
- }
+ if (ret)
+ return -EINVAL;
/* Only initialize EINT if we have EINT pins */
if (data->eint_hw.ap_num > 0) {
ret = mtk_eint_init(pctl, pdev);
if (ret)
- goto chip_error;
+ return ret;
}
return 0;
-
-chip_error:
- gpiochip_remove(pctl->chip);
- return ret;
}
int mtk_pctrl_common_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c
index 87e958d827bf9..363a02106d401 100644
--- a/drivers/pinctrl/mediatek/pinctrl-paris.c
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c
@@ -970,7 +970,7 @@ static int mtk_build_gpiochip(struct mtk_pinctrl *hw)
chip->base = -1;
chip->ngpio = hw->soc->npins;
- ret = gpiochip_add_data(chip, hw);
+ ret = devm_gpiochip_add_data(hw->dev, chip, hw);
if (ret < 0)
return ret;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 694/869] bpf: Fix WARNING in bpf_tracing_link_release
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (692 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 693/869] pinctrl: mediatek: use devm_gpiochip_add_data() for GPIO chip Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 695/869] ext4: fix ABBA deadlock in ext4_xattr_inode_cache_find() Greg Kroah-Hartman
` (175 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Leon Hwang, Pu Lehui, Jiri Olsa,
Kumar Kartikeya Dwivedi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Hwang <leon.hwang@linux.dev>
[ Upstream commit 61aaa8782bec59ecffd22e030f54ef9351bcabf9 ]
The trampoline could be corrupted by the blindly
'tr->flags = BPF_TRAMP_F_TAIL_CALL_CTX' in verifier.
1. A fexit attached to a tail_call_reachable prog. 'tr->flags' became
'BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_TAIL_CALL_CTX'. And, the
trampoline would poke the target prog's nop insn using jmp insn instead
of call insn.
2. Another fexit loaded with the same tail_call_reachable prog target.
'tr->flags' became 'BPF_TRAMP_F_TAIL_CALL_CTX'.
3. Close the first fexit link. Due to no BPF_TRAMP_F_CALL_ORIG in
'tr->flags', the trampoline will fail to restore the prog's nop insn
using call insn.
[ 3.410719] WARNING: kernel/bpf/syscall.c:3551 at bpf_tracing_link_release+0x53/0x60, CPU#1: test_progs/98
...
[ 3.428793] bpf_link_free+0x58/0x130
[ 3.429293] bpf_link_release+0x23/0x30
Fix the warning by updating 'tr->flags' with '|=' and lock.
Fixes: 2b5dcb31a19a ("bpf, x64: Fix tailcall infinite loop")
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
Reviewed-by: Pu Lehui <pulehui@huawei.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Link: https://lore.kernel.org/bpf/20260722151909.69142-2-leon.hwang@linux.dev
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/bpf.h | 3 +++
kernel/bpf/trampoline.c | 7 +++++++
kernel/bpf/verifier.c | 2 +-
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 8bdb4ba4df7ee..427e540a756ee 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1323,6 +1323,8 @@ struct bpf_trampoline *bpf_trampoline_get(u64 key,
void bpf_trampoline_put(struct bpf_trampoline *tr);
int arch_prepare_bpf_dispatcher(void *image, void *buf, s64 *funcs, int num_funcs);
+void bpf_trampoline_set_flags(struct bpf_trampoline *tr, u32 flags);
+
/*
* When the architecture supports STATIC_CALL replace the bpf_dispatcher_fn
* indirection with a direct call to the bpf program. If the architecture does
@@ -1431,6 +1433,7 @@ static inline bool bpf_prog_has_trampoline(const struct bpf_prog *prog)
{
return false;
}
+static inline void bpf_trampoline_set_flags(struct bpf_trampoline *tr, u32 flags) {}
#endif
struct bpf_func_info_aux {
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 894cd6f205f5f..76fdd4ee9225a 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -397,6 +397,13 @@ static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key, int size)
return ERR_PTR(err);
}
+void bpf_trampoline_set_flags(struct bpf_trampoline *tr, u32 flags)
+{
+ mutex_lock(&tr->mutex);
+ tr->flags |= flags;
+ mutex_unlock(&tr->mutex);
+}
+
static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex)
{
struct bpf_tramp_image *im;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a5abb59a925bc..03b6093327187 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -22908,7 +22908,7 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
return -ENOMEM;
if (tgt_prog && tgt_prog->aux->tail_call_reachable)
- tr->flags = BPF_TRAMP_F_TAIL_CALL_CTX;
+ bpf_trampoline_set_flags(tr, BPF_TRAMP_F_TAIL_CALL_CTX);
prog->aux->dst_trampoline = tr;
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 695/869] ext4: fix ABBA deadlock in ext4_xattr_inode_cache_find()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (693 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 694/869] bpf: Fix WARNING in bpf_tracing_link_release Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 696/869] kcfi: Rename CONFIG_CFI_CLANG to CONFIG_CFI Greg Kroah-Hartman
` (174 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jan Kara, Colin Ian King,
Aditya Prakash Srivastava, Theodore Tso, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aditya Prakash Srivastava <aditya.ansh182@gmail.com>
[ Upstream commit 03438084a7b8621fb5c762dd3d04cff5f2630fb2 ]
Syzbot/stress-ng reported an ABBA deadlock in ext4 when exercising
concurrent xattr workloads (using the ea_inode mount/format option).
The deadlock occurs between the running transaction and the eviction
thread:
- Task 1 (stress-ng): Holds a reference to a shared mbcache_entry (ce)
and calls ext4_xattr_inode_cache_find() -> ext4_iget() to retrieve
the corresponding EA inode. Since the EA inode is currently being
evicted, ext4_iget() blocks in __wait_on_freeing_inode() waiting for
eviction to complete.
- Task 2 (eviction thread): Currently evicting the same EA inode in
ext4_evict_ea_inode(). It calls mb_cache_entry_wait_unused(oe) which
blocks waiting for Task 1 to release the reference to the mbcache_entry.
To break this deadlock, implement a new ext4_iget() configuration flag
named EXT4_IGET_NOWAIT. When set, perform a non-blocking lookup of the
inode via VFS's find_inode_nowait() API.
If the inode is currently being evicted (marked with I_FREEING or
I_WILL_FREE) or created (I_CREATING), or if it is not present in the VFS
inode cache (cache miss), simply skip it (returning -ENOENT) rather than
waiting for eviction/creation to complete, breaking the ABBA cycle.
Since we return -ENOENT immediately on a cache miss, we never attempt to
allocate a new inode or call iget_locked(), completely eliminating any
TOCTOU race window.
If the returned inode is I_NEW, wait for its initialization to clear via
wait_on_new_inode(). If initialization fails and the inode is unhashed
during wait_on_new_inode() waking up (e.g., due to an I/O read error in
another thread), safely drop the reference and return -ENOENT. This
unhashed check is executed unconditionally on all cache-hit pathways to
properly handle concurrent initialization failures.
Finally, standard validation checks (including is_bad_inode,
EXT4_EA_INODE_FL, file_acl, and xattr flags) are executed as normal inside
check_igot_inode() to fully guarantee VFS-layer safety.
In ext4_xattr_inode_cache_find(), invoke ext4_iget() with the new
EXT4_IGET_NOWAIT flag to perform the non-blocking cache search.
Suggested-by: Jan Kara <jack@suse.cz>
Reported-by: Colin Ian King <colin.i.king@gmail.com>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219283
Fixes: 0a46ef234756 ("ext4: do not create EA inode under buffer lock")
Signed-off-by: Aditya Prakash Srivastava <aditya.ansh182@gmail.com>
Tested-by: Colin Ian King <colin.i.king@gmail.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260626054821.1729-1-aditya.ansh182@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ext4/ext4.h | 3 ++-
fs/ext4/inode.c | 35 ++++++++++++++++++++++++++++++++---
fs/ext4/xattr.c | 2 +-
3 files changed, 35 insertions(+), 5 deletions(-)
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2984,7 +2984,8 @@ typedef enum {
EXT4_IGET_SPECIAL = 0x0001, /* OK to iget a system inode */
EXT4_IGET_HANDLE = 0x0002, /* Inode # is from a handle */
EXT4_IGET_BAD = 0x0004, /* Allow to iget a bad inode */
- EXT4_IGET_EA_INODE = 0x0008 /* Inode should contain an EA value */
+ EXT4_IGET_EA_INODE = 0x0008, /* Inode should contain an EA value */
+ EXT4_IGET_NOWAIT = 0x0010 /* Non-blocking lookup (skip if freeing) */
} ext4_iget_flags;
extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4783,6 +4783,20 @@ error:
return -EFSCORRUPTED;
}
+static int ext4_iget_match(struct inode *inode, unsigned long ino, void *data)
+{
+ if (inode->i_ino != ino)
+ return 0;
+ spin_lock(&inode->i_lock);
+ if (inode->i_state & (I_FREEING | I_WILL_FREE | I_CREATING)) {
+ spin_unlock(&inode->i_lock);
+ return -1;
+ }
+ __iget(inode);
+ spin_unlock(&inode->i_lock);
+ return 1;
+}
+
struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
ext4_iget_flags flags, const char *function,
unsigned int line)
@@ -4816,9 +4830,24 @@ struct inode *__ext4_iget(struct super_b
return ERR_PTR(-EFSCORRUPTED);
}
- inode = iget_locked(sb, ino);
- if (!inode)
- return ERR_PTR(-ENOMEM);
+ if (flags & EXT4_IGET_NOWAIT) {
+ inode = find_inode_nowait(sb, ino, ext4_iget_match, NULL);
+ if (!inode)
+ return ERR_PTR(-ENOENT);
+
+ if (inode->i_state & I_NEW)
+ wait_on_inode(inode);
+
+ if (unlikely(inode_unhashed(inode))) {
+ iput(inode);
+ return ERR_PTR(-ENOENT);
+ }
+ } else {
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ }
+
if (!(inode->i_state & I_NEW)) {
ret = check_igot_inode(inode, flags, function, line);
if (ret) {
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -1550,7 +1550,7 @@ ext4_xattr_inode_cache_find(struct inode
while (ce) {
ea_inode = ext4_iget(inode->i_sb, ce->e_value,
- EXT4_IGET_EA_INODE);
+ EXT4_IGET_EA_INODE | EXT4_IGET_NOWAIT);
if (IS_ERR(ea_inode))
goto next_entry;
ext4_xattr_inode_set_class(ea_inode);
^ permalink raw reply [flat|nested] 872+ messages in thread
* [PATCH 6.12 696/869] kcfi: Rename CONFIG_CFI_CLANG to CONFIG_CFI
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (694 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 695/869] ext4: fix ABBA deadlock in ext4_xattr_inode_cache_find() Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 697/869] riscv, bpf: Fix kernel stack corruption in tailcall with CFI Greg Kroah-Hartman
` (173 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Linus Walleij, Nathan Chancellor,
Kees Cook, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kees Cook <kees@kernel.org>
[ Upstream commit 23ef9d439769d5f35353650e771c63d13824235b ]
The kernel's CFI implementation uses the KCFI ABI specifically, and is
not strictly tied to a particular compiler. In preparation for GCC
supporting KCFI, rename CONFIG_CFI_CLANG to CONFIG_CFI (along with
associated options).
Use new "transitional" Kconfig option for old CONFIG_CFI_CLANG that will
enable CONFIG_CFI during olddefconfig.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Nathan Chancellor <nathan@kernel.org>
Link: https://lore.kernel.org/r/20250923213422.1105654-3-kees@kernel.org
Signed-off-by: Kees Cook <kees@kernel.org>
[ Adapted to this tree: the kconfig here has no "transitional" keyword, so
the CFI_CLANG compat symbol is omitted; re-applied the rename on top of the local
contents of the conflicting files, converted the remaining
CONFIG_CFI_CLANG users (riscv cfi.c, longest_symbol kunit comment),
and dropped the tools/ cfi_types.h hunk as that file is absent here. ]
Stable-dep-of: 52fb1756ea1d ("riscv, bpf: Fix kernel stack corruption in tailcall with CFI")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
Makefile | 2 +-
arch/Kconfig | 26 ++++++++++++-------------
arch/arm/Kconfig | 2 +-
arch/arm/kernel/hw_breakpoint.c | 2 +-
arch/arm/mm/Makefile | 2 +-
arch/arm/mm/cache-fa.S | 2 +-
arch/arm/mm/cache-v4.S | 2 +-
arch/arm/mm/cache-v4wb.S | 4 ++--
arch/arm/mm/cache-v4wt.S | 2 +-
arch/arm/mm/cache-v6.S | 2 +-
arch/arm/mm/cache-v7.S | 2 +-
arch/arm/mm/cache-v7m.S | 2 +-
arch/arm/mm/proc-arm1020.S | 2 +-
arch/arm/mm/proc-arm1020e.S | 2 +-
arch/arm/mm/proc-arm1022.S | 2 +-
arch/arm/mm/proc-arm1026.S | 2 +-
arch/arm/mm/proc-arm920.S | 2 +-
arch/arm/mm/proc-arm922.S | 2 +-
arch/arm/mm/proc-arm925.S | 2 +-
arch/arm/mm/proc-arm926.S | 2 +-
arch/arm/mm/proc-arm940.S | 2 +-
arch/arm/mm/proc-arm946.S | 2 +-
arch/arm/mm/proc-feroceon.S | 2 +-
arch/arm/mm/proc-mohawk.S | 2 +-
arch/arm/mm/proc-xsc3.S | 2 +-
arch/arm/mm/tlb-v4.S | 2 +-
arch/arm64/Kconfig | 4 ++--
arch/arm64/kernel/debug-monitors.c | 2 +-
arch/arm64/kernel/traps.c | 4 ++--
arch/arm64/kvm/handle_exit.c | 2 +-
arch/riscv/Kconfig | 4 ++--
arch/riscv/include/asm/cfi.h | 4 ++--
arch/riscv/kernel/Makefile | 2 +-
arch/riscv/kernel/cfi.c | 2 +-
arch/riscv/net/bpf_jit_comp64.c | 4 ++--
arch/riscv/purgatory/Makefile | 2 +-
arch/x86/Kconfig | 12 ++++++------
arch/x86/include/asm/cfi.h | 4 ++--
arch/x86/kernel/Makefile | 2 +-
arch/x86/kernel/alternative.c | 4 ++--
arch/x86/kernel/kprobes/core.c | 2 +-
arch/x86/purgatory/Makefile | 2 +-
drivers/misc/lkdtm/cfi.c | 2 +-
include/asm-generic/vmlinux.lds.h | 2 +-
include/linux/cfi.h | 4 ++--
include/linux/cfi_types.h | 6 +++---
init/Kconfig | 4 ++--
kernel/Makefile | 2 +-
kernel/configs/hardening.config | 4 ++--
kernel/module/Kconfig | 2 +-
lib/longest_symbol_kunit.c | 2 +-
tools/perf/util/include/linux/linkage.h | 2 +-
52 files changed, 82 insertions(+), 82 deletions(-)
diff --git a/Makefile b/Makefile
index 9b4b99f66a012..65a714b9fcc54 100644
--- a/Makefile
+++ b/Makefile
@@ -963,7 +963,7 @@ KBUILD_AFLAGS += -fno-lto
export CC_FLAGS_LTO
endif
-ifdef CONFIG_CFI_CLANG
+ifdef CONFIG_CFI
CC_FLAGS_CFI := -fsanitize=kcfi
ifdef CONFIG_CFI_ICALL_NORMALIZE_INTEGERS
CC_FLAGS_CFI += -fsanitize-cfi-icall-experimental-normalize-integers
diff --git a/arch/Kconfig b/arch/Kconfig
index cdb220f6c2cba..ad0e5338b5770 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -812,22 +812,22 @@ config LTO_CLANG_THIN
If unsure, say Y.
endchoice
-config ARCH_SUPPORTS_CFI_CLANG
+config ARCH_SUPPORTS_CFI
bool
help
- An architecture should select this option if it can support Clang's
- Control-Flow Integrity (CFI) checking.
+ An architecture should select this option if it can support Kernel
+ Control-Flow Integrity (CFI) checking (-fsanitize=kcfi).
config ARCH_USES_CFI_TRAPS
bool
-config CFI_CLANG
- bool "Use Clang's Control Flow Integrity (CFI)"
- depends on ARCH_SUPPORTS_CFI_CLANG
+config CFI
+ bool "Use Kernel Control Flow Integrity (kCFI)"
+ depends on ARCH_SUPPORTS_CFI
depends on $(cc-option,-fsanitize=kcfi)
help
- This option enables Clang's forward-edge Control Flow Integrity
- (CFI) checking, where the compiler injects a runtime check to each
+ This option enables forward-edge Control Flow Integrity (CFI)
+ checking, where the compiler injects a runtime check to each
indirect function call to ensure the target is a valid function with
the correct static type. This restricts possible call targets and
makes it more difficult for an attacker to exploit bugs that allow
@@ -838,8 +838,8 @@ config CFI_CLANG
config CFI_ICALL_NORMALIZE_INTEGERS
bool "Normalize CFI tags for integers"
- depends on CFI_CLANG
- depends on HAVE_CFI_ICALL_NORMALIZE_INTEGERS_CLANG
+ depends on CFI
+ depends on HAVE_CFI_ICALL_NORMALIZE_INTEGERS
help
This option normalizes the CFI tags for integer types so that all
integer types of the same size and signedness receive the same CFI
@@ -852,7 +852,7 @@ config CFI_ICALL_NORMALIZE_INTEGERS
This option is necessary for using CFI with Rust. If unsure, say N.
-config HAVE_CFI_ICALL_NORMALIZE_INTEGERS_CLANG
+config HAVE_CFI_ICALL_NORMALIZE_INTEGERS
def_bool y
depends on $(cc-option,-fsanitize=kcfi -fsanitize-cfi-icall-experimental-normalize-integers)
# With GCOV/KASAN we need this fix: https://github.com/llvm/llvm-project/pull/104826
@@ -860,7 +860,7 @@ config HAVE_CFI_ICALL_NORMALIZE_INTEGERS_CLANG
config HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
def_bool y
- depends on HAVE_CFI_ICALL_NORMALIZE_INTEGERS_CLANG
+ depends on HAVE_CFI_ICALL_NORMALIZE_INTEGERS
depends on RUSTC_VERSION >= 107900
depends on ARM64 || X86_64
# With GCOV/KASAN we need this fix: https://github.com/rust-lang/rust/pull/129373
@@ -869,7 +869,7 @@ config HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
config CFI_PERMISSIVE
bool "Use CFI in permissive mode"
- depends on CFI_CLANG
+ depends on CFI
help
When selected, Control Flow Integrity (CFI) violations result in a
warning instead of a kernel panic. This option should only be used
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 51c6b2db9eadf..086a54f996549 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -37,7 +37,7 @@ config ARM
select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT if CPU_V7
select ARCH_NEED_CMPXCHG_1_EMU if CPU_V6
select ARCH_SUPPORTS_ATOMIC_RMW
- select ARCH_SUPPORTS_CFI_CLANG
+ select ARCH_SUPPORTS_CFI
select ARCH_SUPPORTS_HUGETLBFS if ARM_LPAE
select ARCH_SUPPORTS_PER_VMA_LOCK
select ARCH_USE_BUILTIN_BSWAP
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index 6819d4c1f3521..38feb30dfb5f8 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -904,7 +904,7 @@ static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs)
watchpoint_single_step_handler(addr);
}
-#ifdef CONFIG_CFI_CLANG
+#ifdef CONFIG_CFI
static void hw_breakpoint_cfi_handler(struct pt_regs *regs)
{
/*
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index a195cd1d3e6dc..1e22010133714 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -89,7 +89,7 @@ obj-$(CONFIG_CPU_V6) += proc-v6.o
obj-$(CONFIG_CPU_V6K) += proc-v6.o
obj-$(CONFIG_CPU_V7) += proc-v7.o proc-v7-bugs.o
obj-$(CONFIG_CPU_V7M) += proc-v7m.o
-obj-$(CONFIG_CFI_CLANG) += proc.o
+obj-$(CONFIG_CFI) += proc.o
obj-$(CONFIG_OUTER_CACHE) += l2c-common.o
obj-$(CONFIG_CACHE_B15_RAC) += cache-b15-rac.o
diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S
index 4a3668b52a2db..e1641799569bc 100644
--- a/arch/arm/mm/cache-fa.S
+++ b/arch/arm/mm/cache-fa.S
@@ -112,7 +112,7 @@ SYM_FUNC_END(fa_flush_user_cache_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(fa_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b fa_coherent_user_range
#endif
SYM_FUNC_END(fa_coherent_kern_range)
diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S
index 0e94e5193dbd4..001d7042bd469 100644
--- a/arch/arm/mm/cache-v4.S
+++ b/arch/arm/mm/cache-v4.S
@@ -104,7 +104,7 @@ SYM_FUNC_END(v4_coherent_user_range)
* - size - region size
*/
SYM_TYPED_FUNC_START(v4_flush_kern_dcache_area)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b v4_dma_flush_range
#endif
SYM_FUNC_END(v4_flush_kern_dcache_area)
diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S
index ce55a2eef5da4..874fe5310f9a0 100644
--- a/arch/arm/mm/cache-v4wb.S
+++ b/arch/arm/mm/cache-v4wb.S
@@ -136,7 +136,7 @@ SYM_FUNC_END(v4wb_flush_user_cache_range)
*/
SYM_TYPED_FUNC_START(v4wb_flush_kern_dcache_area)
add r1, r0, r1
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b v4wb_coherent_user_range
#endif
SYM_FUNC_END(v4wb_flush_kern_dcache_area)
@@ -152,7 +152,7 @@ SYM_FUNC_END(v4wb_flush_kern_dcache_area)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(v4wb_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b v4wb_coherent_user_range
#endif
SYM_FUNC_END(v4wb_coherent_kern_range)
diff --git a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S
index a97dc267b3b0d..2ee62e4b2b075 100644
--- a/arch/arm/mm/cache-v4wt.S
+++ b/arch/arm/mm/cache-v4wt.S
@@ -108,7 +108,7 @@ SYM_FUNC_END(v4wt_flush_user_cache_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(v4wt_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b v4wt_coherent_user_range
#endif
SYM_FUNC_END(v4wt_coherent_kern_range)
diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S
index 9f415476e2183..5ceea8965ea19 100644
--- a/arch/arm/mm/cache-v6.S
+++ b/arch/arm/mm/cache-v6.S
@@ -117,7 +117,7 @@ SYM_FUNC_END(v6_flush_user_cache_range)
* - the Icache does not read data from the write buffer
*/
SYM_TYPED_FUNC_START(v6_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b v6_coherent_user_range
#endif
SYM_FUNC_END(v6_coherent_kern_range)
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index 201ca05436fad..726681fb7d4de 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -261,7 +261,7 @@ SYM_FUNC_END(v7_flush_user_cache_range)
* - the Icache does not read data from the write buffer
*/
SYM_TYPED_FUNC_START(v7_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b v7_coherent_user_range
#endif
SYM_FUNC_END(v7_coherent_kern_range)
diff --git a/arch/arm/mm/cache-v7m.S b/arch/arm/mm/cache-v7m.S
index 14d719eba729d..7f9cfad2ea210 100644
--- a/arch/arm/mm/cache-v7m.S
+++ b/arch/arm/mm/cache-v7m.S
@@ -286,7 +286,7 @@ SYM_FUNC_END(v7m_flush_user_cache_range)
* - the Icache does not read data from the write buffer
*/
SYM_TYPED_FUNC_START(v7m_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b v7m_coherent_user_range
#endif
SYM_FUNC_END(v7m_coherent_kern_range)
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
index d0ce3414a13e2..4612a4961e817 100644
--- a/arch/arm/mm/proc-arm1020.S
+++ b/arch/arm/mm/proc-arm1020.S
@@ -203,7 +203,7 @@ SYM_FUNC_END(arm1020_flush_user_cache_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(arm1020_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b arm1020_coherent_user_range
#endif
SYM_FUNC_END(arm1020_coherent_kern_range)
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S
index 64f031bf6eff5..b4a8a3a8eda3d 100644
--- a/arch/arm/mm/proc-arm1020e.S
+++ b/arch/arm/mm/proc-arm1020e.S
@@ -200,7 +200,7 @@ SYM_FUNC_END(arm1020e_flush_user_cache_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(arm1020e_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b arm1020e_coherent_user_range
#endif
SYM_FUNC_END(arm1020e_coherent_kern_range)
diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S
index 42ed5ed072528..709870e99e191 100644
--- a/arch/arm/mm/proc-arm1022.S
+++ b/arch/arm/mm/proc-arm1022.S
@@ -199,7 +199,7 @@ SYM_FUNC_END(arm1022_flush_user_cache_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(arm1022_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b arm1022_coherent_user_range
#endif
SYM_FUNC_END(arm1022_coherent_kern_range)
diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S
index b3ae62cd553aa..02f7370a8c5cb 100644
--- a/arch/arm/mm/proc-arm1026.S
+++ b/arch/arm/mm/proc-arm1026.S
@@ -194,7 +194,7 @@ SYM_FUNC_END(arm1026_flush_user_cache_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(arm1026_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b arm1026_coherent_user_range
#endif
SYM_FUNC_END(arm1026_coherent_kern_range)
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index a30df54ad5fae..4727f4b5b6e8d 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -180,7 +180,7 @@ SYM_FUNC_END(arm920_flush_user_cache_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(arm920_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b arm920_coherent_user_range
#endif
SYM_FUNC_END(arm920_coherent_kern_range)
diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S
index aac4e048100d0..5a4a3f4f2683b 100644
--- a/arch/arm/mm/proc-arm922.S
+++ b/arch/arm/mm/proc-arm922.S
@@ -182,7 +182,7 @@ SYM_FUNC_END(arm922_flush_user_cache_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(arm922_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b arm922_coherent_user_range
#endif
SYM_FUNC_END(arm922_coherent_kern_range)
diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S
index 035941faeb2ed..1c4830afe1d39 100644
--- a/arch/arm/mm/proc-arm925.S
+++ b/arch/arm/mm/proc-arm925.S
@@ -229,7 +229,7 @@ SYM_FUNC_END(arm925_flush_user_cache_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(arm925_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b arm925_coherent_user_range
#endif
SYM_FUNC_END(arm925_coherent_kern_range)
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 6f43d6af2d9a7..a09cc3e02efda 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -192,7 +192,7 @@ SYM_FUNC_END(arm926_flush_user_cache_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(arm926_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b arm926_coherent_user_range
#endif
SYM_FUNC_END(arm926_coherent_kern_range)
diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S
index 0d30bb25c42bf..545c076c36d24 100644
--- a/arch/arm/mm/proc-arm940.S
+++ b/arch/arm/mm/proc-arm940.S
@@ -153,7 +153,7 @@ SYM_FUNC_END(arm940_coherent_kern_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(arm940_coherent_user_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b arm940_flush_kern_dcache_area
#endif
SYM_FUNC_END(arm940_coherent_user_range)
diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S
index 27750ace2ceda..f3d4e18c3fba5 100644
--- a/arch/arm/mm/proc-arm946.S
+++ b/arch/arm/mm/proc-arm946.S
@@ -173,7 +173,7 @@ SYM_FUNC_END(arm946_flush_user_cache_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(arm946_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b arm946_coherent_user_range
#endif
SYM_FUNC_END(arm946_coherent_kern_range)
diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S
index f67b2ffac8541..7f08d06c96253 100644
--- a/arch/arm/mm/proc-feroceon.S
+++ b/arch/arm/mm/proc-feroceon.S
@@ -208,7 +208,7 @@ SYM_FUNC_END(feroceon_flush_user_cache_range)
*/
.align 5
SYM_TYPED_FUNC_START(feroceon_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b feroceon_coherent_user_range
#endif
SYM_FUNC_END(feroceon_coherent_kern_range)
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S
index 8e9f38da863a5..4669c63e3121d 100644
--- a/arch/arm/mm/proc-mohawk.S
+++ b/arch/arm/mm/proc-mohawk.S
@@ -163,7 +163,7 @@ SYM_FUNC_END(mohawk_flush_user_cache_range)
* - end - virtual end address
*/
SYM_TYPED_FUNC_START(mohawk_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b mohawk_coherent_user_range
#endif
SYM_FUNC_END(mohawk_coherent_kern_range)
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index 14927b3804524..fd25634a2ed5d 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -223,7 +223,7 @@ SYM_FUNC_END(xsc3_flush_user_cache_range)
* it also trashes the mini I-cache used by JTAG debuggers.
*/
SYM_TYPED_FUNC_START(xsc3_coherent_kern_range)
-#ifdef CONFIG_CFI_CLANG /* Fallthrough if !CFI */
+#ifdef CONFIG_CFI /* Fallthrough if !CFI */
b xsc3_coherent_user_range
#endif
SYM_FUNC_END(xsc3_coherent_kern_range)
diff --git a/arch/arm/mm/tlb-v4.S b/arch/arm/mm/tlb-v4.S
index 09ff69008d94d..079774a02be63 100644
--- a/arch/arm/mm/tlb-v4.S
+++ b/arch/arm/mm/tlb-v4.S
@@ -52,7 +52,7 @@ SYM_FUNC_END(v4_flush_user_tlb_range)
* - start - virtual address (may not be aligned)
* - end - virtual address (may not be aligned)
*/
-#ifdef CONFIG_CFI_CLANG
+#ifdef CONFIG_CFI
SYM_TYPED_FUNC_START(v4_flush_kern_tlb_range)
b .v4_flush_kern_tlb_range
SYM_FUNC_END(v4_flush_kern_tlb_range)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 7ae3cd7cce2ab..b061d08bc4f9e 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -97,7 +97,7 @@ config ARM64
select ARCH_SUPPORTS_SHADOW_CALL_STACK if CC_HAVE_SHADOW_CALL_STACK
select ARCH_SUPPORTS_LTO_CLANG if CPU_LITTLE_ENDIAN
select ARCH_SUPPORTS_LTO_CLANG_THIN
- select ARCH_SUPPORTS_CFI_CLANG
+ select ARCH_SUPPORTS_CFI
select ARCH_SUPPORTS_ATOMIC_RMW
select ARCH_SUPPORTS_INT128 if CC_HAS_INT128
select ARCH_SUPPORTS_NUMA_BALANCING
@@ -207,7 +207,7 @@ config ARM64
select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS \
if DYNAMIC_FTRACE_WITH_ARGS && DYNAMIC_FTRACE_WITH_CALL_OPS
select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS \
- if (DYNAMIC_FTRACE_WITH_ARGS && !CFI_CLANG && \
+ if (DYNAMIC_FTRACE_WITH_ARGS && !CFI && \
(CC_IS_CLANG || !CC_OPTIMIZE_FOR_SIZE))
select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY \
if DYNAMIC_FTRACE_WITH_ARGS
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index 16390fd4ba5ed..cde0877445fa6 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -212,7 +212,7 @@ static int call_el1_break_hook(struct pt_regs *regs, unsigned long esr)
if (esr_brk_comment(esr) == BUG_BRK_IMM)
return bug_brk_handler(regs, esr);
- if (IS_ENABLED(CONFIG_CFI_CLANG) && esr_is_cfi_brk(esr))
+ if (IS_ENABLED(CONFIG_CFI) && esr_is_cfi_brk(esr))
return cfi_brk_handler(regs, esr);
if (esr_brk_comment(esr) == FAULT_BRK_IMM)
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index e6e815ef03c77..490598da448ee 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -1008,7 +1008,7 @@ int bug_brk_handler(struct pt_regs *regs, unsigned long esr)
return DBG_HOOK_HANDLED;
}
-#ifdef CONFIG_CFI_CLANG
+#ifdef CONFIG_CFI
int cfi_brk_handler(struct pt_regs *regs, unsigned long esr)
{
unsigned long target;
@@ -1032,7 +1032,7 @@ int cfi_brk_handler(struct pt_regs *regs, unsigned long esr)
arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
return DBG_HOOK_HANDLED;
}
-#endif /* CONFIG_CFI_CLANG */
+#endif /* CONFIG_CFI */
int reserved_fault_brk_handler(struct pt_regs *regs, unsigned long esr)
{
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index d7c2990e7c9ed..87e0c3b8af92e 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -465,7 +465,7 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr,
kvm_err("nVHE hyp BUG at: %s:%u!\n", file, line);
else
print_nvhe_hyp_panic("BUG", panic_addr);
- } else if (IS_ENABLED(CONFIG_CFI_CLANG) && esr_is_cfi_brk(esr)) {
+ } else if (IS_ENABLED(CONFIG_CFI) && esr_is_cfi_brk(esr)) {
kvm_nvhe_report_cfi_failure(panic_addr);
} else {
print_nvhe_hyp_panic("panic", panic_addr);
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index dcb2fef2fb545..fa1ef7be80ba1 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -58,7 +58,7 @@ config RISCV
select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT
select ARCH_STACKWALK
select ARCH_SUPPORTS_ATOMIC_RMW
- select ARCH_SUPPORTS_CFI_CLANG
+ select ARCH_SUPPORTS_CFI
select ARCH_SUPPORTS_DEBUG_PAGEALLOC if MMU
select ARCH_SUPPORTS_HUGETLBFS if MMU
# LLD >= 14: https://github.com/llvm/llvm-project/issues/50505
@@ -72,7 +72,7 @@ config RISCV
select ARCH_USE_MEMTEST
select ARCH_USE_QUEUED_RWLOCKS
select ARCH_USE_SYM_ANNOTATIONS
- select ARCH_USES_CFI_TRAPS if CFI_CLANG
+ select ARCH_USES_CFI_TRAPS if CFI
select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH if MMU
select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU
select ARCH_WANT_FRAME_POINTERS
diff --git a/arch/riscv/include/asm/cfi.h b/arch/riscv/include/asm/cfi.h
index fb9696d7a3f25..504e84a378e82 100644
--- a/arch/riscv/include/asm/cfi.h
+++ b/arch/riscv/include/asm/cfi.h
@@ -11,7 +11,7 @@
struct pt_regs;
-#ifdef CONFIG_CFI_CLANG
+#ifdef CONFIG_CFI
enum bug_trap_type handle_cfi_failure(struct pt_regs *regs);
#define __bpfcall
static inline int cfi_get_offset(void)
@@ -35,6 +35,6 @@ static inline u32 cfi_get_func_hash(void *func)
{
return 0;
}
-#endif /* CONFIG_CFI_CLANG */
+#endif /* CONFIG_CFI */
#endif /* _ASM_RISCV_CFI_H */
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index 7328e62a7b8e8..1d0e4749534fd 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -113,7 +113,7 @@ obj-$(CONFIG_VMCORE_INFO) += vmcore_info.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
-obj-$(CONFIG_CFI_CLANG) += cfi.o
+obj-$(CONFIG_CFI) += cfi.o
obj-$(CONFIG_EFI) += efi.o
obj-$(CONFIG_COMPAT) += compat_syscall_table.o
diff --git a/arch/riscv/kernel/cfi.c b/arch/riscv/kernel/cfi.c
index 64bdd3e1ab8ca..d045e618a83eb 100644
--- a/arch/riscv/kernel/cfi.c
+++ b/arch/riscv/kernel/cfi.c
@@ -76,7 +76,7 @@ enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
return report_cfi_failure(regs, regs->epc, &target, type);
}
-#ifdef CONFIG_CFI_CLANG
+#ifdef CONFIG_CFI
struct bpf_insn;
/* Must match bpf_func_t / DEFINE_BPF_PROG_RUN() */
diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
index 55c2f85090d45..8d37b8ffa6843 100644
--- a/arch/riscv/net/bpf_jit_comp64.c
+++ b/arch/riscv/net/bpf_jit_comp64.c
@@ -18,7 +18,7 @@
#define RV_MAX_REG_ARGS 8
#define RV_FENTRY_NINSNS 2
#define RV_FENTRY_NBYTES (RV_FENTRY_NINSNS * 4)
-#define RV_KCFI_NINSNS (IS_ENABLED(CONFIG_CFI_CLANG) ? 1 : 0)
+#define RV_KCFI_NINSNS (IS_ENABLED(CONFIG_CFI) ? 1 : 0)
/* imm that allows emit_imm to emit max count insns */
#define RV_MAX_COUNT_IMM 0x7FFF7FF7FF7FF7FF
@@ -469,7 +469,7 @@ static int emit_call(u64 addr, bool fixed_addr, struct rv_jit_context *ctx)
static inline void emit_kcfi(u32 hash, struct rv_jit_context *ctx)
{
- if (IS_ENABLED(CONFIG_CFI_CLANG))
+ if (IS_ENABLED(CONFIG_CFI))
emit(hash, ctx);
}
diff --git a/arch/riscv/purgatory/Makefile b/arch/riscv/purgatory/Makefile
index fb9c917c9b457..d6a5d2635b2b5 100644
--- a/arch/riscv/purgatory/Makefile
+++ b/arch/riscv/purgatory/Makefile
@@ -71,7 +71,7 @@ ifdef CONFIG_STACKPROTECTOR_STRONG
PURGATORY_CFLAGS_REMOVE += -fstack-protector-strong
endif
-ifdef CONFIG_CFI_CLANG
+ifdef CONFIG_CFI
PURGATORY_CFLAGS_REMOVE += $(CC_FLAGS_CFI)
endif
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f717d9c93aa28..18ea98e0799ac 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -122,8 +122,8 @@ config X86
select ARCH_SUPPORTS_PAGE_TABLE_CHECK if X86_64
select ARCH_SUPPORTS_NUMA_BALANCING if X86_64
select ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP if NR_CPUS <= 4096
- select ARCH_SUPPORTS_CFI_CLANG if X86_64
- select ARCH_USES_CFI_TRAPS if X86_64 && CFI_CLANG
+ select ARCH_SUPPORTS_CFI if X86_64
+ select ARCH_USES_CFI_TRAPS if X86_64 && CFI
select ARCH_SUPPORTS_LTO_CLANG
select ARCH_SUPPORTS_LTO_CLANG_THIN
select ARCH_SUPPORTS_RT
@@ -2467,11 +2467,11 @@ config FUNCTION_PADDING_CFI
default 3 if FUNCTION_ALIGNMENT_8B
default 0
-# Basically: FUNCTION_ALIGNMENT - 5*CFI_CLANG
+# Basically: FUNCTION_ALIGNMENT - 5*CFI
# except Kconfig can't do arithmetic :/
config FUNCTION_PADDING_BYTES
int
- default FUNCTION_PADDING_CFI if CFI_CLANG
+ default FUNCTION_PADDING_CFI if CFI
default FUNCTION_ALIGNMENT
config CALL_PADDING
@@ -2481,7 +2481,7 @@ config CALL_PADDING
config FINEIBT
def_bool y
- depends on X86_KERNEL_IBT && CFI_CLANG && MITIGATION_RETPOLINE
+ depends on X86_KERNEL_IBT && CFI && MITIGATION_RETPOLINE
select CALL_PADDING
config HAVE_CALL_THUNKS
@@ -2494,7 +2494,7 @@ config CALL_THUNKS
config PREFIX_SYMBOLS
def_bool y
- depends on CALL_PADDING && !CFI_CLANG
+ depends on CALL_PADDING && !CFI
menuconfig CPU_MITIGATIONS
bool "Mitigations for CPU vulnerabilities"
diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
index 7dd5ab239c87b..7b275e7a42579 100644
--- a/arch/x86/include/asm/cfi.h
+++ b/arch/x86/include/asm/cfi.h
@@ -103,7 +103,7 @@ extern enum cfi_mode cfi_mode;
struct pt_regs;
-#ifdef CONFIG_CFI_CLANG
+#ifdef CONFIG_CFI
enum bug_trap_type handle_cfi_failure(struct pt_regs *regs);
#define __bpfcall
extern u32 cfi_bpf_hash;
@@ -148,7 +148,7 @@ static inline u32 cfi_get_func_hash(void *func)
{
return 0;
}
-#endif /* CONFIG_CFI_CLANG */
+#endif /* CONFIG_CFI */
#if HAS_KERNEL_IBT == 1
#define CFI_NOSEAL(x) asm(IBT_NOSEAL(__stringify(x)))
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 5f58b5a38cac1..b9c07c7f573d7 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -162,7 +162,7 @@ obj-$(CONFIG_UNWINDER_ORC) += unwind_orc.o
obj-$(CONFIG_UNWINDER_FRAME_POINTER) += unwind_frame.o
obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o
-obj-$(CONFIG_CFI_CLANG) += cfi.o
+obj-$(CONFIG_CFI) += cfi.o
obj-$(CONFIG_CALL_THUNKS) += callthunks.o
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index a0550398313d8..8fd36d5f3fb29 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1094,7 +1094,7 @@ void __init_or_module apply_seal_endbr(s32 *start, s32 *end) { }
#ifdef CONFIG_CFI_AUTO_DEFAULT
#define __CFI_DEFAULT CFI_AUTO
-#elif defined(CONFIG_CFI_CLANG)
+#elif defined(CONFIG_CFI)
#define __CFI_DEFAULT CFI_KCFI
#else
#define __CFI_DEFAULT CFI_OFF
@@ -1102,7 +1102,7 @@ void __init_or_module apply_seal_endbr(s32 *start, s32 *end) { }
enum cfi_mode cfi_mode __ro_after_init = __CFI_DEFAULT;
-#ifdef CONFIG_CFI_CLANG
+#ifdef CONFIG_CFI
struct bpf_insn;
/* Must match bpf_func_t / DEFINE_BPF_PROG_RUN() */
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index 72e6a45e7ec24..7df6eee9d9064 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -339,7 +339,7 @@ static bool can_probe(unsigned long paddr)
if (is_exception_insn(&insn))
return false;
- if (IS_ENABLED(CONFIG_CFI_CLANG)) {
+ if (IS_ENABLED(CONFIG_CFI)) {
/*
* The compiler generates the following instruction sequence
* for indirect call checks and cfi.c decodes this;
diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile
index ebdfd7b84feb3..b8ccf9cba861e 100644
--- a/arch/x86/purgatory/Makefile
+++ b/arch/x86/purgatory/Makefile
@@ -57,7 +57,7 @@ ifdef CONFIG_MITIGATION_RETPOLINE
PURGATORY_CFLAGS_REMOVE += $(RETPOLINE_CFLAGS)
endif
-ifdef CONFIG_CFI_CLANG
+ifdef CONFIG_CFI
PURGATORY_CFLAGS_REMOVE += $(CC_FLAGS_CFI)
endif
diff --git a/drivers/misc/lkdtm/cfi.c b/drivers/misc/lkdtm/cfi.c
index 6a33889d0902a..c3971f7caa65e 100644
--- a/drivers/misc/lkdtm/cfi.c
+++ b/drivers/misc/lkdtm/cfi.c
@@ -43,7 +43,7 @@ static void lkdtm_CFI_FORWARD_PROTO(void)
lkdtm_indirect_call((void *)lkdtm_increment_int);
pr_err("FAIL: survived mismatched prototype function call!\n");
- pr_expected_config(CONFIG_CFI_CLANG);
+ pr_expected_config(CONFIG_CFI);
}
/*
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 3c75199947f09..f80d808c800c6 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -150,7 +150,7 @@
#define PATCHABLE_DISCARDS *(__patchable_function_entries)
#endif
-#ifndef CONFIG_ARCH_SUPPORTS_CFI_CLANG
+#ifndef CONFIG_ARCH_SUPPORTS_CFI
/*
* Simply points to ftrace_stub, but with the proper protocol.
* Defined by the linker script in linux/vmlinux.lds.h
diff --git a/include/linux/cfi.h b/include/linux/cfi.h
index f0df518e11dd1..ed4d0cf3f4fa7 100644
--- a/include/linux/cfi.h
+++ b/include/linux/cfi.h
@@ -18,7 +18,7 @@ static inline int cfi_get_offset(void)
}
#endif
-#ifdef CONFIG_CFI_CLANG
+#ifdef CONFIG_CFI
enum bug_trap_type report_cfi_failure(struct pt_regs *regs, unsigned long addr,
unsigned long *target, u32 type);
@@ -27,7 +27,7 @@ static inline enum bug_trap_type report_cfi_failure_noaddr(struct pt_regs *regs,
{
return report_cfi_failure(regs, addr, NULL, 0);
}
-#endif /* CONFIG_CFI_CLANG */
+#endif /* CONFIG_CFI */
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
bool is_cfi_trap(unsigned long addr);
diff --git a/include/linux/cfi_types.h b/include/linux/cfi_types.h
index 6b87136757655..2e098274e45cd 100644
--- a/include/linux/cfi_types.h
+++ b/include/linux/cfi_types.h
@@ -8,7 +8,7 @@
#ifdef __ASSEMBLY__
#include <linux/linkage.h>
-#ifdef CONFIG_CFI_CLANG
+#ifdef CONFIG_CFI
/*
* Use the __kcfi_typeid_<function> type identifier symbol to
* annotate indirectly called assembly functions. The compiler emits
@@ -29,12 +29,12 @@
#define SYM_TYPED_START(name, linkage, align...) \
SYM_TYPED_ENTRY(name, linkage, align)
-#else /* CONFIG_CFI_CLANG */
+#else /* CONFIG_CFI */
#define SYM_TYPED_START(name, linkage, align...) \
SYM_START(name, linkage, align)
-#endif /* CONFIG_CFI_CLANG */
+#endif /* CONFIG_CFI */
#ifndef SYM_TYPED_FUNC_START
#define SYM_TYPED_FUNC_START(name) \
diff --git a/init/Kconfig b/init/Kconfig
index 7b3d72f3a14d1..258041edf6d94 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1979,8 +1979,8 @@ config RUST
depends on !GCC_PLUGIN_RANDSTRUCT
depends on !RANDSTRUCT
depends on !DEBUG_INFO_BTF || (PAHOLE_HAS_LANG_EXCLUDE && !LTO)
- depends on !CFI_CLANG || HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
- select CFI_ICALL_NORMALIZE_INTEGERS if CFI_CLANG
+ depends on !CFI || HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
+ select CFI_ICALL_NORMALIZE_INTEGERS if CFI
depends on !CALL_PADDING || RUSTC_VERSION >= 108100
depends on !KASAN || CC_IS_CLANG
depends on !KASAN_SW_TAGS
diff --git a/kernel/Makefile b/kernel/Makefile
index 87866b037fbed..70e47eca6bce3 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -115,7 +115,7 @@ obj-$(CONFIG_KCSAN) += kcsan/
obj-$(CONFIG_SHADOW_CALL_STACK) += scs.o
obj-$(CONFIG_HAVE_STATIC_CALL) += static_call.o
obj-$(CONFIG_HAVE_STATIC_CALL_INLINE) += static_call_inline.o
-obj-$(CONFIG_CFI_CLANG) += cfi.o
+obj-$(CONFIG_CFI) += cfi.o
obj-$(CONFIG_PERF_EVENTS) += events/
diff --git a/kernel/configs/hardening.config b/kernel/configs/hardening.config
index 3fabb8f55ef6e..2962820aaa157 100644
--- a/kernel/configs/hardening.config
+++ b/kernel/configs/hardening.config
@@ -87,8 +87,8 @@ CONFIG_SECCOMP_FILTER=y
# Provides some protections against SYN flooding.
CONFIG_SYN_COOKIES=y
-# Enable Kernel Control Flow Integrity (currently Clang only).
-CONFIG_CFI_CLANG=y
+# Enable Kernel Control Flow Integrity.
+CONFIG_CFI=y
# CONFIG_CFI_PERMISSIVE is not set
# Attack surface reduction: do not autoload TTY line disciplines.
diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig
index 0c746a150e34e..650a9ef1cfa2a 100644
--- a/kernel/module/Kconfig
+++ b/kernel/module/Kconfig
@@ -400,6 +400,6 @@ config UNUSED_KSYMS_WHITELIST
config MODULES_TREE_LOOKUP
def_bool y
- depends on PERF_EVENTS || TRACING || CFI_CLANG
+ depends on PERF_EVENTS || TRACING || CFI
endif # MODULES
diff --git a/lib/longest_symbol_kunit.c b/lib/longest_symbol_kunit.c
index e3c28ff1807f0..af0067d3ca26e 100644
--- a/lib/longest_symbol_kunit.c
+++ b/lib/longest_symbol_kunit.c
@@ -3,7 +3,7 @@
* Test the longest symbol length. Execute with:
* ./tools/testing/kunit/kunit.py run longest-symbol
* --arch=x86_64 --kconfig_add CONFIG_KPROBES=y --kconfig_add CONFIG_MODULES=y
- * --kconfig_add CONFIG_RETPOLINE=n --kconfig_add CONFIG_CFI_CLANG=n
+ * --kconfig_add CONFIG_RETPOLINE=n --kconfig_add CONFIG_CFI=n
* --kconfig_add CONFIG_MITIGATION_RETPOLINE=n
*/
diff --git a/tools/perf/util/include/linux/linkage.h b/tools/perf/util/include/linux/linkage.h
index 178b00205fe6a..410eeed23b500 100644
--- a/tools/perf/util/include/linux/linkage.h
+++ b/tools/perf/util/include/linux/linkage.h
@@ -120,7 +120,7 @@
#endif
// In the kernel sources (include/linux/cfi_types.h), this has a different
-// definition when CONFIG_CFI_CLANG is used, for tools/ just use the !clang
+// definition when CONFIG_CFI is used, for tools/ just use the !cfi
// definition:
#ifndef SYM_TYPED_START
#define SYM_TYPED_START(name, linkage, align...) \
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 697/869] riscv, bpf: Fix kernel stack corruption in tailcall with CFI
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (695 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 696/869] kcfi: Rename CONFIG_CFI_CLANG to CONFIG_CFI Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 698/869] bpf: Zero queue and stack outputs on lock failure Greg Kroah-Hartman
` (172 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Pu Lehui,
Björn Töpel, Kumar Kartikeya Dwivedi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <pulehui@huawei.com>
[ Upstream commit 52fb1756ea1d2759dfef2d86245be00b05dac3a2 ]
When CONFIG_CFI_CLANG is enabled, prog->bpf_func already skips the kcfi
instruction during setup. Including it again in the tailcall jump offset
causes it to jump over an extra 4 bytes, skipping the stack pointer
adjustment, which will result in kernel stack corruption.
Fixes: 30a59cc79754 ("riscv, bpf: Fix possible infinite tailcall when CONFIG_CFI_CLANG is enabled")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Pu Lehui <pulehui@huawei.com>
Reviewed-by: Björn Töpel <bjorn@kernel.org>
Acked-by: Björn Töpel <bjorn@kernel.org>
Link: https://lore.kernel.org/bpf/20260708064436.2971933-5-pulehui@huaweicloud.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/riscv/net/bpf_jit_comp64.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
index 8d37b8ffa6843..6086503d61edb 100644
--- a/arch/riscv/net/bpf_jit_comp64.c
+++ b/arch/riscv/net/bpf_jit_comp64.c
@@ -18,7 +18,6 @@
#define RV_MAX_REG_ARGS 8
#define RV_FENTRY_NINSNS 2
#define RV_FENTRY_NBYTES (RV_FENTRY_NINSNS * 4)
-#define RV_KCFI_NINSNS (IS_ENABLED(CONFIG_CFI) ? 1 : 0)
/* imm that allows emit_imm to emit max count insns */
#define RV_MAX_COUNT_IMM 0x7FFF7FF7FF7FF7FF
@@ -272,8 +271,8 @@ static void __build_epilogue(bool is_tail_call, struct rv_jit_context *ctx)
if (!is_tail_call)
emit_addiw(RV_REG_A0, RV_REG_A5, 0, ctx);
emit_jalr(RV_REG_ZERO, is_tail_call ? RV_REG_T3 : RV_REG_RA,
- /* kcfi, fentry and TCC init insns will be skipped on tailcall */
- is_tail_call ? (RV_KCFI_NINSNS + RV_FENTRY_NINSNS + 1) * 4 : 0,
+ /* fentry and TCC init insns will be skipped on tailcall */
+ is_tail_call ? (RV_FENTRY_NINSNS + 1) * 4 : 0,
ctx);
}
@@ -2083,6 +2082,8 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx, bool is_subprog)
/* emit kcfi type preamble immediately before the first insn */
emit_kcfi(is_subprog ? cfi_bpf_subprog_hash : cfi_bpf_hash, ctx);
+ /* bpf prog starts here as kcfi skipped during prog->bpf_func setup */
+
/* nops reserved for auipc+jalr pair */
for (i = 0; i < RV_FENTRY_NINSNS; i++)
emit(rv_nop(), ctx);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 698/869] bpf: Zero queue and stack outputs on lock failure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (696 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 697/869] riscv, bpf: Fix kernel stack corruption in tailcall with CFI Greg Kroah-Hartman
@ 2026-10-17 15:58 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 699/869] drm/sched: Use struct for drm_sched_init() params Greg Kroah-Hartman
` (171 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:58 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kumar Kartikeya Dwivedi,
Emil Tsalapatis, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
[ Upstream commit 7ac6e1ae41a09f1dd4baeeff1d028ae49ee01232 ]
Queue and stack pop/peek helpers accept an uninitialized output buffer
because the verifier expects the helper to initialize it. The empty-map
error path clears the buffer, but a failed lock acquisition returns
-EBUSY without writing it.
Clear the output before returning -EBUSY so BPF programs cannot observe
uninitialized stack contents after a failed helper call.
Fixes: a34a9f1a19af ("bpf: Avoid deadlock when using queue and stack maps from NMI")
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Link: https://lore.kernel.org/bpf/20260719125419.1782196-1-memxor@gmail.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/queue_stack_maps.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/queue_stack_maps.c b/kernel/bpf/queue_stack_maps.c
index d869f51ea93a0..36384342d7d89 100644
--- a/kernel/bpf/queue_stack_maps.c
+++ b/kernel/bpf/queue_stack_maps.c
@@ -99,8 +99,10 @@ static long __queue_map_get(struct bpf_map *map, void *value, bool delete)
void *ptr;
if (in_nmi()) {
- if (!raw_spin_trylock_irqsave(&qs->lock, flags))
+ if (!raw_spin_trylock_irqsave(&qs->lock, flags)) {
+ memset(value, 0, qs->map.value_size);
return -EBUSY;
+ }
} else {
raw_spin_lock_irqsave(&qs->lock, flags);
}
@@ -134,8 +136,10 @@ static long __stack_map_get(struct bpf_map *map, void *value, bool delete)
u32 index;
if (in_nmi()) {
- if (!raw_spin_trylock_irqsave(&qs->lock, flags))
+ if (!raw_spin_trylock_irqsave(&qs->lock, flags)) {
+ memset(value, 0, qs->map.value_size);
return -EBUSY;
+ }
} else {
raw_spin_lock_irqsave(&qs->lock, flags);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 699/869] drm/sched: Use struct for drm_sched_init() params
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (697 preceding siblings ...)
2026-10-17 15:58 ` [PATCH 6.12 698/869] bpf: Zero queue and stack outputs on lock failure Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 700/869] drm/msm: Only fini scheduler after successful init Greg Kroah-Hartman
` (170 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Liviu Dudau, Danilo Krummrich,
Philipp Stanner, Sasha Levin, Matthew Brost, Boris Brezillon,
Christian Gmeiner, Frank Binns, Tvrtko Ursulin, Maíra Canal,
Lizhi Hou
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Philipp Stanner <phasta@kernel.org>
[ Upstream commit 796a9f55a8d1d85387b973df9a06cbf4bc2d6327 ]
drm_sched_init() has a great many parameters and upcoming new
functionality for the scheduler might add even more. Generally, the
great number of parameters reduces readability and has already caused
one missnaming, addressed in:
commit 6f1cacf4eba7 ("drm/nouveau: Improve variable name in
nouveau_sched_init()").
Introduce a new struct for the scheduler init parameters and port all
users.
Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>
Acked-by: Matthew Brost <matthew.brost@intel.com> # for Xe
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com> # for Panfrost and Panthor
Reviewed-by: Christian Gmeiner <cgmeiner@igalia.com> # for Etnaviv
Reviewed-by: Frank Binns <frank.binns@imgtec.com> # for Imagination
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com> # for Sched
Reviewed-by: Maíra Canal <mcanal@igalia.com> # for v3d
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Reviewed-by: Lizhi Hou <lizhi.hou@amd.com> # for amdxdna
Signed-off-by: Philipp Stanner <phasta@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20250211111422.21235-2-phasta@kernel.org
Stable-dep-of: e2332abed2a4 ("drm/msm: Only fini scheduler after successful init")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 18 ++++--
drivers/gpu/drm/etnaviv/etnaviv_sched.c | 22 ++++----
drivers/gpu/drm/imagination/pvr_queue.c | 18 ++++--
drivers/gpu/drm/lima/lima_sched.c | 16 ++++--
drivers/gpu/drm/msm/msm_ringbuffer.c | 17 +++---
drivers/gpu/drm/nouveau/nouveau_sched.c | 16 ++++--
drivers/gpu/drm/panfrost/panfrost_job.c | 20 ++++---
drivers/gpu/drm/panthor/panthor_mmu.c | 16 ++++--
drivers/gpu/drm/panthor/panthor_sched.c | 28 ++++++----
drivers/gpu/drm/scheduler/sched_main.c | 50 ++++++-----------
drivers/gpu/drm/v3d/v3d_sched.c | 65 +++++++++-------------
drivers/gpu/drm/xe/xe_execlist.c | 15 +++--
drivers/gpu/drm/xe/xe_gpu_scheduler.c | 17 +++++-
include/drm/gpu_scheduler.h | 36 ++++++++++--
14 files changed, 202 insertions(+), 152 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 692c8883a0364..172cc8cd8356b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -2849,6 +2849,12 @@ static int amdgpu_device_fw_loading(struct amdgpu_device *adev)
static int amdgpu_device_init_schedulers(struct amdgpu_device *adev)
{
+ struct drm_sched_init_args args = {
+ .ops = &amdgpu_sched_ops,
+ .num_rqs = DRM_SCHED_PRIORITY_COUNT,
+ .timeout_wq = adev->reset_domain->wq,
+ .dev = adev->dev,
+ };
long timeout;
int r, i;
@@ -2874,12 +2880,12 @@ static int amdgpu_device_init_schedulers(struct amdgpu_device *adev)
break;
}
- r = drm_sched_init(&ring->sched, &amdgpu_sched_ops, NULL,
- DRM_SCHED_PRIORITY_COUNT,
- ring->num_hw_submission, 0,
- timeout, adev->reset_domain->wq,
- ring->sched_score, ring->name,
- adev->dev);
+ args.timeout = timeout;
+ args.credit_limit = ring->num_hw_submission;
+ args.score = ring->sched_score;
+ args.name = ring->name;
+
+ r = drm_sched_init(&ring->sched, &args);
if (r) {
DRM_ERROR("Failed to create scheduler on ring %s.\n",
ring->name);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
index e60288af35027..ee4cc67214144 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
@@ -134,17 +134,17 @@ int etnaviv_sched_push_job(struct etnaviv_gem_submit *submit)
int etnaviv_sched_init(struct etnaviv_gpu *gpu)
{
- int ret;
-
- ret = drm_sched_init(&gpu->sched, &etnaviv_sched_ops, NULL,
- DRM_SCHED_PRIORITY_COUNT,
- etnaviv_hw_jobs_limit, etnaviv_job_hang_limit,
- msecs_to_jiffies(500), NULL, NULL,
- dev_name(gpu->dev), gpu->dev);
- if (ret)
- return ret;
-
- return 0;
+ const struct drm_sched_init_args args = {
+ .ops = &etnaviv_sched_ops,
+ .num_rqs = DRM_SCHED_PRIORITY_COUNT,
+ .credit_limit = etnaviv_hw_jobs_limit,
+ .hang_limit = etnaviv_job_hang_limit,
+ .timeout = msecs_to_jiffies(500),
+ .name = dev_name(gpu->dev),
+ .dev = gpu->dev,
+ };
+
+ return drm_sched_init(&gpu->sched, &args);
}
void etnaviv_sched_fini(struct etnaviv_gpu *gpu)
diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c
index 367d5915130a9..b660b85b58fdd 100644
--- a/drivers/gpu/drm/imagination/pvr_queue.c
+++ b/drivers/gpu/drm/imagination/pvr_queue.c
@@ -1240,6 +1240,17 @@ struct pvr_queue *pvr_queue_create(struct pvr_context *ctx,
},
};
struct pvr_device *pvr_dev = ctx->pvr_dev;
+ const struct drm_sched_init_args sched_args = {
+ .ops = &pvr_queue_sched_ops,
+ .submit_wq = pvr_dev->sched_wq,
+ .num_rqs = 1,
+ .credit_limit = 64 * 1024,
+ .hang_limit = 1,
+ .timeout = msecs_to_jiffies(500),
+ .timeout_wq = pvr_dev->sched_wq,
+ .name = "pvr-queue",
+ .dev = pvr_dev->base.dev,
+ };
struct drm_gpu_scheduler *sched;
struct pvr_queue *queue;
int ctx_state_size, err;
@@ -1312,12 +1323,7 @@ struct pvr_queue *pvr_queue_create(struct pvr_context *ctx,
queue->timeline_ufo.value = cpu_map;
- err = drm_sched_init(&queue->scheduler,
- &pvr_queue_sched_ops,
- pvr_dev->sched_wq, 1, 64 * 1024, 1,
- msecs_to_jiffies(500),
- pvr_dev->sched_wq, NULL, "pvr-queue",
- pvr_dev->base.dev);
+ err = drm_sched_init(&queue->scheduler, &sched_args);
if (err)
goto err_release_ufo;
diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c
index 00f0b2907cb6d..9b21eada6c49d 100644
--- a/drivers/gpu/drm/lima/lima_sched.c
+++ b/drivers/gpu/drm/lima/lima_sched.c
@@ -517,18 +517,22 @@ int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name)
{
unsigned int timeout = lima_sched_timeout_ms > 0 ?
lima_sched_timeout_ms : 10000;
+ const struct drm_sched_init_args args = {
+ .ops = &lima_sched_ops,
+ .num_rqs = DRM_SCHED_PRIORITY_COUNT,
+ .credit_limit = 1,
+ .hang_limit = lima_job_hang_limit,
+ .timeout = msecs_to_jiffies(timeout),
+ .name = name,
+ .dev = pipe->ldev->dev,
+ };
pipe->fence_context = dma_fence_context_alloc(1);
spin_lock_init(&pipe->fence_lock);
INIT_WORK(&pipe->recover_work, lima_sched_recover_work);
- return drm_sched_init(&pipe->base, &lima_sched_ops, NULL,
- DRM_SCHED_PRIORITY_COUNT,
- 1,
- lima_job_hang_limit,
- msecs_to_jiffies(timeout), NULL,
- NULL, name, pipe->ldev->dev);
+ return drm_sched_init(&pipe->base, &args);
}
void lima_sched_pipe_fini(struct lima_sched_pipe *pipe)
diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c
index 9d6655f96f0ce..8a20355ca314a 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.c
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.c
@@ -59,8 +59,14 @@ static const struct drm_sched_backend_ops msm_sched_ops = {
struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id,
void *memptrs, uint64_t memptrs_iova)
{
+ struct drm_sched_init_args args = {
+ .ops = &msm_sched_ops,
+ .num_rqs = DRM_SCHED_PRIORITY_COUNT,
+ .credit_limit = num_hw_submissions,
+ .timeout = MAX_SCHEDULE_TIMEOUT,
+ .dev = gpu->dev->dev,
+ };
struct msm_ringbuffer *ring;
- long sched_timeout;
char name[32];
int ret;
@@ -87,6 +93,7 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id,
}
msm_gem_object_set_name(ring->bo, "ring%d", id);
+ args.name = to_msm_bo(ring->bo)->name,
ring->end = ring->start + (MSM_GPU_RINGBUFFER_SZ >> 2);
ring->next = ring->start;
@@ -95,13 +102,7 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id,
ring->memptrs = memptrs;
ring->memptrs_iova = memptrs_iova;
- /* currently managing hangcheck ourselves: */
- sched_timeout = MAX_SCHEDULE_TIMEOUT;
-
- ret = drm_sched_init(&ring->sched, &msm_sched_ops, NULL,
- DRM_SCHED_PRIORITY_COUNT,
- num_hw_submissions, 0, sched_timeout,
- NULL, NULL, to_msm_bo(ring->bo)->name, gpu->dev->dev);
+ ret = drm_sched_init(&ring->sched, &args);
if (ret) {
goto fail;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c
index 23f60b7d0e4f2..7676d962a9598 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sched.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sched.c
@@ -405,7 +405,14 @@ nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm,
{
struct drm_gpu_scheduler *drm_sched = &sched->base;
struct drm_sched_entity *entity = &sched->entity;
- const long timeout = msecs_to_jiffies(NOUVEAU_SCHED_JOB_TIMEOUT_MS);
+ struct drm_sched_init_args args = {
+ .ops = &nouveau_sched_ops,
+ .num_rqs = DRM_SCHED_PRIORITY_COUNT,
+ .credit_limit = credit_limit,
+ .timeout = msecs_to_jiffies(NOUVEAU_SCHED_JOB_TIMEOUT_MS),
+ .name = "nouveau_sched",
+ .dev = drm->dev->dev
+ };
int ret;
if (!wq) {
@@ -417,10 +424,9 @@ nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm,
sched->wq = wq;
}
- ret = drm_sched_init(drm_sched, &nouveau_sched_ops, wq,
- NOUVEAU_SCHED_PRIORITY_COUNT,
- credit_limit, 0, timeout,
- NULL, NULL, "nouveau_sched", drm->dev->dev);
+ args.submit_wq = wq,
+
+ ret = drm_sched_init(drm_sched, &args);
if (ret)
goto fail_wq;
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
index df49d37d0e7eb..303709e5e3b4c 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -830,8 +830,16 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
int panfrost_job_init(struct panfrost_device *pfdev)
{
+ struct drm_sched_init_args args = {
+ .ops = &panfrost_sched_ops,
+ .num_rqs = DRM_SCHED_PRIORITY_COUNT,
+ .credit_limit = 2,
+ .timeout = msecs_to_jiffies(JOB_TIMEOUT_MS),
+ .timeout_wq = pfdev->reset.wq,
+ .name = "pan_js",
+ .dev = pfdev->dev,
+ };
struct panfrost_job_slot *js;
- unsigned int nentries = 2;
int ret, j;
/* All GPUs have two entries per queue, but without jobchain
@@ -839,7 +847,7 @@ int panfrost_job_init(struct panfrost_device *pfdev)
* so let's just advertise one entry in that case.
*/
if (!panfrost_has_hw_feature(pfdev, HW_FEATURE_JOBCHAIN_DISAMBIGUATION))
- nentries = 1;
+ args.credit_limit = 1;
pfdev->js = js = devm_kzalloc(pfdev->dev, sizeof(*js), GFP_KERNEL);
if (!js)
@@ -869,13 +877,7 @@ int panfrost_job_init(struct panfrost_device *pfdev)
for (j = 0; j < NUM_JOB_SLOTS; j++) {
js->queue[j].fence_context = dma_fence_context_alloc(1);
- ret = drm_sched_init(&js->queue[j].sched,
- &panfrost_sched_ops, NULL,
- DRM_SCHED_PRIORITY_COUNT,
- nentries, 0,
- msecs_to_jiffies(JOB_TIMEOUT_MS),
- pfdev->reset.wq,
- NULL, "pan_js", pfdev->dev);
+ ret = drm_sched_init(&js->queue[j].sched, &args);
if (ret) {
dev_err(pfdev->dev, "Failed to create scheduler: %d.", ret);
goto err_sched;
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index 3cad487c1b727..30107d28d230b 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -2296,6 +2296,16 @@ panthor_vm_create(struct panthor_device *ptdev, bool for_mcu,
u64 full_va_range = 1ull << va_bits;
struct drm_gem_object *dummy_gem;
struct drm_gpu_scheduler *sched;
+ const struct drm_sched_init_args sched_args = {
+ .ops = &panthor_vm_bind_ops,
+ .submit_wq = ptdev->mmu->vm.wq,
+ .num_rqs = 1,
+ .credit_limit = 1,
+ /* Bind operations are synchronous for now, no timeout needed. */
+ .timeout = MAX_SCHEDULE_TIMEOUT,
+ .name = "panthor-vm-bind",
+ .dev = ptdev->base.dev,
+ };
struct io_pgtable_cfg pgtbl_cfg;
u64 mair, min_va, va_range;
struct panthor_vm *vm;
@@ -2355,11 +2365,7 @@ panthor_vm_create(struct panthor_device *ptdev, bool for_mcu,
goto err_mm_takedown;
}
- /* Bind operations are synchronous for now, no timeout needed. */
- ret = drm_sched_init(&vm->sched, &panthor_vm_bind_ops, ptdev->mmu->vm.wq,
- 1, 1, 0,
- MAX_SCHEDULE_TIMEOUT, NULL, NULL,
- "panthor-vm-bind", ptdev->base.dev);
+ ret = drm_sched_init(&vm->sched, &sched_args);
if (ret)
goto err_free_io_pgtable;
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index 95649ea56ba88..e3fbe34924ceb 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -3290,6 +3290,22 @@ static struct panthor_queue *
group_create_queue(struct panthor_group *group,
const struct drm_panthor_queue_create *args)
{
+ const struct drm_sched_init_args sched_args = {
+ .ops = &panthor_queue_sched_ops,
+ .submit_wq = group->ptdev->scheduler->wq,
+ .num_rqs = 1,
+ /*
+ * The credit limit argument tells us the total number of
+ * instructions across all CS slots in the ringbuffer, with
+ * some jobs requiring twice as many as others, depending on
+ * their profiling status.
+ */
+ .credit_limit = args->ringbuf_size / sizeof(u64),
+ .timeout = msecs_to_jiffies(JOB_TIMEOUT_MS),
+ .timeout_wq = group->ptdev->reset.wq,
+ .name = "panthor-queue",
+ .dev = group->ptdev->base.dev,
+ };
struct drm_gpu_scheduler *drm_sched;
struct panthor_queue *queue;
int ret;
@@ -3360,17 +3376,7 @@ group_create_queue(struct panthor_group *group,
if (ret)
goto err_free_queue;
- /*
- * Credit limit argument tells us the total number of instructions
- * across all CS slots in the ringbuffer, with some jobs requiring
- * twice as many as others, depending on their profiling status.
- */
- ret = drm_sched_init(&queue->scheduler, &panthor_queue_sched_ops,
- group->ptdev->scheduler->wq, 1,
- args->ringbuf_size / sizeof(u64),
- 0, msecs_to_jiffies(JOB_TIMEOUT_MS),
- group->ptdev->reset.wq,
- NULL, "panthor-queue", group->ptdev->base.dev);
+ ret = drm_sched_init(&queue->scheduler, &sched_args);
if (ret)
goto err_free_queue;
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index 34ebc2fa3a5a4..9a80d01152672 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -1236,40 +1236,24 @@ static void drm_sched_run_job_work(struct work_struct *w)
* drm_sched_init - Init a gpu scheduler instance
*
* @sched: scheduler instance
- * @ops: backend operations for this scheduler
- * @submit_wq: workqueue to use for submission. If NULL, an ordered wq is
- * allocated and used
- * @num_rqs: number of runqueues, one for each priority, up to DRM_SCHED_PRIORITY_COUNT
- * @credit_limit: the number of credits this scheduler can hold from all jobs
- * @hang_limit: number of times to allow a job to hang before dropping it
- * @timeout: timeout value in jiffies for the scheduler
- * @timeout_wq: workqueue to use for timeout work. If NULL, the system_wq is
- * used
- * @score: optional score atomic shared with other schedulers
- * @name: name used for debugging
- * @dev: target &struct device
+ * @args: scheduler initialization arguments
*
* Return 0 on success, otherwise error code.
*/
-int drm_sched_init(struct drm_gpu_scheduler *sched,
- const struct drm_sched_backend_ops *ops,
- struct workqueue_struct *submit_wq,
- u32 num_rqs, u32 credit_limit, unsigned int hang_limit,
- long timeout, struct workqueue_struct *timeout_wq,
- atomic_t *score, const char *name, struct device *dev)
+int drm_sched_init(struct drm_gpu_scheduler *sched, const struct drm_sched_init_args *args)
{
int i;
- sched->ops = ops;
- sched->credit_limit = credit_limit;
- sched->name = name;
- sched->timeout = timeout;
- sched->timeout_wq = timeout_wq ? : system_wq;
- sched->hang_limit = hang_limit;
- sched->score = score ? score : &sched->_score;
- sched->dev = dev;
+ sched->ops = args->ops;
+ sched->credit_limit = args->credit_limit;
+ sched->name = args->name;
+ sched->timeout = args->timeout;
+ sched->hang_limit = args->hang_limit;
+ sched->timeout_wq = args->timeout_wq ? args->timeout_wq : system_wq;
+ sched->score = args->score ? args->score : &sched->_score;
+ sched->dev = args->dev;
- if (num_rqs > DRM_SCHED_PRIORITY_COUNT) {
+ if (args->num_rqs > DRM_SCHED_PRIORITY_COUNT) {
/* This is a gross violation--tell drivers what the problem is.
*/
drm_err(sched, "%s: num_rqs cannot be greater than DRM_SCHED_PRIORITY_COUNT\n",
@@ -1284,16 +1268,16 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
return 0;
}
- if (submit_wq) {
- sched->submit_wq = submit_wq;
+ if (args->submit_wq) {
+ sched->submit_wq = args->submit_wq;
sched->own_submit_wq = false;
} else {
#ifdef CONFIG_LOCKDEP
- sched->submit_wq = alloc_ordered_workqueue_lockdep_map(name,
+ sched->submit_wq = alloc_ordered_workqueue_lockdep_map(args->name,
WQ_MEM_RECLAIM,
&drm_sched_lockdep_map);
#else
- sched->submit_wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
+ sched->submit_wq = alloc_ordered_workqueue(args->name, WQ_MEM_RECLAIM);
#endif
if (!sched->submit_wq)
return -ENOMEM;
@@ -1301,11 +1285,11 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
sched->own_submit_wq = true;
}
- sched->sched_rq = kmalloc_array(num_rqs, sizeof(*sched->sched_rq),
+ sched->sched_rq = kmalloc_array(args->num_rqs, sizeof(*sched->sched_rq),
GFP_KERNEL | __GFP_ZERO);
if (!sched->sched_rq)
goto Out_check_own;
- sched->num_rqs = num_rqs;
+ sched->num_rqs = args->num_rqs;
for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) {
sched->sched_rq[i] = kzalloc(sizeof(*sched->sched_rq[i]), GFP_KERNEL);
if (!sched->sched_rq[i])
diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
index 5bc656509ee90..70bd566cf6d42 100644
--- a/drivers/gpu/drm/v3d/v3d_sched.c
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
@@ -865,67 +865,54 @@ static const struct drm_sched_backend_ops v3d_cpu_sched_ops = {
.free_job = v3d_sched_job_free
};
+static int
+v3d_queue_sched_init(struct v3d_dev *v3d, const struct drm_sched_backend_ops *ops,
+ enum v3d_queue queue, const char *name)
+{
+ struct drm_sched_init_args args = {
+ .num_rqs = DRM_SCHED_PRIORITY_COUNT,
+ .credit_limit = 1,
+ .timeout = msecs_to_jiffies(500),
+ .dev = v3d->drm.dev,
+ };
+
+ args.ops = ops;
+ args.name = name;
+
+ return drm_sched_init(&v3d->queue[queue].sched, &args);
+}
+
int
v3d_sched_init(struct v3d_dev *v3d)
{
- int hw_jobs_limit = 1;
- int job_hang_limit = 0;
- int hang_limit_ms = 500;
int ret;
- ret = drm_sched_init(&v3d->queue[V3D_BIN].sched,
- &v3d_bin_sched_ops, NULL,
- DRM_SCHED_PRIORITY_COUNT,
- hw_jobs_limit, job_hang_limit,
- msecs_to_jiffies(hang_limit_ms), NULL,
- NULL, "v3d_bin", v3d->drm.dev);
+ ret = v3d_queue_sched_init(v3d, &v3d_bin_sched_ops, V3D_BIN, "v3d_bin");
if (ret)
return ret;
- ret = drm_sched_init(&v3d->queue[V3D_RENDER].sched,
- &v3d_render_sched_ops, NULL,
- DRM_SCHED_PRIORITY_COUNT,
- hw_jobs_limit, job_hang_limit,
- msecs_to_jiffies(hang_limit_ms), NULL,
- NULL, "v3d_render", v3d->drm.dev);
+ ret = v3d_queue_sched_init(v3d, &v3d_render_sched_ops, V3D_RENDER,
+ "v3d_render");
if (ret)
goto fail;
- ret = drm_sched_init(&v3d->queue[V3D_TFU].sched,
- &v3d_tfu_sched_ops, NULL,
- DRM_SCHED_PRIORITY_COUNT,
- hw_jobs_limit, job_hang_limit,
- msecs_to_jiffies(hang_limit_ms), NULL,
- NULL, "v3d_tfu", v3d->drm.dev);
+ ret = v3d_queue_sched_init(v3d, &v3d_tfu_sched_ops, V3D_TFU, "v3d_tfu");
if (ret)
goto fail;
if (v3d_has_csd(v3d)) {
- ret = drm_sched_init(&v3d->queue[V3D_CSD].sched,
- &v3d_csd_sched_ops, NULL,
- DRM_SCHED_PRIORITY_COUNT,
- hw_jobs_limit, job_hang_limit,
- msecs_to_jiffies(hang_limit_ms), NULL,
- NULL, "v3d_csd", v3d->drm.dev);
+ ret = v3d_queue_sched_init(v3d, &v3d_csd_sched_ops, V3D_CSD,
+ "v3d_csd");
if (ret)
goto fail;
- ret = drm_sched_init(&v3d->queue[V3D_CACHE_CLEAN].sched,
- &v3d_cache_clean_sched_ops, NULL,
- DRM_SCHED_PRIORITY_COUNT,
- hw_jobs_limit, job_hang_limit,
- msecs_to_jiffies(hang_limit_ms), NULL,
- NULL, "v3d_cache_clean", v3d->drm.dev);
+ ret = v3d_queue_sched_init(v3d, &v3d_cache_clean_sched_ops,
+ V3D_CACHE_CLEAN, "v3d_cache_clean");
if (ret)
goto fail;
}
- ret = drm_sched_init(&v3d->queue[V3D_CPU].sched,
- &v3d_cpu_sched_ops, NULL,
- DRM_SCHED_PRIORITY_COUNT,
- 1, job_hang_limit,
- msecs_to_jiffies(hang_limit_ms), NULL,
- NULL, "v3d_cpu", v3d->drm.dev);
+ ret = v3d_queue_sched_init(v3d, &v3d_cpu_sched_ops, V3D_CPU, "v3d_cpu");
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/xe/xe_execlist.c b/drivers/gpu/drm/xe/xe_execlist.c
index 6a59165b95690..99bfb50df1cac 100644
--- a/drivers/gpu/drm/xe/xe_execlist.c
+++ b/drivers/gpu/drm/xe/xe_execlist.c
@@ -331,6 +331,15 @@ static const struct drm_sched_backend_ops drm_sched_ops = {
static int execlist_exec_queue_init(struct xe_exec_queue *q)
{
struct drm_gpu_scheduler *sched;
+ const struct drm_sched_init_args args = {
+ .ops = &drm_sched_ops,
+ .num_rqs = 1,
+ .credit_limit = q->lrc[0]->ring.size / MAX_JOB_SIZE_BYTES,
+ .hang_limit = XE_SCHED_HANG_LIMIT,
+ .timeout = XE_SCHED_JOB_TIMEOUT,
+ .name = q->hwe->name,
+ .dev = gt_to_xe(q->gt)->drm.dev,
+ };
struct xe_execlist_exec_queue *exl;
struct xe_device *xe = gt_to_xe(q->gt);
int err;
@@ -345,11 +354,7 @@ static int execlist_exec_queue_init(struct xe_exec_queue *q)
exl->q = q;
- err = drm_sched_init(&exl->sched, &drm_sched_ops, NULL, 1,
- q->lrc[0]->ring.size / MAX_JOB_SIZE_BYTES,
- XE_SCHED_HANG_LIMIT, XE_SCHED_JOB_TIMEOUT,
- NULL, NULL, q->hwe->name,
- gt_to_xe(q->gt)->drm.dev);
+ err = drm_sched_init(&exl->sched, &args);
if (err)
goto err_free;
diff --git a/drivers/gpu/drm/xe/xe_gpu_scheduler.c b/drivers/gpu/drm/xe/xe_gpu_scheduler.c
index 50361b4638f96..869b43a4151d2 100644
--- a/drivers/gpu/drm/xe/xe_gpu_scheduler.c
+++ b/drivers/gpu/drm/xe/xe_gpu_scheduler.c
@@ -63,13 +63,24 @@ int xe_sched_init(struct xe_gpu_scheduler *sched,
atomic_t *score, const char *name,
struct device *dev)
{
+ const struct drm_sched_init_args args = {
+ .ops = ops,
+ .submit_wq = submit_wq,
+ .num_rqs = 1,
+ .credit_limit = hw_submission,
+ .hang_limit = hang_limit,
+ .timeout = timeout,
+ .timeout_wq = timeout_wq,
+ .score = score,
+ .name = name,
+ .dev = dev,
+ };
+
sched->ops = xe_ops;
INIT_LIST_HEAD(&sched->msgs);
INIT_WORK(&sched->work_process_msg, xe_sched_process_msg_work);
- return drm_sched_init(&sched->base, ops, submit_wq, 1, hw_submission,
- hang_limit, timeout, timeout_wq, score, name,
- dev);
+ return drm_sched_init(&sched->base, &args);
}
void xe_sched_fini(struct xe_gpu_scheduler *sched)
diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h
index 4246ed5b97039..be2644f96da8e 100644
--- a/include/drm/gpu_scheduler.h
+++ b/include/drm/gpu_scheduler.h
@@ -550,12 +550,38 @@ struct drm_gpu_scheduler {
struct device *dev;
};
+/**
+ * struct drm_sched_init_args - parameters for initializing a DRM GPU scheduler
+ *
+ * @ops: backend operations provided by the driver
+ * @submit_wq: workqueue to use for submission. If NULL, an ordered wq is
+ * allocated and used.
+ * @num_rqs: Number of run-queues. This may be at most DRM_SCHED_PRIORITY_COUNT,
+ * as there's usually one run-queue per priority, but may be less.
+ * @credit_limit: the number of credits this scheduler can hold from all jobs
+ * @hang_limit: number of times to allow a job to hang before dropping it.
+ * This mechanism is DEPRECATED. Set it to 0.
+ * @timeout: timeout value in jiffies for submitted jobs.
+ * @timeout_wq: workqueue to use for timeout work. If NULL, the system_wq is used.
+ * @score: score atomic shared with other schedulers. May be NULL.
+ * @name: name (typically the driver's name). Used for debugging
+ * @dev: associated device. Used for debugging
+ */
+struct drm_sched_init_args {
+ const struct drm_sched_backend_ops *ops;
+ struct workqueue_struct *submit_wq;
+ struct workqueue_struct *timeout_wq;
+ u32 num_rqs;
+ u32 credit_limit;
+ unsigned int hang_limit;
+ long timeout;
+ atomic_t *score;
+ const char *name;
+ struct device *dev;
+};
+
int drm_sched_init(struct drm_gpu_scheduler *sched,
- const struct drm_sched_backend_ops *ops,
- struct workqueue_struct *submit_wq,
- u32 num_rqs, u32 credit_limit, unsigned int hang_limit,
- long timeout, struct workqueue_struct *timeout_wq,
- atomic_t *score, const char *name, struct device *dev);
+ const struct drm_sched_init_args *args);
void drm_sched_fini(struct drm_gpu_scheduler *sched);
int drm_sched_job_init(struct drm_sched_job *job,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 700/869] drm/msm: Only fini scheduler after successful init
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (698 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 699/869] drm/sched: Use struct for drm_sched_init() params Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 701/869] firmware: arm_scmi: Fix SCMI device destroy lifetimes Greg Kroah-Hartman
` (169 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Ruoyu Wang, Rob Clark, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <ruoyuw560@gmail.com>
[ Upstream commit e2332abed2a4d3caa59052095dc16e4ce44791ea ]
msm_ringbuffer_new() destroys a partially initialized ring through
msm_ringbuffer_destroy() when an allocation or scheduler setup step
fails.
If drm_sched_init() fails before it finishes initializing the scheduler,
the failure path still calls drm_sched_fini(). That teardown path assumes
the scheduler work items, lists, and workqueue state were initialized.
Track successful scheduler initialization and call drm_sched_fini() only
after drm_sched_init() returned 0.
This issue was found by a static analysis checker and confirmed by
manual source review.
Fixes: 1d8a5ca436ee ("drm/msm: Conversion to drm scheduler")
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
Patchwork: https://patchwork.freedesktop.org/patch/738905/
Message-ID: <20260709062309.4168362-1-ruoyuw560@gmail.com>
Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/msm/msm_ringbuffer.c | 7 ++++---
drivers/gpu/drm/msm/msm_ringbuffer.h | 1 +
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c
index 8a20355ca314a..917768a17a0b9 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.c
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.c
@@ -103,9 +103,9 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id,
ring->memptrs_iova = memptrs_iova;
ret = drm_sched_init(&ring->sched, &args);
- if (ret) {
+ if (ret)
goto fail;
- }
+ ring->sched_initialized = true;
INIT_LIST_HEAD(&ring->submits);
spin_lock_init(&ring->submit_lock);
@@ -127,7 +127,8 @@ void msm_ringbuffer_destroy(struct msm_ringbuffer *ring)
if (IS_ERR_OR_NULL(ring))
return;
- drm_sched_fini(&ring->sched);
+ if (ring->sched_initialized)
+ drm_sched_fini(&ring->sched);
msm_fence_context_free(ring->fctx);
diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.h b/drivers/gpu/drm/msm/msm_ringbuffer.h
index 0d6beb8cd39a7..72e4de1aafa2c 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.h
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.h
@@ -52,6 +52,7 @@ struct msm_ringbuffer {
* The job scheduler for this ring.
*/
struct drm_gpu_scheduler sched;
+ bool sched_initialized;
/*
* List of in-flight submits on this ring. Protected by submit_lock.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 701/869] firmware: arm_scmi: Fix SCMI device destroy lifetimes
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (699 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 700/869] drm/msm: Only fini scheduler after successful init Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 702/869] fs/resctrl: Prevent use-after-free in rdtgroup_kn_put() Greg Kroah-Hartman
` (168 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Sashiko, Sudeep Holla, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <sudeep.holla@kernel.org>
[ Upstream commit 6abe8fe36b29ff51d1a42c2f338972883f4751a5 ]
scmi_child_dev_find() drops the reference returned by
device_find_child() before returning the scmi_device pointer. A
concurrent unregister can then release the device while the destroy path
is still using the returned pointer.
Make the lookup helper return the device_find_child() reference and keep
it until scmi_device_destroy() has finished unregistering the child.
Also split device_unregister() in __scmi_device_destroy() so the SCMI bus
ID is not made reusable until after device_del() has removed the old
scmi_dev.N name from sysfs. This avoids a new SCMI device reusing the
same ID while the old device is still registered.
The final device release callback is also a possible cleanup path when
SCMI children are deleted by driver core recursion rather than
__scmi_device_destroy(). Release the SCMI bus ID from a common helper
used by destroy, register-failure and final-release paths, and clear
scmi_dev->id after freeing it so the final release cannot free the same
ID again.
Fixes: 9ca67840c0dd ("firmware: arm_scmi: Balance device refcount when destroying devices")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://patch.msgid.link/20260714-scmi_core_fixes-v6-15-3afe499d46e3@kernel.org
Signed-off-by: Sudeep Holla <sudeep.holla@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/firmware/arm_scmi/bus.c | 36 ++++++++++++++++++++++-----------
1 file changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
index 771b6da2d83b6..8769078e36894 100644
--- a/drivers/firmware/arm_scmi/bus.c
+++ b/drivers/firmware/arm_scmi/bus.c
@@ -249,8 +249,9 @@ static int scmi_match_by_id_table(struct device *dev, void *data)
(id_table->name && !strcmp(sdev->name, id_table->name));
}
-static struct scmi_device *scmi_child_dev_find(struct device *parent,
- int prot_id, const char *name)
+/* Returns a device_find_child() reference which must be dropped by caller. */
+static struct scmi_device *
+scmi_child_dev_find_get(struct device *parent, int prot_id, const char *name)
{
struct scmi_device_id id_table;
struct device *dev;
@@ -262,9 +263,6 @@ static struct scmi_device *scmi_child_dev_find(struct device *parent,
if (!dev)
return NULL;
- /* Drop the refcnt bumped implicitly by device_find_child */
- put_device(dev);
-
return to_scmi_dev(dev);
}
@@ -332,10 +330,19 @@ void scmi_driver_unregister(struct scmi_driver *driver)
}
EXPORT_SYMBOL_GPL(scmi_driver_unregister);
+static void scmi_device_release_resources(struct scmi_device *scmi_dev)
+{
+ if (scmi_dev->id) {
+ ida_free(&scmi_bus_id, scmi_dev->id);
+ scmi_dev->id = 0;
+ }
+}
+
static void scmi_device_release(struct device *dev)
{
struct scmi_device *scmi_dev = to_scmi_dev(dev);
+ scmi_device_release_resources(scmi_dev);
kfree_const(scmi_dev->name);
kfree(scmi_dev);
}
@@ -350,8 +357,9 @@ static void __scmi_device_destroy(struct scmi_device *scmi_dev)
if (scmi_dev->protocol_id == SCMI_PROTOCOL_SYSTEM)
atomic_set(&scmi_syspower_registered, 0);
- ida_free(&scmi_bus_id, scmi_dev->id);
- device_unregister(&scmi_dev->dev);
+ device_del(&scmi_dev->dev);
+ scmi_device_release_resources(scmi_dev);
+ put_device(&scmi_dev->dev);
}
static struct scmi_device *
@@ -368,9 +376,11 @@ __scmi_device_create(struct device_node *np, struct device *parent,
* each DT defined protocol at probe time, and the concurrent
* registration of SCMI drivers.
*/
- scmi_dev = scmi_child_dev_find(parent, protocol, name);
- if (scmi_dev)
+ scmi_dev = scmi_child_dev_find_get(parent, protocol, name);
+ if (scmi_dev) {
+ put_device(&scmi_dev->dev);
return scmi_dev;
+ }
/*
* Ignore any possible subsequent failures while creating the device
@@ -421,8 +431,8 @@ __scmi_device_create(struct device_node *np, struct device *parent,
return scmi_dev;
put_dev:
+ scmi_device_release_resources(scmi_dev);
put_device(&scmi_dev->dev);
- ida_free(&scmi_bus_id, id);
return NULL;
}
@@ -494,9 +504,11 @@ void scmi_device_destroy(struct device *parent, int protocol, const char *name)
{
struct scmi_device *scmi_dev;
- scmi_dev = scmi_child_dev_find(parent, protocol, name);
- if (scmi_dev)
+ scmi_dev = scmi_child_dev_find_get(parent, protocol, name);
+ if (scmi_dev) {
__scmi_device_destroy(scmi_dev);
+ put_device(&scmi_dev->dev);
+ }
}
EXPORT_SYMBOL_GPL(scmi_device_destroy);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 702/869] fs/resctrl: Prevent use-after-free in rdtgroup_kn_put()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (700 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 701/869] firmware: arm_scmi: Fix SCMI device destroy lifetimes Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 703/869] RDMA/rvt: Return NULL after port allocation failure Greg Kroah-Hartman
` (167 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Reinette Chatre,
Borislav Petkov (AMD), Ben Horgan, Tony Luck, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Reinette Chatre <reinette.chatre@intel.com>
[ Upstream commit f5bcf539484d2d604c2f2330e09487ea090b21c7 ]
A struct rdtgroup is reference counted via rdtgroup::waitcount. Callers that
need the structure to remain valid across a sleep (while waiting on acquiring
rdtgroup_mutex) take a reference with rdtgroup_kn_get() and release it with
rdtgroup_kn_put().
The release path is intended to serve as the fallback freer: if the count
drops to zero and the group has already been marked RDT_DELETED,
rdtgroup_kn_put() frees the structure.
The bulk teardown paths free_all_child_rdtgrp() and rmdir_all_sub() resulting
from a resctrl directory remove or resctrl fs unmount act as the primary
freer: they hold rdtgroup_mutex and free each rdtgroup whose waitcount is
zero, otherwise they set RDT_DELETED and leave the freeing to the last waiter.
These two freers race. rdtgroup_kn_put() commits waitcount == 0 with
atomic_dec_and_test() outside rdtgroup_mutex, then reads rdtgroup::flags.
Between those two operations a concurrent caller of free_all_child_rdtgrp()
or rmdir_all_sub() (which holds the mutex) can observe waitcount == 0 via
atomic_read(), call rdtgroup_remove(), and kfree() the structure.
The subsequent read of rdtgroup::flags in rdtgroup_kn_put() is then
a use-after-free, and the structure may even be freed twice if the freed
memory happens to satisfy the RDT_DELETED flag check.
Replace the bare atomic_dec_and_test() with atomic_dec_and_mutex_lock() so
that the decrement-to-zero takes rdtgroup_mutex before the count becomes
globally visible. The inspection of rdtgroup::flags then runs under the same
mutex held by the bulk freers, making the two paths mutually exclusive.
The common case where the count does not reach zero remains lock-free. Defer
kernfs_unbreak_active_protection() until after the mutex is dropped since
kernfs active protections functionally wrap rdtgroup_mutex. Remove resource
group, which in turn drops its kernfs reference, after kernfs protection is
restored.
[ bp: Split the commit messsages into smaller, easier-parseable paragraphs. ]
Fixes: b8511ccc75c0 ("x86/resctrl: Fix use-after-free when deleting resource groups")
Closes: https://sashiko.dev/#/patchset/20260515193944.15114-1-tony.luck%40intel.com?part=1
Reported-by: Sashiko <sashiko-bot@kernel.org>
Assisted-by: GitHub_Copilot:gemini-3.1-pro
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Ben Horgan <ben.horgan@arm.com>
Reviewed-by: Tony Luck <tony.luck@intel.com>
Link: https://patch.msgid.link/8d028bbea582dc382a4cc166b235f75bd5901aea.1783963505.git.reinette.chatre@intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kernel/cpu/resctrl/rdtgroup.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
index 3db8992d1ae5f..868e260947a10 100644
--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
@@ -2447,15 +2447,24 @@ static void rdtgroup_kn_get(struct rdtgroup *rdtgrp, struct kernfs_node *kn)
static void rdtgroup_kn_put(struct rdtgroup *rdtgrp, struct kernfs_node *kn)
{
- if (atomic_dec_and_test(&rdtgrp->waitcount) &&
- (rdtgrp->flags & RDT_DELETED)) {
+ bool needs_free;
+
+ if (!atomic_dec_and_mutex_lock(&rdtgrp->waitcount, &rdtgroup_mutex)) {
+ kernfs_unbreak_active_protection(kn);
+ return;
+ }
+
+ needs_free = rdtgrp->flags & RDT_DELETED;
+
+ mutex_unlock(&rdtgroup_mutex);
+
+ kernfs_unbreak_active_protection(kn);
+
+ if (needs_free) {
if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED)
rdtgroup_pseudo_lock_remove(rdtgrp);
- kernfs_unbreak_active_protection(kn);
rdtgroup_remove(rdtgrp);
- } else {
- kernfs_unbreak_active_protection(kn);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 703/869] RDMA/rvt: Return NULL after port allocation failure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (701 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 702/869] fs/resctrl: Prevent use-after-free in rdtgroup_kn_put() Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 704/869] esp: do not unref managed frag pages in esp_ssg_unref() Greg Kroah-Hartman
` (166 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Kalesh AP, Leon Romanovsky,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <leonro@nvidia.com>
[ Upstream commit 2982eaf3b9d2d953318c74cd6f1b7576ea6d7b1f ]
rvt_alloc_device() deallocates the IB device when its port array cannot
be allocated but then returns the pointer to the released allocation.
Callers treat any non-NULL value as valid and dereference it, resulting
in a use-after-free.
Return NULL immediately after deallocation so callers can propagate the
allocation failure.
Fixes: ff6acd69518e ("IB/rdmavt: Add device structure allocation")
Link: https://patch.msgid.link/20260708-clean-init-one-hfi1-v1-1-b9e9641268a5@nvidia.com
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/sw/rdmavt/vt.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/infiniband/sw/rdmavt/vt.c b/drivers/infiniband/sw/rdmavt/vt.c
index 5499025e8a0ad..b1750f2a6dcbc 100644
--- a/drivers/infiniband/sw/rdmavt/vt.c
+++ b/drivers/infiniband/sw/rdmavt/vt.c
@@ -54,8 +54,10 @@ struct rvt_dev_info *rvt_alloc_device(size_t size, int nports)
return rdi;
rdi->ports = kcalloc(nports, sizeof(*rdi->ports), GFP_KERNEL);
- if (!rdi->ports)
+ if (!rdi->ports) {
ib_dealloc_device(&rdi->ibdev);
+ return NULL;
+ }
return rdi;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 704/869] esp: do not unref managed frag pages in esp_ssg_unref()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (702 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 703/869] RDMA/rvt: Return NULL after port allocation failure Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 705/869] platform/x86: asus-wmi: fix resource leaks on probe failure Greg Kroah-Hartman
` (165 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Maher Azzouzi, Steffen Klassert,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maher Azzouzi <maherazz04@gmail.com>
[ Upstream commit 21697720ff43b8dfa25b8e8d9ca7f56f4597fc80 ]
esp_ssg_unref() releases the page references held on the source
scatterlist after the AEAD operation completes. It calls
skb_page_unref() on every frag page for an out-of-place transform
(req->src != req->dst), and in the error path of esp_output_tail()
(already_unref == true) on the request's own scatterlist.
This is wrong when the skb carries managed frags
(SKBFL_MANAGED_FRAG_REFS). Managed frags are owned by a zerocopy ubuf
and the skb does not hold a per-frag page reference; io_uring SEND_ZC
with a registered buffer attaches the bvec pages this way via
io_sg_from_iter(). The rest of the stack honours this invariant:
skb_release_data() skips the per-frag unref when SKBFL_MANAGED_FRAG_REFS
is set, and skb_zcopy_managed() is the guard used at the other unref
sites.
esp_ssg_unref() is missing that guard, so for a managed-frag skb it
drops a page reference the skb never acquired. This can underflow the
page reference count and free a page that is still in use.
Guard the function with skb_zcopy_managed() so both unref paths are
skipped for managed-frag skbs, matching skb_release_data().
Fixes: cac2661c53f3 ("esp4: Avoid skb_cow_data whenever possible")
Fixes: 03e2a30f6a27 ("esp6: Avoid skb_cow_data whenever possible")
Signed-off-by: Maher Azzouzi <maherazz04@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv4/esp4.c | 7 +++++++
net/ipv6/esp6.c | 7 +++++++
2 files changed, 14 insertions(+)
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index fb78dc6b7e148..8944f812e4b55 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -104,6 +104,13 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb)
struct aead_request *req;
struct scatterlist *sg;
+ /* Managed frags are owned by the zerocopy ubuf; the skb holds no
+ * per-frag page reference, so we must not drop one here. Mirrors
+ * the SKBFL_MANAGED_FRAG_REFS handling in skb_release_data().
+ */
+ if (skb_zcopy_managed(skb))
+ return;
+
if (x->props.flags & XFRM_STATE_ESN)
extralen += sizeof(struct esp_output_extra);
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 7411aac0707b2..3061e74799170 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -121,6 +121,13 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb)
struct aead_request *req;
struct scatterlist *sg;
+ /* Managed frags are owned by the zerocopy ubuf; the skb holds no
+ * per-frag page reference, so we must not drop one here. Mirrors
+ * the SKBFL_MANAGED_FRAG_REFS handling in skb_release_data().
+ */
+ if (skb_zcopy_managed(skb))
+ return;
+
if (x->props.flags & XFRM_STATE_ESN)
extralen += sizeof(struct esp_output_extra);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 705/869] platform/x86: asus-wmi: fix resource leaks on probe failure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (703 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 704/869] esp: do not unref managed frag pages in esp_ssg_unref() Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 706/869] usb: gadget: uac: validate rate list length before storing Greg Kroah-Hartman
` (164 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Marco Scardovi, Ilpo Järvinen,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marco Scardovi <scardracs@disroot.org>
[ Upstream commit ef3daa2b84a2b8499ce9e2ce1c865dca36d39f95 ]
During driver initialization in asus_wmi_add(), various subsystems are
registered sequentially. However, the error path labels are out of order
relative to the registration sequence.
Specifically:
1. If asus_wmi_custom_fan_curve_init() fails, the driver jumps to
fail_custom_fan_curve. Because this label is placed below fail_sysfs,
it bypasses the cleanup calls for the input device and sysfs groups,
which were successfully registered before, leaking those resources.
2. If asus_screenpad_init() fails, the driver jumps to fail_screenpad.
Because fail_screenpad is placed below fail_backlight, it bypasses the
cleanup calls for backlight and rfkill, leaking those resources.
Fix these resource leaks by reordering the error path labels in
asus_wmi_add() to match the exact reverse order of the resource
allocations.
Fixes: 0f0ac158d28f ("platform/x86: asus-wmi: Add support for custom fan curves")
Fixes: 2c97d3e55b70 ("platform/x86: asus-wmi: add support for ASUS screenpad")
Assisted-by: Antigravity:gemini-3.5-flash
Signed-off-by: Marco Scardovi <scardracs@disroot.org>
Link: https://patch.msgid.link/20260617155104.10111-1-scardracs@disroot.org
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/platform/x86/asus-wmi.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 5d701fde07df4..c8a8e30f8d736 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -4840,20 +4840,20 @@ static int asus_wmi_add(struct platform_device *pdev)
return 0;
fail_wmi_handler:
+ asus_screenpad_exit(asus);
+fail_screenpad:
asus_wmi_backlight_exit(asus);
fail_backlight:
asus_wmi_rfkill_exit(asus);
-fail_screenpad:
- asus_screenpad_exit(asus);
fail_rfkill:
asus_wmi_led_exit(asus);
fail_leds:
+fail_custom_fan_curve:
fail_hwmon:
asus_wmi_input_exit(asus);
fail_input:
asus_wmi_sysfs_exit(asus->platform_device);
fail_sysfs:
-fail_custom_fan_curve:
fail_platform_profile_setup:
if (asus->platform_profile_support)
platform_profile_remove();
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 706/869] usb: gadget: uac: validate rate list length before storing
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (704 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 705/869] platform/x86: asus-wmi: fix resource leaks on probe failure Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 707/869] bpf: Reject rdonly/rdwr_buf_size kfunc arguments that exceed u32 max Greg Kroah-Hartman
` (163 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Qing Ming, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qing Ming <a0yami@mailbox.org>
[ Upstream commit 844d83d5964b87919b958ff48405188c6ddae9cc ]
UAC1 and UAC2 configfs rate-list attributes parse a comma-separated
list of sampling rates and store each parsed value in fixed-size arrays.
The arrays have UAC_MAX_RATES entries, but the store paths do not check
that the input contains at most that many tokens before writing through
opts->name##s[i++].
Writing more than ten rates therefore writes past the end of the
p_srates[] or c_srates[] array in struct f_uac1_opts or struct
f_uac2_opts.
With CONFIG_UBSAN_BOUNDS enabled, writing an 11-entry rate list to the
UAC1 p_srate attribute reports:
UBSAN: array-index-out-of-bounds
drivers/usb/gadget/function/f_uac1.c:1669:1
index 10 is out of range for type 'int [10]'
__ubsan_handle_out_of_bounds.cold
f_uac1_opts_p_srate_store
configfs_write_iter
vfs_write
ksys_write
do_syscall_64
The same reproducer against the UAC2 p_srate attribute reports:
UBSAN: array-index-out-of-bounds
drivers/usb/gadget/function/f_uac2.c:2087:1
index 10 is out of range for type 'int [10]'
__ubsan_handle_out_of_bounds.cold
f_uac2_opts_p_srate_store
configfs_write_iter
vfs_write
ksys_write
do_syscall_64
Reject additional tokens once UAC_MAX_RATES entries have been parsed.
Also keep the original kstrdup() pointer for kfree(), because strsep()
advances the parsing cursor. Freeing the advanced cursor leaks the
original buffer on successful parses and can free an interior pointer on
some error paths.
Fixes: 695d39ffc2b5 ("usb: gadget: f_uac1: Support multiple sampling rates")
Fixes: a7339e4f5788 ("usb: gadget: f_uac2: Support multiple sampling rates")
Signed-off-by: Qing Ming <a0yami@mailbox.org>
Link: https://patch.msgid.link/20260519143319.147494-1-a0yami@mailbox.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/usb/gadget/function/f_uac1.c | 13 +++++++++----
drivers/usb/gadget/function/f_uac2.c | 13 +++++++++----
2 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
index c87e74afc8815..0a247cca34881 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -1594,7 +1594,8 @@ static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
struct f_uac1_opts *opts = to_f_uac1_opts(item); \
- char *split_page = NULL; \
+ char *buf = NULL; \
+ char *split_page; \
int ret = -EINVAL; \
char *token; \
u32 num; \
@@ -1608,18 +1609,22 @@ static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \
\
i = 0; \
memset(opts->name##s, 0x00, sizeof(opts->name##s)); \
- split_page = kstrdup(page, GFP_KERNEL); \
+ buf = kstrdup(page, GFP_KERNEL); \
+ split_page = buf; \
while ((token = strsep(&split_page, ",")) != NULL) { \
ret = kstrtou32(token, 0, &num); \
if (ret) \
goto end; \
- \
+ if (i >= UAC_MAX_RATES) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
opts->name##s[i++] = num; \
ret = len; \
}; \
\
end: \
- kfree(split_page); \
+ kfree(buf); \
mutex_unlock(&opts->lock); \
return ret; \
} \
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 9b324821c93bd..e45db4444c49f 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -2012,7 +2012,8 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
struct f_uac2_opts *opts = to_f_uac2_opts(item); \
- char *split_page = NULL; \
+ char *buf = NULL; \
+ char *split_page; \
int ret = -EINVAL; \
char *token; \
u32 num; \
@@ -2026,18 +2027,22 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
\
i = 0; \
memset(opts->name##s, 0x00, sizeof(opts->name##s)); \
- split_page = kstrdup(page, GFP_KERNEL); \
+ buf = kstrdup(page, GFP_KERNEL); \
+ split_page = buf; \
while ((token = strsep(&split_page, ",")) != NULL) { \
ret = kstrtou32(token, 0, &num); \
if (ret) \
goto end; \
- \
+ if (i >= UAC_MAX_RATES) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
opts->name##s[i++] = num; \
ret = len; \
}; \
\
end: \
- kfree(split_page); \
+ kfree(buf); \
mutex_unlock(&opts->lock); \
return ret; \
} \
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 707/869] bpf: Reject rdonly/rdwr_buf_size kfunc arguments that exceed u32 max
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (705 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 706/869] usb: gadget: uac: validate rate list length before storing Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 708/869] platform/x86: dell-wmi-base: Fix handling of ultra performance key Greg Kroah-Hartman
` (162 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Dudar, Eduard Zingerman,
Kumar Kartikeya Dwivedi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicholas Dudar <main.kalliope@gmail.com>
[ Upstream commit 2aaf67f0516fde29620d0edfc29c01b9ea7ad430 ]
check_kfunc_args() detects a kfunc argument named rdonly_buf_size or
rdwr_buf_size and stores reg->var_off.value into meta->r0_size, a u64,
and does not bound it. check_kfunc_call() later copies that value into
the returned register's mem_size field:
meta->r0_size = reg->var_off.value;
...
regs[BPF_REG_0].mem_size = meta.r0_size;
regs[BPF_REG_0].mem_size is u32. A constant whose upper 32 bits are set
gets truncated instead of causing a load-time rejection, so the verifier
records a PTR_TO_MEM register with an approximately 4 GiB mem_size for
whatever allocation the kfunc returned. A later access check against
that register uses the truncated, wrong bound.
Reject rdonly_buf_size/rdwr_buf_size values that exceed U32_MAX at the
point meta->r0_size is set.
Fixes: eb1f7f71c126 ("bpf/verifier: allow kfunc to return an allocated mem")
Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/bpf/20260709155837.1879230-2-main.kalliope@gmail.com
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 03b6093327187..7c814248e842c 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -12347,6 +12347,11 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
}
meta->r0_size = reg->var_off.value;
+ if (meta->r0_size > U32_MAX) {
+ verbose(env, "R%d rdonly/rdwr_buf_size exceeds u32 max\n",
+ regno);
+ return -EINVAL;
+ }
ret = mark_chain_precision(env, regno);
if (ret)
return ret;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 708/869] platform/x86: dell-wmi-base: Fix handling of ultra performance key
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (706 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 707/869] bpf: Reject rdonly/rdwr_buf_size kfunc arguments that exceed u32 max Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 709/869] bpf: Reject writes through untrusted BTF pointers Greg Kroah-Hartman
` (161 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Armin Wolf, Ilpo Järvinen,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Armin Wolf <W_Armin@gmx.de>
[ Upstream commit adfd6846bea13667ff28f8aaf00c32fbd69825ab ]
The commit message of commit 5fbd827eb9c2 ("platform/x86: dell-wmi: Recognise or support new switches")
states that the ultra performance key contains additional data
after the type and code fields. The event data passed to
dell_wmi_process_key() is already parsed, so "buffer" already
starts after those two fields.
Use the correct index for accessing the first data field to avoid
a potential buffer overread.
Fixes: 5fbd827eb9c2 ("platform/x86: dell-wmi: Recognise or support new switches")
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Link: https://patch.msgid.link/20260612173451.467629-4-W_Armin@gmx.de
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/platform/x86/dell/dell-wmi-base.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/platform/x86/dell/dell-wmi-base.c b/drivers/platform/x86/dell/dell-wmi-base.c
index 713ec2c12a04e..4838992ee5f99 100644
--- a/drivers/platform/x86/dell/dell-wmi-base.c
+++ b/drivers/platform/x86/dell/dell-wmi-base.c
@@ -442,7 +442,7 @@ static int dell_wmi_process_key(struct wmi_device *wdev, int type, int code, u16
SW_TABLET_MODE, !buffer[0]);
return 1;
} else if (type == 0x0012 && code == 0x000d && remaining > 0) {
- value = (buffer[2] == 2);
+ value = (buffer[0] == 2);
used = 1;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 709/869] bpf: Reject writes through untrusted BTF pointers
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (707 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 708/869] platform/x86: dell-wmi-base: Fix handling of ultra performance key Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 710/869] time/namespace: Validate nanosecond field in proc_timens_set_offset() Greg Kroah-Hartman
` (160 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Dudar,
Kumar Kartikeya Dwivedi, Eduard Zingerman, Amery Hung,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicholas Dudar <main.kalliope@gmail.com>
[ Upstream commit ac65c710cc643cbc52b899627577357867249530 ]
check_ptr_to_btf_access() lets program-type btf_struct_access callbacks
validate writes before the default BTF access path rejects non-read
accesses. That bypasses the read-only policy for untrusted BTF pointers
created by helpers such as bpf_rdonly_cast().
Reject non-read accesses through PTR_UNTRUSTED BTF pointers at the
common entry point, before the callback branch to handle all cases.
Fixes: 282de143ead9 ("bpf: Introduce allocated objects support")
Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Reviewed-by: Amery Hung <ameryhung@gmail.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 7c814248e842c..ba665811c7fe6 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -6907,6 +6907,11 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
return -EACCES;
}
+ if (atype != BPF_READ && (type_flag(reg->type) & PTR_UNTRUSTED)) {
+ verbose(env, "only read is supported\n");
+ return -EACCES;
+ }
+
if (env->ops->btf_struct_access && !type_is_alloc(reg->type) && atype == BPF_WRITE) {
if (!btf_is_kernel(reg->btf)) {
verbose(env, "verifier internal error: reg->btf must be kernel btf\n");
@@ -6915,8 +6920,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
ret = env->ops->btf_struct_access(&env->log, reg, off, size);
} else {
/* Writes are permitted with default btf_struct_access for
- * program allocated objects (which always have ref_obj_id > 0),
- * but not for untrusted PTR_TO_BTF_ID | MEM_ALLOC.
+ * program allocated objects (which always have ref_obj_id > 0).
*/
if (atype != BPF_READ && !type_is_ptr_alloc_obj(reg->type)) {
verbose(env, "only read is supported\n");
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 710/869] time/namespace: Validate nanosecond field in proc_timens_set_offset()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (708 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 709/869] bpf: Reject writes through untrusted BTF pointers Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 711/869] bpf: Reject MEM_ALLOC BTF accesses past object bounds Greg Kroah-Hartman
` (159 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Malaya Kumar Rout, Thomas Gleixner,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Malaya Kumar Rout <malayarout91@gmail.com>
[ Upstream commit 06aba58e58492d2b8eae059274caed29025ea96e ]
The function validates tv_sec to be within [-KTIME_SEC_MAX, KTIME_SEC_MAX]
but never validates that tv_nsec is within the valid range of
[0, NSEC_PER_SEC-1] before using it in timespec64_add().
timespec64_add() expects both timespec64 structures to have normalized
values with tv_nsec in the range [0, 999999999]. If off->val.tv_nsec
contains invalid values (negative or >= NSEC_PER_SEC), it could lead to
incorrect calculations or unexpected behavior.
Add validation to ensure tv_nsec is within the valid range before
performing the addition.
Fixes: 04a8682a71be ("fs/proc: Introduce /proc/pid/timens_offsets")
Signed-off-by: Malaya Kumar Rout <malayarout91@gmail.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260704093429.89350-1-malayarout91@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/time/namespace.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/kernel/time/namespace.c b/kernel/time/namespace.c
index 0775b9ec952af..09a4cc85a9fbc 100644
--- a/kernel/time/namespace.c
+++ b/kernel/time/namespace.c
@@ -410,6 +410,11 @@ int proc_timens_set_offset(struct file *file, struct task_struct *p,
goto out;
}
+ if (off->val.tv_nsec < 0 || off->val.tv_nsec >= NSEC_PER_SEC) {
+ err = -EINVAL;
+ goto out;
+ }
+
err = -ERANGE;
if (off->val.tv_sec > KTIME_SEC_MAX ||
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 711/869] bpf: Reject MEM_ALLOC BTF accesses past object bounds
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (709 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 710/869] time/namespace: Validate nanosecond field in proc_timens_set_offset() Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 712/869] dmaengine: xilinx_dma: Fix CPU stall in xilinx_dma_poll_timeout Greg Kroah-Hartman
` (158 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yiyang Chen, Amery Hung,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
[ Upstream commit 9c9ee0324c774490ae953162aaaf4561d222bd93 ]
BTF struct walks relax the struct-size check for accesses through a
trailing flexible array. That is valid for ordinary BTF type walking, but
PTR_TO_BTF_ID | MEM_ALLOC values point to objects allocated with the static
BTF type size.
When walking a MEM_ALLOC object, reject the access before applying the
flexible-array relaxation if the access range extends past the struct size.
Apply the same policy to struct ID matching so kfunc and kptr type checks
do not walk past the allocated object bounds either.
Fixes: 958cf2e273f0 ("bpf: Introduce bpf_obj_new")
Fixes: 36d8bdf75a93 ("bpf: Add alloc/xchg/direct_access support for local percpu kptr")
Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
Reviewed-by: Amery Hung <ameryhung@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/bpf/4b8c8a81102ba4b595011434c881194f264ddc59.1782807039.git.chenyy23@mails.tsinghua.edu.cn
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/bpf.h | 2 +-
kernel/bpf/btf.c | 17 +++++++++++------
kernel/bpf/verifier.c | 11 +++++++----
3 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 427e540a756ee..f43aa1cd1b0b3 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -2658,7 +2658,7 @@ int btf_struct_access(struct bpf_verifier_log *log,
bool btf_struct_ids_match(struct bpf_verifier_log *log,
const struct btf *btf, u32 id, int off,
const struct btf *need_btf, u32 need_type_id,
- bool strict);
+ bool strict, bool walk_flex_arrays);
int btf_distill_func_proto(struct bpf_verifier_log *log,
struct btf *btf,
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 0c6d0b029f016..cd63c1e27f601 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -6841,7 +6841,7 @@ enum bpf_struct_walk_result {
static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
const struct btf_type *t, int off, int size,
u32 *next_btf_id, enum bpf_type_flag *flag,
- const char **field_name)
+ const char **field_name, bool walk_flex_arrays)
{
u32 i, moff, mtrue_end, msize = 0, total_nelems = 0;
const struct btf_type *mtype, *elem_type = NULL;
@@ -6868,11 +6868,14 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
*flag |= PTR_UNTRUSTED;
if (off + size > t->size) {
+ struct btf_array *array_elem;
+
+ if (!walk_flex_arrays)
+ goto error;
+
/* If the last element is a variable size array, we may
* need to relax the rule.
*/
- struct btf_array *array_elem;
-
if (vlen == 0)
goto error;
@@ -7133,7 +7136,8 @@ int btf_struct_access(struct bpf_verifier_log *log,
t = btf_type_by_id(btf, id);
do {
- err = btf_struct_walk(log, btf, t, off, size, &id, &tmp_flag, field_name);
+ err = btf_struct_walk(log, btf, t, off, size, &id, &tmp_flag,
+ field_name, !type_is_alloc(reg->type));
switch (err) {
case WALK_PTR:
@@ -7189,7 +7193,7 @@ bool btf_types_are_same(const struct btf *btf1, u32 id1,
bool btf_struct_ids_match(struct bpf_verifier_log *log,
const struct btf *btf, u32 id, int off,
const struct btf *need_btf, u32 need_type_id,
- bool strict)
+ bool strict, bool walk_flex_arrays)
{
const struct btf_type *type;
enum bpf_type_flag flag = 0;
@@ -7208,7 +7212,8 @@ bool btf_struct_ids_match(struct bpf_verifier_log *log,
type = btf_type_by_id(btf, id);
if (!type)
return false;
- err = btf_struct_walk(log, btf, type, off, 1, &id, &flag, NULL);
+ err = btf_struct_walk(log, btf, type, off, 1, &id, &flag, NULL,
+ walk_flex_arrays);
if (err != WALK_STRUCT)
return false;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index ba665811c7fe6..9f5eed4a7290a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5570,7 +5570,8 @@ static int map_kptr_match_type(struct bpf_verifier_env *env,
*/
if (!btf_struct_ids_match(&env->log, reg->btf, reg->btf_id, reg->off,
kptr_field->kptr.btf, kptr_field->kptr.btf_id,
- kptr_field->type != BPF_KPTR_UNREF))
+ kptr_field->type != BPF_KPTR_UNREF,
+ !type_is_alloc(reg->type)))
goto bad_type;
return 0;
bad_type:
@@ -8895,7 +8896,7 @@ static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
if (!btf_struct_ids_match(&env->log, reg->btf, reg->btf_id, reg->off,
btf_vmlinux, *arg_btf_id,
- strict_type_match)) {
+ strict_type_match, !type_is_alloc(reg->type))) {
verbose(env, "R%d is of type %s but %s is expected\n",
regno, btf_type_name(reg->btf, reg->btf_id),
btf_type_name(btf_vmlinux, *arg_btf_id));
@@ -11858,7 +11859,8 @@ static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
reg_ref_t = btf_type_skip_modifiers(reg_btf, reg_ref_id, ®_ref_id);
reg_ref_tname = btf_name_by_offset(reg_btf, reg_ref_t->name_off);
- struct_same = btf_struct_ids_match(&env->log, reg_btf, reg_ref_id, reg->off, meta->btf, ref_id, strict_type_match);
+ struct_same = btf_struct_ids_match(&env->log, reg_btf, reg_ref_id, reg->off, meta->btf, ref_id,
+ strict_type_match, !type_is_alloc(reg->type));
/* If kfunc is accepting a projection type (ie. __sk_buff), it cannot
* actually use it -- it must cast to the underlying type. So we allow
* caller to pass in the underlying type.
@@ -12214,7 +12216,8 @@ __process_kf_arg_ptr_to_graph_node(struct bpf_verifier_env *env,
et = btf_type_by_id(field->graph_root.btf, field->graph_root.value_btf_id);
t = btf_type_by_id(reg->btf, reg->btf_id);
if (!btf_struct_ids_match(&env->log, reg->btf, reg->btf_id, 0, field->graph_root.btf,
- field->graph_root.value_btf_id, true)) {
+ field->graph_root.value_btf_id, true,
+ !type_is_alloc(reg->type))) {
verbose(env, "operation on %s expects arg#1 %s at offset=%d "
"in struct %s, but arg is at offset=%d in struct %s\n",
btf_field_type_name(head_field_type),
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 712/869] dmaengine: xilinx_dma: Fix CPU stall in xilinx_dma_poll_timeout
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (710 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 711/869] bpf: Reject MEM_ALLOC BTF accesses past object bounds Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 713/869] drm/amd/display: Fix dangling pointer in CRTC reset function Greg Kroah-Hartman
` (157 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Suraj Gupta, Frank Li, Alex Bereza,
Vinod Koul, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Bereza <alex@bereza.email>
[ Upstream commit aa99c4d1d63bbc26a5fc4c667d89b2595743c19d ]
Currently when calling xilinx_dma_poll_timeout with delay_us=0 and a
condition that is never fulfilled, the CPU busy-waits for prolonged time
and the timeout triggers only with a massive delay causing a CPU stall.
This happens due to a huge underestimation of wall clock time in
poll_timeout_us_atomic. Commit 7349a69cf312 ("iopoll: Do not use
timekeeping in read_poll_timeout_atomic()") changed the behavior to no
longer use ktime_get at the expense of underestimation of wall clock
time which appears to be very large for delay_us=0. Instead of timing
out after approximately XILINX_DMA_LOOP_COUNT microseconds, the timeout
takes XILINX_DMA_LOOP_COUNT * 1000 * (time that the overhead of the for
loop in poll_timeout_us_atomic takes) which is in the range of several
minutes for XILINX_DMA_LOOP_COUNT=1000000. Fix this by using a non-zero
value for delay_us. Use delay_us=10 to keep the delay in the hot path of
starting DMA transfers minimal but still avoid CPU stalls in case of
unexpected hardware failures.
One-off measurement with delay_us=0 causes the cpu to busy wait around 7
minutes in the timeout case. After applying this patch with delay_us=10
the measured timeout was 1053428 microseconds which is roughly
equivalent to the expected 1000000 microseconds specified in
XILINX_DMA_LOOP_COUNT.
Add a constant XILINX_DMA_POLL_DELAY_US for delay_us value.
Fixes: 9495f2648287 ("dmaengine: xilinx_vdma: Use readl_poll_timeout instead of do while loop's")
Fixes: 7349a69cf312 ("iopoll: Do not use timekeeping in read_poll_timeout_atomic()")
Reviewed-by: Suraj Gupta <suraj.gupta2@amd.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Alex Bereza <alex@bereza.email>
Link: https://patch.msgid.link/20260402-fix-atomic-poll-timeout-regression-v4-1-f30d6a6c13cb@bereza.email
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/dma/xilinx/xilinx_dma.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 4a89ad8c90a34..39e6625c143cc 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -166,6 +166,8 @@
/* Delay loop counter to prevent hardware failure */
#define XILINX_DMA_LOOP_COUNT 1000000
+/* Delay between polls (avoid a delay of 0 to prevent CPU stalls) */
+#define XILINX_DMA_POLL_DELAY_US 10
/* AXI DMA Specific Registers/Offsets */
#define XILINX_DMA_REG_SRCDSTADDR 0x18
@@ -1315,7 +1317,8 @@ static int xilinx_dma_stop_transfer(struct xilinx_dma_chan *chan)
/* Wait for the hardware to halt */
return xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val,
- val & XILINX_DMA_DMASR_HALTED, 0,
+ val & XILINX_DMA_DMASR_HALTED,
+ XILINX_DMA_POLL_DELAY_US,
XILINX_DMA_LOOP_COUNT);
}
@@ -1330,7 +1333,8 @@ static int xilinx_cdma_stop_transfer(struct xilinx_dma_chan *chan)
u32 val;
return xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val,
- val & XILINX_DMA_DMASR_IDLE, 0,
+ val & XILINX_DMA_DMASR_IDLE,
+ XILINX_DMA_POLL_DELAY_US,
XILINX_DMA_LOOP_COUNT);
}
@@ -1347,7 +1351,8 @@ static void xilinx_dma_start(struct xilinx_dma_chan *chan)
/* Wait for the hardware to start */
err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMASR, val,
- !(val & XILINX_DMA_DMASR_HALTED), 0,
+ !(val & XILINX_DMA_DMASR_HALTED),
+ XILINX_DMA_POLL_DELAY_US,
XILINX_DMA_LOOP_COUNT);
if (err) {
@@ -1780,7 +1785,8 @@ static int xilinx_dma_reset(struct xilinx_dma_chan *chan)
/* Wait for the hardware to finish reset */
err = xilinx_dma_poll_timeout(chan, XILINX_DMA_REG_DMACR, tmp,
- !(tmp & XILINX_DMA_DMACR_RESET), 0,
+ !(tmp & XILINX_DMA_DMACR_RESET),
+ XILINX_DMA_POLL_DELAY_US,
XILINX_DMA_LOOP_COUNT);
if (err) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 713/869] drm/amd/display: Fix dangling pointer in CRTC reset function
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (711 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 712/869] dmaengine: xilinx_dma: Fix CPU stall in xilinx_dma_poll_timeout Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 714/869] drm/amd/display: Fix dangling pointer in plane " Greg Kroah-Hartman
` (156 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Evgenii Burenchev,
Mario Limonciello (AMD), Mario Limonciello, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Evgenii Burenchev <evg28bur@yandex.ru>
[ Upstream commit 0aeed866cb938943908c3ba46422128e49d2d080 ]
amdgpu_dm_crtc_reset_state() frees the old state before allocating
a new one. If kzalloc() fails, the function returns without updating
the state pointer, leaving a dangling pointer to already freed memory.
Fix this by allocating the new state first. On allocation failure, the
old state remains untouched and the function safely returns.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Fixes: e7b07ceef2a6 ("drm/amd/display: Merge amdgpu_dm_crtc and dm_crtc_state")
Signed-off-by: Evgenii Burenchev <evg28bur@yandex.ru>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Link: https://patch.msgid.link/20260629090435.9729-4-evg28bur@yandex.ru
[adjust for movement around current amd-staging-drm-next]
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 779c2c3ffbc0d..824e88fe54c6f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -479,13 +479,13 @@ static void amdgpu_dm_crtc_reset_state(struct drm_crtc *crtc)
{
struct dm_crtc_state *state;
- if (crtc->state)
- amdgpu_dm_crtc_destroy_state(crtc, crtc->state);
-
state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (WARN_ON(!state))
+ if (!state)
return;
+ if (crtc->state)
+ amdgpu_dm_crtc_destroy_state(crtc, crtc->state);
+
__drm_atomic_helper_crtc_reset(crtc, &state->base);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 714/869] drm/amd/display: Fix dangling pointer in plane reset function
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (712 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 713/869] drm/amd/display: Fix dangling pointer in CRTC reset function Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 715/869] mm/page_owner: use memcg_data snapshot to avoid TOCTOU in print_page_owner_memcg() Greg Kroah-Hartman
` (155 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Evgenii Burenchev,
Mario Limonciello (AMD), Mario Limonciello, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Evgenii Burenchev <evg28bur@yandex.ru>
[ Upstream commit 98cad4bd1443975d972f4c7f705980da03722a22 ]
amdgpu_dm_plane_drm_plane_reset() frees the old state before allocating
a new one. If kzalloc() fails, the function returns without updating
the state pointer, leaving a dangling pointer to already freed memory.
Fix this by allocating the new state first. On allocation failure, the
old state remains untouched and the function safely returns.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Fixes: 5d945cbcd4b1 ("drm/amd/display: Create a file dedicated to planes")
Signed-off-by: Evgenii Burenchev <evg28bur@yandex.ru>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Link: https://patch.msgid.link/20260629090435.9729-3-evg28bur@yandex.ru
[adjust for movement around current amd-staging-drm-next]
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index 97eeabc556a05..a033628c3d549 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1415,17 +1415,15 @@ static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
static void amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane)
{
- struct dm_plane_state *amdgpu_state = NULL;
-
- if (plane->state)
- plane->funcs->atomic_destroy_state(plane, plane->state);
+ struct dm_plane_state *amdgpu_state;
amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL);
- WARN_ON(amdgpu_state == NULL);
-
if (!amdgpu_state)
return;
+ if (plane->state)
+ plane->funcs->atomic_destroy_state(plane, plane->state);
+
__drm_atomic_helper_plane_reset(plane, &amdgpu_state->base);
amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 715/869] mm/page_owner: use memcg_data snapshot to avoid TOCTOU in print_page_owner_memcg()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (713 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 714/869] drm/amd/display: Fix dangling pointer in plane " Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 716/869] nfsd: convert nfsd_net boolean flags to unsigned long flags word Greg Kroah-Hartman
` (154 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ye Liu, Sashiko, Zi Yan,
Vlastimil Babka (SUSE), Brendan Jackman, Johannes Weiner,
Lorenzo Stoakes, Michal Hocko, Suren Baghdasaryan,
David Hildenbrand (Arm), Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ye Liu <ye.liu@linux.dev>
[ Upstream commit 90f095b816e25c6a9e4446d299bac5007fdcb3df ]
print_page_owner_memcg() reads page->memcg_data via READ_ONCE() at the
start to guard against tail pages and NULL data. However, it later
re-reads page->memcg_data locklessly in two places:
1: page_memcg_check(page)
2: PageMemcgKmem(page) (via folio_memcg_kmem(), which includes
VM_BUG_ON assertions for tail pages and MEMCG_DATA_OBJEXTS)
If the page is concurrently freed and reallocated as a THP tail page or
slab page between these calls, the VM_BUG_ON assertions can trigger on
CONFIG_DEBUG_VM=y builds, crashing the kernel.
Fix both TOCTOU issues by using the memcg_data snapshot throughout.
Link: https://lore.kernel.org/20260714015117.78351-10-ye.liu@linux.dev
Fixes: fcf8935832b8 ("mm/page_owner: print memcg information")
Signed-off-by: Ye Liu <ye.liu@linux.dev>
Reported-by: Sashiko <sashiko-bot@kernel.org>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Cc: Brendan Jackman <jackmanb@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: David Hildenbrand (Arm) <david@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/page_owner.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/mm/page_owner.c b/mm/page_owner.c
index f92cec789eee5..5d1c946c0008f 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -501,6 +501,7 @@ static inline int print_page_owner_memcg(char *kbuf, size_t count, int ret,
{
#ifdef CONFIG_MEMCG
unsigned long memcg_data;
+ struct obj_cgroup *objcg;
struct mem_cgroup *memcg;
bool online;
char name[80];
@@ -510,11 +511,14 @@ static inline int print_page_owner_memcg(char *kbuf, size_t count, int ret,
if (!memcg_data)
goto out_unlock;
- if (memcg_data & MEMCG_DATA_OBJEXTS)
+ if (memcg_data & MEMCG_DATA_OBJEXTS) {
ret += scnprintf(kbuf + ret, count - ret,
"Slab cache page\n");
+ goto out_unlock;
+ }
- memcg = page_memcg_check(page);
+ objcg = (void *)(memcg_data & ~OBJEXTS_FLAGS_MASK);
+ memcg = objcg ? obj_cgroup_memcg(objcg) : NULL;
if (!memcg)
goto out_unlock;
@@ -522,7 +526,7 @@ static inline int print_page_owner_memcg(char *kbuf, size_t count, int ret,
cgroup_name(memcg->css.cgroup, name, sizeof(name));
ret += scnprintf(kbuf + ret, count - ret,
"Charged %sto %smemcg %s\n",
- PageMemcgKmem(page) ? "(via objcg) " : "",
+ (memcg_data & MEMCG_DATA_KMEM) ? "(via objcg) " : "",
online ? "" : "offline ",
name);
out_unlock:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 716/869] nfsd: convert nfsd_net boolean flags to unsigned long flags word
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (714 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 715/869] mm/page_owner: use memcg_data snapshot to avoid TOCTOU in print_page_owner_memcg() Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 717/869] mm/hugetlb: refactor code around vmemmap_walk Greg Kroah-Hartman
` (153 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Chris Mason, Chuck Lever,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Mason <clm@meta.com>
[ Upstream commit 11a5fe42e1811f793e04ef885b639ea7668f439d ]
nfsd_net contains several boolean fields that are accessed from
concurrent contexts without serialization. In particular,
nfsd4_end_grace() guards its drain path with a plain bool:
if (nn->grace_ended)
return;
nn->grace_ended = true;
The read and the write are independent, and nothing in struct
nfsd_net serializes them. At least two contexts can reach this
code with no lock held:
laundromat path
laundry_wq kworker
nfs4_laundromat()
nfsd4_end_grace()
RECLAIM_COMPLETE path
nfsd compound kthread
nfsd4_reclaim_complete()
inc_reclaim_complete()
nfsd4_end_grace()
Both callers can observe grace_ended == false on different CPUs,
both store true, and both proceed into nfsd4_record_grace_done(),
which invokes the active client_tracking_ops->grace_done callback.
For tracking ops that drain reclaim_str_hashtbl (legacy_tracking_ops
via nfsd4_recdir_purge_old, and the cld v1+ ops via
nfsd4_cld_grace_done), grace_done calls nfs4_release_reclaim(),
which walks every bucket of reclaim_str_hashtbl with no lock and
calls nfs4_remove_reclaim_record() (list_del + kfree) on each
entry. Two concurrent walkers corrupt the list and double-free
every nfs4_client_reclaim. A concurrent nfsd4_find_reclaim_client()
iterating the same bucket reads through freed memory.
A third call site exists in nfs4_state_start_net() on the
skip_grace startup path, but it runs under nfsd_mutex before any
client has connected and before the laundromat's first delayed
work fires, so it cannot race with the two callers above.
Replace the scattered boolean fields in nfsd_net with a single
unsigned long flags word and an enum nfsd_net_flag for the bit
positions. The grace_ended race is fixed by using
test_and_set_bit(), which is atomic on all architectures. The
remaining flags (grace_end_forced, in_grace, somebody_reclaimed,
track_reclaim_completes, nfsd_net_up, lockd_up) are converted to
use test_bit/set_bit/clear_bit for consistency. This avoids
sub-word cmpxchg issues on architectures like Hexagon that only
support word-sized atomic operations.
Fixes: 362063a595be ("nfsd: keep a tally of RECLAIM_COMPLETE operations when using nfsdcld")
Cc: stable@vger.kernel.org
Assisted-by: kres:claude-opus-4-7
Reported-by: Chris Mason <clm@meta.com>
Signed-off-by: Chris Mason <clm@meta.com>
Link: https://patch.msgid.link/20260530-nfsd-fixes-v2-3-f27e8eb4d974@kernel.org
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/netns.h | 19 +++++++++++--------
fs/nfsd/nfs4proc.c | 2 +-
fs/nfsd/nfs4recover.c | 12 ++++++------
fs/nfsd/nfs4state.c | 41 +++++++++++++++++++++++++----------------
fs/nfsd/nfsctl.c | 4 ++--
fs/nfsd/nfssvc.c | 22 +++++++++++-----------
6 files changed, 56 insertions(+), 44 deletions(-)
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index 550ee3c4fc26c..a42d36b85b224 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -27,6 +27,16 @@
struct cld_net;
struct nfsd4_client_tracking_ops;
+enum nfsd_net_flag {
+ NFSD_NET_GRACE_ENDED,
+ NFSD_NET_GRACE_END_FORCED,
+ NFSD_NET_IN_GRACE,
+ NFSD_NET_SOMEBODY_RECLAIMED,
+ NFSD_NET_TRACK_RECLAIM_COMPLETES,
+ NFSD_NET_UP,
+ NFSD_NET_LOCKD_UP,
+};
+
enum {
/* cache misses due only to checksum comparison failures */
NFSD_STATS_PAYLOAD_MISSES,
@@ -65,8 +75,7 @@ struct nfsd_net {
struct cache_detail *nametoid_cache;
struct lock_manager nfsd4_manager;
- bool grace_ended;
- bool grace_end_forced;
+ unsigned long flags;
bool client_tracking_active;
time64_t boot_time;
time64_t boot_time_bt; /* same instant in CLOCK_BOOTTIME */
@@ -124,19 +133,13 @@ struct nfsd_net {
spinlock_t blocked_locks_lock;
struct file *rec_file;
- bool in_grace;
const struct nfsd4_client_tracking_ops *client_tracking_ops;
time64_t nfsd4_lease;
time64_t nfsd4_grace;
- bool somebody_reclaimed;
- bool track_reclaim_completes;
atomic_t nr_reclaim_complete;
- bool nfsd_net_up;
- bool lockd_up;
-
seqlock_t writeverf_lock;
unsigned char writeverf[8];
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index efc7cd0ae73b3..f94c01d23ea7c 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -627,7 +627,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
pr_warn("nfsd4_process_open2 failed to open newly-created file: status=%u\n",
be32_to_cpu(status));
if (reclaim && !status)
- nn->somebody_reclaimed = true;
+ set_bit(NFSD_NET_SOMEBODY_RECLAIMED, &nn->flags);
out:
if (open->op_filp) {
fput(open->op_filp);
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 41bc53288a142..d49bc03afc2f0 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -229,7 +229,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
out_unlock:
inode_unlock(d_inode(dir));
if (status == 0) {
- if (nn->in_grace)
+ if (test_bit(NFSD_NET_IN_GRACE, &nn->flags))
__nfsd4_create_reclaim_record_grace(clp, dname, nn);
vfs_fsync(nn->rec_file, 0);
} else {
@@ -391,7 +391,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
nfs4_reset_creds(original_cred);
if (status == 0) {
vfs_fsync(nn->rec_file, 0);
- if (nn->in_grace)
+ if (test_bit(NFSD_NET_IN_GRACE, &nn->flags))
__nfsd4_remove_reclaim_record_grace(dname,
HEXDIR_LEN, nn);
}
@@ -449,7 +449,7 @@ nfsd4_recdir_purge_old(struct nfsd_net *nn)
{
int status;
- nn->in_grace = false;
+ clear_bit(NFSD_NET_IN_GRACE, &nn->flags);
if (!nn->rec_file)
return;
status = mnt_want_write_file(nn->rec_file);
@@ -531,7 +531,7 @@ nfsd4_init_recdir(struct net *net)
nfs4_reset_creds(original_cred);
if (!status)
- nn->in_grace = true;
+ set_bit(NFSD_NET_IN_GRACE, &nn->flags);
return status;
}
@@ -1510,7 +1510,7 @@ nfs4_cld_state_init(struct net *net)
INIT_LIST_HEAD(&nn->reclaim_str_hashtbl[i]);
nn->reclaim_str_hashtbl_size = 0;
init_rwsem(&nn->reclaim_str_hashtbl_lock);
- nn->track_reclaim_completes = true;
+ set_bit(NFSD_NET_TRACK_RECLAIM_COMPLETES, &nn->flags);
atomic_set(&nn->nr_reclaim_complete, 0);
return 0;
@@ -1521,7 +1521,7 @@ nfs4_cld_state_shutdown(struct net *net)
{
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
- nn->track_reclaim_completes = false;
+ clear_bit(NFSD_NET_TRACK_RECLAIM_COMPLETES, &nn->flags);
kfree(nn->reclaim_str_hashtbl);
}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 0e74cf87fc541..c9a55105fa8e7 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2608,7 +2608,7 @@ static void inc_reclaim_complete(struct nfs4_client *clp)
{
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
- if (!nn->track_reclaim_completes)
+ if (!test_bit(NFSD_NET_TRACK_RECLAIM_COMPLETES, &nn->flags))
return;
down_read(&nn->reclaim_str_hashtbl_lock);
@@ -4863,8 +4863,6 @@ nfsd4_init_leases_net(struct nfsd_net *nn)
nn->nfsd4_lease = 90; /* default lease time */
nn->nfsd4_grace = 90;
- nn->somebody_reclaimed = false;
- nn->track_reclaim_completes = false;
nn->clverifier_counter = get_random_u32();
nn->clientid_base = get_random_u32();
nn->clientid_counter = nn->clientid_base + 1;
@@ -6467,12 +6465,21 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
static void
nfsd4_end_grace(struct nfsd_net *nn)
{
- /* do nothing if grace period already ended */
- if (nn->grace_ended)
+ /*
+ * nfsd4_end_grace() can be entered concurrently from the
+ * laundromat workqueue and from an nfsd compound thread
+ * handling RECLAIM_COMPLETE. Without serialization, both
+ * callers can observe NFSD_NET_GRACE_ENDED clear and proceed
+ * into nfsd4_record_grace_done(). For tracking ops whose
+ * grace_done drains reclaim_str_hashtbl, that results in
+ * list corruption and a double free of every
+ * nfs4_client_reclaim entry. Use an atomic test-and-set so
+ * exactly one caller proceeds.
+ */
+ if (test_and_set_bit(NFSD_NET_GRACE_ENDED, &nn->flags))
return;
trace_nfsd_grace_complete(nn);
- nn->grace_ended = true;
/*
* If the server goes down again right now, an NFSv4
* client will still be allowed to reclaim after it comes back up,
@@ -6514,11 +6521,12 @@ bool nfsd4_force_end_grace(struct nfsd_net *nn)
if (!nn->client_tracking_ops)
return false;
spin_lock(&nn->client_lock);
- if (nn->grace_ended || !nn->client_tracking_active) {
+ if (test_bit(NFSD_NET_GRACE_ENDED, &nn->flags) ||
+ !nn->client_tracking_active) {
spin_unlock(&nn->client_lock);
return false;
}
- WRITE_ONCE(nn->grace_end_forced, true);
+ set_bit(NFSD_NET_GRACE_END_FORCED, &nn->flags);
mod_delayed_work(laundry_wq, &nn->laundromat_work, 0);
spin_unlock(&nn->client_lock);
return true;
@@ -6533,9 +6541,9 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
time64_t double_grace_period_end = nn->boot_time_bt +
2 * nn->nfsd4_lease;
- if (READ_ONCE(nn->grace_end_forced))
+ if (test_bit(NFSD_NET_GRACE_END_FORCED, &nn->flags))
return false;
- if (nn->track_reclaim_completes) {
+ if (test_bit(NFSD_NET_TRACK_RECLAIM_COMPLETES, &nn->flags)) {
int size;
down_read(&nn->reclaim_str_hashtbl_lock);
@@ -6544,9 +6552,9 @@ static bool clients_still_reclaiming(struct nfsd_net *nn)
if (atomic_read(&nn->nr_reclaim_complete) == size)
return false;
}
- if (!nn->somebody_reclaimed)
+ if (!test_bit(NFSD_NET_SOMEBODY_RECLAIMED, &nn->flags))
return false;
- nn->somebody_reclaimed = false;
+ clear_bit(NFSD_NET_SOMEBODY_RECLAIMED, &nn->flags);
/*
* If we've given them *two* lease times to reclaim, and they're
* still not done, give up:
@@ -8404,7 +8412,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid);
status = 0;
if (lock->lk_reclaim)
- nn->somebody_reclaimed = true;
+ set_bit(NFSD_NET_SOMEBODY_RECLAIMED, &nn->flags);
break;
case FILE_LOCK_DEFERRED:
kref_put(&nbl->nbl_kref, free_nbl);
@@ -8974,8 +8982,8 @@ static int nfs4_state_create_net(struct net *net)
nn->unconf_name_tree = RB_ROOT;
nn->boot_time = ktime_get_real_seconds();
nn->boot_time_bt = ktime_get_boottime_seconds();
- nn->grace_ended = false;
- nn->grace_end_forced = false;
+ clear_bit(NFSD_NET_GRACE_ENDED, &nn->flags);
+ clear_bit(NFSD_NET_GRACE_END_FORCED, &nn->flags);
nn->client_tracking_active = false;
nn->nfsd4_manager.block_opens = true;
INIT_LIST_HEAD(&nn->nfsd4_manager.list);
@@ -9062,7 +9070,8 @@ nfs4_state_start_net(struct net *net)
spin_lock(&nn->client_lock);
nn->client_tracking_active = true;
spin_unlock(&nn->client_lock);
- if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0)
+ if (test_bit(NFSD_NET_TRACK_RECLAIM_COMPLETES, &nn->flags) &&
+ nn->reclaim_str_hashtbl_size == 0)
goto skip_grace;
printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n",
nn->nfsd4_grace, net->ns.inum);
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 16fd95a23e113..5646e07b74c3b 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -301,7 +301,7 @@ static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb);
mutex_lock(&nfsd_mutex);
nn = net_generic(netns(file), nfsd_net_id);
- if (nn->nfsd_net_up)
+ if (test_bit(NFSD_NET_UP, &nn->flags))
nfsd4_revoke_states(nn, path.dentry->d_sb);
else
error = -EINVAL;
@@ -1150,7 +1150,7 @@ static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size)
}
return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%c\n",
- nn->grace_ended ? 'Y' : 'N');
+ test_bit(NFSD_NET_GRACE_ENDED, &nn->flags) ? 'Y' : 'N');
}
#endif
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 57754dfacf9cb..1927fbf26d56d 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -381,7 +381,7 @@ static int nfsd_startup_net(struct net *net, const struct cred *cred)
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
int ret;
- if (nn->nfsd_net_up)
+ if (test_bit(NFSD_NET_UP, &nn->flags))
return 0;
ret = nfsd_startup_generic();
@@ -391,11 +391,11 @@ static int nfsd_startup_net(struct net *net, const struct cred *cred)
if (ret)
goto out_socks;
- if (nfsd_needs_lockd(nn) && !nn->lockd_up) {
+ if (nfsd_needs_lockd(nn) && !test_bit(NFSD_NET_LOCKD_UP, &nn->flags)) {
ret = lockd_up(net, cred);
if (ret)
goto out_socks;
- nn->lockd_up = true;
+ set_bit(NFSD_NET_LOCKD_UP, &nn->flags);
}
ret = nfsd_file_cache_start_net(net);
@@ -413,7 +413,7 @@ static int nfsd_startup_net(struct net *net, const struct cred *cred)
if (ret)
goto out_reply_cache;
- nn->nfsd_net_up = true;
+ set_bit(NFSD_NET_UP, &nn->flags);
return 0;
out_reply_cache:
@@ -421,9 +421,9 @@ static int nfsd_startup_net(struct net *net, const struct cred *cred)
out_filecache:
nfsd_file_cache_shutdown_net(net);
out_lockd:
- if (nn->lockd_up) {
+ if (test_bit(NFSD_NET_LOCKD_UP, &nn->flags)) {
lockd_down(net);
- nn->lockd_up = false;
+ clear_bit(NFSD_NET_LOCKD_UP, &nn->flags);
}
out_socks:
nfsd_shutdown_generic();
@@ -434,7 +434,7 @@ static void nfsd_shutdown_net(struct net *net)
{
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
- if (nn->nfsd_net_up) {
+ if (test_bit(NFSD_NET_UP, &nn->flags)) {
percpu_ref_kill_and_confirm(&nn->nfsd_net_ref, nfsd_net_done);
wait_for_completion(&nn->nfsd_net_confirm_done);
@@ -442,18 +442,18 @@ static void nfsd_shutdown_net(struct net *net)
nfs4_state_shutdown_net(net);
nfsd_reply_cache_shutdown(nn);
nfsd_file_cache_shutdown_net(net);
- if (nn->lockd_up) {
+ if (test_bit(NFSD_NET_LOCKD_UP, &nn->flags)) {
lockd_down(net);
- nn->lockd_up = false;
+ clear_bit(NFSD_NET_LOCKD_UP, &nn->flags);
}
wait_for_completion(&nn->nfsd_net_free_done);
}
percpu_ref_exit(&nn->nfsd_net_ref);
- if (nn->nfsd_net_up)
+ if (test_bit(NFSD_NET_UP, &nn->flags))
nfsd_shutdown_generic();
- nn->nfsd_net_up = false;
+ clear_bit(NFSD_NET_UP, &nn->flags);
}
static DEFINE_SPINLOCK(nfsd_notifier_lock);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 717/869] mm/hugetlb: refactor code around vmemmap_walk
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (715 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 716/869] nfsd: convert nfsd_net boolean flags to unsigned long flags word Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 718/869] mm/hugetlb: initialize gigantic bootmem hugepage struct pages earlier Greg Kroah-Hartman
` (152 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kiryl Shutsemau, Muchun Song,
Albert Ou, Alexandre Ghiti, Baoquan He, Christoph Lameter,
David Hildenbrand (arm), David Rientjes, Frank van der Linden,
Harry Yoo, Huacai Chen, Johannes Weiner, Jonathan Corbet,
Lorenzo Stoakes, Matthew Wilcox (Oracle), Michal Hocko,
Mike Rapoport, Oscar Salvador, Palmer Dabbelt, Paul Walmsley,
Roman Gushchin, Usama Arif, Vlastimil Babka, WANG Xuerui, Zi Yan,
Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiryl Shutsemau <kas@kernel.org>
[ Upstream commit c0b495b91a47b6c5ee54cf00e620dbadeb884253 ]
To prepare for removing fake head pages, the vmemmap_walk code is being
reworked.
The reuse_page and reuse_addr variables are being eliminated. There will
no longer be an expectation regarding the reuse address in relation to the
operated range. Instead, the caller will provide head and tail vmemmap
pages.
Currently, vmemmap_head and vmemmap_tail are set to the same page, but
this will change in the future.
The only functional change is that __hugetlb_vmemmap_optimize_folio() will
abandon optimization if memory allocation fails.
Link: https://lkml.kernel.org/r/20260227194302.274384-11-kas@kernel.org
Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
Reviewed-by: Muchun Song <muchun.song@linux.dev>
Cc: Albert Ou <aou@eecs.berkeley.edu>
Cc: Alexandre Ghiti <alex@ghiti.fr>
Cc: Baoquan He <bhe@redhat.com>
Cc: Christoph Lameter <cl@gentwo.org>
Cc: David Hildenbrand (arm) <david@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Frank van der Linden <fvdl@google.com>
Cc: Harry Yoo <harry.yoo@oracle.com>
Cc: Huacai Chen <chenhuacai@kernel.org>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Paul Walmsley <paul.walmsley@sifive.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Usama Arif <usamaarif642@gmail.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: WANG Xuerui <kernel@xen0n.name>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Stable-dep-of: b1b7c045e808 ("mm/hugetlb: initialize gigantic bootmem hugepage struct pages earlier")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/hugetlb_vmemmap.c | 224 +++++++++++++++++--------------------------
1 file changed, 89 insertions(+), 135 deletions(-)
diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c
index 95496e9358430..1394c13c1516f 100644
--- a/mm/hugetlb_vmemmap.c
+++ b/mm/hugetlb_vmemmap.c
@@ -24,8 +24,8 @@
*
* @remap_pte: called for each lowest-level entry (PTE).
* @nr_walked: the number of walked pte.
- * @reuse_page: the page which is reused for the tail vmemmap pages.
- * @reuse_addr: the virtual address of the @reuse_page page.
+ * @vmemmap_head: the page to be installed as first in the vmemmap range
+ * @vmemmap_tail: the page to be installed as non-first in the vmemmap range
* @vmemmap_pages: the list head of the vmemmap pages that can be freed
* or is mapped from.
* @flags: used to modify behavior in vmemmap page table walking
@@ -34,11 +34,13 @@
struct vmemmap_remap_walk {
void (*remap_pte)(pte_t *pte, unsigned long addr,
struct vmemmap_remap_walk *walk);
+
unsigned long nr_walked;
- struct page *reuse_page;
- unsigned long reuse_addr;
+ struct page *vmemmap_head;
+ struct page *vmemmap_tail;
struct list_head *vmemmap_pages;
+
/* Skip the TLB flush when we split the PMD */
#define VMEMMAP_SPLIT_NO_TLB_FLUSH BIT(0)
/* Skip the TLB flush when we remap the PTE */
@@ -140,14 +142,7 @@ static int vmemmap_pte_entry(pte_t *pte, unsigned long addr,
{
struct vmemmap_remap_walk *vmemmap_walk = walk->private;
- /*
- * The reuse_page is found 'first' in page table walking before
- * starting remapping.
- */
- if (!vmemmap_walk->reuse_page)
- vmemmap_walk->reuse_page = pte_page(ptep_get(pte));
- else
- vmemmap_walk->remap_pte(pte, addr, vmemmap_walk);
+ vmemmap_walk->remap_pte(pte, addr, vmemmap_walk);
vmemmap_walk->nr_walked++;
return 0;
@@ -207,18 +202,12 @@ static void free_vmemmap_page_list(struct list_head *list)
static void vmemmap_remap_pte(pte_t *pte, unsigned long addr,
struct vmemmap_remap_walk *walk)
{
- /*
- * Remap the tail pages as read-only to catch illegal write operation
- * to the tail pages.
- */
- pgprot_t pgprot = PAGE_KERNEL_RO;
struct page *page = pte_page(ptep_get(pte));
pte_t entry;
/* Remapping the head page requires r/w */
- if (unlikely(addr == walk->reuse_addr)) {
- pgprot = PAGE_KERNEL;
- list_del(&walk->reuse_page->lru);
+ if (unlikely(walk->nr_walked == 0 && walk->vmemmap_head)) {
+ list_del(&walk->vmemmap_head->lru);
/*
* Makes sure that preceding stores to the page contents from
@@ -226,53 +215,50 @@ static void vmemmap_remap_pte(pte_t *pte, unsigned long addr,
* write.
*/
smp_wmb();
+
+ entry = mk_pte(walk->vmemmap_head, PAGE_KERNEL);
+ } else {
+ /*
+ * Remap the tail pages as read-only to catch illegal write
+ * operation to the tail pages.
+ */
+ entry = mk_pte(walk->vmemmap_tail, PAGE_KERNEL_RO);
}
- entry = mk_pte(walk->reuse_page, pgprot);
list_add(&page->lru, walk->vmemmap_pages);
set_pte_at(&init_mm, addr, pte, entry);
}
-/*
- * How many struct page structs need to be reset. When we reuse the head
- * struct page, the special metadata (e.g. page->flags or page->mapping)
- * cannot copy to the tail struct page structs. The invalid value will be
- * checked in the free_tail_page_prepare(). In order to avoid the message
- * of "corrupted mapping in tail page". We need to reset at least 4 (one
- * head struct page struct and three tail struct page structs) struct page
- * structs.
- */
-#define NR_RESET_STRUCT_PAGE 4
-
-static inline void reset_struct_pages(struct page *start)
-{
- struct page *from = start + NR_RESET_STRUCT_PAGE;
-
- BUILD_BUG_ON(NR_RESET_STRUCT_PAGE * 2 > PAGE_SIZE / sizeof(struct page));
- memcpy(start, from, sizeof(*from) * NR_RESET_STRUCT_PAGE);
-}
-
static void vmemmap_restore_pte(pte_t *pte, unsigned long addr,
struct vmemmap_remap_walk *walk)
{
- pgprot_t pgprot = PAGE_KERNEL;
struct page *page;
- void *to;
-
- BUG_ON(pte_page(ptep_get(pte)) != walk->reuse_page);
+ struct page *from, *to;
page = list_first_entry(walk->vmemmap_pages, struct page, lru);
list_del(&page->lru);
+
+ /*
+ * Initialize tail pages in the newly allocated vmemmap page.
+ *
+ * There is folio-scope metadata that is encoded in the first few
+ * tail pages.
+ *
+ * Use the value last tail page in the page with the head page
+ * to initialize the rest of tail pages.
+ */
+ from = compound_head((struct page *)addr) +
+ PAGE_SIZE / sizeof(struct page) - 1;
to = page_to_virt(page);
- copy_page(to, (void *)walk->reuse_addr);
- reset_struct_pages(to);
+ for (int i = 0; i < PAGE_SIZE / sizeof(struct page); i++, to++)
+ *to = *from;
/*
* Makes sure that preceding stores to the page contents become visible
* before the set_pte_at() write.
*/
smp_wmb();
- set_pte_at(&init_mm, addr, pte, mk_pte(page, pgprot));
+ set_pte_at(&init_mm, addr, pte, mk_pte(page, PAGE_KERNEL));
}
/**
@@ -282,33 +268,28 @@ static void vmemmap_restore_pte(pte_t *pte, unsigned long addr,
* to remap.
* @end: end address of the vmemmap virtual address range that we want to
* remap.
- * @reuse: reuse address.
- *
* Return: %0 on success, negative error code otherwise.
*/
-static int vmemmap_remap_split(unsigned long start, unsigned long end,
- unsigned long reuse)
+static int vmemmap_remap_split(unsigned long start, unsigned long end)
{
struct vmemmap_remap_walk walk = {
.remap_pte = NULL,
.flags = VMEMMAP_SPLIT_NO_TLB_FLUSH,
};
- /* See the comment in the vmemmap_remap_free(). */
- BUG_ON(start - reuse != PAGE_SIZE);
-
- return vmemmap_remap_range(reuse, end, &walk);
+ return vmemmap_remap_range(start, end, &walk);
}
/**
* vmemmap_remap_free - remap the vmemmap virtual address range [@start, @end)
- * to the page which @reuse is mapped to, then free vmemmap
- * which the range are mapped to.
+ * to use @vmemmap_head/tail, then free vmemmap which
+ * the range are mapped to.
* @start: start address of the vmemmap virtual address range that we want
* to remap.
* @end: end address of the vmemmap virtual address range that we want to
* remap.
- * @reuse: reuse address.
+ * @vmemmap_head: the page to be installed as first in the vmemmap range
+ * @vmemmap_tail: the page to be installed as non-first in the vmemmap range
* @vmemmap_pages: list to deposit vmemmap pages to be freed. It is callers
* responsibility to free pages.
* @flags: modifications to vmemmap_remap_walk flags
@@ -316,69 +297,38 @@ static int vmemmap_remap_split(unsigned long start, unsigned long end,
* Return: %0 on success, negative error code otherwise.
*/
static int vmemmap_remap_free(unsigned long start, unsigned long end,
- unsigned long reuse,
+ struct page *vmemmap_head,
+ struct page *vmemmap_tail,
struct list_head *vmemmap_pages,
unsigned long flags)
{
int ret;
struct vmemmap_remap_walk walk = {
.remap_pte = vmemmap_remap_pte,
- .reuse_addr = reuse,
+ .vmemmap_head = vmemmap_head,
+ .vmemmap_tail = vmemmap_tail,
.vmemmap_pages = vmemmap_pages,
.flags = flags,
};
- int nid = page_to_nid((struct page *)reuse);
- gfp_t gfp_mask = GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN;
- /*
- * Allocate a new head vmemmap page to avoid breaking a contiguous
- * block of struct page memory when freeing it back to page allocator
- * in free_vmemmap_page_list(). This will allow the likely contiguous
- * struct page backing memory to be kept contiguous and allowing for
- * more allocations of hugepages. Fallback to the currently
- * mapped head page in case should it fail to allocate.
- */
- walk.reuse_page = alloc_pages_node(nid, gfp_mask, 0);
- if (walk.reuse_page) {
- copy_page(page_to_virt(walk.reuse_page),
- (void *)walk.reuse_addr);
- list_add(&walk.reuse_page->lru, vmemmap_pages);
- memmap_pages_add(1);
- }
+ ret = vmemmap_remap_range(start, end, &walk);
+ if (!ret || !walk.nr_walked)
+ return ret;
+
+ end = start + walk.nr_walked * PAGE_SIZE;
/*
- * In order to make remapping routine most efficient for the huge pages,
- * the routine of vmemmap page table walking has the following rules
- * (see more details from the vmemmap_pte_range()):
- *
- * - The range [@start, @end) and the range [@reuse, @reuse + PAGE_SIZE)
- * should be continuous.
- * - The @reuse address is part of the range [@reuse, @end) that we are
- * walking which is passed to vmemmap_remap_range().
- * - The @reuse address is the first in the complete range.
- *
- * So we need to make sure that @start and @reuse meet the above rules.
+ * vmemmap_pages contains pages from the previous vmemmap_remap_range()
+ * call which failed. These are pages which were removed from
+ * the vmemmap. They will be restored in the following call.
*/
- BUG_ON(start - reuse != PAGE_SIZE);
+ walk = (struct vmemmap_remap_walk) {
+ .remap_pte = vmemmap_restore_pte,
+ .vmemmap_pages = vmemmap_pages,
+ .flags = 0,
+ };
- ret = vmemmap_remap_range(reuse, end, &walk);
- if (ret && walk.nr_walked) {
- end = reuse + walk.nr_walked * PAGE_SIZE;
- /*
- * vmemmap_pages contains pages from the previous
- * vmemmap_remap_range call which failed. These
- * are pages which were removed from the vmemmap.
- * They will be restored in the following call.
- */
- walk = (struct vmemmap_remap_walk) {
- .remap_pte = vmemmap_restore_pte,
- .reuse_addr = reuse,
- .vmemmap_pages = vmemmap_pages,
- .flags = 0,
- };
-
- vmemmap_remap_range(reuse, end, &walk);
- }
+ vmemmap_remap_range(start, end, &walk);
return ret;
}
@@ -415,29 +365,24 @@ static int alloc_vmemmap_page_list(unsigned long start, unsigned long end,
* to remap.
* @end: end address of the vmemmap virtual address range that we want to
* remap.
- * @reuse: reuse address.
* @flags: modifications to vmemmap_remap_walk flags
*
* Return: %0 on success, negative error code otherwise.
*/
static int vmemmap_remap_alloc(unsigned long start, unsigned long end,
- unsigned long reuse, unsigned long flags)
+ unsigned long flags)
{
LIST_HEAD(vmemmap_pages);
struct vmemmap_remap_walk walk = {
.remap_pte = vmemmap_restore_pte,
- .reuse_addr = reuse,
.vmemmap_pages = &vmemmap_pages,
.flags = flags,
};
- /* See the comment in the vmemmap_remap_free(). */
- BUG_ON(start - reuse != PAGE_SIZE);
-
if (alloc_vmemmap_page_list(start, end, &vmemmap_pages))
return -ENOMEM;
- return vmemmap_remap_range(reuse, end, &walk);
+ return vmemmap_remap_range(start, end, &walk);
}
DEFINE_STATIC_KEY_FALSE(hugetlb_optimize_vmemmap_key);
@@ -450,8 +395,7 @@ static int __hugetlb_vmemmap_restore_folio(const struct hstate *h,
struct folio *folio, unsigned long flags)
{
int ret;
- unsigned long vmemmap_start = (unsigned long)&folio->page, vmemmap_end;
- unsigned long vmemmap_reuse;
+ unsigned long vmemmap_start, vmemmap_end;
VM_WARN_ON_ONCE_FOLIO(!folio_test_hugetlb(folio), folio);
VM_WARN_ON_ONCE_FOLIO(folio_ref_count(folio), folio);
@@ -462,18 +406,18 @@ static int __hugetlb_vmemmap_restore_folio(const struct hstate *h,
if (flags & VMEMMAP_SYNCHRONIZE_RCU)
synchronize_rcu();
+ vmemmap_start = (unsigned long)&folio->page;
vmemmap_end = vmemmap_start + hugetlb_vmemmap_size(h);
- vmemmap_reuse = vmemmap_start;
+
vmemmap_start += HUGETLB_VMEMMAP_RESERVE_SIZE;
/*
* The pages which the vmemmap virtual address range [@vmemmap_start,
- * @vmemmap_end) are mapped to are freed to the buddy allocator, and
- * the range is mapped to the page which @vmemmap_reuse is mapped to.
+ * @vmemmap_end) are mapped to are freed to the buddy allocator.
* When a HugeTLB page is freed to the buddy allocator, previously
* discarded vmemmap pages must be allocated and remapping.
*/
- ret = vmemmap_remap_alloc(vmemmap_start, vmemmap_end, vmemmap_reuse, flags);
+ ret = vmemmap_remap_alloc(vmemmap_start, vmemmap_end, flags);
if (!ret) {
folio_clear_hugetlb_vmemmap_optimized(folio);
static_branch_dec(&hugetlb_optimize_vmemmap_key);
@@ -561,9 +505,9 @@ static int __hugetlb_vmemmap_optimize_folio(const struct hstate *h,
struct list_head *vmemmap_pages,
unsigned long flags)
{
- int ret = 0;
- unsigned long vmemmap_start = (unsigned long)&folio->page, vmemmap_end;
- unsigned long vmemmap_reuse;
+ unsigned long vmemmap_start, vmemmap_end;
+ struct page *vmemmap_head, *vmemmap_tail;
+ int nid, ret = 0;
VM_WARN_ON_ONCE_FOLIO(!folio_test_hugetlb(folio), folio);
VM_WARN_ON_ONCE_FOLIO(folio_ref_count(folio), folio);
@@ -588,18 +532,30 @@ static int __hugetlb_vmemmap_optimize_folio(const struct hstate *h,
*/
folio_set_hugetlb_vmemmap_optimized(folio);
+ nid = folio_nid(folio);
+ vmemmap_head = alloc_pages_node(nid, GFP_KERNEL, 0);
+ if (!vmemmap_head) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ copy_page(page_to_virt(vmemmap_head), folio);
+ list_add(&vmemmap_head->lru, vmemmap_pages);
+ memmap_pages_add(1);
+
+ vmemmap_tail = vmemmap_head;
+ vmemmap_start = (unsigned long)&folio->page;
vmemmap_end = vmemmap_start + hugetlb_vmemmap_size(h);
- vmemmap_reuse = vmemmap_start;
- vmemmap_start += HUGETLB_VMEMMAP_RESERVE_SIZE;
/*
- * Remap the vmemmap virtual address range [@vmemmap_start, @vmemmap_end)
- * to the page which @vmemmap_reuse is mapped to. Add pages previously
- * mapping the range to vmemmap_pages list so that they can be freed by
- * the caller.
+ * Remap the vmemmap virtual address range [@vmemmap_start, @vmemmap_end).
+ * Add pages previously mapping the range to vmemmap_pages list so that
+ * they can be freed by the caller.
*/
- ret = vmemmap_remap_free(vmemmap_start, vmemmap_end, vmemmap_reuse,
+ ret = vmemmap_remap_free(vmemmap_start, vmemmap_end,
+ vmemmap_head, vmemmap_tail,
vmemmap_pages, flags);
+out:
if (ret) {
static_branch_dec(&hugetlb_optimize_vmemmap_key);
folio_clear_hugetlb_vmemmap_optimized(folio);
@@ -628,21 +584,19 @@ void hugetlb_vmemmap_optimize_folio(const struct hstate *h, struct folio *folio)
static int hugetlb_vmemmap_split_folio(const struct hstate *h, struct folio *folio)
{
- unsigned long vmemmap_start = (unsigned long)&folio->page, vmemmap_end;
- unsigned long vmemmap_reuse;
+ unsigned long vmemmap_start, vmemmap_end;
if (!vmemmap_should_optimize_folio(h, folio))
return 0;
+ vmemmap_start = (unsigned long)&folio->page;
vmemmap_end = vmemmap_start + hugetlb_vmemmap_size(h);
- vmemmap_reuse = vmemmap_start;
- vmemmap_start += HUGETLB_VMEMMAP_RESERVE_SIZE;
/*
* Split PMDs on the vmemmap virtual address range [@vmemmap_start,
* @vmemmap_end]
*/
- return vmemmap_remap_split(vmemmap_start, vmemmap_end, vmemmap_reuse);
+ return vmemmap_remap_split(vmemmap_start, vmemmap_end);
}
void hugetlb_vmemmap_optimize_folios(struct hstate *h, struct list_head *folio_list)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 718/869] mm/hugetlb: initialize gigantic bootmem hugepage struct pages earlier
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (716 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 717/869] mm/hugetlb: refactor code around vmemmap_walk Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 719/869] ACPI: bus: Introduce acpi_bus_get_primary_device() Greg Kroah-Hartman
` (151 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Muchun Song,
Mike Rapoport (Microsoft), Oscar Salvador, Aneesh Kumar K.V,
David Hildenbrand, Frank van der Linden, Liam R. Howlett,
Lorenzo Stoakes, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Oscar Salvador (SUSE), Ritesh Harjani (IBM),
Usama Arif, Vlastimil Babka, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muchun Song <songmuchun@bytedance.com>
[ Upstream commit b1b7c045e808c761b1cc8c19b3040fadedda3fef ]
Gigantic bootmem HugeTLB pages are currently initialized from
hugetlb_init(), but page_alloc_init_late() runs earlier and walks
pageblocks to determine zone contiguity.
If a bootmem HugeTLB region is marked noinit, set_zone_contiguous() can
observe still-uninitialized struct pages through
__pageblock_pfn_to_page(). This may not trigger an immediate failure, but
it can make set_zone_contiguous() compute the wrong zone contiguity state.
If extra poisoned-page checks are added in this path, such as
PF_POISONED_CHECK() in page_zone_id(), it can also trigger an early boot
panic.
Initialize gigantic bootmem HugeTLB struct pages from
page_alloc_init_late(), before zone contiguity is evaluated, so later page
allocator setup only sees valid struct page state. This also makes the
initialization order more natural, as struct pages should be initialized
before later code inspects them.
Link: https://lore.kernel.org/20260612035903.2468601-5-songmuchun@bytedance.com
Fixes: fde1c4ecf916 ("mm: hugetlb: skip initialization of gigantic tail struct pages if freed by HVO")
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: Oscar Salvador <osalvador@suse.de>
Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.ibm.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: Frank van der Linden <fvdl@google.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oscar Salvador (SUSE) <osalvador@kernel.org>
Cc: "Ritesh Harjani (IBM)" <ritesh.list@gmail.com>
Cc: Usama Arif <usama.arif@linux.dev>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/hugetlb.h | 6 ++++++
mm/hugetlb.c | 9 ++++++---
mm/mm_init.c | 2 ++
3 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index dfea039a1dc89..7eaabacdf1105 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -172,6 +172,8 @@ struct address_space *hugetlb_folio_mapping_lock_write(struct folio *folio);
extern int sysctl_hugetlb_shm_group;
extern struct list_head huge_boot_pages[MAX_NUMNODES];
+void hugetlb_bootmem_struct_page_init(void);
+
/* arch callbacks */
#ifndef CONFIG_HIGHPTE
@@ -1265,6 +1267,10 @@ static inline bool hugetlbfs_pagecache_present(
{
return false;
}
+
+static inline void hugetlb_bootmem_struct_page_init(void)
+{
+}
#endif /* CONFIG_HUGETLB_PAGE */
static inline spinlock_t *huge_pte_lock(struct hstate *h,
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 7fccb866dab96..68e0cc0748cac 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -3260,6 +3260,10 @@ static void __init gather_bootmem_prealloc_node(unsigned long nid)
struct huge_bootmem_page *m;
struct hstate *h = NULL, *prev_h = NULL;
+ /* The lists are only initialized once a gigantic hstate was allocated. */
+ if (!huge_boot_pages[nid].next)
+ return;
+
list_for_each_entry(m, &huge_boot_pages[nid], list) {
struct page *page = virt_to_page(m);
struct folio *folio = (void *)page;
@@ -3302,7 +3306,7 @@ static void __init gather_bootmem_prealloc_parallel(unsigned long start,
gather_bootmem_prealloc_node(nid);
}
-static void __init gather_bootmem_prealloc(void)
+void __init hugetlb_bootmem_struct_page_init(void)
{
struct padata_mt_job job = {
.thread_fn = gather_bootmem_prealloc_parallel,
@@ -3457,7 +3461,7 @@ static unsigned long __init hugetlb_pages_alloc_boot(struct hstate *h)
* - For gigantic pages, this is called early in the boot process and
* pages are allocated from memblock allocated or something similar.
* Gigantic pages are actually added to pools later with the routine
- * gather_bootmem_prealloc.
+ * hugetlb_bootmem_struct_page_init.
* - For non-gigantic pages, this is called later in the boot process after
* all of mm is up and functional. Pages are allocated from buddy and
* then added to hugetlb pools.
@@ -4496,7 +4500,6 @@ static int __init hugetlb_init(void)
hugetlb_cma_check();
hugetlb_init_hstates();
- gather_bootmem_prealloc();
report_hugepages();
hugetlb_sysfs_init();
diff --git a/mm/mm_init.c b/mm/mm_init.c
index 65f997ddd740d..77f5f62628b71 100644
--- a/mm/mm_init.c
+++ b/mm/mm_init.c
@@ -29,6 +29,7 @@
#include <linux/cma.h>
#include <linux/crash_dump.h>
#include <linux/execmem.h>
+#include <linux/hugetlb.h>
#include <linux/vmstat.h>
#include "internal.h"
#include "slab.h"
@@ -2320,6 +2321,7 @@ void __init page_alloc_init_late(void)
/* Reinit limits that are based on free pages after the kernel is up */
files_maxfiles_init();
#endif
+ hugetlb_bootmem_struct_page_init();
/* Accounting of total+free memory is stable at this point. */
mem_init_print_info();
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 719/869] ACPI: bus: Introduce acpi_bus_get_primary_device()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (717 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 718/869] mm/hugetlb: initialize gigantic bootmem hugepage struct pages earlier Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 720/869] powerpc/xive: add error return value to xive_smp_probe() Greg Kroah-Hartman
` (150 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rafael J. Wysocki, Andy Shevchenko,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
[ Upstream commit 72530e1f72b0515a73fd88292254d04fecf03649 ]
The function used for obtaining the first "physical" device for which
the given ACPI one is the ACPI companion, acpi_get_first_physical_node(),
may return a stale device pointer (mostly in theory) because
acpi_unbind_one() may run as a whole after dropping the ACPI device's
physical_node_lock in acpi_get_first_physical_node() and before it
returns. The last reference to the "physical" device may be dropped
then before the pointer to it is returned to the caller.
If that happens and the acpi_get_first_physical_node() caller invokes
get_device() on the pointer obtained from it, which is done by the
majority of its callers, a use-after-free will occur.
To prepare for addressing this problem, introduce a new function for
getting the first "physical" device associated with the given ACPI one
(the "primary physical device") that will also reference count the
device in question before returning a pointer to it.
Make that new function and acpi_get_first_physical_node() share the
physical node list lookup code.
No intentional functional impact.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://patch.msgid.link/2843318.mvXUDI8C0e@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/acpi/bus.c | 54 +++++++++++++++++++++++++++++------------
include/acpi/acpi_bus.h | 6 +++++
2 files changed, 44 insertions(+), 16 deletions(-)
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 9deb98c0a6fee..da0d6628ee417 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -747,30 +747,52 @@ static int __init acpi_setup_sb_notify_handler(void)
Device Matching
-------------------------------------------------------------------------- */
+
+static struct device *primary_physical_device(struct acpi_device *adev)
+{
+ struct acpi_device_physical_node *pn;
+
+ pn = list_first_entry_or_null(&adev->physical_node_list,
+ struct acpi_device_physical_node, node);
+ if (pn)
+ return pn->dev;
+
+ return NULL;
+}
+
/**
- * acpi_get_first_physical_node - Get first physical node of an ACPI device
+ * acpi_bus_get_primary_device - Get first physical device for a given ACPI one
+ * @adev: ACPI device to get the first physical device for.
+ *
+ * Find the first physical device for which @adev is the ACPI companion and
+ * reference count it if present.
+ *
+ * Return: Pointer to the first physical counterpart of @adev or NULL if there
+ * are none. Callers are responsible for invoking put_device() on the returned
+ * device.
+ */
+struct device *acpi_bus_get_primary_device(struct acpi_device *adev)
+{
+ if (!adev)
+ return NULL;
+
+ guard(mutex)(&adev->physical_node_lock);
+
+ return get_device(primary_physical_device(adev));
+}
+EXPORT_SYMBOL_GPL(acpi_bus_get_primary_device);
+
+/**
+ * acpi_get_first_physical_node - Find first physical node of an ACPI device
* @adev: ACPI device in question
*
* Return: First physical node of ACPI device @adev
*/
struct device *acpi_get_first_physical_node(struct acpi_device *adev)
{
- struct mutex *physical_node_lock = &adev->physical_node_lock;
- struct device *phys_dev;
-
- mutex_lock(physical_node_lock);
- if (list_empty(&adev->physical_node_list)) {
- phys_dev = NULL;
- } else {
- const struct acpi_device_physical_node *node;
+ guard(mutex)(&adev->physical_node_lock);
- node = list_first_entry(&adev->physical_node_list,
- struct acpi_device_physical_node, node);
-
- phys_dev = node->dev;
- }
- mutex_unlock(physical_node_lock);
- return phys_dev;
+ return primary_physical_device(adev);
}
EXPORT_SYMBOL_GPL(acpi_get_first_physical_node);
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 2aa34fcc10a15..b8cf06904fa20 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -677,6 +677,7 @@ void acpi_bus_unregister_driver(struct acpi_driver *driver);
int acpi_bus_scan(acpi_handle handle);
void acpi_bus_trim(struct acpi_device *start);
acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd);
+struct device *acpi_bus_get_primary_device(struct acpi_device *adev);
int acpi_match_device_ids(struct acpi_device *device,
const struct acpi_device_id *ids);
void acpi_set_modalias(struct acpi_device *adev, const char *default_id,
@@ -1000,6 +1001,11 @@ int acpi_scan_add_dep(acpi_handle handle, struct acpi_handle_list *dep_devices);
u32 arch_acpi_add_auto_dep(acpi_handle handle);
#else /* CONFIG_ACPI */
+static inline struct device *acpi_bus_get_primary_device(struct acpi_device *adev)
+{
+ return NULL;
+}
+
static inline int register_acpi_bus_type(void *bus) { return 0; }
static inline int unregister_acpi_bus_type(void *bus) { return 0; }
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 720/869] powerpc/xive: add error return value to xive_smp_probe()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (718 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 719/869] ACPI: bus: Introduce acpi_bus_get_primary_device() Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 721/869] powerpc/xive: propagate IPI init errors to prevent use-after-free Greg Kroah-Hartman
` (149 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Gou Hao, Wentao Guan, jiazhenyuan,
Cédric Le Goater, Madhavan Srinivasan, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gou Hao <gouhao@uniontech.com>
[ Upstream commit ab5ae5dceb86614f6c9e7488f91b652000edfdc5 ]
xive_smp_probe() calls xive_init_ipis() which can fail, but its
return value is currently ignored. Change xive_smp_probe() to
return int so that errors can be propagated to callers.
This is a preparatory patch for the next one.
No functional change yet; the return value is always 0 at this point.
Signed-off-by: Gou Hao <gouhao@uniontech.com>
Reviewed-by: Wentao Guan <guanwentao@uniontech.com>
Reviewed-by: jiazhenyuan <jiazhenyuan@uniontech.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/20260727104215.184786-3-gouhao@uniontech.com
Stable-dep-of: 411a3c016e7a ("powerpc/xive: propagate IPI init errors to prevent use-after-free")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/powerpc/include/asm/xive.h | 4 ++--
arch/powerpc/sysdev/xive/common.c | 4 +++-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/include/asm/xive.h b/arch/powerpc/include/asm/xive.h
index 92930b0b5d0e1..8ac7c1d3564fc 100644
--- a/arch/powerpc/include/asm/xive.h
+++ b/arch/powerpc/include/asm/xive.h
@@ -91,7 +91,7 @@ static inline bool xive_enabled(void) { return __xive_enabled; }
bool xive_spapr_init(void);
bool xive_native_init(void);
-void xive_smp_probe(void);
+int xive_smp_probe(void);
int xive_smp_prepare_cpu(unsigned int cpu);
void xive_smp_setup_cpu(void);
void xive_smp_disable_cpu(void);
@@ -154,7 +154,7 @@ static inline bool xive_enabled(void) { return false; }
static inline bool xive_spapr_init(void) { return false; }
static inline bool xive_native_init(void) { return false; }
-static inline void xive_smp_probe(void) { }
+static inline int xive_smp_probe(void) { return -EINVAL; }
static inline int xive_smp_prepare_cpu(unsigned int cpu) { return -EINVAL; }
static inline void xive_smp_setup_cpu(void) { }
static inline void xive_smp_disable_cpu(void) { }
diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c
index fa01818c1972c..8665431e23217 100644
--- a/arch/powerpc/sysdev/xive/common.c
+++ b/arch/powerpc/sysdev/xive/common.c
@@ -1270,7 +1270,7 @@ noinstr static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc)
xive_ops->put_ipi(cpu, xc);
}
-void __init xive_smp_probe(void)
+int __init xive_smp_probe(void)
{
smp_ops->cause_ipi = xive_cause_ipi;
@@ -1279,6 +1279,8 @@ void __init xive_smp_probe(void)
/* Allocate and setup IPI for the boot CPU */
xive_setup_cpu_ipi(smp_processor_id());
+
+ return 0;
}
#endif /* CONFIG_SMP */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 721/869] powerpc/xive: propagate IPI init errors to prevent use-after-free
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (719 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 720/869] powerpc/xive: add error return value to xive_smp_probe() Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 722/869] remoteproc: qcom_wcnss: Fix handling the lack of PD regulators in v3 Greg Kroah-Hartman
` (148 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Gou Hao, Wentao Guan, jiazhenyuan,
Cédric Le Goater, Madhavan Srinivasan, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gou Hao <gouhao@uniontech.com>
[ Upstream commit 411a3c016e7a95f5fa105a0587e07d0647a77727 ]
When xive_init_ipis() fails (e.g. irq_domain_alloc_irqs() fails),
the error path frees the global xive_ipis array. However,
xive_smp_probe() previously ignored this failure and proceeded to
call xive_setup_cpu_ipi(), which dereferences the already-freed
xive_ipis pointer -- a use-after-free.
Now that xive_smp_probe() returns int (previous patch), propagate
the error from xive_init_ipis() and xive_setup_cpu_ipi() through
xive_smp_probe(). Check the return value in both pnv_smp_probe()
and pSeries_smp_probe() so that IPI setup is aborted cleanly on
failure, avoiding the use-after-free.
Fixes: 243e25112d06 ("powerpc/xive: Native exploitation of the XIVE interrupt controller")
Fixes: cbc06f051c52 ("powerpc/xive: Do not skip CPU-less nodes when creating the IPIs")
Signed-off-by: Gou Hao <gouhao@uniontech.com>
Reviewed-by: Wentao Guan <guanwentao@uniontech.com>
Reviewed-by: jiazhenyuan <jiazhenyuan@uniontech.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/20260727104215.184786-4-gouhao@uniontech.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/powerpc/platforms/powernv/smp.c | 8 +++++---
arch/powerpc/platforms/pseries/smp.c | 8 +++++---
arch/powerpc/sysdev/xive/common.c | 10 ++++++----
3 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index 8f14f0581a21b..6fd88c5a55e14 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -329,10 +329,12 @@ static void pnv_cause_ipi(int cpu)
static void __init pnv_smp_probe(void)
{
- if (xive_enabled())
- xive_smp_probe();
- else
+ if (xive_enabled()) {
+ if (xive_smp_probe() < 0)
+ return;
+ } else {
xics_smp_probe();
+ }
if (cpu_has_feature(CPU_FTR_DBELL)) {
ic_cause_ipi = smp_ops->cause_ipi;
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index c597711ef20a2..0d9b0b901807e 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -194,10 +194,12 @@ static int pseries_cause_nmi_ipi(int cpu)
static __init void pSeries_smp_probe(void)
{
- if (xive_enabled())
- xive_smp_probe();
- else
+ if (xive_enabled()) {
+ if (xive_smp_probe() < 0)
+ return;
+ } else {
xics_smp_probe();
+ }
/* No doorbell facility, must use the interrupt controller for IPIs */
if (!cpu_has_feature(CPU_FTR_DBELL))
diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c
index 8665431e23217..f42ace1095934 100644
--- a/arch/powerpc/sysdev/xive/common.c
+++ b/arch/powerpc/sysdev/xive/common.c
@@ -1272,15 +1272,17 @@ noinstr static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc)
int __init xive_smp_probe(void)
{
+ int ret;
+
smp_ops->cause_ipi = xive_cause_ipi;
/* Register the IPI */
- xive_init_ipis();
+ ret = xive_init_ipis();
+ if (ret < 0)
+ return ret;
/* Allocate and setup IPI for the boot CPU */
- xive_setup_cpu_ipi(smp_processor_id());
-
- return 0;
+ return xive_setup_cpu_ipi(smp_processor_id());
}
#endif /* CONFIG_SMP */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 722/869] remoteproc: qcom_wcnss: Fix handling the lack of PD regulators in v3
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (720 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 721/869] powerpc/xive: propagate IPI init errors to prevent use-after-free Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 723/869] ksmbd: remove redundant DACL check in smb_check_perm_dacl Greg Kroah-Hartman
` (147 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Val Packett, Konrad Dybcio,
Bjorn Andersson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Val Packett <val@packett.cool>
[ Upstream commit 3dbc90b9c22ea96e37bf55f6011e63b5123ec668 ]
The changes introduced to handle single power domain platforms have
swapped the info pointer increment from num_pd_vregs to num_pds, which
would shift the info pointer past the end of the array for pronto-v3,
which does not list power domain regulators in vregs.
This showed up as a difference between GCC- and LLVM-compiled kernels
on SDM632 devices, where only with LLVM one would get the
"regulator request with no identifier" error, because the out-of-bounds
memory ended up being zeroed. Fix by skipping the increment when there
are more power domains than regulators.
Signed-off-by: Val Packett <val@packett.cool>
Fixes: 65991ea8a6d1 ("remoteproc: qcom_wcnss: Handle platforms with only single power domain")
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Fixes: 65991ea8a6d1 ("remoteproc: qcom_wcnss: Handle platforms with only single power domain")
Link: https://lore.kernel.org/r/20260201210230.911220-1-val@packett.cool
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/remoteproc/qcom_wcnss.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index 2c7e519a2254b..0a0eb1d7da829 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -441,25 +441,31 @@ static void wcnss_release_pds(struct qcom_wcnss *wcnss)
}
static int wcnss_init_regulators(struct qcom_wcnss *wcnss,
- const struct wcnss_vreg_info *info,
- int num_vregs, int num_pd_vregs)
+ const struct wcnss_data *data)
{
+ const struct wcnss_vreg_info *info = data->vregs;
struct regulator_bulk_data *bulk;
+ size_t i, possible_pds = 0, num_vregs = data->num_vregs;
int ret;
- int i;
+
+ for (i = 0; i < WCNSS_MAX_PDS; i++)
+ if (data->pd_names[i])
+ possible_pds++;
/*
* If attaching the power domains suceeded we can skip requesting
* the regulators for the power domains. For old device trees we need to
* reserve extra space to manage them through the regulator interface.
*/
- if (wcnss->num_pds) {
+ if (possible_pds >= num_vregs) {
+ /* Do nothing if vregs do not include PD regulators (pronto-v3) */
+ } else if (wcnss->num_pds) {
info += wcnss->num_pds;
/* Handle single power domain case */
- if (wcnss->num_pds < num_pd_vregs)
- num_vregs += num_pd_vregs - wcnss->num_pds;
+ if (wcnss->num_pds < data->num_pd_vregs)
+ num_vregs += data->num_pd_vregs - wcnss->num_pds;
} else {
- num_vregs += num_pd_vregs;
+ num_vregs += data->num_pd_vregs;
}
bulk = devm_kcalloc(wcnss->dev,
@@ -612,8 +618,7 @@ static int wcnss_probe(struct platform_device *pdev)
if (ret && (ret != -ENODATA || !data->num_pd_vregs))
return ret;
- ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs,
- data->num_pd_vregs);
+ ret = wcnss_init_regulators(wcnss, data);
if (ret)
goto detach_pds;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 723/869] ksmbd: remove redundant DACL check in smb_check_perm_dacl
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (721 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 722/869] remoteproc: qcom_wcnss: Fix handling the lack of PD regulators in v3 Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 724/869] ksmbd: fix maximum allowed access checks Greg Kroah-Hartman
` (146 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alexey Velichayshiy, Namjae Jeon,
Steve French, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Velichayshiy <a.velichayshiy@ispras.ru>
[ Upstream commit 8dd2e58b62731a96e276ee0545fb910ffb2057d9 ]
A zero value of pdacl->num_aces is already handled at the start of
smb_check_perm_dacl() so the second check is useless.
Drop the unreachable code block, no functional impact intended.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Signed-off-by: Alexey Velichayshiy <a.velichayshiy@ispras.ru>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Stable-dep-of: cc2f133e80eb ("ksmbd: fix maximum allowed access checks")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/smbacl.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
index 2a46646b3a0e4..114fd2e67725d 100644
--- a/fs/smb/server/smbacl.c
+++ b/fs/smb/server/smbacl.c
@@ -1511,9 +1511,6 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
granted |= le32_to_cpu(ace->access_req);
ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size));
}
-
- if (!pdacl->num_aces)
- granted = GENERIC_ALL_FLAGS;
}
if (!uid)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 724/869] ksmbd: fix maximum allowed access checks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (722 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 723/869] ksmbd: remove redundant DACL check in smb_check_perm_dacl Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 725/869] drm/amdkfd: fix SMI event cross-process information leak Greg Kroah-Hartman
` (145 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Namjae Jeon, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit cc2f133e80eb2c4a04bfa77a2f207749fe2f516a ]
The DACL permission check looks for an ACE matching the current user and
falls back to the Everyone ACE. It does not consider an Authenticated
Users ACE, even though an authenticated session is a member of that
well-known group.
As a result, opening a file whose access is granted through S-1-5-11 can
incorrectly fail with STATUS_ACCESS_DENIED. Treat an Authenticated Users
ACE as a fallback entry alongside Everyone.
The maximal access calculation also combines access masks from every ACE,
regardless of whether its SID applies to the current user. This can grant
rights belonging to an unrelated principal. Process only ACEs applying to
the user, Everyone, or Authenticated Users, and accumulate allowed and
denied masks in ACL order. Preserve explicitly requested access bits so
they are validated against the resulting maximal mask.
When ACCESS_SYSTEM_SECURITY is denied, report STATUS_PRIVILEGE_NOT_HELD
instead of the generic STATUS_ACCESS_DENIED. Access to the system ACL
requires a security privilege that ksmbd does not grant.
For regular files, include FILE_EXECUTE in maximal access when the client
requested GENERIC_EXECUTE and the DACL grants the complete file-read set.
Keep a direct FILE_EXECUTE request subject to the explicit DACL bit. This
matches the POSIX file ACL mapping without broadening specific execute
requests.
Do not replace rights from an applicable NT ACE with a POSIX ACL entry.
The POSIX ACL is only a fallback when no user, Everyone, or Authenticated
Users ACE applies; otherwise it can incorrectly broaden the stored DACL.
This fixes smb2.maximum_allowed.maximum_allowed.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/smb2pdu.c | 9 ++++-
fs/smb/server/smbacl.c | 83 ++++++++++++++++++++++++++---------------
fs/smb/server/smbacl.h | 2 +-
3 files changed, 61 insertions(+), 33 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 6212e615aa0a1..57b908ea33016 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -3269,6 +3269,7 @@ int smb2_open(struct ksmbd_work *work)
if (file_present && !(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) {
rc = smb_check_perm_dacl(conn, &path, &daccess,
+ req->DesiredAccess,
sess->user->uid);
if (rc)
goto err_out;
@@ -3813,8 +3814,12 @@ int smb2_open(struct ksmbd_work *work)
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
else if (rc == -EOPNOTSUPP)
rsp->hdr.Status = STATUS_NOT_SUPPORTED;
- else if (rc == -EACCES || rc == -ESTALE || rc == -EXDEV)
- rsp->hdr.Status = STATUS_ACCESS_DENIED;
+ else if (rc == -EACCES || rc == -ESTALE || rc == -EXDEV) {
+ if (req->DesiredAccess & FILE_ACCESS_SYSTEM_SECURITY_LE)
+ rsp->hdr.Status = STATUS_PRIVILEGE_NOT_HELD;
+ else
+ rsp->hdr.Status = STATUS_ACCESS_DENIED;
+ }
else if (rc == -ENOENT)
rsp->hdr.Status = STATUS_OBJECT_NAME_INVALID;
else if (rc == -EPERM)
diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
index 114fd2e67725d..a4447c9c660dc 100644
--- a/fs/smb/server/smbacl.c
+++ b/fs/smb/server/smbacl.c
@@ -1445,7 +1445,7 @@ bool smb_inherit_flags(int flags, bool is_dir)
}
int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
- __le32 *pdaccess, int uid)
+ __le32 *pdaccess, __le32 raw_daccess, int uid)
{
struct mnt_idmap *idmap = mnt_idmap(path->mnt);
struct smb_ntsd *pntsd = NULL;
@@ -1455,10 +1455,11 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
unsigned int dacl_offset;
size_t dacl_struct_end;
struct smb_sid sid;
- int granted = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE);
+ int requested = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE);
+ int granted = requested;
struct smb_ace *ace;
int i, found = 0;
- unsigned int access_bits = 0;
+ unsigned int access_bits = 0, denied = 0;
struct smb_ace *others_ace = NULL;
struct posix_acl_entry *pa_entry;
unsigned int sid_type = SIDOWNER;
@@ -1492,10 +1493,13 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
goto err_out;
}
+ if (!uid)
+ sid_type = SIDUNIX_USER;
+ id_to_sid(uid, sid_type, &sid);
+
if (*pdaccess & FILE_MAXIMAL_ACCESS_LE) {
- granted = READ_CONTROL | WRITE_DAC | FILE_READ_ATTRIBUTES |
+ access_bits = READ_CONTROL | WRITE_DAC | FILE_READ_ATTRIBUTES |
DELETE;
-
ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
aces_size = pdacl_size - sizeof(struct smb_acl);
for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) {
@@ -1508,15 +1512,41 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
CIFS_SID_BASE_SIZE)
break;
aces_size -= ace_size;
- granted |= le32_to_cpu(ace->access_req);
+
+ if (ace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
+ ace_size < offsetof(struct smb_ace, sid) +
+ CIFS_SID_BASE_SIZE +
+ sizeof(__le32) * ace->sid.num_subauth)
+ break;
+
+ if (ace->flags & INHERIT_ONLY_ACE ||
+ (compare_sids(&sid, &ace->sid) &&
+ compare_sids(&sid_unix_NFS_mode, &ace->sid) &&
+ compare_sids(&sid_everyone, &ace->sid) &&
+ compare_sids(&sid_authusers, &ace->sid)))
+ goto next_ace;
+
+ switch (ace->type) {
+ case ACCESS_ALLOWED_ACE_TYPE:
+ access_bits |= le32_to_cpu(ace->access_req);
+ break;
+ case ACCESS_DENIED_ACE_TYPE:
+ case ACCESS_DENIED_CALLBACK_ACE_TYPE:
+ denied |= ~access_bits &
+ le32_to_cpu(ace->access_req);
+ break;
+ }
+next_ace:
ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size));
}
+ access_bits &= ~denied;
+ if ((raw_daccess & FILE_GENERIC_EXECUTE_LE) &&
+ S_ISREG(d_inode(path->dentry)->i_mode) &&
+ (access_bits & GENERIC_READ_FLAGS) == GENERIC_READ_FLAGS)
+ access_bits |= FILE_EXECUTE;
+ granted = requested | access_bits;
}
- if (!uid)
- sid_type = SIDUNIX_USER;
- id_to_sid(uid, sid_type, &sid);
-
ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
aces_size = pdacl_size - sizeof(struct smb_acl);
for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) {
@@ -1540,25 +1570,16 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
found = 1;
break;
}
- if (!compare_sids(&sid_everyone, &ace->sid))
+ if (!compare_sids(&sid_everyone, &ace->sid) ||
+ !compare_sids(&sid_authusers, &ace->sid))
others_ace = ace;
ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size));
}
- if (*pdaccess & FILE_MAXIMAL_ACCESS_LE && found) {
- granted = READ_CONTROL | WRITE_DAC | FILE_READ_ATTRIBUTES |
- DELETE;
-
- granted |= le32_to_cpu(ace->access_req);
-
- if (!pdacl->num_aces)
- granted = GENERIC_ALL_FLAGS;
- }
-
if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
posix_acls = get_inode_acl(d_inode(path->dentry), ACL_TYPE_ACCESS);
- if (!IS_ERR_OR_NULL(posix_acls) && !found) {
+ if (!IS_ERR_OR_NULL(posix_acls) && !found && !others_ace) {
unsigned int id = -1;
pa_entry = posix_acls->a_entries;
@@ -1596,14 +1617,16 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
}
}
- switch (ace->type) {
- case ACCESS_ALLOWED_ACE_TYPE:
- access_bits = le32_to_cpu(ace->access_req);
- break;
- case ACCESS_DENIED_ACE_TYPE:
- case ACCESS_DENIED_CALLBACK_ACE_TYPE:
- access_bits = le32_to_cpu(~ace->access_req);
- break;
+ if (!(*pdaccess & FILE_MAXIMAL_ACCESS_LE)) {
+ switch (ace->type) {
+ case ACCESS_ALLOWED_ACE_TYPE:
+ access_bits = le32_to_cpu(ace->access_req);
+ break;
+ case ACCESS_DENIED_ACE_TYPE:
+ case ACCESS_DENIED_CALLBACK_ACE_TYPE:
+ access_bits = le32_to_cpu(~ace->access_req);
+ break;
+ }
}
check_access_bits:
diff --git a/fs/smb/server/smbacl.h b/fs/smb/server/smbacl.h
index ab21ba2cd4df3..bf0312bfa0405 100644
--- a/fs/smb/server/smbacl.h
+++ b/fs/smb/server/smbacl.h
@@ -95,7 +95,7 @@ bool smb_inherit_flags(int flags, bool is_dir);
int smb_inherit_dacl(struct ksmbd_conn *conn, const struct path *path,
unsigned int uid, unsigned int gid);
int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
- __le32 *pdaccess, int uid);
+ __le32 *pdaccess, __le32 raw_daccess, int uid);
int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
const struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
bool type_check, bool get_write);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 725/869] drm/amdkfd: fix SMI event cross-process information leak
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (723 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 724/869] ksmbd: fix maximum allowed access checks Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 726/869] drm/amdgpu: Update SRIOV Exchange Headers for RAS Telemetry Support Greg Kroah-Hartman
` (144 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yongqiang Sun, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongqiang Sun <Yongqiang.Sun@amd.com>
[ Upstream commit 92a8dba246d371fe268280e5fd74b0955688e6df ]
kfd_smi_ev_enabled() skips the suser privilege check when pid=0.
PROCESS_START, PROCESS_END, and VMFAULT events are emitted with
pid=0 while carrying another process's PID and command name, so any
/dev/kfd user in the render group can monitor all GPU workloads.
Pass the target process PID into kfd_smi_event_add() for these events
so the existing per-client filter restricts delivery to the owning
process or CAP_SYS_ADMIN subscribers.
Signed-off-by: Yongqiang Sun <Yongqiang.Sun@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c
index 592953fe9afc2..8010ef10e572c 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c
@@ -255,8 +255,10 @@ void kfd_smi_event_update_vmfault(struct kfd_node *dev, uint16_t pasid)
if (task_info) {
/* Report VM faults from user applications, not retry from kernel */
if (task_info->pid)
- kfd_smi_event_add(0, dev, KFD_SMI_EVENT_VMFAULT, KFD_EVENT_FMT_VMFAULT(
- task_info->pid, task_info->task_name));
+ kfd_smi_event_add(task_info->tgid, dev,
+ KFD_SMI_EVENT_VMFAULT,
+ KFD_EVENT_FMT_VMFAULT(task_info->pid,
+ task_info->task_name));
amdgpu_vm_put_task_info(task_info);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 726/869] drm/amdgpu: Update SRIOV Exchange Headers for RAS Telemetry Support
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (724 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 725/869] drm/amdkfd: fix SMI event cross-process information leak Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 727/869] drm/amdgpu/ras: add ras_suspend callback and use it for cp_ecc_error_irq Greg Kroah-Hartman
` (143 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Victor Skvortsov, Zhigang Luo,
Alex Deucher, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Skvortsov <victor.skvortsov@amd.com>
[ Upstream commit 60c58d72afb81d2dc3f52f638eff5197511ac114 ]
The SRIOV PF/VF Data exchange is extended by 64KB for VF RAS Telemetry data.
Add Host RAS Telemetry enable capabilities bitfields.
Add a new VF msg REQ_RAS_ERROR_COUNT, the host response data will be populated
in the RAS Telemetry region.
Signed-off-by: Victor Skvortsov <victor.skvortsov@amd.com>
Reviewed-by: Zhigang Luo <zhigang.luo@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Stable-dep-of: e3829992dd9f ("drm/amdgpu/ras: add ras_suspend callback and use it for cp_ecc_error_irq")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h | 131 +++++++++++++++++---
drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h | 3 +
2 files changed, 115 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h
index 6e9eeaeb3de1d..b4f9c2f4e92cc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h
@@ -28,17 +28,21 @@
#define AMD_SRIOV_MSG_VBIOS_SIZE_KB 64
#define AMD_SRIOV_MSG_DATAEXCHANGE_OFFSET_KB AMD_SRIOV_MSG_VBIOS_SIZE_KB
#define AMD_SRIOV_MSG_DATAEXCHANGE_SIZE_KB 4
-
+#define AMD_SRIOV_MSG_TMR_OFFSET_KB 2048
+#define AMD_SRIOV_MSG_BAD_PAGE_SIZE_KB 2
+#define AMD_SRIOV_RAS_TELEMETRY_SIZE_KB 64
/*
* layout
- * 0 64KB 65KB 66KB
- * | VBIOS | PF2VF | VF2PF | Bad Page | ...
- * | 64KB | 1KB | 1KB |
+ * 0 64KB 65KB 66KB 68KB 132KB
+ * | VBIOS | PF2VF | VF2PF | Bad Page | RAS Telemetry Region | ...
+ * | 64KB | 1KB | 1KB | 2KB | 64KB | ...
*/
+
#define AMD_SRIOV_MSG_SIZE_KB 1
#define AMD_SRIOV_MSG_PF2VF_OFFSET_KB AMD_SRIOV_MSG_DATAEXCHANGE_OFFSET_KB
#define AMD_SRIOV_MSG_VF2PF_OFFSET_KB (AMD_SRIOV_MSG_PF2VF_OFFSET_KB + AMD_SRIOV_MSG_SIZE_KB)
#define AMD_SRIOV_MSG_BAD_PAGE_OFFSET_KB (AMD_SRIOV_MSG_VF2PF_OFFSET_KB + AMD_SRIOV_MSG_SIZE_KB)
+#define AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB (AMD_SRIOV_MSG_BAD_PAGE_OFFSET_KB + AMD_SRIOV_MSG_BAD_PAGE_SIZE_KB)
/*
* PF2VF history log:
@@ -86,30 +90,59 @@ enum amd_sriov_ucode_engine_id {
union amd_sriov_msg_feature_flags {
struct {
- uint32_t error_log_collect : 1;
- uint32_t host_load_ucodes : 1;
- uint32_t host_flr_vramlost : 1;
- uint32_t mm_bw_management : 1;
- uint32_t pp_one_vf_mode : 1;
- uint32_t reg_indirect_acc : 1;
- uint32_t av1_support : 1;
- uint32_t vcn_rb_decouple : 1;
- uint32_t mes_info_enable : 1;
- uint32_t reserved : 23;
+ uint32_t error_log_collect : 1;
+ uint32_t host_load_ucodes : 1;
+ uint32_t host_flr_vramlost : 1;
+ uint32_t mm_bw_management : 1;
+ uint32_t pp_one_vf_mode : 1;
+ uint32_t reg_indirect_acc : 1;
+ uint32_t av1_support : 1;
+ uint32_t vcn_rb_decouple : 1;
+ uint32_t mes_info_dump_enable : 1;
+ uint32_t ras_caps : 1;
+ uint32_t ras_telemetry : 1;
+ uint32_t reserved : 21;
} flags;
uint32_t all;
};
union amd_sriov_reg_access_flags {
struct {
- uint32_t vf_reg_access_ih : 1;
- uint32_t vf_reg_access_mmhub : 1;
- uint32_t vf_reg_access_gc : 1;
- uint32_t reserved : 29;
+ uint32_t vf_reg_access_ih : 1;
+ uint32_t vf_reg_access_mmhub : 1;
+ uint32_t vf_reg_access_gc : 1;
+ uint32_t reserved : 29;
} flags;
uint32_t all;
};
+union amd_sriov_ras_caps {
+ struct {
+ uint64_t block_umc : 1;
+ uint64_t block_sdma : 1;
+ uint64_t block_gfx : 1;
+ uint64_t block_mmhub : 1;
+ uint64_t block_athub : 1;
+ uint64_t block_pcie_bif : 1;
+ uint64_t block_hdp : 1;
+ uint64_t block_xgmi_wafl : 1;
+ uint64_t block_df : 1;
+ uint64_t block_smn : 1;
+ uint64_t block_sem : 1;
+ uint64_t block_mp0 : 1;
+ uint64_t block_mp1 : 1;
+ uint64_t block_fuse : 1;
+ uint64_t block_mca : 1;
+ uint64_t block_vcn : 1;
+ uint64_t block_jpeg : 1;
+ uint64_t block_ih : 1;
+ uint64_t block_mpio : 1;
+ uint64_t poison_propogation_mode : 1;
+ uint64_t reserved : 44;
+ } bits;
+ uint64_t all;
+};
+
union amd_sriov_msg_os_info {
struct {
uint32_t windows : 1;
@@ -158,7 +191,7 @@ struct amd_sriov_msg_pf2vf_info_header {
uint32_t reserved[2];
};
-#define AMD_SRIOV_MSG_PF2VF_INFO_FILLED_SIZE (49)
+#define AMD_SRIOV_MSG_PF2VF_INFO_FILLED_SIZE (55)
struct amd_sriov_msg_pf2vf_info {
/* header contains size and version */
struct amd_sriov_msg_pf2vf_info_header header;
@@ -211,6 +244,12 @@ struct amd_sriov_msg_pf2vf_info {
uint32_t pcie_atomic_ops_support_flags;
/* Portion of GPU memory occupied by VF. MAX value is 65535, but set to uint32_t to maintain alignment with reserved size */
uint32_t gpu_capacity;
+ /* vf bdf on host pci tree for debug only */
+ uint32_t bdf_on_host;
+ uint32_t more_bp; //Reserved for future use.
+ union amd_sriov_ras_caps ras_en_caps;
+ union amd_sriov_ras_caps ras_telemetry_en_caps;
+
/* reserved */
uint32_t reserved[256 - AMD_SRIOV_MSG_PF2VF_INFO_FILLED_SIZE];
} __packed;
@@ -283,8 +322,12 @@ enum amd_sriov_mailbox_request_message {
MB_REQ_MSG_REL_GPU_FINI_ACCESS,
MB_REQ_MSG_REQ_GPU_RESET_ACCESS,
MB_REQ_MSG_REQ_GPU_INIT_DATA,
+ MB_REQ_MSG_PSP_VF_CMD_RELAY,
MB_REQ_MSG_LOG_VF_ERROR = 200,
+ MB_REQ_MSG_READY_TO_RESET = 201,
+ MB_REQ_MSG_RAS_POISON = 202,
+ MB_REQ_RAS_ERROR_COUNT = 203,
};
/* mailbox message send from host to guest */
@@ -297,10 +340,60 @@ enum amd_sriov_mailbox_response_message {
MB_RES_MSG_FAIL,
MB_RES_MSG_QUERY_ALIVE,
MB_RES_MSG_GPU_INIT_DATA_READY,
+ MB_RES_MSG_RAS_ERROR_COUNT_READY = 11,
MB_RES_MSG_TEXT_MESSAGE = 255
};
+enum amd_sriov_ras_telemetry_gpu_block {
+ RAS_TELEMETRY_GPU_BLOCK_UMC = 0,
+ RAS_TELEMETRY_GPU_BLOCK_SDMA = 1,
+ RAS_TELEMETRY_GPU_BLOCK_GFX = 2,
+ RAS_TELEMETRY_GPU_BLOCK_MMHUB = 3,
+ RAS_TELEMETRY_GPU_BLOCK_ATHUB = 4,
+ RAS_TELEMETRY_GPU_BLOCK_PCIE_BIF = 5,
+ RAS_TELEMETRY_GPU_BLOCK_HDP = 6,
+ RAS_TELEMETRY_GPU_BLOCK_XGMI_WAFL = 7,
+ RAS_TELEMETRY_GPU_BLOCK_DF = 8,
+ RAS_TELEMETRY_GPU_BLOCK_SMN = 9,
+ RAS_TELEMETRY_GPU_BLOCK_SEM = 10,
+ RAS_TELEMETRY_GPU_BLOCK_MP0 = 11,
+ RAS_TELEMETRY_GPU_BLOCK_MP1 = 12,
+ RAS_TELEMETRY_GPU_BLOCK_FUSE = 13,
+ RAS_TELEMETRY_GPU_BLOCK_MCA = 14,
+ RAS_TELEMETRY_GPU_BLOCK_VCN = 15,
+ RAS_TELEMETRY_GPU_BLOCK_JPEG = 16,
+ RAS_TELEMETRY_GPU_BLOCK_IH = 17,
+ RAS_TELEMETRY_GPU_BLOCK_MPIO = 18,
+ RAS_TELEMETRY_GPU_BLOCK_COUNT = 19,
+};
+
+struct amd_sriov_ras_telemetry_header {
+ uint32_t checksum;
+ uint32_t used_size;
+ uint32_t reserved[2];
+};
+
+struct amd_sriov_ras_telemetry_error_count {
+ struct {
+ uint32_t ce_count;
+ uint32_t ue_count;
+ uint32_t de_count;
+ uint32_t ce_overflow_count;
+ uint32_t ue_overflow_count;
+ uint32_t de_overflow_count;
+ uint32_t reserved[6];
+ } block[RAS_TELEMETRY_GPU_BLOCK_COUNT];
+};
+
+struct amdsriov_ras_telemetry {
+ struct amd_sriov_ras_telemetry_header header;
+
+ union {
+ struct amd_sriov_ras_telemetry_error_count error_count;
+ } body;
+};
+
/* version data stored in MAILBOX_MSGBUF_RCV_DW1 for future expansion */
enum amd_sriov_gpu_init_data_version {
GPU_INIT_DATA_READY_V1 = 1,
diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h
index 1d099ffb3a5a2..9d61d76e1bf96 100644
--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h
+++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h
@@ -40,6 +40,7 @@ enum idh_request {
IDH_LOG_VF_ERROR = 200,
IDH_READY_TO_RESET = 201,
IDH_RAS_POISON = 202,
+ IDH_REQ_RAS_ERROR_COUNT = 203,
};
enum idh_event {
@@ -54,6 +55,8 @@ enum idh_event {
IDH_RAS_POISON_READY,
IDH_PF_SOFT_FLR_NOTIFICATION,
IDH_RAS_ERROR_DETECTED,
+ IDH_RAS_ERROR_COUNT_READY = 11,
+
IDH_TEXT_MESSAGE = 255,
};
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 727/869] drm/amdgpu/ras: add ras_suspend callback and use it for cp_ecc_error_irq
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (725 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 726/869] drm/amdgpu: Update SRIOV Exchange Headers for RAS Telemetry Support Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 728/869] wifi: iwlwifi: simplify nested if checks Greg Kroah-Hartman
` (142 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Yunxiang Li, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yunxiang Li <Yunxiang.Li@amd.com>
[ Upstream commit e3829992dd9fa0a82511af4f01733fc854cd15a5 ]
cp_ecc_error_irq is acquired in amdgpu_gfx_ras_late_init() but
released in gfx_v9_0_hw_fini(), so the put site has to query
amdgpu_irq_enabled() because the get is skipped on SR-IOV VF.
ras_late_init / ras_fini have no suspend counterpart, so move the
put to amdgpu_gfx_ras_suspend() / amdgpu_gfx_ras_fini() and add a
matching ras_suspend callback that is invoked from
amdgpu_ras_suspend() before disable_all_features(). The get and
put now sit in the same place and check the same condition (not
VF, funcs registered), no refcount querying needed.
An active flag gates ras_fini so the
suspend-then-unload-without-resume path falls into
amdgpu_ras_block_late_fini_default() instead of double-releasing
what ras_suspend already cleaned up.
Drop the cp_ecc_error_irq put from gfx_v9_0_hw_fini(). gfx_v8_0
manages cp_ecc_error_irq locally and is unaffected; no other GFX
generation has this IRQ.
Signed-off-by: Yunxiang Li <Yunxiang.Li@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 23 +++++++++++++++++-
drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h | 3 ++-
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 32 +++++++++++++++++++++----
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h | 1 +
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 --
5 files changed, 53 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index 171603c4ee6c9..66e7f899de2a9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -922,7 +922,7 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r
if (r)
return r;
- if (adev->gfx.cp_ecc_error_irq.funcs) {
+ if (!amdgpu_sriov_vf(adev) && adev->gfx.cp_ecc_error_irq.funcs) {
r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0);
if (r)
goto late_fini;
@@ -937,6 +937,21 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r
return r;
}
+void amdgpu_gfx_ras_suspend(struct amdgpu_device *adev,
+ struct ras_common_if *ras_block)
+{
+ if (!amdgpu_sriov_vf(adev) && adev->gfx.cp_ecc_error_irq.funcs)
+ amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0);
+}
+
+void amdgpu_gfx_ras_fini(struct amdgpu_device *adev,
+ struct ras_common_if *ras_block)
+{
+ if (!amdgpu_sriov_vf(adev) && adev->gfx.cp_ecc_error_irq.funcs)
+ amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0);
+ amdgpu_ras_block_late_fini(adev, ras_block);
+}
+
int amdgpu_gfx_ras_sw_init(struct amdgpu_device *adev)
{
int err = 0;
@@ -965,6 +980,12 @@ int amdgpu_gfx_ras_sw_init(struct amdgpu_device *adev)
if (!ras->ras_block.ras_late_init)
ras->ras_block.ras_late_init = amdgpu_gfx_ras_late_init;
+ if (!ras->ras_block.ras_suspend)
+ ras->ras_block.ras_suspend = amdgpu_gfx_ras_suspend;
+
+ if (!ras->ras_block.ras_fini)
+ ras->ras_block.ras_fini = amdgpu_gfx_ras_fini;
+
/* If not defined special ras_cb function, use default ras_cb */
if (!ras->ras_block.ras_cb)
ras->ras_block.ras_cb = amdgpu_gfx_process_ras_data_cb;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
index 5644e10a86a99..e64dcfdbfadd9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
@@ -547,7 +547,8 @@ bool amdgpu_gfx_is_me_queue_enabled(struct amdgpu_device *adev, int me,
void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable);
int amdgpu_get_gfx_off_status(struct amdgpu_device *adev, uint32_t *value);
int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block);
-void amdgpu_gfx_ras_fini(struct amdgpu_device *adev);
+void amdgpu_gfx_ras_suspend(struct amdgpu_device *adev, struct ras_common_if *ras_block);
+void amdgpu_gfx_ras_fini(struct amdgpu_device *adev, struct ras_common_if *ras_block);
int amdgpu_get_gfx_off_entrycount(struct amdgpu_device *adev, u64 *value);
int amdgpu_get_gfx_off_residency(struct amdgpu_device *adev, u32 *residency);
int amdgpu_set_gfx_off_residency(struct amdgpu_device *adev, bool value);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
index bf563904b3fa9..1784e484798b5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -90,6 +90,9 @@ struct amdgpu_ras_block_list {
struct list_head node;
struct amdgpu_ras_block_object *ras_obj;
+
+ /* set by ras_late_init, cleared by ras_suspend/ras_fini */
+ bool active;
};
const char *get_ras_block_str(struct ras_common_if *ras_block)
@@ -3874,10 +3877,23 @@ void amdgpu_ras_resume(struct amdgpu_device *adev)
void amdgpu_ras_suspend(struct amdgpu_device *adev)
{
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
+ struct amdgpu_ras_block_list *node;
+ struct amdgpu_ras_block_object *obj;
if (!adev->ras_enabled || !con)
return;
+ /* run per-block ras_suspend before tearing down the RAS context */
+ list_for_each_entry(node, &adev->ras_list, node) {
+ if (!node->active)
+ continue;
+
+ obj = node->ras_obj;
+ if (obj && obj->ras_suspend)
+ obj->ras_suspend(adev, &obj->ras_comm);
+ node->active = false;
+ }
+
amdgpu_ras_disable_all_features(adev, 0);
/* Make sure all ras objects are disabled. */
if (AMDGPU_RAS_GET_FEATURES(con->features))
@@ -3931,8 +3947,15 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev)
obj->ras_comm.name, r);
return r;
}
- } else
- amdgpu_ras_block_late_init_default(adev, &obj->ras_comm);
+ } else {
+ r = amdgpu_ras_block_late_init_default(adev, &obj->ras_comm);
+ if (r) {
+ dev_err(adev->dev, "%s failed to execute ras_block_late_init_default! ret:%d\n",
+ obj->ras_comm.name, r);
+ return r;
+ }
+ }
+ node->active = true;
}
return 0;
@@ -3966,11 +3989,12 @@ int amdgpu_ras_fini(struct amdgpu_device *adev)
list_for_each_entry_safe(ras_node, tmp, &adev->ras_list, node) {
if (ras_node->ras_obj) {
obj = ras_node->ras_obj;
- if (amdgpu_ras_is_supported(adev, obj->ras_comm.block) &&
- obj->ras_fini)
+ /* fall back to default cleanup if ras_suspend already ran */
+ if (ras_node->active && obj->ras_fini)
obj->ras_fini(adev, &obj->ras_comm);
else
amdgpu_ras_block_late_fini_default(adev, &obj->ras_comm);
+ ras_node->active = false;
}
/* Clear ras blocks from ras_list and free ras block list node */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
index 7e7521fedafc7..a705b1157d8e1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
@@ -706,6 +706,7 @@ struct amdgpu_ras_block_object {
int (*ras_block_match)(struct amdgpu_ras_block_object *block_obj,
enum amdgpu_ras_block block, uint32_t sub_block_index);
int (*ras_late_init)(struct amdgpu_device *adev, struct ras_common_if *ras_block);
+ void (*ras_suspend)(struct amdgpu_device *adev, struct ras_common_if *ras_block);
void (*ras_fini)(struct amdgpu_device *adev, struct ras_common_if *ras_block);
ras_ih_cb ras_cb;
const struct amdgpu_ras_block_hw_ops *hw_ops;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index 06ab40412200f..870ec359ed4b6 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -4018,8 +4018,6 @@ static int gfx_v9_0_hw_fini(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__GFX))
- amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.bad_op_irq, 0);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 728/869] wifi: iwlwifi: simplify nested if checks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (726 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 727/869] drm/amdgpu/ras: add ras_suspend callback and use it for cp_ecc_error_irq Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 729/869] wifi: iwlwifi: mvm: fix P2P-Device binding handling Greg Kroah-Hartman
` (141 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johannes Berg, Miri Korenblit,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Berg <johannes.berg@intel.com>
[ Upstream commit 63a59880ec116cebb8a01ead28b1b23c3846ebb9 ]
In the absence of (an) else clause(s), "if (a) if (b)" is
equivalent to "if (a && b)", so simplify the code a bit.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250102161730.7ddc9cb1ea50.If18bd94706d6c821e34c38a4704bf85dca6207b2@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Stable-dep-of: b74e377cad92 ("wifi: iwlwifi: mvm: fix P2P-Device binding handling")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/intel/iwlwifi/mvm/binding.c | 7 +++----
drivers/net/wireless/intel/iwlwifi/mvm/link.c | 5 ++---
drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 6 +++---
3 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
index 458b97930059e..58e9a940024db 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
@@ -2,7 +2,7 @@
/*
* Copyright (C) 2012-2014, 2020 Intel Corporation
* Copyright (C) 2016 Intel Deutschland GmbH
- * Copyright (C) 2022 Intel Corporation
+ * Copyright (C) 2022, 2024 Intel Corporation
*/
#include <net/mac80211.h>
#include "fw-api.h"
@@ -158,9 +158,8 @@ int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
ret = iwl_mvm_binding_update(mvm, vif, mvmvif->deflink.phy_ctxt,
false);
- if (!ret)
- if (iwl_mvm_sf_update(mvm, vif, true))
- IWL_ERR(mvm, "Failed to update SF state\n");
+ if (!ret && iwl_mvm_sf_update(mvm, vif, true))
+ IWL_ERR(mvm, "Failed to update SF state\n");
return ret;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
index 2b06521680020..e886200924bdf 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
@@ -410,9 +410,8 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_REMOVE);
- if (!ret)
- if (iwl_mvm_sf_update(mvm, vif, true))
- IWL_ERR(mvm, "Failed to update SF state\n");
+ if (!ret && iwl_mvm_sf_update(mvm, vif, true))
+ IWL_ERR(mvm, "Failed to update SF state\n");
return ret;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
index 8903a5692dfbb..a822448ad5ea5 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
@@ -139,9 +139,9 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans)
if (trans_pcie->is_down)
return;
- if (trans->state >= IWL_TRANS_FW_STARTED)
- if (trans_pcie->fw_reset_handshake)
- iwl_trans_pcie_fw_reset_handshake(trans);
+ if (trans->state >= IWL_TRANS_FW_STARTED &&
+ trans_pcie->fw_reset_handshake)
+ iwl_trans_pcie_fw_reset_handshake(trans);
trans_pcie->is_down = true;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 729/869] wifi: iwlwifi: mvm: fix P2P-Device binding handling
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (727 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 728/869] wifi: iwlwifi: simplify nested if checks Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 730/869] RDMA/counter: Fix num_counters leak on bind_qp failure in alloc_and_bind() Greg Kroah-Hartman
` (140 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johannes Berg, Miri Korenblit,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Berg <johannes.berg@intel.com>
[ Upstream commit b74e377cad9271950c57472867c469e4b5b2ff0c ]
Our binding handling for P2P-Device can run into the following
scenario, as observed by our testing:
- a station interface is connected on some channel
- the P2P-Device does a remain-on-channel (ROC) on that channel
- the ROC ends, and the P2P-Device is removed from the binding,
but the phy_ctxt pointer is left around as a PHY cache so we
don't need to recalibrate to the channel again and again in
case it's not shared
- a binding update by the station interface, even a removal,
will re-add the P2P-Device to the binding
- the P2P-Device is removed, which removes the PHY context, but
it's still in the binding so the firmware crashes
Since the P2P device is removed from the binding and only re-
added by unrelated code, but we want to keep the phy_ctxt around
as a cache for future ROC usage, fix it by adding a boolean that
indicates whether or not the P2P-Device should be added to the
binding, and handle that in the binding iterator. That way, the
station interface cannot re-add the P2P-Device to the binding
when that isn't active.
Assisted-by: Github Copilot:claude-opus-4-6
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Link: https://patch.msgid.link/20260527230313.07f94335ae06.I384238b0859343c4a9a9dda20682be1aad89cc9d@changeid
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/wireless/intel/iwlwifi/mvm/binding.c | 5 ++++-
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 12 +++++++++++-
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 +++
drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 3 ++-
4 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
index 58e9a940024db..0812522edea0d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
@@ -2,7 +2,7 @@
/*
* Copyright (C) 2012-2014, 2020 Intel Corporation
* Copyright (C) 2016 Intel Deutschland GmbH
- * Copyright (C) 2022, 2024 Intel Corporation
+ * Copyright (C) 2022, 2024, 2026 Intel Corporation
*/
#include <net/mac80211.h>
#include "fw-api.h"
@@ -76,6 +76,9 @@ static void iwl_mvm_iface_iterator(void *_data, u8 *mac,
if (vif == data->ignore_vif)
return;
+ if (vif->type == NL80211_IFTYPE_P2P_DEVICE && !mvmvif->p2p_in_binding)
+ return;
+
if (mvmvif->deflink.phy_ctxt != data->phyctxt)
return;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 6ac4215677057..91d0d2dfef893 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -1098,6 +1098,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
spin_unlock_bh(&mvm->time_event_lock);
mvmvif->roc_activity = ROC_NUM_ACTIVITIES;
+ mvmvif->p2p_in_binding = false;
mvmvif->bf_enabled = false;
mvmvif->ba_enabled = false;
@@ -4786,6 +4787,7 @@ static int iwl_mvm_add_aux_sta_for_hs20(struct iwl_mvm *mvm, u32 lmac_id)
static int iwl_mvm_roc_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
lockdep_assert_held(&mvm->mutex);
@@ -4794,10 +4796,18 @@ static int iwl_mvm_roc_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (WARN(ret, "Failed binding P2P_DEVICE\n"))
return ret;
+ mvmvif->p2p_in_binding = true;
+
/* The station and queue allocation must be done only after the binding
* is done, as otherwise the FW might incorrectly configure its state.
*/
- return iwl_mvm_add_p2p_bcast_sta(mvm, vif);
+ ret = iwl_mvm_add_p2p_bcast_sta(mvm, vif);
+ if (ret) {
+ iwl_mvm_binding_remove_vif(mvm, vif);
+ mvmvif->p2p_in_binding = false;
+ }
+
+ return ret;
}
static int iwl_mvm_roc(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 67d188409ca31..4e1dbfb3705e3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -454,6 +454,8 @@ struct iwl_mvm_esr_exit {
* @unblock_esr_tpt_wk: work for unblocking EMLSR when tpt is high enough.
* @roc_activity: currently running ROC activity for this vif (or
* ROC_NUM_ACTIVITIES if no activity is running).
+ * @p2p_in_binding: indicates that this P2P-Device interface should be
+ * added to the binding, i.e. is running ROC right now
* @session_prot_connection_loss: the connection was lost due to session
* protection ending without receiving a beacon, so we need to now
* protect the deauth separately
@@ -565,6 +567,7 @@ struct iwl_mvm_vif {
struct iwl_mvm_time_event_data time_event_data;
struct iwl_mvm_time_event_data hs_time_event_data;
enum iwl_roc_activity roc_activity;
+ bool p2p_in_binding;
/* TCP Checksum Offload */
netdev_features_t features;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
index c0b58e4a4cc1c..bdd05062824d6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2024 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2024, 2026 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2017 Intel Deutschland GmbH
*/
@@ -90,6 +90,7 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)
} else {
iwl_mvm_rm_p2p_bcast_sta(mvm, vif);
iwl_mvm_binding_remove_vif(mvm, vif);
+ mvmvif->p2p_in_binding = false;
}
/* Do not remove the PHY context as removing and adding
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 730/869] RDMA/counter: Fix num_counters leak on bind_qp failure in alloc_and_bind()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (728 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 729/869] wifi: iwlwifi: mvm: fix P2P-Device binding handling Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 731/869] virt: acrn: Remove unused list acrn_irqfd_clients Greg Kroah-Hartman
` (139 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Tao Cui, Jason Gunthorpe,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tao Cui <cuitao@kylinos.cn>
[ Upstream commit 4fbc8230009f5b1bcd13cc74c5a6a43ddba141fd ]
When __rdma_counter_bind_qp() fails in alloc_and_bind(), the error path
jumps to err_mode which frees the counter without decrementing
port_counter->num_counters. The only place that decrements is
rdma_counter_free(), which is unreachable since the counter was never
successfully bound.
This leak accumulates across repeated failures, permanently preventing
the port from switching to AUTO mode (-EBUSY in __counter_set_mode())
and blocking the MANUAL→NONE auto-revert in rdma_counter_free(). When
the mode was NONE before the call, the MANUAL mode set by
__counter_set_mode() also leaks since the revert logic is never
reached.
Add an err_bind label between the num_counters increment and the
existing err_mode label. It decrements num_counters and mirrors the
MANUAL→NONE revert from rdma_counter_free(), ensuring the port state
is fully restored on bind failure.
Link: https://patch.msgid.link/r/20260520104546.1776253-2-cuitao@kylinos.cn
Signed-off-by: Tao Cui <cuitao@kylinos.cn>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/infiniband/core/counters.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/infiniband/core/counters.c b/drivers/infiniband/core/counters.c
index 8cbca897fc531..78a76b4fa6f68 100644
--- a/drivers/infiniband/core/counters.c
+++ b/drivers/infiniband/core/counters.c
@@ -190,12 +190,19 @@ static struct rdma_counter *alloc_and_bind(struct ib_device *dev, u32 port,
ret = __rdma_counter_bind_qp(counter, qp);
if (ret)
- goto err_mode;
+ goto err_bind;
rdma_restrack_parent_name(&counter->res, &qp->res);
rdma_restrack_add(&counter->res);
return counter;
+err_bind:
+ mutex_lock(&port_counter->lock);
+ port_counter->num_counters--;
+ if (!port_counter->num_counters &&
+ port_counter->mode.mode == RDMA_COUNTER_MODE_MANUAL)
+ __counter_set_mode(port_counter, RDMA_COUNTER_MODE_NONE, 0);
+ mutex_unlock(&port_counter->lock);
err_mode:
rdma_free_hw_stats_struct(counter->stats);
err_stats:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 731/869] virt: acrn: Remove unused list acrn_irqfd_clients
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (729 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 730/869] RDMA/counter: Fix num_counters leak on bind_qp failure in alloc_and_bind() Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 732/869] virt: acrn: Fix irqfd use-after-free during eventfd shutdown Greg Kroah-Hartman
` (138 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dr. David Alan Gilbert, Fei Li,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dr. David Alan Gilbert <linux@treblig.org>
[ Upstream commit 97e72c1e0c5424cd8d7b95c31144e713c44c4244 ]
It doesn't look like this was ever used.
Build tested only.
Signed-off-by: "Dr. David Alan Gilbert" <linux@treblig.org>
Acked-by: Fei Li <fei1.li@intel.com>
Link: https://lore.kernel.org/r/20250430003623.313541-1-linux@treblig.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: 666c7f9e0792 ("virt: acrn: Fix irqfd use-after-free during eventfd shutdown")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/virt/acrn/irqfd.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/virt/acrn/irqfd.c b/drivers/virt/acrn/irqfd.c
index 9994d818bb7e1..5574fbf878209 100644
--- a/drivers/virt/acrn/irqfd.c
+++ b/drivers/virt/acrn/irqfd.c
@@ -16,8 +16,6 @@
#include "acrn_drv.h"
-static LIST_HEAD(acrn_irqfd_clients);
-
/**
* struct hsm_irqfd - Properties of HSM irqfd
* @vm: Associated VM pointer
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 732/869] virt: acrn: Fix irqfd use-after-free during eventfd shutdown
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (730 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 731/869] virt: acrn: Remove unused list acrn_irqfd_clients Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 733/869] PM: sleep: core: Synchronize runtime PM status of parents and children Greg Kroah-Hartman
` (137 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Sicong Huang, Fei Li, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sicong Huang <congei42@163.com>
[ Upstream commit 666c7f9e07925aa0863348f960e09bb89f8f05a3 ]
acrn_irqfd_deassign() and the eventfd EPOLLHUP wakeup can race and free
the same struct hsm_irqfd:
CPU0 CPU1
---- ----
eventfd_release()
wake_up_poll(EPOLLHUP)
hsm_irqfd_wakeup()
queue_work(&irqfd->shutdown)
acrn_irqfd_deassign()
hsm_irqfd_shutdown()
list_del_init()
eventfd_ctx_remove_wait_queue()
eventfd_ctx_put()
kfree(irqfd)
hsm_irqfd_shutdown_work()
container_of(work, ..., shutdown)
irqfd->vm <-- use-after-free
The deassign path freed the irqfd while a shutdown work item was
already queued by EPOLLHUP (or vice versa), so the work item could
resurrect a dangling pointer through container_of().
Switch to the lifetime model used by KVM irqfds:
- Deassign/deinit only deactivate the irqfd: remove it from vm->irqfds
under irqfds_lock and queue the cleanup work.
- hsm_irqfd_shutdown_work() becomes the sole owner that unhooks the
eventfd waitqueue entry, drops the eventfd reference and frees the
irqfd.
- A new HSM_IRQFD_FLAG_SHUTDOWN bit guarded by test_and_set_bit()
ensures the cleanup work is queued at most once, no matter how many
of {EPOLLHUP, deassign, deinit} fire concurrently. This is safe to
call from the waitqueue callback, which runs with wqh->lock held and
IRQs disabled and therefore cannot take irqfds_lock.
- acrn_irqfd_deassign() flushes vm->irqfd_wq before returning so the
eventfd is fully detached on return. acrn_irqfd_deinit() deactivates
every irqfd, flushes the workqueue and only then destroys it, so no
path can queue_work() onto a torn-down workqueue.
- acrn_irqfd_assign() now installs the eventfd waitqueue entry and
publishes the irqfd to vm->irqfds under irqfds_lock, so the irqfd is
never visible to deassign/deinit before its waitqueue entry is in
place, and any EPOLLHUP that fires in the assign window queues
cleanup work that blocks on irqfds_lock until publication is done.
Signed-off-by: Sicong Huang <congei42@163.com>
Reviewed-by: Fei Li <fei1.li@intel.com>
Link: https://patch.msgid.link/20260519112018.2135000-2-congei42@163.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/virt/acrn/irqfd.c | 71 ++++++++++++++++++++++++---------------
1 file changed, 44 insertions(+), 27 deletions(-)
diff --git a/drivers/virt/acrn/irqfd.c b/drivers/virt/acrn/irqfd.c
index 5574fbf878209..1b1a33d702c10 100644
--- a/drivers/virt/acrn/irqfd.c
+++ b/drivers/virt/acrn/irqfd.c
@@ -16,6 +16,9 @@
#include "acrn_drv.h"
+/* Cleanup work has been queued; set via test_and_set_bit(). */
+#define HSM_IRQFD_FLAG_SHUTDOWN 0
+
/**
* struct hsm_irqfd - Properties of HSM irqfd
* @vm: Associated VM pointer
@@ -25,6 +28,7 @@
* @list: Entry within &acrn_vm.irqfds of irqfds of a VM
* @pt: Structure for select/poll on the associated eventfd
* @msi: MSI data
+ * @flags: Internal lifecycle flags (HSM_IRQFD_FLAG_*)
*/
struct hsm_irqfd {
struct acrn_vm *vm;
@@ -34,6 +38,7 @@ struct hsm_irqfd {
struct list_head list;
poll_table pt;
struct acrn_msi_entry msi;
+ unsigned long flags;
};
static void acrn_irqfd_inject(struct hsm_irqfd *irqfd)
@@ -44,30 +49,29 @@ static void acrn_irqfd_inject(struct hsm_irqfd *irqfd)
irqfd->msi.msi_data);
}
-static void hsm_irqfd_shutdown(struct hsm_irqfd *irqfd)
+/* Queue the cleanup work at most once. Safe from atomic context. */
+static void hsm_irqfd_queue_shutdown(struct hsm_irqfd *irqfd)
{
- u64 cnt;
-
- lockdep_assert_held(&irqfd->vm->irqfds_lock);
-
- /* remove from wait queue */
- list_del_init(&irqfd->list);
- eventfd_ctx_remove_wait_queue(irqfd->eventfd, &irqfd->wait, &cnt);
- eventfd_ctx_put(irqfd->eventfd);
- kfree(irqfd);
+ if (!test_and_set_bit(HSM_IRQFD_FLAG_SHUTDOWN, &irqfd->flags))
+ queue_work(irqfd->vm->irqfd_wq, &irqfd->shutdown);
}
+/* Sole owner of @irqfd: unhook waitqueue, drop eventfd ref, free. */
static void hsm_irqfd_shutdown_work(struct work_struct *work)
{
- struct hsm_irqfd *irqfd;
- struct acrn_vm *vm;
+ struct hsm_irqfd *irqfd = container_of(work, struct hsm_irqfd,
+ shutdown);
+ struct acrn_vm *vm = irqfd->vm;
+ u64 cnt;
- irqfd = container_of(work, struct hsm_irqfd, shutdown);
- vm = irqfd->vm;
mutex_lock(&vm->irqfds_lock);
if (!list_empty(&irqfd->list))
- hsm_irqfd_shutdown(irqfd);
+ list_del_init(&irqfd->list);
mutex_unlock(&vm->irqfds_lock);
+
+ eventfd_ctx_remove_wait_queue(irqfd->eventfd, &irqfd->wait, &cnt);
+ eventfd_ctx_put(irqfd->eventfd);
+ kfree(irqfd);
}
/* Called with wqh->lock held and interrupts disabled */
@@ -76,17 +80,16 @@ static int hsm_irqfd_wakeup(wait_queue_entry_t *wait, unsigned int mode,
{
unsigned long poll_bits = (unsigned long)key;
struct hsm_irqfd *irqfd;
- struct acrn_vm *vm;
irqfd = container_of(wait, struct hsm_irqfd, wait);
- vm = irqfd->vm;
+
if (poll_bits & POLLIN)
/* An event has been signaled, inject an interrupt */
acrn_irqfd_inject(irqfd);
if (poll_bits & POLLHUP)
- /* Do shutdown work in thread to hold wqh->lock */
- queue_work(vm->irqfd_wq, &irqfd->shutdown);
+ /* Defer teardown to the cleanup work; can't sleep here. */
+ hsm_irqfd_queue_shutdown(irqfd);
return 0;
}
@@ -143,6 +146,12 @@ static int acrn_irqfd_assign(struct acrn_vm *vm, struct acrn_irqfd *args)
init_waitqueue_func_entry(&irqfd->wait, hsm_irqfd_wakeup);
init_poll_funcptr(&irqfd->pt, hsm_irqfd_poll_func);
+ /*
+ * Hold irqfds_lock across waitqueue install and list_add so the
+ * irqfd is not visible to deassign/deinit before its waitqueue
+ * entry is in place, and any racing EPOLLHUP cleanup work blocks
+ * on irqfds_lock until publication completes.
+ */
mutex_lock(&vm->irqfds_lock);
list_for_each_entry(tmp, &vm->irqfds, list) {
if (irqfd->eventfd != tmp->eventfd)
@@ -151,14 +160,12 @@ static int acrn_irqfd_assign(struct acrn_vm *vm, struct acrn_irqfd *args)
mutex_unlock(&vm->irqfds_lock);
goto fail;
}
- list_add_tail(&irqfd->list, &vm->irqfds);
- mutex_unlock(&vm->irqfds_lock);
- /* Check the pending event in this stage */
events = vfs_poll(fd_file(f), &irqfd->pt);
-
+ list_add_tail(&irqfd->list, &vm->irqfds);
if (events & EPOLLIN)
acrn_irqfd_inject(irqfd);
+ mutex_unlock(&vm->irqfds_lock);
fdput(f);
return 0;
@@ -185,13 +192,17 @@ static int acrn_irqfd_deassign(struct acrn_vm *vm,
mutex_lock(&vm->irqfds_lock);
list_for_each_entry_safe(irqfd, tmp, &vm->irqfds, list) {
if (irqfd->eventfd == eventfd) {
- hsm_irqfd_shutdown(irqfd);
+ list_del_init(&irqfd->list);
+ hsm_irqfd_queue_shutdown(irqfd);
break;
}
}
mutex_unlock(&vm->irqfds_lock);
eventfd_ctx_put(eventfd);
+ /* Wait for cleanup work to finish so the eventfd is fully detached. */
+ flush_workqueue(vm->irqfd_wq);
+
return 0;
}
@@ -224,9 +235,15 @@ void acrn_irqfd_deinit(struct acrn_vm *vm)
struct hsm_irqfd *irqfd, *next;
dev_dbg(acrn_dev.this_device, "VM %u irqfd deinit.\n", vm->vmid);
- destroy_workqueue(vm->irqfd_wq);
+
mutex_lock(&vm->irqfds_lock);
- list_for_each_entry_safe(irqfd, next, &vm->irqfds, list)
- hsm_irqfd_shutdown(irqfd);
+ list_for_each_entry_safe(irqfd, next, &vm->irqfds, list) {
+ list_del_init(&irqfd->list);
+ hsm_irqfd_queue_shutdown(irqfd);
+ }
mutex_unlock(&vm->irqfds_lock);
+
+ /* Drain all cleanup work before tearing the workqueue down. */
+ flush_workqueue(vm->irqfd_wq);
+ destroy_workqueue(vm->irqfd_wq);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 733/869] PM: sleep: core: Synchronize runtime PM status of parents and children
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (731 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 732/869] virt: acrn: Fix irqfd use-after-free during eventfd shutdown Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 734/869] PM: sleep: core: Restrict power.set_active propagation Greg Kroah-Hartman
` (136 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johan Hovold, Manivannan Sadhasivam,
Rafael J. Wysocki, Johan Hovold, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
[ Upstream commit 3775fc538f535a7c5adaf11990c7932a0bd1f9eb ]
Commit 6e176bf8d461 ("PM: sleep: core: Do not skip callbacks in the
resume phase") overlooked the case in which the parent of a device with
DPM_FLAG_SMART_SUSPEND set did not use that flag and could be runtime-
suspended before a transition into a system-wide sleep state. In that
case, if the child is resumed during the subsequent transition from
that state into the working state, its runtime PM status will be set to
RPM_ACTIVE, but the runtime PM status of the parent will not be updated
accordingly, even though the parent will be resumed too, because of the
dev_pm_skip_suspend() check in device_resume_noirq().
Address this problem by tracking the need to set the runtime PM status
to RPM_ACTIVE during system-wide resume transitions for devices with
DPM_FLAG_SMART_SUSPEND set and all of the devices depended on by them.
Fixes: 6e176bf8d461 ("PM: sleep: core: Do not skip callbacks in the resume phase")
Closes: https://lore.kernel.org/linux-pm/Z30p2Etwf3F2AUvD@hovoldconsulting.com/
Reported-by: Johan Hovold <johan@kernel.org>
Tested-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Johan Hovold <johan+linaro@kernel.org>
Tested-by: Johan Hovold <johan+linaro@kernel.org>
Link: https://patch.msgid.link/12619233.O9o76ZdvQC@rjwysocki.net
Stable-dep-of: 36d74f17e03f ("driver core: Avoid warning when removing a device while its supplier is unbinding")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/base/power/main.c | 29 ++++++++++++++++++++---------
include/linux/pm.h | 1 +
2 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index abb16a5bb7967..71489b46a07bb 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -654,13 +654,15 @@ static void device_resume_noirq(struct device *dev, pm_message_t state, bool asy
* so change its status accordingly.
*
* Otherwise, the device is going to be resumed, so set its PM-runtime
- * status to "active", but do that only if DPM_FLAG_SMART_SUSPEND is set
- * to avoid confusing drivers that don't use it.
+ * status to "active" unless its power.set_active flag is clear, in
+ * which case it is not necessary to update its PM-runtime status.
*/
- if (skip_resume)
+ if (skip_resume) {
pm_runtime_set_suspended(dev);
- else if (dev_pm_skip_suspend(dev))
+ } else if (dev->power.set_active) {
pm_runtime_set_active(dev);
+ dev->power.set_active = false;
+ }
if (dev->pm_domain) {
info = "noirq power domain ";
@@ -1187,18 +1189,24 @@ static pm_message_t resume_event(pm_message_t sleep_state)
return PMSG_ON;
}
-static void dpm_superior_set_must_resume(struct device *dev)
+static void dpm_superior_set_must_resume(struct device *dev, bool set_active)
{
struct device_link *link;
int idx;
- if (dev->parent)
+ if (dev->parent) {
dev->parent->power.must_resume = true;
+ if (set_active)
+ dev->parent->power.set_active = true;
+ }
idx = device_links_read_lock();
- list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node)
+ list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) {
link->supplier->power.must_resume = true;
+ if (set_active)
+ link->supplier->power.set_active = true;
+ }
device_links_read_unlock(idx);
}
@@ -1275,8 +1283,11 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
dev->power.may_skip_resume) || !pm_runtime_need_not_resume(dev))
dev->power.must_resume = true;
- if (dev->power.must_resume)
- dpm_superior_set_must_resume(dev);
+ if (dev->power.must_resume) {
+ dev->power.set_active = dev->power.set_active ||
+ dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND);
+ dpm_superior_set_must_resume(dev, dev->power.set_active);
+ }
Complete:
complete_all(&dev->power.completion);
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 97b0e23363c82..a478737115cd9 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -683,6 +683,7 @@ struct dev_pm_info {
bool no_pm_callbacks:1; /* Owned by the PM core */
bool async_in_progress:1; /* Owned by the PM core */
bool must_resume:1; /* Owned by the PM core */
+ bool set_active:1; /* Owned by the PM core */
bool may_skip_resume:1; /* Set by subsystems */
#else
bool should_wakeup:1;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 734/869] PM: sleep: core: Restrict power.set_active propagation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (732 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 733/869] PM: sleep: core: Synchronize runtime PM status of parents and children Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 735/869] PM: Rearrange documentation related to __pm_runtime_disable() Greg Kroah-Hartman
` (135 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jon Hunter, Johan Hovold,
Rafael J. Wysocki, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
[ Upstream commit 7585946243d614bd2cd4e13377be2c711c9539e0 ]
Commit 3775fc538f53 ("PM: sleep: core: Synchronize runtime PM status of
parents and children") exposed an issue related to simple_pm_bus_pm_ops
that uses pm_runtime_force_suspend() and pm_runtime_force_resume() as
bus type PM callbacks for the noirq phases of system-wide suspend and
resume.
The problem is that pm_runtime_force_suspend() does not distinguish
runtime-suspended devices from devices for which runtime PM has never
been enabled, so if it sees a device with runtime PM status set to
RPM_ACTIVE, it will assume that runtime PM is enabled for that device
and so it will attempt to suspend it with the help of its runtime PM
callbacks which may not be ready for that. As it turns out, this
causes simple_pm_bus_runtime_suspend() to crash due to a NULL pointer
dereference.
Another problem related to the above commit and simple_pm_bus_pm_ops is
that setting runtime PM status of a device handled by the latter to
RPM_ACTIVE will actually prevent it from being resumed because
pm_runtime_force_resume() only resumes devices with runtime PM status
set to RPM_SUSPENDED.
To mitigate these issues, do not allow power.set_active to propagate
beyond the parent of the device with DPM_FLAG_SMART_SUSPEND set that
will need to be resumed, which should be a sufficient stop-gap for the
time being, but they will need to be properly addressed in the future
because in general during system-wide resume it is necessary to resume
all devices in a dependency chain in which at least one device is going
to be resumed.
Fixes: 3775fc538f53 ("PM: sleep: core: Synchronize runtime PM status of parents and children")
Closes: https://lore.kernel.org/linux-pm/1c2433d4-7e0f-4395-b841-b8eac7c25651@nvidia.com/
Reported-by: Jon Hunter <jonathanh@nvidia.com>
Tested-by: Johan Hovold <johan+linaro@kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/6137505.lOV4Wx5bFT@rjwysocki.net
Stable-dep-of: 36d74f17e03f ("driver core: Avoid warning when removing a device while its supplier is unbinding")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/base/power/main.c | 21 +++++++++------------
1 file changed, 9 insertions(+), 12 deletions(-)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 71489b46a07bb..34645758b2f1b 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1189,24 +1189,18 @@ static pm_message_t resume_event(pm_message_t sleep_state)
return PMSG_ON;
}
-static void dpm_superior_set_must_resume(struct device *dev, bool set_active)
+static void dpm_superior_set_must_resume(struct device *dev)
{
struct device_link *link;
int idx;
- if (dev->parent) {
+ if (dev->parent)
dev->parent->power.must_resume = true;
- if (set_active)
- dev->parent->power.set_active = true;
- }
idx = device_links_read_lock();
- list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) {
+ list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node)
link->supplier->power.must_resume = true;
- if (set_active)
- link->supplier->power.set_active = true;
- }
device_links_read_unlock(idx);
}
@@ -1284,9 +1278,12 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
dev->power.must_resume = true;
if (dev->power.must_resume) {
- dev->power.set_active = dev->power.set_active ||
- dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND);
- dpm_superior_set_must_resume(dev, dev->power.set_active);
+ if (dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) {
+ dev->power.set_active = true;
+ if (dev->parent && !dev->parent->power.ignore_children)
+ dev->parent->power.set_active = true;
+ }
+ dpm_superior_set_must_resume(dev);
}
Complete:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 735/869] PM: Rearrange documentation related to __pm_runtime_disable()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (733 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 734/869] PM: sleep: core: Restrict power.set_active propagation Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 736/869] PM: Block enabling of runtime PM during system suspend Greg Kroah-Hartman
` (134 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rafael J. Wysocki, Ulf Hansson,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
[ Upstream commit 258e231dc29fbd72bc82c16859a8304f71780ba2 ]
There are only two callers of __pm_runtime_disable(), one of which is
device_suspend_late() and the other is pm_runtime_disable() that has
its own kerneldoc comment and there are no plans to add any more of
them. Since they use different values of the __pm_runtime_disable()
second parameter, the actual code behavior is different in each case,
but it is all documented in the __pm_runtime_disable() kerneldoc comment
which is not particularly straightforward.
For this reason, move the information from the __pm_runtime_disable()
kerneldoc comment to the pm_runtime_disable() one and into a separate
comment in device_suspend_late() and remove the __pm_runtime_disable()
kerneldoc comment altogether.
No functional impact.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Link: https://patch.msgid.link/12617588.O9o76ZdvQC@rjwysocki.net
Stable-dep-of: 36d74f17e03f ("driver core: Avoid warning when removing a device while its supplier is unbinding")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/base/power/main.c | 4 ++++
drivers/base/power/runtime.c | 14 --------------
include/linux/pm_runtime.h | 17 ++++++++++++-----
3 files changed, 16 insertions(+), 19 deletions(-)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 34645758b2f1b..577202aaaffbf 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1401,6 +1401,10 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
TRACE_DEVICE(dev);
TRACE_SUSPEND(0);
+ /*
+ * Disable runtime PM for the device without checking if there is a
+ * pending resume request for it.
+ */
__pm_runtime_disable(dev, false);
dpm_wait_for_subordinate(dev, async);
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 167ff6f7a3fec..b81d12a45aeb1 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1469,20 +1469,6 @@ int pm_runtime_barrier(struct device *dev)
}
EXPORT_SYMBOL_GPL(pm_runtime_barrier);
-/**
- * __pm_runtime_disable - Disable runtime PM of a device.
- * @dev: Device to handle.
- * @check_resume: If set, check if there's a resume request for the device.
- *
- * Increment power.disable_depth for the device and if it was zero previously,
- * cancel all pending runtime PM requests for the device and wait for all
- * operations in progress to complete. The device can be either active or
- * suspended after its runtime PM has been disabled.
- *
- * If @check_resume is set and there's a resume request pending when
- * __pm_runtime_disable() is called and power.disable_depth is zero, the
- * function will wake up the device before disabling its runtime PM.
- */
void __pm_runtime_disable(struct device *dev, bool check_resume)
{
spin_lock_irq(&dev->power.lock);
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 142ab39a3b386..dfc367df1c305 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -562,11 +562,18 @@ static inline int pm_runtime_set_suspended(struct device *dev)
* pm_runtime_disable - Disable runtime PM for a device.
* @dev: Target device.
*
- * Prevent the runtime PM framework from working with @dev (by incrementing its
- * "blocking" counter).
- *
- * For each invocation of this function for @dev there must be a matching
- * pm_runtime_enable() call in order for runtime PM to be enabled for it.
+ * Prevent the runtime PM framework from working with @dev by incrementing its
+ * "disable" counter.
+ *
+ * If the counter is zero when this function runs and there is a pending runtime
+ * resume request for @dev, it will be resumed. If the counter is still zero at
+ * that point, all of the pending runtime PM requests for @dev will be canceled
+ * and all runtime PM operations in progress involving it will be waited for to
+ * complete.
+ *
+ * For each invocation of this function for @dev, there must be a matching
+ * pm_runtime_enable() call, so that runtime PM is eventually enabled for it
+ * again.
*/
static inline void pm_runtime_disable(struct device *dev)
{
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 736/869] PM: Block enabling of runtime PM during system suspend
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (734 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 735/869] PM: Rearrange documentation related to __pm_runtime_disable() Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 737/869] PM: runtime: Introduce pm_runtime_blocked() Greg Kroah-Hartman
` (133 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rafael J. Wysocki, Ulf Hansson,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
[ Upstream commit 3e5eee147b7b0f5a93f56beffe34e81fdd00fa0d ]
If device_prepare() runs on a device that has never had runtime
PM enabled so far, it may reasonably assume that runtime PM will
not be enabled for that device during the system suspend-resume
cycle currently in progress, but this has never been guaranteed.
To verify this assumption, make device_prepare() arrange for
triggering a device warning accompanied by a call trace dump if
runtime PM is enabled for such a device after it has returned.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Link: https://patch.msgid.link/6131109.lOV4Wx5bFT@rjwysocki.net
Stable-dep-of: 36d74f17e03f ("driver core: Avoid warning when removing a device while its supplier is unbinding")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/base/power/main.c | 9 +++++++++
drivers/base/power/runtime.c | 24 ++++++++++++++++++++++++
include/linux/pm.h | 1 +
include/linux/pm_runtime.h | 4 ++++
4 files changed, 38 insertions(+)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 577202aaaffbf..f523eaf021e5e 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1107,6 +1107,8 @@ static void device_complete(struct device *dev, pm_message_t state)
device_unlock(dev);
out:
+ /* If enabling runtime PM for the device is blocked, unblock it. */
+ pm_runtime_unblock(dev);
pm_runtime_put(dev);
}
@@ -1813,6 +1815,13 @@ static int device_prepare(struct device *dev, pm_message_t state)
* it again during the complete phase.
*/
pm_runtime_get_noresume(dev);
+ /*
+ * If runtime PM is disabled for the device at this point and it has
+ * never been enabled so far, it should not be enabled until this system
+ * suspend-resume cycle is complete, so prepare to trigger a warning on
+ * subsequent attempts to enable it.
+ */
+ pm_runtime_block_if_disabled(dev);
if (dev->power.syscore)
return 0;
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index b81d12a45aeb1..8f01b394ea3be 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1469,6 +1469,26 @@ int pm_runtime_barrier(struct device *dev)
}
EXPORT_SYMBOL_GPL(pm_runtime_barrier);
+void pm_runtime_block_if_disabled(struct device *dev)
+{
+ spin_lock_irq(&dev->power.lock);
+
+ if (dev->power.disable_depth && dev->power.last_status == RPM_INVALID)
+ dev->power.last_status = RPM_BLOCKED;
+
+ spin_unlock_irq(&dev->power.lock);
+}
+
+void pm_runtime_unblock(struct device *dev)
+{
+ spin_lock_irq(&dev->power.lock);
+
+ if (dev->power.last_status == RPM_BLOCKED)
+ dev->power.last_status = RPM_INVALID;
+
+ spin_unlock_irq(&dev->power.lock);
+}
+
void __pm_runtime_disable(struct device *dev, bool check_resume)
{
spin_lock_irq(&dev->power.lock);
@@ -1527,6 +1547,10 @@ void pm_runtime_enable(struct device *dev)
if (--dev->power.disable_depth > 0)
goto out;
+ if (dev->power.last_status == RPM_BLOCKED) {
+ dev_warn(dev, "Attempt to enable runtime PM when it is blocked\n");
+ dump_stack();
+ }
dev->power.last_status = RPM_INVALID;
dev->power.accounting_timestamp = ktime_get_mono_fast_ns();
diff --git a/include/linux/pm.h b/include/linux/pm.h
index a478737115cd9..b14c20603ef71 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -600,6 +600,7 @@ enum rpm_status {
RPM_RESUMING,
RPM_SUSPENDED,
RPM_SUSPENDING,
+ RPM_BLOCKED,
};
/*
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index dfc367df1c305..c52125d990bf6 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -78,6 +78,8 @@ extern int pm_runtime_get_if_in_use(struct device *dev);
extern int pm_schedule_suspend(struct device *dev, unsigned int delay);
extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
extern int pm_runtime_barrier(struct device *dev);
+extern void pm_runtime_block_if_disabled(struct device *dev);
+extern void pm_runtime_unblock(struct device *dev);
extern void pm_runtime_enable(struct device *dev);
extern void __pm_runtime_disable(struct device *dev, bool check_resume);
extern void pm_runtime_allow(struct device *dev);
@@ -275,6 +277,8 @@ static inline int pm_runtime_get_if_active(struct device *dev)
static inline int __pm_runtime_set_status(struct device *dev,
unsigned int status) { return 0; }
static inline int pm_runtime_barrier(struct device *dev) { return 0; }
+static inline void pm_runtime_block_if_disabled(struct device *dev) {}
+static inline void pm_runtime_unblock(struct device *dev) {}
static inline void pm_runtime_enable(struct device *dev) {}
static inline void __pm_runtime_disable(struct device *dev, bool c) {}
static inline void pm_runtime_allow(struct device *dev) {}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 737/869] PM: runtime: Introduce pm_runtime_blocked()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (735 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 736/869] PM: Block enabling of runtime PM during system suspend Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 738/869] PM: sleep: Use DPM_FLAG_SMART_SUSPEND conditionally Greg Kroah-Hartman
` (132 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rafael J. Wysocki, Ulf Hansson,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
[ Upstream commit 758cc55ce3d5d79e8f98adbd03ad2cd29133af33 ]
Introduce a new helper function called pm_runtime_blocked()
for checking the power.last_status value indicating whether or not
enabling runtime PM for the given device has been blocked (which
happens in the "prepare" phase of system-wide suspend if runtime
PM is disabled for the given device at that point).
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Link: https://patch.msgid.link/4632087.LvFx2qVVIh@rjwysocki.net
Stable-dep-of: 36d74f17e03f ("driver core: Avoid warning when removing a device while its supplier is unbinding")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/base/power/runtime.c | 17 +++++++++++++++++
include/linux/pm_runtime.h | 2 ++
2 files changed, 19 insertions(+)
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 8f01b394ea3be..d189d88937753 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1590,6 +1590,23 @@ int devm_pm_runtime_set_active_enabled(struct device *dev)
}
EXPORT_SYMBOL_GPL(devm_pm_runtime_set_active_enabled);
+bool pm_runtime_blocked(struct device *dev)
+{
+ bool ret;
+
+ /*
+ * dev->power.last_status is a bit field, so in case it is updated via
+ * RMW, read it under the spin lock.
+ */
+ spin_lock_irq(&dev->power.lock);
+
+ ret = dev->power.last_status == RPM_BLOCKED;
+
+ spin_unlock_irq(&dev->power.lock);
+
+ return ret;
+}
+
static void pm_runtime_disable_action(void *data)
{
pm_runtime_dont_use_autosuspend(data);
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index c52125d990bf6..41db4d628d25e 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -82,6 +82,7 @@ extern void pm_runtime_block_if_disabled(struct device *dev);
extern void pm_runtime_unblock(struct device *dev);
extern void pm_runtime_enable(struct device *dev);
extern void __pm_runtime_disable(struct device *dev, bool check_resume);
+extern bool pm_runtime_blocked(struct device *dev);
extern void pm_runtime_allow(struct device *dev);
extern void pm_runtime_forbid(struct device *dev);
extern void pm_runtime_no_callbacks(struct device *dev);
@@ -281,6 +282,7 @@ static inline void pm_runtime_block_if_disabled(struct device *dev) {}
static inline void pm_runtime_unblock(struct device *dev) {}
static inline void pm_runtime_enable(struct device *dev) {}
static inline void __pm_runtime_disable(struct device *dev, bool c) {}
+static inline bool pm_runtime_blocked(struct device *dev) { return true; }
static inline void pm_runtime_allow(struct device *dev) {}
static inline void pm_runtime_forbid(struct device *dev) {}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 738/869] PM: sleep: Use DPM_FLAG_SMART_SUSPEND conditionally
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (736 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 737/869] PM: runtime: Introduce pm_runtime_blocked() Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 739/869] PM: sleep: Fix bit masking operation Greg Kroah-Hartman
` (131 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rafael J. Wysocki, Ulf Hansson,
Sasha Levin, Bjorn Helgaas
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
[ Upstream commit bca84a7b93fdc744d79d94423c2cb905b1832310 ]
A recent discussion has revealed that using DPM_FLAG_SMART_SUSPEND
unconditionally is generally problematic because it may lead to
situations in which the device's runtime PM information is internally
inconsistent or does not reflect its real state [1].
For this reason, change the handling of DPM_FLAG_SMART_SUSPEND so that
it is only taken into account if it is consistently set by the drivers
of all devices having any PM callbacks throughout dependency graphs in
accordance with the following rules:
- The "smart suspend" feature is only enabled for devices whose drivers
ask for it (that is, set DPM_FLAG_SMART_SUSPEND) and for devices
without PM callbacks unless they have never had runtime PM enabled.
- The "smart suspend" feature is not enabled for a device if it has not
been enabled for the device's parent unless the parent does not take
children into account or it has never had runtime PM enabled.
- The "smart suspend" feature is not enabled for a device if it has not
been enabled for one of the device's suppliers taking runtime PM into
account unless that supplier has never had runtime PM enabled.
Namely, introduce a new device PM flag called smart_suspend that is only
set if the above conditions are met and update all DPM_FLAG_SMART_SUSPEND
users to check power.smart_suspend instead of directly checking the
latter.
At the same time, drop the power.set_active flage introduced recently
in commit 3775fc538f53 ("PM: sleep: core: Synchronize runtime PM status
of parents and children") because it is now sufficient to check
power.smart_suspend along with the dev_pm_skip_resume() return value
to decide whether or not pm_runtime_set_active() needs to be called
for the device.
Link: https://lore.kernel.org/linux-pm/CAPDyKFroyU3YDSfw_Y6k3giVfajg3NQGwNWeteJWqpW29BojhQ@mail.gmail.com/ [1]
Fixes: 7585946243d6 ("PM: sleep: core: Restrict power.set_active propagation")
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: Bjorn Helgaas <bhelgaas@google.com> # drivers/pci
Link: https://patch.msgid.link/1914558.tdWV9SEqCh@rjwysocki.net
Stable-dep-of: 36d74f17e03f ("driver core: Avoid warning when removing a device while its supplier is unbinding")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/acpi/device_pm.c | 4 +--
drivers/base/power/main.c | 63 ++++++++++++++++++++++++++++++---------
drivers/mfd/intel-lpss.c | 2 +-
drivers/pci/pci-driver.c | 6 ++--
include/linux/device.h | 9 ++++++
include/linux/pm.h | 2 +-
6 files changed, 64 insertions(+), 22 deletions(-)
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 3b4d048c49417..dbd4446025ecd 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -1161,7 +1161,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_complete);
*/
int acpi_subsys_suspend(struct device *dev)
{
- if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
+ if (!dev_pm_smart_suspend(dev) ||
acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
pm_runtime_resume(dev);
@@ -1320,7 +1320,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_restore_early);
*/
int acpi_subsys_poweroff(struct device *dev)
{
- if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
+ if (!dev_pm_smart_suspend(dev) ||
acpi_dev_needs_resume(dev, ACPI_COMPANION(dev)))
pm_runtime_resume(dev);
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index f523eaf021e5e..cac90c7480d2b 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -654,15 +654,13 @@ static void device_resume_noirq(struct device *dev, pm_message_t state, bool asy
* so change its status accordingly.
*
* Otherwise, the device is going to be resumed, so set its PM-runtime
- * status to "active" unless its power.set_active flag is clear, in
+ * status to "active" unless its power.smart_suspend flag is clear, in
* which case it is not necessary to update its PM-runtime status.
*/
- if (skip_resume) {
+ if (skip_resume)
pm_runtime_set_suspended(dev);
- } else if (dev->power.set_active) {
+ else if (dev_pm_smart_suspend(dev))
pm_runtime_set_active(dev);
- dev->power.set_active = false;
- }
if (dev->pm_domain) {
info = "noirq power domain ";
@@ -1279,14 +1277,8 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
dev->power.may_skip_resume) || !pm_runtime_need_not_resume(dev))
dev->power.must_resume = true;
- if (dev->power.must_resume) {
- if (dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) {
- dev->power.set_active = true;
- if (dev->parent && !dev->parent->power.ignore_children)
- dev->parent->power.set_active = true;
- }
+ if (dev->power.must_resume)
dpm_superior_set_must_resume(dev);
- }
Complete:
complete_all(&dev->power.completion);
@@ -1795,6 +1787,49 @@ int dpm_suspend(pm_message_t state)
return error;
}
+static void device_prepare_smart_suspend(struct device *dev)
+{
+ struct device_link *link;
+ int idx;
+
+ /*
+ * The "smart suspend" feature is enabled for devices whose drivers ask
+ * for it and for devices without PM callbacks unless runtime PM is
+ * disabled and enabling it is blocked for them.
+ *
+ * However, if "smart suspend" is not enabled for the device's parent
+ * or any of its suppliers that take runtime PM into account, it cannot
+ * be enabled for the device either.
+ */
+ dev->power.smart_suspend = (dev->power.no_pm_callbacks ||
+ dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) &&
+ !pm_runtime_blocked(dev);
+
+ if (!dev_pm_smart_suspend(dev))
+ return;
+
+ if (dev->parent && !dev_pm_smart_suspend(dev->parent) &&
+ !dev->parent->power.ignore_children && !pm_runtime_blocked(dev->parent)) {
+ dev->power.smart_suspend = false;
+ return;
+ }
+
+ idx = device_links_read_lock();
+
+ list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) {
+ if (!(link->flags | DL_FLAG_PM_RUNTIME))
+ continue;
+
+ if (!dev_pm_smart_suspend(link->supplier) &&
+ !pm_runtime_blocked(link->supplier)) {
+ dev->power.smart_suspend = false;
+ break;
+ }
+ }
+
+ device_links_read_unlock(idx);
+}
+
/**
* device_prepare - Prepare a device for system power transition.
* @dev: Device to handle.
@@ -1856,6 +1891,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
pm_runtime_put(dev);
return ret;
}
+ device_prepare_smart_suspend(dev);
/*
* A positive return value from ->prepare() means "this device appears
* to be runtime-suspended and its state is fine, so if it really is
@@ -2031,6 +2067,5 @@ void device_pm_check_callbacks(struct device *dev)
bool dev_pm_skip_suspend(struct device *dev)
{
- return dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) &&
- pm_runtime_status_suspended(dev);
+ return dev_pm_smart_suspend(dev) && pm_runtime_status_suspended(dev);
}
diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c
index 2a9018112dfc8..6901a61a09a4e 100644
--- a/drivers/mfd/intel-lpss.c
+++ b/drivers/mfd/intel-lpss.c
@@ -480,7 +480,7 @@ EXPORT_SYMBOL_NS_GPL(intel_lpss_remove, INTEL_LPSS);
static int resume_lpss_device(struct device *dev, void *data)
{
- if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND))
+ if (!dev_pm_smart_suspend(dev))
pm_runtime_resume(dev);
return 0;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index f74299cb10e3e..f4828252e2225 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -839,8 +839,7 @@ static int pci_pm_suspend(struct device *dev)
* suspend callbacks can cope with runtime-suspended devices, it is
* better to resume the device from runtime suspend here.
*/
- if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
- pci_dev_need_resume(pci_dev)) {
+ if (!dev_pm_smart_suspend(dev) || pci_dev_need_resume(pci_dev)) {
pm_runtime_resume(dev);
pci_dev->state_saved = false;
} else {
@@ -1181,8 +1180,7 @@ static int pci_pm_poweroff(struct device *dev)
}
/* The reason to do that is the same as in pci_pm_suspend(). */
- if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
- pci_dev_need_resume(pci_dev)) {
+ if (!dev_pm_smart_suspend(dev) || pci_dev_need_resume(pci_dev)) {
pm_runtime_resume(dev);
pci_dev->state_saved = false;
} else {
diff --git a/include/linux/device.h b/include/linux/device.h
index 7969d02fe628d..971ae3bdc1aca 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -994,6 +994,15 @@ static inline bool dev_pm_test_driver_flags(struct device *dev, u32 flags)
return !!(dev->power.driver_flags & flags);
}
+static inline bool dev_pm_smart_suspend(struct device *dev)
+{
+#ifdef CONFIG_PM_SLEEP
+ return dev->power.smart_suspend;
+#else
+ return false;
+#endif
+}
+
static inline void device_lock(struct device *dev)
{
mutex_lock(&dev->mutex);
diff --git a/include/linux/pm.h b/include/linux/pm.h
index b14c20603ef71..6bc5598075262 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -683,8 +683,8 @@ struct dev_pm_info {
bool syscore:1;
bool no_pm_callbacks:1; /* Owned by the PM core */
bool async_in_progress:1; /* Owned by the PM core */
+ bool smart_suspend:1; /* Owned by the PM core */
bool must_resume:1; /* Owned by the PM core */
- bool set_active:1; /* Owned by the PM core */
bool may_skip_resume:1; /* Set by subsystems */
#else
bool should_wakeup:1;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 739/869] PM: sleep: Fix bit masking operation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (737 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 738/869] PM: sleep: Use DPM_FLAG_SMART_SUSPEND conditionally Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 740/869] driver core: Add device_link_test() for testing device link flags Greg Kroah-Hartman
` (130 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Colin Ian King, Rafael J. Wysocki,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Colin Ian King <colin.i.king@gmail.com>
[ Upstream commit 3860cbe239639503e56bd4365c6bf4cb957ef04e ]
The mask operation link->flags | DL_FLAG_PM_RUNTIME is always true which
is incorrect. The mask operation should be using the bit-wise &
operator. Fix this.
Fixes: bca84a7b93fd ("PM: sleep: Use DPM_FLAG_SMART_SUSPEND conditionally")
Signed-off-by: Colin Ian King <colin.i.king@gmail.com>
Link: https://patch.msgid.link/20250319114324.791829-1-colin.i.king@gmail.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Stable-dep-of: 36d74f17e03f ("driver core: Avoid warning when removing a device while its supplier is unbinding")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/base/power/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index cac90c7480d2b..89f0da18c98fe 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1817,7 +1817,7 @@ static void device_prepare_smart_suspend(struct device *dev)
idx = device_links_read_lock();
list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) {
- if (!(link->flags | DL_FLAG_PM_RUNTIME))
+ if (!(link->flags & DL_FLAG_PM_RUNTIME))
continue;
if (!dev_pm_smart_suspend(link->supplier) &&
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 740/869] driver core: Add device_link_test() for testing device link flags
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (738 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 739/869] PM: sleep: Fix bit masking operation Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 741/869] driver core: Avoid warning when removing a device while its supplier is unbinding Greg Kroah-Hartman
` (129 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Rafael J. Wysocki, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
[ Upstream commit b29929b819f35503024c6a7e6ad442f6e36c68a0 ]
To avoid coding mistakes like the one fixed by commit 3860cbe23963 ("PM:
sleep: Fix bit masking operation"), introduce device_link_test() for
testing device link flags and use it where applicable.
No intentional functional impact.
Signed-off-by: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
Link: https://lore.kernel.org/r/2793309.mvXUDI8C0e@rjwysocki.net
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: 36d74f17e03f ("driver core: Avoid warning when removing a device while its supplier is unbinding")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/base/core.c | 73 ++++++++++++++++++------------------
drivers/base/power/main.c | 2 +-
drivers/base/power/runtime.c | 6 +--
include/linux/device.h | 5 +++
4 files changed, 45 insertions(+), 41 deletions(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index a6134a5e5e110..ca874afa9aa5f 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -533,9 +533,9 @@ static ssize_t auto_remove_on_show(struct device *dev,
struct device_link *link = to_devlink(dev);
const char *output;
- if (link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER)
+ if (device_link_test(link, DL_FLAG_AUTOREMOVE_SUPPLIER))
output = "supplier unbind";
- else if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER)
+ else if (device_link_test(link, DL_FLAG_AUTOREMOVE_CONSUMER))
output = "consumer unbind";
else
output = "never";
@@ -549,7 +549,7 @@ static ssize_t runtime_pm_show(struct device *dev,
{
struct device_link *link = to_devlink(dev);
- return sysfs_emit(buf, "%d\n", !!(link->flags & DL_FLAG_PM_RUNTIME));
+ return sysfs_emit(buf, "%d\n", device_link_test(link, DL_FLAG_PM_RUNTIME));
}
static DEVICE_ATTR_RO(runtime_pm);
@@ -558,8 +558,7 @@ static ssize_t sync_state_only_show(struct device *dev,
{
struct device_link *link = to_devlink(dev);
- return sysfs_emit(buf, "%d\n",
- !!(link->flags & DL_FLAG_SYNC_STATE_ONLY));
+ return sysfs_emit(buf, "%d\n", device_link_test(link, DL_FLAG_SYNC_STATE_ONLY));
}
static DEVICE_ATTR_RO(sync_state_only);
@@ -865,12 +864,12 @@ struct device_link *device_link_add(struct device *consumer,
if (link->consumer != consumer)
continue;
- if (link->flags & DL_FLAG_INFERRED &&
+ if (device_link_test(link, DL_FLAG_INFERRED) &&
!(flags & DL_FLAG_INFERRED))
link->flags &= ~DL_FLAG_INFERRED;
if (flags & DL_FLAG_PM_RUNTIME) {
- if (!(link->flags & DL_FLAG_PM_RUNTIME)) {
+ if (!device_link_test(link, DL_FLAG_PM_RUNTIME)) {
pm_runtime_new_link(consumer);
link->flags |= DL_FLAG_PM_RUNTIME;
}
@@ -880,8 +879,8 @@ struct device_link *device_link_add(struct device *consumer,
if (flags & DL_FLAG_STATELESS) {
kref_get(&link->kref);
- if (link->flags & DL_FLAG_SYNC_STATE_ONLY &&
- !(link->flags & DL_FLAG_STATELESS)) {
+ if (device_link_test(link, DL_FLAG_SYNC_STATE_ONLY) &&
+ !device_link_test(link, DL_FLAG_STATELESS)) {
link->flags |= DL_FLAG_STATELESS;
goto reorder;
} else {
@@ -896,7 +895,7 @@ struct device_link *device_link_add(struct device *consumer,
* update the existing link to stay around longer.
*/
if (flags & DL_FLAG_AUTOREMOVE_SUPPLIER) {
- if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) {
+ if (device_link_test(link, DL_FLAG_AUTOREMOVE_CONSUMER)) {
link->flags &= ~DL_FLAG_AUTOREMOVE_CONSUMER;
link->flags |= DL_FLAG_AUTOREMOVE_SUPPLIER;
}
@@ -904,12 +903,12 @@ struct device_link *device_link_add(struct device *consumer,
link->flags &= ~(DL_FLAG_AUTOREMOVE_CONSUMER |
DL_FLAG_AUTOREMOVE_SUPPLIER);
}
- if (!(link->flags & DL_FLAG_MANAGED)) {
+ if (!device_link_test(link, DL_FLAG_MANAGED)) {
kref_get(&link->kref);
link->flags |= DL_FLAG_MANAGED;
device_link_init_status(link, consumer, supplier);
}
- if (link->flags & DL_FLAG_SYNC_STATE_ONLY &&
+ if (device_link_test(link, DL_FLAG_SYNC_STATE_ONLY) &&
!(flags & DL_FLAG_SYNC_STATE_ONLY)) {
link->flags &= ~DL_FLAG_SYNC_STATE_ONLY;
goto reorder;
@@ -1013,7 +1012,7 @@ static void __device_link_del(struct kref *kref)
static void device_link_put_kref(struct device_link *link)
{
- if (link->flags & DL_FLAG_STATELESS)
+ if (device_link_test(link, DL_FLAG_STATELESS))
kref_put(&link->kref, __device_link_del);
else if (!device_is_registered(link->consumer))
__device_link_del(&link->kref);
@@ -1077,7 +1076,7 @@ static void device_links_missing_supplier(struct device *dev)
if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) {
WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
} else {
- WARN_ON(!(link->flags & DL_FLAG_SYNC_STATE_ONLY));
+ WARN_ON(!device_link_test(link, DL_FLAG_SYNC_STATE_ONLY));
WRITE_ONCE(link->status, DL_STATE_DORMANT);
}
}
@@ -1145,14 +1144,14 @@ int device_links_check_suppliers(struct device *dev)
device_links_write_lock();
list_for_each_entry(link, &dev->links.suppliers, c_node) {
- if (!(link->flags & DL_FLAG_MANAGED))
+ if (!device_link_test(link, DL_FLAG_MANAGED))
continue;
if (link->status != DL_STATE_AVAILABLE &&
- !(link->flags & DL_FLAG_SYNC_STATE_ONLY)) {
+ !device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)) {
if (dev_is_best_effort(dev) &&
- link->flags & DL_FLAG_INFERRED &&
+ device_link_test(link, DL_FLAG_INFERRED) &&
!link->supplier->can_match) {
ret = -EAGAIN;
continue;
@@ -1201,7 +1200,7 @@ static void __device_links_queue_sync_state(struct device *dev,
return;
list_for_each_entry(link, &dev->links.consumers, s_node) {
- if (!(link->flags & DL_FLAG_MANAGED))
+ if (!device_link_test(link, DL_FLAG_MANAGED))
continue;
if (link->status != DL_STATE_ACTIVE)
return;
@@ -1341,7 +1340,7 @@ void device_links_force_bind(struct device *dev)
device_links_write_lock();
list_for_each_entry_safe(link, ln, &dev->links.suppliers, c_node) {
- if (!(link->flags & DL_FLAG_MANAGED))
+ if (!device_link_test(link, DL_FLAG_MANAGED))
continue;
if (link->status != DL_STATE_AVAILABLE) {
@@ -1394,7 +1393,7 @@ void device_links_driver_bound(struct device *dev)
device_links_write_lock();
list_for_each_entry(link, &dev->links.consumers, s_node) {
- if (!(link->flags & DL_FLAG_MANAGED))
+ if (!device_link_test(link, DL_FLAG_MANAGED))
continue;
/*
@@ -1410,7 +1409,7 @@ void device_links_driver_bound(struct device *dev)
WARN_ON(link->status != DL_STATE_DORMANT);
WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
- if (link->flags & DL_FLAG_AUTOPROBE_CONSUMER)
+ if (device_link_test(link, DL_FLAG_AUTOPROBE_CONSUMER))
driver_deferred_probe_add(link->consumer);
}
@@ -1422,11 +1421,11 @@ void device_links_driver_bound(struct device *dev)
list_for_each_entry_safe(link, ln, &dev->links.suppliers, c_node) {
struct device *supplier;
- if (!(link->flags & DL_FLAG_MANAGED))
+ if (!device_link_test(link, DL_FLAG_MANAGED))
continue;
supplier = link->supplier;
- if (link->flags & DL_FLAG_SYNC_STATE_ONLY) {
+ if (device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)) {
/*
* When DL_FLAG_SYNC_STATE_ONLY is set, it means no
* other DL_MANAGED_LINK_FLAGS have been set. So, it's
@@ -1434,7 +1433,7 @@ void device_links_driver_bound(struct device *dev)
*/
device_link_drop_managed(link);
} else if (dev_is_best_effort(dev) &&
- link->flags & DL_FLAG_INFERRED &&
+ device_link_test(link, DL_FLAG_INFERRED) &&
link->status != DL_STATE_CONSUMER_PROBE &&
!link->supplier->can_match) {
/*
@@ -1486,10 +1485,10 @@ static void __device_links_no_driver(struct device *dev)
struct device_link *link, *ln;
list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) {
- if (!(link->flags & DL_FLAG_MANAGED))
+ if (!device_link_test(link, DL_FLAG_MANAGED))
continue;
- if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) {
+ if (device_link_test(link, DL_FLAG_AUTOREMOVE_CONSUMER)) {
device_link_drop_managed(link);
continue;
}
@@ -1501,7 +1500,7 @@ static void __device_links_no_driver(struct device *dev)
if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) {
WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
} else {
- WARN_ON(!(link->flags & DL_FLAG_SYNC_STATE_ONLY));
+ WARN_ON(!device_link_test(link, DL_FLAG_SYNC_STATE_ONLY));
WRITE_ONCE(link->status, DL_STATE_DORMANT);
}
}
@@ -1526,7 +1525,7 @@ void device_links_no_driver(struct device *dev)
device_links_write_lock();
list_for_each_entry(link, &dev->links.consumers, s_node) {
- if (!(link->flags & DL_FLAG_MANAGED))
+ if (!device_link_test(link, DL_FLAG_MANAGED))
continue;
/*
@@ -1563,10 +1562,10 @@ void device_links_driver_cleanup(struct device *dev)
device_links_write_lock();
list_for_each_entry_safe(link, ln, &dev->links.consumers, s_node) {
- if (!(link->flags & DL_FLAG_MANAGED))
+ if (!device_link_test(link, DL_FLAG_MANAGED))
continue;
- WARN_ON(link->flags & DL_FLAG_AUTOREMOVE_CONSUMER);
+ WARN_ON(device_link_test(link, DL_FLAG_AUTOREMOVE_CONSUMER));
WARN_ON(link->status != DL_STATE_SUPPLIER_UNBIND);
/*
@@ -1575,7 +1574,7 @@ void device_links_driver_cleanup(struct device *dev)
* has moved to DL_STATE_SUPPLIER_UNBIND.
*/
if (link->status == DL_STATE_SUPPLIER_UNBIND &&
- link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER)
+ device_link_test(link, DL_FLAG_AUTOREMOVE_SUPPLIER))
device_link_drop_managed(link);
WRITE_ONCE(link->status, DL_STATE_DORMANT);
@@ -1609,7 +1608,7 @@ bool device_links_busy(struct device *dev)
device_links_write_lock();
list_for_each_entry(link, &dev->links.consumers, s_node) {
- if (!(link->flags & DL_FLAG_MANAGED))
+ if (!device_link_test(link, DL_FLAG_MANAGED))
continue;
if (link->status == DL_STATE_CONSUMER_PROBE
@@ -1651,8 +1650,8 @@ void device_links_unbind_consumers(struct device *dev)
list_for_each_entry(link, &dev->links.consumers, s_node) {
enum device_link_state status;
- if (!(link->flags & DL_FLAG_MANAGED) ||
- link->flags & DL_FLAG_SYNC_STATE_ONLY)
+ if (!device_link_test(link, DL_FLAG_MANAGED) ||
+ device_link_test(link, DL_FLAG_SYNC_STATE_ONLY))
continue;
status = link->status;
@@ -1808,7 +1807,7 @@ static void fw_devlink_parse_fwtree(struct fwnode_handle *fwnode)
static void fw_devlink_relax_link(struct device_link *link)
{
- if (!(link->flags & DL_FLAG_INFERRED))
+ if (!device_link_test(link, DL_FLAG_INFERRED))
return;
if (device_link_flag_is_sync_state_only(link->flags))
@@ -1844,7 +1843,7 @@ static int fw_devlink_dev_sync_state(struct device *dev, void *data)
struct device_link *link = to_devlink(dev);
struct device *sup = link->supplier;
- if (!(link->flags & DL_FLAG_MANAGED) ||
+ if (!device_link_test(link, DL_FLAG_MANAGED) ||
link->status == DL_STATE_ACTIVE || sup->state_synced ||
!dev_has_sync_state(sup))
return 0;
@@ -2126,7 +2125,7 @@ static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle,
* such due to a cycle.
*/
if (device_link_flag_is_sync_state_only(dev_link->flags) &&
- !(dev_link->flags & DL_FLAG_CYCLE))
+ !device_link_test(dev_link, DL_FLAG_CYCLE))
continue;
if (__fw_devlink_relax_cycles(con_handle,
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 89f0da18c98fe..fab8df1e29e62 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1817,7 +1817,7 @@ static void device_prepare_smart_suspend(struct device *dev)
idx = device_links_read_lock();
list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) {
- if (!(link->flags & DL_FLAG_PM_RUNTIME))
+ if (!device_link_test(link, DL_FLAG_PM_RUNTIME))
continue;
if (!dev_pm_smart_suspend(link->supplier) &&
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index d189d88937753..b0b72fa2a1202 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -290,7 +290,7 @@ static int rpm_get_suppliers(struct device *dev)
device_links_read_lock_held()) {
int retval;
- if (!(link->flags & DL_FLAG_PM_RUNTIME))
+ if (!device_link_test(link, DL_FLAG_PM_RUNTIME))
continue;
retval = pm_runtime_get_sync(link->supplier);
@@ -1900,7 +1900,7 @@ void pm_runtime_get_suppliers(struct device *dev)
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
device_links_read_lock_held())
- if (link->flags & DL_FLAG_PM_RUNTIME) {
+ if (device_link_test(link, DL_FLAG_PM_RUNTIME)) {
link->supplier_preactivated = true;
pm_runtime_get_sync(link->supplier);
}
@@ -1954,7 +1954,7 @@ static void pm_runtime_drop_link_count(struct device *dev)
*/
void pm_runtime_drop_link(struct device_link *link)
{
- if (!(link->flags & DL_FLAG_PM_RUNTIME))
+ if (!device_link_test(link, DL_FLAG_PM_RUNTIME))
return;
pm_runtime_drop_link_count(link->consumer);
diff --git a/include/linux/device.h b/include/linux/device.h
index 971ae3bdc1aca..cc2ef7f0539cd 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -1262,6 +1262,11 @@ void device_links_supplier_sync_state_pause(void);
void device_links_supplier_sync_state_resume(void);
void device_link_wait_removal(void);
+static inline bool device_link_test(const struct device_link *link, u32 flags)
+{
+ return !!(link->flags & flags);
+}
+
/* Create alias, so I can be autoloaded. */
#define MODULE_ALIAS_CHARDEV(major,minor) \
MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor))
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 741/869] driver core: Avoid warning when removing a device while its supplier is unbinding
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (739 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 740/869] driver core: Add device_link_test() for testing device link flags Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 742/869] serial: 8250: invert serial8250_register_8250_port() CIR condition Greg Kroah-Hartman
` (128 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Herve Codina, Rafael J. Wysocki,
Saravana Kannan, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Herve Codina <herve.codina@bootlin.com>
[ Upstream commit 36d74f17e03f7e60e1b08fbe16cfad6e69cc3aa9 ]
During driver removal, the following warning can appear:
WARNING: CPU: 1 PID: 139 at drivers/base/core.c:1497 __device_links_no_driver+0xcc/0xfc
...
Call trace:
__device_links_no_driver+0xcc/0xfc (P)
device_links_driver_cleanup+0xa8/0xf0
device_release_driver_internal+0x208/0x23c
device_links_unbind_consumers+0xe0/0x108
device_release_driver_internal+0xec/0x23c
device_links_unbind_consumers+0xe0/0x108
device_release_driver_internal+0xec/0x23c
device_links_unbind_consumers+0xe0/0x108
device_release_driver_internal+0xec/0x23c
driver_detach+0xa0/0x12c
bus_remove_driver+0x6c/0xbc
driver_unregister+0x30/0x60
pci_unregister_driver+0x20/0x9c
lan966x_pci_driver_exit+0x18/0xa90 [lan966x_pci]
This warning is triggered when a consumer is removed because the links
status of its supplier is not DL_DEV_DRIVER_BOUND and the link flag
DL_FLAG_SYNC_STATE_ONLY is not set.
The topology in terms of consumers/suppliers used was the following
(consumer ---> supplier):
i2c -----------> OIC ----> PCI device
| ^
| |
+---> pinctrl ---+
When the PCI device is removed, the OIC (interrupt controller) has to be
removed. In order to remove the OIC, pinctrl and i2c need to be removed
and to remove pinctrl, i2c need to be removed. The removal order is:
1) i2c
2) pinctrl
3) OIC
4) PCI device
In details, the removal sequence is the following (with 0000:01:00.0 the
PCI device):
driver_detach: call device_release_driver_internal(0000:01:00.0)...
device_links_busy(0000:01:00.0):
links->status = DL_DEV_UNBINDING
device_links_unbind_consumers(0000:01:00.0):
0000:01:00.0--oic link->status = DL_STATE_SUPPLIER_UNBIND
call device_release_driver_internal(oic)...
device_links_busy(oic):
links->status = DL_DEV_UNBINDING
device_links_unbind_consumers(oic):
oic--pinctrl link->status = DL_STATE_SUPPLIER_UNBIND
call device_release_driver_internal(pinctrl)...
device_links_busy(pinctrl):
links->status = DL_DEV_UNBINDING
device_links_unbind_consumers(pinctrl):
pinctrl--i2c link->status = DL_STATE_SUPPLIER_UNBIND
call device_release_driver_internal(i2c)...
device_links_busy(i2c): links->status = DL_DEV_UNBINDING
__device_links_no_driver(i2c)...
pinctrl--i2c link->status is DL_STATE_SUPPLIER_UNBIND
oic--i2c link->status is DL_STATE_ACTIVE
oic--i2c link->supplier->links.status is DL_DEV_UNBINDING
The warning is triggered by the i2c removal because the OIC (supplier)
links status is not DL_DEV_DRIVER_BOUND. Its links status is indeed set
to DL_DEV_UNBINDING.
It is perfectly legit to have the links status set to DL_DEV_UNBINDING
in that case. Indeed we had started to unbind the OIC which triggered
the consumer unbinding and didn't finish yet when the i2c is unbound.
Avoid the warning when the supplier links status is set to
DL_DEV_UNBINDING and thus support this removal sequence without any
warnings.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Reviewed-by: Rafael J. Wysocki <rafael@kernel.org>
Reviewed-by: Saravana Kannan <saravanak@google.com>
Link: https://patch.msgid.link/20260511155755.34428-4-herve.codina@bootlin.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/base/core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index ca874afa9aa5f..130354f898e7e 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1500,7 +1500,8 @@ static void __device_links_no_driver(struct device *dev)
if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) {
WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
} else {
- WARN_ON(!device_link_test(link, DL_FLAG_SYNC_STATE_ONLY));
+ WARN_ON(link->supplier->links.status != DL_DEV_UNBINDING &&
+ !device_link_test(link, DL_FLAG_SYNC_STATE_ONLY));
WRITE_ONCE(link->status, DL_STATE_DORMANT);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 742/869] serial: 8250: invert serial8250_register_8250_port() CIR condition
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (740 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 741/869] driver core: Avoid warning when removing a device while its supplier is unbinding Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 743/869] tty: serial: 8250: protect against NULL uart->port.dev in register Greg Kroah-Hartman
` (127 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jiri Slaby (SUSE),
Ilpo Järvinen, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Slaby (SUSE) <jirislaby@kernel.org>
[ Upstream commit 05b537a175442c530593013ea31b3f48d5624916 ]
There is no point in a long 'if' in serial8250_register_8250_port() to
just return ENOSPC for PORT_8250_CIR ports. Invert the condition and
return immediately.
'gpios' variable was moved to its set location.
And return ENODEV instead of ENOSPC. The latter is a leftover from the
previous find-uart 'if'. The former makes a lot more sense in this case.
Signed-off-by: "Jiri Slaby (SUSE)" <jirislaby@kernel.org>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://lore.kernel.org/r/20250611100319.186924-31-jirislaby@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: 941c9f84c9b6 ("tty: serial: 8250: protect against NULL uart->port.dev in register")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/tty/serial/8250/8250_core.c | 253 ++++++++++++++--------------
1 file changed, 127 insertions(+), 126 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 68baf75bdadc4..d7034f305c7b2 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -715,139 +715,140 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
nr_uarts++;
}
- if (uart->port.type != PORT_8250_CIR) {
- struct mctrl_gpios *gpios;
-
- if (uart->port.dev)
- uart_remove_one_port(&serial8250_reg, &uart->port);
-
- uart->port.ctrl_id = up->port.ctrl_id;
- uart->port.port_id = up->port.port_id;
- uart->port.iobase = up->port.iobase;
- uart->port.membase = up->port.membase;
- uart->port.irq = up->port.irq;
- uart->port.irqflags = up->port.irqflags;
- uart->port.uartclk = up->port.uartclk;
- uart->port.fifosize = up->port.fifosize;
- uart->port.regshift = up->port.regshift;
- uart->port.iotype = up->port.iotype;
- uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
- uart->bugs = up->bugs;
- uart->port.mapbase = up->port.mapbase;
- uart->port.mapsize = up->port.mapsize;
- uart->port.private_data = up->port.private_data;
- uart->tx_loadsz = up->tx_loadsz;
- uart->capabilities = up->capabilities;
- uart->port.throttle = up->port.throttle;
- uart->port.unthrottle = up->port.unthrottle;
- uart->port.rs485_config = up->port.rs485_config;
- uart->port.rs485_supported = up->port.rs485_supported;
- uart->port.rs485 = up->port.rs485;
- uart->rs485_start_tx = up->rs485_start_tx;
- uart->rs485_stop_tx = up->rs485_stop_tx;
- uart->lsr_save_mask = up->lsr_save_mask;
- uart->dma = up->dma;
-
- /* Take tx_loadsz from fifosize if it wasn't set separately */
- if (uart->port.fifosize && !uart->tx_loadsz)
- uart->tx_loadsz = uart->port.fifosize;
-
- if (up->port.dev) {
- uart->port.dev = up->port.dev;
- ret = uart_get_rs485_mode(&uart->port);
- if (ret)
- goto err;
- }
+ if (uart->port.type == PORT_8250_CIR) {
+ ret = -ENODEV;
+ goto unlock;
+ }
- if (up->port.flags & UPF_FIXED_TYPE)
- uart->port.type = up->port.type;
+ if (uart->port.dev)
+ uart_remove_one_port(&serial8250_reg, &uart->port);
+
+ uart->port.ctrl_id = up->port.ctrl_id;
+ uart->port.port_id = up->port.port_id;
+ uart->port.iobase = up->port.iobase;
+ uart->port.membase = up->port.membase;
+ uart->port.irq = up->port.irq;
+ uart->port.irqflags = up->port.irqflags;
+ uart->port.uartclk = up->port.uartclk;
+ uart->port.fifosize = up->port.fifosize;
+ uart->port.regshift = up->port.regshift;
+ uart->port.iotype = up->port.iotype;
+ uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
+ uart->bugs = up->bugs;
+ uart->port.mapbase = up->port.mapbase;
+ uart->port.mapsize = up->port.mapsize;
+ uart->port.private_data = up->port.private_data;
+ uart->tx_loadsz = up->tx_loadsz;
+ uart->capabilities = up->capabilities;
+ uart->port.throttle = up->port.throttle;
+ uart->port.unthrottle = up->port.unthrottle;
+ uart->port.rs485_config = up->port.rs485_config;
+ uart->port.rs485_supported = up->port.rs485_supported;
+ uart->port.rs485 = up->port.rs485;
+ uart->rs485_start_tx = up->rs485_start_tx;
+ uart->rs485_stop_tx = up->rs485_stop_tx;
+ uart->lsr_save_mask = up->lsr_save_mask;
+ uart->dma = up->dma;
+
+ /* Take tx_loadsz from fifosize if it wasn't set separately */
+ if (uart->port.fifosize && !uart->tx_loadsz)
+ uart->tx_loadsz = uart->port.fifosize;
+
+ if (up->port.dev) {
+ uart->port.dev = up->port.dev;
+ ret = uart_get_rs485_mode(&uart->port);
+ if (ret)
+ goto err;
+ }
- /*
- * Only call mctrl_gpio_init(), if the device has no ACPI
- * companion device
- */
- if (!has_acpi_companion(uart->port.dev)) {
- gpios = mctrl_gpio_init(&uart->port, 0);
- if (IS_ERR(gpios)) {
- ret = PTR_ERR(gpios);
- goto err;
- } else {
- uart->gpios = gpios;
- }
- }
+ if (up->port.flags & UPF_FIXED_TYPE)
+ uart->port.type = up->port.type;
- serial8250_set_defaults(uart);
-
- /* Possibly override default I/O functions. */
- if (up->port.serial_in)
- uart->port.serial_in = up->port.serial_in;
- if (up->port.serial_out)
- uart->port.serial_out = up->port.serial_out;
- if (up->port.handle_irq)
- uart->port.handle_irq = up->port.handle_irq;
- /* Possibly override set_termios call */
- if (up->port.set_termios)
- uart->port.set_termios = up->port.set_termios;
- if (up->port.set_ldisc)
- uart->port.set_ldisc = up->port.set_ldisc;
- if (up->port.get_mctrl)
- uart->port.get_mctrl = up->port.get_mctrl;
- if (up->port.set_mctrl)
- uart->port.set_mctrl = up->port.set_mctrl;
- if (up->port.get_divisor)
- uart->port.get_divisor = up->port.get_divisor;
- if (up->port.set_divisor)
- uart->port.set_divisor = up->port.set_divisor;
- if (up->port.startup)
- uart->port.startup = up->port.startup;
- if (up->port.shutdown)
- uart->port.shutdown = up->port.shutdown;
- if (up->port.pm)
- uart->port.pm = up->port.pm;
- if (up->port.handle_break)
- uart->port.handle_break = up->port.handle_break;
- if (up->dl_read)
- uart->dl_read = up->dl_read;
- if (up->dl_write)
- uart->dl_write = up->dl_write;
-
- if (uart->port.type != PORT_8250_CIR) {
- if (uart_console_registered(&uart->port))
- pm_runtime_get_sync(uart->port.dev);
-
- if (serial8250_isa_config != NULL)
- serial8250_isa_config(0, &uart->port,
- &uart->capabilities);
-
- serial8250_apply_quirks(uart);
- ret = uart_add_one_port(&serial8250_reg,
- &uart->port);
- if (ret)
- goto err;
-
- ret = uart->port.line;
+ /*
+ * Only call mctrl_gpio_init(), if the device has no ACPI
+ * companion device
+ */
+ if (!has_acpi_companion(uart->port.dev)) {
+ struct mctrl_gpios *gpios = mctrl_gpio_init(&uart->port, 0);
+ if (IS_ERR(gpios)) {
+ ret = PTR_ERR(gpios);
+ goto err;
} else {
- dev_info(uart->port.dev,
- "skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
- uart->port.iobase,
- (unsigned long long)uart->port.mapbase,
- uart->port.irq);
-
- ret = 0;
+ uart->gpios = gpios;
}
+ }
- if (!uart->lsr_save_mask)
- uart->lsr_save_mask = LSR_SAVE_FLAGS; /* Use default LSR mask */
+ serial8250_set_defaults(uart);
+
+ /* Possibly override default I/O functions. */
+ if (up->port.serial_in)
+ uart->port.serial_in = up->port.serial_in;
+ if (up->port.serial_out)
+ uart->port.serial_out = up->port.serial_out;
+ if (up->port.handle_irq)
+ uart->port.handle_irq = up->port.handle_irq;
+ /* Possibly override set_termios call */
+ if (up->port.set_termios)
+ uart->port.set_termios = up->port.set_termios;
+ if (up->port.set_ldisc)
+ uart->port.set_ldisc = up->port.set_ldisc;
+ if (up->port.get_mctrl)
+ uart->port.get_mctrl = up->port.get_mctrl;
+ if (up->port.set_mctrl)
+ uart->port.set_mctrl = up->port.set_mctrl;
+ if (up->port.get_divisor)
+ uart->port.get_divisor = up->port.get_divisor;
+ if (up->port.set_divisor)
+ uart->port.set_divisor = up->port.set_divisor;
+ if (up->port.startup)
+ uart->port.startup = up->port.startup;
+ if (up->port.shutdown)
+ uart->port.shutdown = up->port.shutdown;
+ if (up->port.pm)
+ uart->port.pm = up->port.pm;
+ if (up->port.handle_break)
+ uart->port.handle_break = up->port.handle_break;
+ if (up->dl_read)
+ uart->dl_read = up->dl_read;
+ if (up->dl_write)
+ uart->dl_write = up->dl_write;
- /* Initialise interrupt backoff work if required */
- if (up->overrun_backoff_time_ms > 0) {
- uart->overrun_backoff_time_ms =
- up->overrun_backoff_time_ms;
- INIT_DELAYED_WORK(&uart->overrun_backoff,
- serial_8250_overrun_backoff_work);
- } else {
- uart->overrun_backoff_time_ms = 0;
- }
+ if (uart->port.type != PORT_8250_CIR) {
+ if (uart_console_registered(&uart->port))
+ pm_runtime_get_sync(uart->port.dev);
+
+ if (serial8250_isa_config != NULL)
+ serial8250_isa_config(0, &uart->port,
+ &uart->capabilities);
+
+ serial8250_apply_quirks(uart);
+ ret = uart_add_one_port(&serial8250_reg,
+ &uart->port);
+ if (ret)
+ goto err;
+
+ ret = uart->port.line;
+ } else {
+ dev_info(uart->port.dev,
+ "skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
+ uart->port.iobase,
+ (unsigned long long)uart->port.mapbase,
+ uart->port.irq);
+
+ ret = 0;
+ }
+
+ if (!uart->lsr_save_mask)
+ uart->lsr_save_mask = LSR_SAVE_FLAGS; /* Use default LSR mask */
+
+ /* Initialise interrupt backoff work if required */
+ if (up->overrun_backoff_time_ms > 0) {
+ uart->overrun_backoff_time_ms =
+ up->overrun_backoff_time_ms;
+ INIT_DELAYED_WORK(&uart->overrun_backoff,
+ serial_8250_overrun_backoff_work);
+ } else {
+ uart->overrun_backoff_time_ms = 0;
}
unlock:
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 743/869] tty: serial: 8250: protect against NULL uart->port.dev in register
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (741 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 742/869] serial: 8250: invert serial8250_register_8250_port() CIR condition Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 744/869] drm/amdgpu: Remove unused amdgpu_i2c functions Greg Kroah-Hartman
` (126 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Stepan Ionichev, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stepan Ionichev <sozdayvek@gmail.com>
[ Upstream commit 941c9f84c9b6310f7aaa1c8c785dcc634ee33050 ]
serial8250_register_8250_port() conditionally copies uart->port.dev
from up->port.dev only when up->port.dev is non-NULL:
if (up->port.dev) {
uart->port.dev = up->port.dev;
...
}
So if both the existing uart slot and up have a NULL ->dev,
uart->port.dev remains NULL. The very next ACPI companion check
then dereferences it unconditionally:
if (!has_acpi_companion(uart->port.dev)) {
has_acpi_companion() reads dev->fwnode without a NULL guard
(include/linux/acpi.h), so this NULL-derefs the kernel for the
remaining no-dev case rather than just skipping the
mctrl_gpio_init() initialisation as intended.
smatch flags the inconsistency:
drivers/tty/serial/8250/8250_core.c:767
serial8250_register_8250_port() error: 'uart->port.dev' could be
null (see line 719)
Guard the call with a NULL check so register continues to work
for callers that legitimately have no parent device (legacy
non-OF/non-ACPI registrations).
No functional change for callers that pass a non-NULL ->dev.
Signed-off-by: Stepan Ionichev <sozdayvek@gmail.com>
Link: https://patch.msgid.link/20260508181237.11146-1-sozdayvek@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/tty/serial/8250/8250_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index d7034f305c7b2..f35a060a73a74 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -768,7 +768,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
* Only call mctrl_gpio_init(), if the device has no ACPI
* companion device
*/
- if (!has_acpi_companion(uart->port.dev)) {
+ if (uart->port.dev && !has_acpi_companion(uart->port.dev)) {
struct mctrl_gpios *gpios = mctrl_gpio_init(&uart->port, 0);
if (IS_ERR(gpios)) {
ret = PTR_ERR(gpios);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 744/869] drm/amdgpu: Remove unused amdgpu_i2c functions
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (742 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 743/869] tty: serial: 8250: protect against NULL uart->port.dev in register Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 745/869] drm/amdgpu/atombios: drop empty function Greg Kroah-Hartman
` (125 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dr. David Alan Gilbert, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dr. David Alan Gilbert <linux@treblig.org>
[ Upstream commit 0ee239911634dd29c3b05e1138d617cc3cab33fa ]
amdgpu_i2c_add and amdgpu_i2c_init were added in 2015's commit
d38ceaf99ed0 ("drm/amdgpu: add core driver (v4)")
but never used.
Remove them.
Signed-off-by: Dr. David Alan Gilbert <linux@treblig.org>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Stable-dep-of: a99cd231cd92 ("drm/amdgpu: Bound GPIO I2C table entry count from VBIOS")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c | 25 -------------------------
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h | 4 ----
2 files changed, 29 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
index 00d6211e0fbf9..f0765ccde6680 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
@@ -225,15 +225,6 @@ void amdgpu_i2c_destroy(struct amdgpu_i2c_chan *i2c)
kfree(i2c);
}
-/* Add the default buses */
-void amdgpu_i2c_init(struct amdgpu_device *adev)
-{
- if (amdgpu_hw_i2c)
- DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n");
-
- amdgpu_atombios_i2c_init(adev);
-}
-
/* remove all the buses */
void amdgpu_i2c_fini(struct amdgpu_device *adev)
{
@@ -247,22 +238,6 @@ void amdgpu_i2c_fini(struct amdgpu_device *adev)
}
}
-/* Add additional buses */
-void amdgpu_i2c_add(struct amdgpu_device *adev,
- const struct amdgpu_i2c_bus_rec *rec,
- const char *name)
-{
- struct drm_device *dev = adev_to_drm(adev);
- int i;
-
- for (i = 0; i < AMDGPU_MAX_I2C_BUS; i++) {
- if (!adev->i2c_bus[i]) {
- adev->i2c_bus[i] = amdgpu_i2c_create(dev, rec, name);
- return;
- }
- }
-}
-
/* looks up bus based on id */
struct amdgpu_i2c_chan *
amdgpu_i2c_lookup(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h
index 63c2ff7499e17..21e3d1dad0a12 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h
@@ -28,11 +28,7 @@ struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev,
const struct amdgpu_i2c_bus_rec *rec,
const char *name);
void amdgpu_i2c_destroy(struct amdgpu_i2c_chan *i2c);
-void amdgpu_i2c_init(struct amdgpu_device *adev);
void amdgpu_i2c_fini(struct amdgpu_device *adev);
-void amdgpu_i2c_add(struct amdgpu_device *adev,
- const struct amdgpu_i2c_bus_rec *rec,
- const char *name);
struct amdgpu_i2c_chan *
amdgpu_i2c_lookup(struct amdgpu_device *adev,
const struct amdgpu_i2c_bus_rec *i2c_bus);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 745/869] drm/amdgpu/atombios: drop empty function
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (743 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 744/869] drm/amdgpu: Remove unused amdgpu_i2c functions Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 746/869] drm/amdgpu: rework i2c init and fini Greg Kroah-Hartman
` (124 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Harry Wentland, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <alexander.deucher@amd.com>
[ Upstream commit ba7f8eb7e447a8120f5bcb8e8d72964324ee5b84 ]
This was leftover from when amdgpu was forked from radeon.
The function is empty so drop it.
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Stable-dep-of: a99cd231cd92 ("drm/amdgpu: Bound GPIO I2C table entry count from VBIOS")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
index 0c8975ac5af9e..9297460706579 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
@@ -36,13 +36,6 @@
#include "atombios_encoders.h"
#include "bif/bif_4_1_d.h"
-static void amdgpu_atombios_lookup_i2c_gpio_quirks(struct amdgpu_device *adev,
- ATOM_GPIO_I2C_ASSIGMENT *gpio,
- u8 index)
-{
-
-}
-
static struct amdgpu_i2c_bus_rec amdgpu_atombios_get_bus_rec_for_i2c_gpio(ATOM_GPIO_I2C_ASSIGMENT *gpio)
{
struct amdgpu_i2c_bus_rec i2c;
@@ -108,9 +101,6 @@ struct amdgpu_i2c_bus_rec amdgpu_atombios_lookup_i2c_gpio(struct amdgpu_device *
gpio = &i2c_info->asGPIO_Info[0];
for (i = 0; i < num_indices; i++) {
-
- amdgpu_atombios_lookup_i2c_gpio_quirks(adev, gpio, i);
-
if (gpio->sucI2cId.ucAccess == id) {
i2c = amdgpu_atombios_get_bus_rec_for_i2c_gpio(gpio);
break;
@@ -142,8 +132,6 @@ void amdgpu_atombios_i2c_init(struct amdgpu_device *adev)
gpio = &i2c_info->asGPIO_Info[0];
for (i = 0; i < num_indices; i++) {
- amdgpu_atombios_lookup_i2c_gpio_quirks(adev, gpio, i);
-
i2c = amdgpu_atombios_get_bus_rec_for_i2c_gpio(gpio);
if (i2c.valid) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 746/869] drm/amdgpu: rework i2c init and fini
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (744 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 745/869] drm/amdgpu/atombios: drop empty function Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 747/869] drm/amdgpu: Bound GPIO I2C table entry count from VBIOS Greg Kroah-Hartman
` (123 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Harry Wentland, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <alexander.deucher@amd.com>
[ Upstream commit 1c0b144bf7628a62575a4ec26623f7a6cdf0cb2b ]
No functional change. Rework the code to allow for
adding some additional i2c buses in conjunction with DC
in the future.
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Stable-dep-of: a99cd231cd92 ("drm/amdgpu: Bound GPIO I2C table entry count from VBIOS")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 6 ++----
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c | 8 ++++++++
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h | 1 +
3 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 172cc8cd8356b..13363330820a8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -4518,8 +4518,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
goto failed;
}
/* init i2c buses */
- if (!amdgpu_device_has_dc_support(adev))
- amdgpu_atombios_i2c_init(adev);
+ amdgpu_i2c_init(adev);
}
}
@@ -4793,8 +4792,7 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
amdgpu_reset_fini(adev);
/* free i2c buses */
- if (!amdgpu_device_has_dc_support(adev))
- amdgpu_i2c_fini(adev);
+ amdgpu_i2c_fini(adev);
if (amdgpu_emu_mode != 1)
amdgpu_atombios_fini(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
index f0765ccde6680..72f73a186dd94 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
@@ -225,6 +225,14 @@ void amdgpu_i2c_destroy(struct amdgpu_i2c_chan *i2c)
kfree(i2c);
}
+void amdgpu_i2c_init(struct amdgpu_device *adev)
+{
+ if (!adev->is_atom_fw) {
+ if (!amdgpu_device_has_dc_support(adev))
+ amdgpu_atombios_i2c_init(adev);
+ }
+}
+
/* remove all the buses */
void amdgpu_i2c_fini(struct amdgpu_device *adev)
{
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h
index 21e3d1dad0a12..1d3d3806e0ddb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h
@@ -28,6 +28,7 @@ struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev,
const struct amdgpu_i2c_bus_rec *rec,
const char *name);
void amdgpu_i2c_destroy(struct amdgpu_i2c_chan *i2c);
+void amdgpu_i2c_init(struct amdgpu_device *adev);
void amdgpu_i2c_fini(struct amdgpu_device *adev);
struct amdgpu_i2c_chan *
amdgpu_i2c_lookup(struct amdgpu_device *adev,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 747/869] drm/amdgpu: Bound GPIO I2C table entry count from VBIOS
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (745 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 746/869] drm/amdgpu: rework i2c init and fini Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 748/869] gpiolib: make value setters have return values Greg Kroah-Hartman
` (122 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Candice Li, Tao Zhou, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Candice Li <candice.li@amd.com>
[ Upstream commit a99cd231cd924b7160fecb9fb3a94b801522323b ]
Reject undersized tables and cap the derived entry count
to AMDGPU_MAX_I2C_BUS so we do not overrun adev->i2c_bus[]
or walk an absurd number of entries on corrupt size fields.
Signed-off-by: Candice Li <candice.li@amd.com>
Reviewed-by: Tao Zhou <tao.zhou1@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c | 21 ++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
index 9297460706579..9254b85d4e70d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
@@ -36,6 +36,21 @@
#include "atombios_encoders.h"
#include "bif/bif_4_1_d.h"
+/* VBIOS-reported table size is unchecked against the image; cap iterations and
+ * adev->i2c_bus[] indexing to AMDGPU_MAX_I2C_BUS.
+ */
+static int amdgpu_atombios_gpio_i2c_num_entries(uint16_t size)
+{
+ u32 bytes;
+
+ if (size < sizeof(ATOM_COMMON_TABLE_HEADER))
+ return 0;
+
+ bytes = size - sizeof(ATOM_COMMON_TABLE_HEADER);
+ return (int)min_t(u32, bytes / sizeof(ATOM_GPIO_I2C_ASSIGMENT),
+ AMDGPU_MAX_I2C_BUS);
+}
+
static struct amdgpu_i2c_bus_rec amdgpu_atombios_get_bus_rec_for_i2c_gpio(ATOM_GPIO_I2C_ASSIGMENT *gpio)
{
struct amdgpu_i2c_bus_rec i2c;
@@ -96,8 +111,7 @@ struct amdgpu_i2c_bus_rec amdgpu_atombios_lookup_i2c_gpio(struct amdgpu_device *
if (amdgpu_atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
- num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
- sizeof(ATOM_GPIO_I2C_ASSIGMENT);
+ num_indices = amdgpu_atombios_gpio_i2c_num_entries(size);
gpio = &i2c_info->asGPIO_Info[0];
for (i = 0; i < num_indices; i++) {
@@ -127,8 +141,7 @@ void amdgpu_atombios_i2c_init(struct amdgpu_device *adev)
if (amdgpu_atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
- num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
- sizeof(ATOM_GPIO_I2C_ASSIGMENT);
+ num_indices = amdgpu_atombios_gpio_i2c_num_entries(size);
gpio = &i2c_info->asGPIO_Info[0];
for (i = 0; i < num_indices; i++) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 748/869] gpiolib: make value setters have return values
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (746 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 747/869] drm/amdgpu: Bound GPIO I2C table entry count from VBIOS Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 749/869] gpiolib: wrap gpio_chip::set() Greg Kroah-Hartman
` (121 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Linus Walleij, Uwe Kleine-König,
Bartosz Golaszewski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
[ Upstream commit 8ce258f62f90cb2d339cc39fa43e5634594a9dfb ]
Change the in-kernel consumer interface for GPIOs: make all variants of
value setters that don't have a return value, return a signed integer
instead. That will allow these routines to indicate failures to callers.
This doesn't change the implementation just yet, we'll do it in
subsequent commits.
We need to update the gpio-latch module as it passes the address of
value setters as a function pointer argument and thus cares about its
type.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Link: https://lore.kernel.org/r/20250220-gpio-set-retval-v2-2-bc4cfd38dae3@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Stable-dep-of: c87c9046c4e0 ("pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpio/gpio-latch.c | 2 +-
drivers/gpio/gpiolib.c | 53 ++++++++++++++++++++---------------
include/linux/gpio.h | 4 +--
include/linux/gpio/consumer.h | 22 +++++++++------
4 files changed, 46 insertions(+), 35 deletions(-)
diff --git a/drivers/gpio/gpio-latch.c b/drivers/gpio/gpio-latch.c
index d7c3b20c8482e..e935b3b34117d 100644
--- a/drivers/gpio/gpio-latch.c
+++ b/drivers/gpio/gpio-latch.c
@@ -72,7 +72,7 @@ static int gpio_latch_get_direction(struct gpio_chip *gc, unsigned int offset)
}
static void gpio_latch_set_unlocked(struct gpio_latch_priv *priv,
- void (*set)(struct gpio_desc *desc, int value),
+ int (*set)(struct gpio_desc *desc, int value),
unsigned int offset, bool val)
{
int latch = offset / priv->n_latched_gpios;
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 878f9ab4a0982..e73c1e1444f7d 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -3330,13 +3330,13 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value);
* @desc: gpio descriptor whose state need to be set.
* @value: Non-zero for setting it HIGH otherwise it will set to LOW.
*/
-static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
+static int gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
{
int ret = 0, offset = gpio_chip_hwgpio(desc);
CLASS(gpio_chip_guard, guard)(desc);
if (!guard.gc)
- return;
+ return -ENODEV;
if (value) {
ret = guard.gc->direction_input(guard.gc, offset);
@@ -3350,6 +3350,8 @@ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
gpiod_err(desc,
"%s: Error in set_value for open drain err %d\n",
__func__, ret);
+
+ return ret;
}
/*
@@ -3357,13 +3359,13 @@ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
* @desc: gpio descriptor whose state need to be set.
* @value: Non-zero for setting it HIGH otherwise it will set to LOW.
*/
-static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value)
+static int gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value)
{
int ret = 0, offset = gpio_chip_hwgpio(desc);
CLASS(gpio_chip_guard, guard)(desc);
if (!guard.gc)
- return;
+ return -ENODEV;
if (value) {
ret = guard.gc->direction_output(guard.gc, offset, 1);
@@ -3377,16 +3379,20 @@ static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value
gpiod_err(desc,
"%s: Error in set_value for open source err %d\n",
__func__, ret);
+
+ return ret;
}
-static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value)
+static int gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value)
{
CLASS(gpio_chip_guard, guard)(desc);
if (!guard.gc)
- return;
+ return -ENODEV;
trace_gpio_value(desc_to_gpio(desc), 0, value);
guard.gc->set(guard.gc, gpio_chip_hwgpio(desc), value);
+
+ return 0;
}
/*
@@ -3544,12 +3550,12 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
* This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
-void gpiod_set_raw_value(struct gpio_desc *desc, int value)
+int gpiod_set_raw_value(struct gpio_desc *desc, int value)
{
- VALIDATE_DESC_VOID(desc);
+ VALIDATE_DESC(desc);
/* Should be using gpiod_set_raw_value_cansleep() */
WARN_ON(desc->gdev->can_sleep);
- gpiod_set_raw_value_commit(desc, value);
+ return gpiod_set_raw_value_commit(desc, value);
}
EXPORT_SYMBOL_GPL(gpiod_set_raw_value);
@@ -3562,16 +3568,17 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value);
* different semantic quirks like active low and open drain/source
* handling.
*/
-static void gpiod_set_value_nocheck(struct gpio_desc *desc, int value)
+static int gpiod_set_value_nocheck(struct gpio_desc *desc, int value)
{
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value;
+
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
- gpio_set_open_drain_value_commit(desc, value);
+ return gpio_set_open_drain_value_commit(desc, value);
else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
- gpio_set_open_source_value_commit(desc, value);
- else
- gpiod_set_raw_value_commit(desc, value);
+ return gpio_set_open_source_value_commit(desc, value);
+
+ return gpiod_set_raw_value_commit(desc, value);
}
/**
@@ -3585,12 +3592,12 @@ static void gpiod_set_value_nocheck(struct gpio_desc *desc, int value)
* This function can be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
-void gpiod_set_value(struct gpio_desc *desc, int value)
+int gpiod_set_value(struct gpio_desc *desc, int value)
{
- VALIDATE_DESC_VOID(desc);
+ VALIDATE_DESC(desc);
/* Should be using gpiod_set_value_cansleep() */
WARN_ON(desc->gdev->can_sleep);
- gpiod_set_value_nocheck(desc, value);
+ return gpiod_set_value_nocheck(desc, value);
}
EXPORT_SYMBOL_GPL(gpiod_set_value);
@@ -4003,11 +4010,11 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep);
*
* This function is to be called from contexts that can sleep.
*/
-void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
+int gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
{
might_sleep();
- VALIDATE_DESC_VOID(desc);
- gpiod_set_raw_value_commit(desc, value);
+ VALIDATE_DESC(desc);
+ return gpiod_set_raw_value_commit(desc, value);
}
EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep);
@@ -4021,11 +4028,11 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep);
*
* This function is to be called from contexts that can sleep.
*/
-void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
+int gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
{
might_sleep();
- VALIDATE_DESC_VOID(desc);
- gpiod_set_value_nocheck(desc, value);
+ VALIDATE_DESC(desc);
+ return gpiod_set_value_nocheck(desc, value);
}
EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 2d105be7bbc33..8bd6e6ac98c1f 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -94,7 +94,7 @@ static inline int gpio_get_value_cansleep(unsigned gpio)
}
static inline void gpio_set_value_cansleep(unsigned gpio, int value)
{
- return gpiod_set_raw_value_cansleep(gpio_to_desc(gpio), value);
+ gpiod_set_raw_value_cansleep(gpio_to_desc(gpio), value);
}
static inline int gpio_get_value(unsigned gpio)
@@ -103,7 +103,7 @@ static inline int gpio_get_value(unsigned gpio)
}
static inline void gpio_set_value(unsigned gpio, int value)
{
- return gpiod_set_raw_value(gpio_to_desc(gpio), value);
+ gpiod_set_raw_value(gpio_to_desc(gpio), value);
}
static inline int gpio_to_irq(unsigned gpio)
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index db2dfbae8edbd..4a87c24686e36 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -119,7 +119,7 @@ int gpiod_get_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
struct gpio_array *array_info,
unsigned long *value_bitmap);
-void gpiod_set_value(struct gpio_desc *desc, int value);
+int gpiod_set_value(struct gpio_desc *desc, int value);
int gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
struct gpio_array *array_info,
@@ -129,7 +129,7 @@ int gpiod_get_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
struct gpio_array *array_info,
unsigned long *value_bitmap);
-void gpiod_set_raw_value(struct gpio_desc *desc, int value);
+int gpiod_set_raw_value(struct gpio_desc *desc, int value);
int gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
struct gpio_array *array_info,
@@ -141,7 +141,7 @@ int gpiod_get_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
struct gpio_array *array_info,
unsigned long *value_bitmap);
-void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
+int gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
int gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
struct gpio_array *array_info,
@@ -151,7 +151,7 @@ int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
struct gpio_array *array_info,
unsigned long *value_bitmap);
-void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
+int gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
struct gpio_array *array_info,
@@ -375,10 +375,11 @@ static inline int gpiod_get_array_value(unsigned int array_size,
WARN_ON(desc_array);
return 0;
}
-static inline void gpiod_set_value(struct gpio_desc *desc, int value)
+static inline int gpiod_set_value(struct gpio_desc *desc, int value)
{
/* GPIO can never have been requested */
WARN_ON(desc);
+ return 0;
}
static inline int gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
@@ -404,10 +405,11 @@ static inline int gpiod_get_raw_array_value(unsigned int array_size,
WARN_ON(desc_array);
return 0;
}
-static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value)
+static inline int gpiod_set_raw_value(struct gpio_desc *desc, int value)
{
/* GPIO can never have been requested */
WARN_ON(desc);
+ return 0;
}
static inline int gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
@@ -434,10 +436,11 @@ static inline int gpiod_get_array_value_cansleep(unsigned int array_size,
WARN_ON(desc_array);
return 0;
}
-static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
+static inline int gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
{
/* GPIO can never have been requested */
WARN_ON(desc);
+ return 0;
}
static inline int gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
@@ -463,11 +466,12 @@ static inline int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
WARN_ON(desc_array);
return 0;
}
-static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc,
- int value)
+static inline int gpiod_set_raw_value_cansleep(struct gpio_desc *desc,
+ int value)
{
/* GPIO can never have been requested */
WARN_ON(desc);
+ return 0;
}
static inline int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 749/869] gpiolib: wrap gpio_chip::set()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (747 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 748/869] gpiolib: make value setters have return values Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 750/869] gpiolib: rework the wrapper around gpio_chip::set_multiple() Greg Kroah-Hartman
` (120 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Linus Walleij, Uwe Kleine-König,
Bartosz Golaszewski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
[ Upstream commit d36058b89a4aa30865d4cfeb101bbfd1d1dcb22f ]
We have three places where we dereference the gpio_chip::set() callback.
In order to make it easier to incorporate the upcoming new variant of
this callback (one returning an integer value), wrap it in a helper so
that the dereferencing only happens once.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Link: https://lore.kernel.org/r/20250220-gpio-set-retval-v2-3-bc4cfd38dae3@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Stable-dep-of: c87c9046c4e0 ("pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpio/gpiolib.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e73c1e1444f7d..68fa92b79137c 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2722,6 +2722,17 @@ int gpiod_direction_input(struct gpio_desc *desc)
}
EXPORT_SYMBOL_GPL(gpiod_direction_input);
+static int gpiochip_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ lockdep_assert_held(&gc->gpiodev->srcu);
+
+ if (WARN_ON(unlikely(!gc->set)))
+ return -EOPNOTSUPP;
+
+ gc->set(gc, offset, value);
+ return 0;
+}
+
static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
{
int val = !!value, ret = 0;
@@ -2758,7 +2769,9 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
* If we can't actively set the direction, we are some
* output-only chip, so just drive the output as desired.
*/
- guard.gc->set(guard.gc, gpio_chip_hwgpio(desc), val);
+ ret = gpiochip_set(guard.gc, gpio_chip_hwgpio(desc), val);
+ if (ret)
+ return ret;
}
if (!ret)
@@ -3390,9 +3403,7 @@ static int gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value)
return -ENODEV;
trace_gpio_value(desc_to_gpio(desc), 0, value);
- guard.gc->set(guard.gc, gpio_chip_hwgpio(desc), value);
-
- return 0;
+ return gpiochip_set(guard.gc, gpio_chip_hwgpio(desc), value);
}
/*
@@ -3417,7 +3428,7 @@ static void gpio_chip_set_multiple(struct gpio_chip *gc,
/* set outputs if the corresponding mask bit is set */
for_each_set_bit(i, mask, gc->ngpio)
- gc->set(gc, i, test_bit(i, bits));
+ gpiochip_set(gc, i, test_bit(i, bits));
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 750/869] gpiolib: rework the wrapper around gpio_chip::set_multiple()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (748 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 749/869] gpiolib: wrap gpio_chip::set() Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 751/869] gpiolib: introduce gpio_chip setters that return values Greg Kroah-Hartman
` (119 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Linus Walleij, Uwe Kleine-König,
Bartosz Golaszewski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
[ Upstream commit 9b407312755fd5db012413ca005f0f3a661db8dd ]
Make the existing wrapper around gpio_chip::set_multiple() consistent
with the one for gpio_chip::set(): make it return int, add a lockdep
assertion, warn on missing set callback and move the code a bit for
better readability.
Add return value checks in all call places.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Link: https://lore.kernel.org/r/20250220-gpio-set-retval-v2-4-bc4cfd38dae3@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Stable-dep-of: c87c9046c4e0 ("pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpio/gpiolib.c | 40 +++++++++++++++++++++++++++++-----------
1 file changed, 29 insertions(+), 11 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 68fa92b79137c..5f23da5ef8c93 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -3415,21 +3415,33 @@ static int gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value)
* defines which outputs are to be changed
* @bits: bit value array; one bit per output; BITS_PER_LONG bits per word
* defines the values the outputs specified by mask are to be set to
+ *
+ * Returns: 0 on success, negative error number on failure.
*/
-static void gpio_chip_set_multiple(struct gpio_chip *gc,
- unsigned long *mask, unsigned long *bits)
+static int gpiochip_set_multiple(struct gpio_chip *gc,
+ unsigned long *mask, unsigned long *bits)
{
+ unsigned int i;
+ int ret;
+
lockdep_assert_held(&gc->gpiodev->srcu);
+ if (WARN_ON(unlikely(!gc->set_multiple && !gc->set)))
+ return -EOPNOTSUPP;
+
if (gc->set_multiple) {
gc->set_multiple(gc, mask, bits);
- } else {
- unsigned int i;
+ return 0;
+ }
- /* set outputs if the corresponding mask bit is set */
- for_each_set_bit(i, mask, gc->ngpio)
- gpiochip_set(gc, i, test_bit(i, bits));
+ /* set outputs if the corresponding mask bit is set */
+ for_each_set_bit(i, mask, gc->ngpio) {
+ ret = gpiochip_set(gc, i, test_bit(i, bits));
+ if (ret)
+ break;
}
+
+ return ret;
}
int gpiod_set_array_value_complex(bool raw, bool can_sleep,
@@ -3439,7 +3451,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
unsigned long *value_bitmap)
{
struct gpio_chip *gc;
- int i = 0;
+ int i = 0, ret;
/*
* Validate array_info against desc_array and its size.
@@ -3462,7 +3474,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
bitmap_xor(value_bitmap, value_bitmap,
array_info->invert_mask, array_size);
- gpio_chip_set_multiple(gc, array_info->set_mask, value_bitmap);
+ ret = gpiochip_set_multiple(gc, array_info->set_mask,
+ value_bitmap);
+ if (ret)
+ return ret;
i = find_first_zero_bit(array_info->set_mask, array_size);
if (i == array_size)
@@ -3539,8 +3554,11 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
} while ((i < array_size) &&
gpio_device_chip_cmp(desc_array[i]->gdev, guard.gc));
/* push collected bits to outputs */
- if (count != 0)
- gpio_chip_set_multiple(guard.gc, mask, bits);
+ if (count != 0) {
+ ret = gpiochip_set_multiple(guard.gc, mask, bits);
+ if (ret)
+ return ret;
+ }
if (mask != fastpath_mask)
bitmap_free(mask);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 751/869] gpiolib: introduce gpio_chip setters that return values
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (749 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 750/869] gpiolib: rework the wrapper around gpio_chip::set_multiple() Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 752/869] pinctrl: mediatek: paris: dont double-check the GPIO number Greg Kroah-Hartman
` (118 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Linus Walleij, Uwe Kleine-König,
Bartosz Golaszewski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
[ Upstream commit 98ce1eb1fd87ea1b016e0913ef6836ab0139b5c4 ]
Add new variants of the set() and set_multiple() callbacks that have
integer return values allowing to indicate failures to users of the GPIO
consumer API. Until we convert all GPIO providers treewide to using
them, they will live in parallel to the existing ones.
Make sure that providers cannot define both. Prefer the new ones and
only use the old ones as fallback.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Link: https://lore.kernel.org/r/20250220-gpio-set-retval-v2-5-bc4cfd38dae3@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Stable-dep-of: c87c9046c4e0 ("pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpio/gpiolib.c | 28 ++++++++++++++++++++++++++--
drivers/leds/leds-aw200xx.c | 2 +-
include/linux/gpio/driver.h | 10 ++++++++++
3 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5f23da5ef8c93..5f73f0c29cf6a 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -945,6 +945,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
int base = 0;
int ret;
+ /* Only allow one set() and one set_multiple(). */
+ if ((gc->set && gc->set_rv) ||
+ (gc->set_multiple && gc->set_multiple_rv))
+ return -EINVAL;
+
gdev = kzalloc(sizeof(*gdev), GFP_KERNEL);
if (!gdev)
return -ENOMEM;
@@ -2724,11 +2729,21 @@ EXPORT_SYMBOL_GPL(gpiod_direction_input);
static int gpiochip_set(struct gpio_chip *gc, unsigned int offset, int value)
{
+ int ret;
+
lockdep_assert_held(&gc->gpiodev->srcu);
- if (WARN_ON(unlikely(!gc->set)))
+ if (WARN_ON(unlikely(!gc->set && !gc->set_rv)))
return -EOPNOTSUPP;
+ if (gc->set_rv) {
+ ret = gc->set_rv(gc, offset, value);
+ if (ret > 0)
+ ret = -EBADE;
+
+ return ret;
+ }
+
gc->set(gc, offset, value);
return 0;
}
@@ -3426,9 +3441,18 @@ static int gpiochip_set_multiple(struct gpio_chip *gc,
lockdep_assert_held(&gc->gpiodev->srcu);
- if (WARN_ON(unlikely(!gc->set_multiple && !gc->set)))
+ if (WARN_ON(unlikely(!gc->set_multiple && !gc->set_multiple_rv &&
+ !gc->set && !gc->set_rv)))
return -EOPNOTSUPP;
+ if (gc->set_multiple_rv) {
+ ret = gc->set_multiple_rv(gc, mask, bits);
+ if (ret > 0)
+ ret = -EBADE;
+
+ return ret;
+ }
+
if (gc->set_multiple) {
gc->set_multiple(gc, mask, bits);
return 0;
diff --git a/drivers/leds/leds-aw200xx.c b/drivers/leds/leds-aw200xx.c
index f9d9844e02738..7adf77c0a48a9 100644
--- a/drivers/leds/leds-aw200xx.c
+++ b/drivers/leds/leds-aw200xx.c
@@ -379,7 +379,7 @@ static void aw200xx_enable(const struct aw200xx *const chip)
static void aw200xx_disable(const struct aw200xx *const chip)
{
- return gpiod_set_value_cansleep(chip->hwen, 0);
+ gpiod_set_value_cansleep(chip->hwen, 0);
}
static int aw200xx_probe_get_display_rows(struct device *dev,
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 2dd7cb9cc270a..ac42f0164d5f9 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -346,6 +346,10 @@ struct gpio_irq_chip {
* stores them in "bits", returns 0 on success or negative error
* @set: assigns output value for signal "offset"
* @set_multiple: assigns output values for multiple signals defined by "mask"
+ * @set_rv: assigns output value for signal "offset", returns 0 on success or
+ * negative error value
+ * @set_multiple_rv: assigns output values for multiple signals defined by
+ * "mask", returns 0 on success or negative error value
* @set_config: optional hook for all kinds of settings. Uses the same
* packed config format as generic pinconf.
* @to_irq: optional hook supporting non-static gpiod_to_irq() mappings;
@@ -441,6 +445,12 @@ struct gpio_chip {
void (*set_multiple)(struct gpio_chip *gc,
unsigned long *mask,
unsigned long *bits);
+ int (*set_rv)(struct gpio_chip *gc,
+ unsigned int offset,
+ int value);
+ int (*set_multiple_rv)(struct gpio_chip *gc,
+ unsigned long *mask,
+ unsigned long *bits);
int (*set_config)(struct gpio_chip *gc,
unsigned int offset,
unsigned long config);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 752/869] pinctrl: mediatek: paris: dont double-check the GPIO number
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (750 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 751/869] gpiolib: introduce gpio_chip setters that return values Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 753/869] pinctrl: mediatek: paris: use new GPIO line value setter callbacks Greg Kroah-Hartman
` (117 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bartosz Golaszewski, Linus Walleij,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
[ Upstream commit 9c791cbaf3cf2671404dc4f7679548071b38e104 ]
GPIO core already makes sure we don't pass invalid GPIO numbers down to
the driver callbacks. Remove needless checks from the driver.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Link: https://lore.kernel.org/20250425-gpiochip-set-rv-pinctrl-mediatek-v1-2-93e6a01855e7@linaro.org
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Stable-dep-of: c87c9046c4e0 ("pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pinctrl/mediatek/pinctrl-paris.c | 19 -------------------
1 file changed, 19 deletions(-)
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c
index 363a02106d401..dcb2e420f5e71 100644
--- a/drivers/pinctrl/mediatek/pinctrl-paris.c
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c
@@ -840,9 +840,6 @@ static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio)
const struct mtk_pin_desc *desc;
int value, err;
- if (gpio >= hw->soc->npins)
- return -EINVAL;
-
/*
* "Virtual" GPIOs are always and only used for interrupts
* Since they are only used for interrupts, they are always inputs
@@ -868,9 +865,6 @@ static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio)
const struct mtk_pin_desc *desc;
int value, err;
- if (gpio >= hw->soc->npins)
- return -EINVAL;
-
desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio];
err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value);
@@ -885,9 +879,6 @@ static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
struct mtk_pinctrl *hw = gpiochip_get_data(chip);
const struct mtk_pin_desc *desc;
- if (gpio >= hw->soc->npins)
- return;
-
desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio];
mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value);
@@ -895,22 +886,12 @@ static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
{
- struct mtk_pinctrl *hw = gpiochip_get_data(chip);
-
- if (gpio >= hw->soc->npins)
- return -EINVAL;
-
return pinctrl_gpio_direction_input(chip, gpio);
}
static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
int value)
{
- struct mtk_pinctrl *hw = gpiochip_get_data(chip);
-
- if (gpio >= hw->soc->npins)
- return -EINVAL;
-
mtk_gpio_set(chip, gpio, value);
return pinctrl_gpio_direction_output(chip, gpio);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 753/869] pinctrl: mediatek: paris: use new GPIO line value setter callbacks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (751 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 752/869] pinctrl: mediatek: paris: dont double-check the GPIO number Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 754/869] pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction Greg Kroah-Hartman
` (116 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bartosz Golaszewski, Linus Walleij,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
[ Upstream commit 1849d1a3d388caf898b18791c40edac464c809d1 ]
struct gpio_chip now has callbacks for setting line values that return
an integer, allowing to indicate failures. Convert the driver to using
them.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Link: https://lore.kernel.org/20250425-gpiochip-set-rv-pinctrl-mediatek-v1-3-93e6a01855e7@linaro.org
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Stable-dep-of: c87c9046c4e0 ("pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pinctrl/mediatek/pinctrl-paris.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c
index dcb2e420f5e71..58243ddc1142f 100644
--- a/drivers/pinctrl/mediatek/pinctrl-paris.c
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c
@@ -874,14 +874,14 @@ static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio)
return !!value;
}
-static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
+static int mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
{
struct mtk_pinctrl *hw = gpiochip_get_data(chip);
const struct mtk_pin_desc *desc;
desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio];
- mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value);
+ return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value);
}
static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
@@ -892,7 +892,11 @@ static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
int value)
{
- mtk_gpio_set(chip, gpio, value);
+ int ret;
+
+ ret = mtk_gpio_set(chip, gpio, value);
+ if (ret)
+ return ret;
return pinctrl_gpio_direction_output(chip, gpio);
}
@@ -945,7 +949,7 @@ static int mtk_build_gpiochip(struct mtk_pinctrl *hw)
chip->direction_input = mtk_gpio_direction_input;
chip->direction_output = mtk_gpio_direction_output;
chip->get = mtk_gpio_get;
- chip->set = mtk_gpio_set;
+ chip->set_rv = mtk_gpio_set;
chip->to_irq = mtk_gpio_to_irq;
chip->set_config = mtk_gpio_set_config;
chip->base = -1;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 754/869] pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (752 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 753/869] pinctrl: mediatek: paris: use new GPIO line value setter callbacks Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 755/869] genirq/proc: Switch to lock guards Greg Kroah-Hartman
` (115 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Chen-Yu Tsai, Linus Walleij,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen-Yu Tsai <wenst@chromium.org>
[ Upstream commit c87c9046c4e00d599454e033a477176c4d73ac2a ]
pinctrl_gpio_direction_input() / pinctrl_gpio_direction_output() take
the pinctrl mutex. This causes a gpiochip operations to need to sleep.
Worse yet, the .can_sleep field in the gpiochip is not set. This causes
the shared GPIO proxy to trip over, as it uses gpiod_cansleep() to check
whether it can use a spinlock or needs a mutex. In this case, it ends
up taking a spinlock, then calls pinctrl_gpio_direction_output(), which
takes a mutex. This causes a huge warning.
While this class of Mediatek hardware does not have separate clear/set
registers, the pinctrl context has a spinlock that is taken whenever
a register read-modify-write is done. Also, once the GPIO function is
selected / muxed in, further GPIO operations do not involve pinctrl
operations or state. The GPIO direction and level values do not require
toggling the pinmux or any other pin config options.
Switch to directly calling mtk_pinmux_gpio_set_direction() in the GPIO
set direction callbacks to avoid taking the pinctrl mutex. Drop the
.gpio_set_direction field in mtk_pmxops to signal we are no longer using
the pinctrl GPIO layer for setting the direction.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pinctrl/mediatek/pinctrl-paris.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c
index 58243ddc1142f..e07ffe1a38bcc 100644
--- a/drivers/pinctrl/mediatek/pinctrl-paris.c
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c
@@ -771,7 +771,6 @@ static const struct pinmux_ops mtk_pmxops = {
.get_function_name = mtk_pmx_get_func_name,
.get_function_groups = mtk_pmx_get_func_groups,
.set_mux = mtk_pmx_set_mux,
- .gpio_set_direction = mtk_pinmux_gpio_set_direction,
.gpio_request_enable = mtk_pinmux_gpio_request_enable,
};
@@ -886,19 +885,22 @@ static int mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
{
- return pinctrl_gpio_direction_input(chip, gpio);
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+
+ return mtk_pinmux_gpio_set_direction(hw->pctrl, NULL, gpio, true);
}
static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
int value)
{
+ struct mtk_pinctrl *hw = gpiochip_get_data(chip);
int ret;
ret = mtk_gpio_set(chip, gpio, value);
if (ret)
return ret;
- return pinctrl_gpio_direction_output(chip, gpio);
+ return mtk_pinmux_gpio_set_direction(hw->pctrl, NULL, gpio, false);
}
static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 755/869] genirq/proc: Switch to lock guards
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (753 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 754/869] pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 756/869] genirq: Consistently use %u format specifier for unsigned int variables Greg Kroah-Hartman
` (114 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Thomas Gleixner,
Peter Zijlstra (Intel), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <tglx@linutronix.de>
[ Upstream commit 659ff9c9d77b8ad9d9c18e264abc9a56bd19230e ]
Convert all lock/unlock pairs to guards and tidy up the code.
No functional change.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/all/20250429065420.373998838@linutronix.de
Stable-dep-of: c2c7983c93f5 ("genirq/proc: Size interrupt directory names for 10-digit interrupt numbers")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/irq/proc.c | 65 +++++++++++++++++------------------------------
1 file changed, 24 insertions(+), 41 deletions(-)
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 9081ada81c3d0..24fe3bd56d86f 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -81,20 +81,18 @@ static int show_irq_affinity(int type, struct seq_file *m)
static int irq_affinity_hint_proc_show(struct seq_file *m, void *v)
{
struct irq_desc *desc = irq_to_desc((long)m->private);
- unsigned long flags;
cpumask_var_t mask;
if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
return -ENOMEM;
- raw_spin_lock_irqsave(&desc->lock, flags);
- if (desc->affinity_hint)
- cpumask_copy(mask, desc->affinity_hint);
- raw_spin_unlock_irqrestore(&desc->lock, flags);
+ scoped_guard(raw_spinlock_irq, &desc->lock) {
+ if (desc->affinity_hint)
+ cpumask_copy(mask, desc->affinity_hint);
+ }
seq_printf(m, "%*pb\n", cpumask_pr_args(mask));
free_cpumask_var(mask);
-
return 0;
}
@@ -295,23 +293,18 @@ static int irq_spurious_proc_show(struct seq_file *m, void *v)
#define MAX_NAMELEN 128
-static int name_unique(unsigned int irq, struct irqaction *new_action)
+static bool name_unique(unsigned int irq, struct irqaction *new_action)
{
struct irq_desc *desc = irq_to_desc(irq);
struct irqaction *action;
- unsigned long flags;
- int ret = 1;
- raw_spin_lock_irqsave(&desc->lock, flags);
+ guard(raw_spinlock_irq)(&desc->lock);
for_each_action_of_desc(desc, action) {
if ((action != new_action) && action->name &&
- !strcmp(new_action->name, action->name)) {
- ret = 0;
- break;
- }
+ !strcmp(new_action->name, action->name))
+ return false;
}
- raw_spin_unlock_irqrestore(&desc->lock, flags);
- return ret;
+ return true;
}
void register_handler_proc(unsigned int irq, struct irqaction *action)
@@ -319,8 +312,7 @@ void register_handler_proc(unsigned int irq, struct irqaction *action)
char name [MAX_NAMELEN];
struct irq_desc *desc = irq_to_desc(irq);
- if (!desc->dir || action->dir || !action->name ||
- !name_unique(irq, action))
+ if (!desc->dir || action->dir || !action->name || !name_unique(irq, action))
return;
snprintf(name, MAX_NAMELEN, "%s", action->name);
@@ -347,17 +339,16 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)
* added, not when the descriptor is created, so multiple
* tasks might try to register at the same time.
*/
- mutex_lock(®ister_lock);
+ guard(mutex)(®ister_lock);
if (desc->dir)
- goto out_unlock;
-
- sprintf(name, "%d", irq);
+ return;
/* create /proc/irq/1234 */
+ sprintf(name, "%d", irq);
desc->dir = proc_mkdir(name, root_irq_dir);
if (!desc->dir)
- goto out_unlock;
+ return;
#ifdef CONFIG_SMP
umode_t umode = S_IRUGO;
@@ -366,31 +357,27 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)
umode |= S_IWUSR;
/* create /proc/irq/<irq>/smp_affinity */
- proc_create_data("smp_affinity", umode, desc->dir,
- &irq_affinity_proc_ops, irqp);
+ proc_create_data("smp_affinity", umode, desc->dir, &irq_affinity_proc_ops, irqp);
/* create /proc/irq/<irq>/affinity_hint */
proc_create_single_data("affinity_hint", 0444, desc->dir,
- irq_affinity_hint_proc_show, irqp);
+ irq_affinity_hint_proc_show, irqp);
/* create /proc/irq/<irq>/smp_affinity_list */
proc_create_data("smp_affinity_list", umode, desc->dir,
&irq_affinity_list_proc_ops, irqp);
- proc_create_single_data("node", 0444, desc->dir, irq_node_proc_show,
- irqp);
+ proc_create_single_data("node", 0444, desc->dir, irq_node_proc_show, irqp);
# ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK
proc_create_single_data("effective_affinity", 0444, desc->dir,
- irq_effective_aff_proc_show, irqp);
+ irq_effective_aff_proc_show, irqp);
proc_create_single_data("effective_affinity_list", 0444, desc->dir,
- irq_effective_aff_list_proc_show, irqp);
+ irq_effective_aff_list_proc_show, irqp);
# endif
#endif
proc_create_single_data("spurious", 0444, desc->dir,
- irq_spurious_proc_show, (void *)(long)irq);
+ irq_spurious_proc_show, (void *)(long)irq);
-out_unlock:
- mutex_unlock(®ister_lock);
}
void unregister_irq_proc(unsigned int irq, struct irq_desc *desc)
@@ -467,7 +454,6 @@ int show_interrupts(struct seq_file *p, void *v)
int i = *(loff_t *) v, j;
struct irqaction *action;
struct irq_desc *desc;
- unsigned long flags;
if (i > ACTUAL_NR_IRQS)
return 0;
@@ -486,19 +472,19 @@ int show_interrupts(struct seq_file *p, void *v)
seq_putc(p, '\n');
}
- rcu_read_lock();
+ guard(rcu)();
desc = irq_to_desc(i);
if (!desc || irq_settings_is_hidden(desc))
- goto outsparse;
+ return 0;
if (!desc->action || irq_desc_is_chained(desc) || !desc->kstat_irqs)
- goto outsparse;
+ return 0;
seq_printf(p, "%*d: ", prec, i);
for_each_online_cpu(j)
seq_printf(p, "%10u ", desc->kstat_irqs ? per_cpu(desc->kstat_irqs->cnt, j) : 0);
- raw_spin_lock_irqsave(&desc->lock, flags);
+ guard(raw_spinlock_irq)(&desc->lock);
if (desc->irq_data.chip) {
if (desc->irq_data.chip->irq_print_chip)
desc->irq_data.chip->irq_print_chip(&desc->irq_data, p);
@@ -527,9 +513,6 @@ int show_interrupts(struct seq_file *p, void *v)
}
seq_putc(p, '\n');
- raw_spin_unlock_irqrestore(&desc->lock, flags);
-outsparse:
- rcu_read_unlock();
return 0;
}
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 756/869] genirq: Consistently use %u format specifier for unsigned int variables
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (754 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 755/869] genirq/proc: Switch to lock guards Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 757/869] genirq/proc: Size interrupt directory names for 10-digit interrupt numbers Greg Kroah-Hartman
` (113 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Andy Shevchenko, Thomas Gleixner,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
[ Upstream commit 47af06c9d31fe558493de4e04f9a07847dc4992f ]
There are three cases in the genirq code when the irq, as an unsigned
integer variable, is converted to text representation by sprintf().
In two cases it uses '%d' specifier which is for signed values. While
it's not a problem right now, potentially it might be in the future
in case too big (> INT_MAX) number will appear there.
Consistently use '%u' format specifier for @irq which is declared as
unsigned int in all these cases.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20250509154643.1499171-1-andriy.shevchenko@linux.intel.com
Stable-dep-of: c2c7983c93f5 ("genirq/proc: Size interrupt directory names for 10-digit interrupt numbers")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/irq/debugfs.c | 2 +-
kernel/irq/proc.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/kernel/irq/debugfs.c b/kernel/irq/debugfs.c
index c6ffb97966bed..8bcde325b05c0 100644
--- a/kernel/irq/debugfs.c
+++ b/kernel/irq/debugfs.c
@@ -231,7 +231,7 @@ void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *desc)
if (!irq_dir || !desc || desc->debugfs_file)
return;
- sprintf(name, "%d", irq);
+ sprintf(name, "%u", irq);
desc->debugfs_file = debugfs_create_file(name, 0644, irq_dir, desc,
&dfs_irq_ops);
}
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 24fe3bd56d86f..6cb9e19e710cf 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -309,7 +309,7 @@ static bool name_unique(unsigned int irq, struct irqaction *new_action)
void register_handler_proc(unsigned int irq, struct irqaction *action)
{
- char name [MAX_NAMELEN];
+ char name[MAX_NAMELEN];
struct irq_desc *desc = irq_to_desc(irq);
if (!desc->dir || action->dir || !action->name || !name_unique(irq, action))
@@ -345,7 +345,7 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)
return;
/* create /proc/irq/1234 */
- sprintf(name, "%d", irq);
+ sprintf(name, "%u", irq);
desc->dir = proc_mkdir(name, root_irq_dir);
if (!desc->dir)
return;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 757/869] genirq/proc: Size interrupt directory names for 10-digit interrupt numbers
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (755 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 756/869] genirq: Consistently use %u format specifier for unsigned int variables Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 758/869] media: chips-media: wave5: Release m2m_ctx after Instance Removed from List Greg Kroah-Hartman
` (112 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pengpeng Hou, Thomas Gleixner,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <pengpeng@iscas.ac.cn>
[ Upstream commit c2c7983c93f5d86962318be7e7298f1bc3feb1a6 ]
/proc/irq/<n>/ directory names are built in `char name[10]` buffers
with `sprintf(name, "%u", irq)`.
Ten-digit IRQ numbers already need 11 bytes including the trailing NUL, and
current sparse-IRQ configurations allow interrupt numbers in that range.
Size the temporary name buffer for the current decimal form and switch
to bounded formatting when creating or removing the proc entry.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260404101001.1-genirq-proc-pengpeng@iscas.ac.cn
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/irq/proc.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 6cb9e19e710cf..2ad08b9a41016 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -10,6 +10,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>
+#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/mutex.h>
@@ -323,7 +324,7 @@ void register_handler_proc(unsigned int irq, struct irqaction *action)
#undef MAX_NAMELEN
-#define MAX_NAMELEN 10
+#define MAX_NAMELEN 11
void register_irq_proc(unsigned int irq, struct irq_desc *desc)
{
@@ -345,7 +346,7 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)
return;
/* create /proc/irq/1234 */
- sprintf(name, "%u", irq);
+ snprintf(name, MAX_NAMELEN, "%u", irq);
desc->dir = proc_mkdir(name, root_irq_dir);
if (!desc->dir)
return;
@@ -398,7 +399,7 @@ void unregister_irq_proc(unsigned int irq, struct irq_desc *desc)
#endif
remove_proc_entry("spurious", desc->dir);
- sprintf(name, "%u", irq);
+ snprintf(name, MAX_NAMELEN, "%u", irq);
remove_proc_entry(name, root_irq_dir);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 758/869] media: chips-media: wave5: Release m2m_ctx after Instance Removed from List
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (756 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 757/869] genirq/proc: Size interrupt directory names for 10-digit interrupt numbers Greg Kroah-Hartman
@ 2026-10-17 15:59 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 759/869] i3c: master: svc: Fix npcm845 FIFO empty issue Greg Kroah-Hartman
` (111 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 15:59 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Brandon Brnich, Nicolas Dufresne,
Jackson Lee, Hans Verkuil, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brandon Brnich <b-brnich@ti.com>
[ Upstream commit 7cdbd7bb21949a8fda10c7104a2b12ee363cbf5c ]
Possible use after free if IRQ thread manages to obtain spinlock between
m2m_ctx release and wave5_release function removing stream instance from
list of active instances. The IRQ thread looks for the m2m_ctx which is
freed so null pointer dereference occurs.
Signed-off-by: Brandon Brnich <b-brnich@ti.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Tested-by: Jackson Lee <jackson.lee@chipsnmedia.com>
Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/media/platform/chips-media/wave5/wave5-helper.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c
index 56914c749c045..f5deae9480923 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-helper.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c
@@ -67,7 +67,6 @@ int wave5_vpu_release_device(struct file *filp,
int ret = 0;
unsigned long flags;
- v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
/*
* To prevent Null reference exception, the existing irq handler were
* separated to two modules.
@@ -88,6 +87,9 @@ int wave5_vpu_release_device(struct file *filp,
list_del_init(&inst->list);
spin_unlock_irqrestore(&inst->dev->irq_spinlock, flags);
mutex_unlock(&inst->dev->irq_lock);
+
+ v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
+
if (inst->state != VPU_INST_STATE_NONE) {
u32 fail_res;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 759/869] i3c: master: svc: Fix npcm845 FIFO empty issue
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (757 preceding siblings ...)
2026-10-17 15:59 ` [PATCH 6.12 758/869] media: chips-media: wave5: Release m2m_ctx after Instance Removed from List Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 760/869] i3c: master: svc: Fix npcm845 invalid slvstart event Greg Kroah-Hartman
` (110 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Frank Li, Stanley Chu,
Alexandre Belloni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanley Chu <yschu@nuvoton.com>
[ Upstream commit 4008a74e0f9b0ec25441028e324452933644ed2a ]
I3C HW stalls the write transfer if the transmit FIFO becomes empty,
when new data is written to FIFO, I3C HW resumes the transfer but the
first transmitted data bit may have the wrong value.
Fill the FIFO in advance to prevent FIFO from becoming empty.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Stanley Chu <yschu@nuvoton.com>
Link: https://lore.kernel.org/r/20250306075429.2265183-4-yschu@nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Stable-dep-of: 1effa3adfe53 ("i3c: master: svc: Prevent IRQ storm from false SLVSTART on NPCM845")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/i3c/master/svc-i3c-master.c | 71 +++++++++++++++++++++++++----
1 file changed, 61 insertions(+), 10 deletions(-)
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index d5cc26955454a..a9107aef1eefe 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -113,6 +113,7 @@
#define SVC_I3C_MWDATAHE 0x0BC
#define SVC_I3C_MRDATAB 0x0C0
#define SVC_I3C_MRDATAH 0x0C8
+#define SVC_I3C_MWDATAB1 0x0CC
#define SVC_I3C_MWMSG_SDR 0x0D0
#define SVC_I3C_MRMSG_SDR 0x0D4
#define SVC_I3C_MWMSG_DDR 0x0D8
@@ -133,6 +134,16 @@
#define SVC_I3C_EVENT_IBI GENMASK(7, 0)
#define SVC_I3C_EVENT_HOTJOIN BIT(31)
+/*
+ * SVC_I3C_QUIRK_FIFO_EMPTY:
+ * I3C HW stalls the write transfer if the transmit FIFO becomes empty,
+ * when new data is written to FIFO, I3C HW resumes the transfer but
+ * the first transmitted data bit may have the wrong value.
+ * Workaround:
+ * Fill the FIFO in advance to prevent FIFO from becoming empty.
+ */
+#define SVC_I3C_QUIRK_FIFO_EMPTY BIT(0)
+
struct svc_i3c_cmd {
u8 addr;
bool rnw;
@@ -236,6 +247,11 @@ struct svc_i3c_i2c_dev_data {
struct i3c_generic_ibi_pool *ibi_pool;
};
+static inline bool svc_has_quirk(struct svc_i3c_master *master, u32 quirk)
+{
+ return (master->drvdata->quirks & quirk);
+}
+
static inline bool is_events_enabled(struct svc_i3c_master *master, u32 mask)
{
return !!(master->enabled_events & mask);
@@ -892,7 +908,7 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master,
u8 *addrs, unsigned int *count)
{
u64 prov_id[SVC_I3C_MAX_DEVS] = {}, nacking_prov_id = 0;
- unsigned int dev_nb = 0, last_addr = 0;
+ unsigned int dev_nb = 0, last_addr = 0, dyn_addr;
u32 reg;
int ret, i;
@@ -934,6 +950,25 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master,
if (SVC_I3C_MSTATUS_RXPEND(reg)) {
u8 data[6];
+ /*
+ * One slave sends its ID to request for address assignment,
+ * prefilling the dynamic address can reduce SCL clock stalls
+ * and also fix the SVC_I3C_QUIRK_FIFO_EMPTY quirk.
+ *
+ * Ideally, prefilling before the processDAA command is better.
+ * However, it requires an additional check to write the dyn_addr
+ * at the right time because the driver needs to write the processDAA
+ * command twice for one assignment.
+ * Prefilling here is safe and efficient because the FIFO starts
+ * filling within a few hundred nanoseconds, which is significantly
+ * faster compared to the 64 SCL clock cycles.
+ */
+ dyn_addr = i3c_master_get_free_addr(&master->base, last_addr + 1);
+ if (dyn_addr < 0)
+ return -ENOSPC;
+
+ writel(dyn_addr, master->regs + SVC_I3C_MWDATAB);
+
/*
* We only care about the 48-bit provisioned ID yet to
* be sure a device does not nack an address twice.
@@ -1007,21 +1042,16 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master,
if (ret)
break;
- /* Give the slave device a suitable dynamic address */
- ret = i3c_master_get_free_addr(&master->base, last_addr + 1);
- if (ret < 0)
- break;
-
- addrs[dev_nb] = ret;
+ addrs[dev_nb] = dyn_addr;
dev_dbg(master->dev, "DAA: device %d assigned to 0x%02x\n",
dev_nb, addrs[dev_nb]);
-
- writel(addrs[dev_nb], master->regs + SVC_I3C_MWDATAB);
last_addr = addrs[dev_nb++];
}
/* Need manual issue STOP except for Complete condition */
svc_i3c_master_emit_stop(master);
+ svc_i3c_master_flush_fifo(master);
+
return ret;
}
@@ -1218,6 +1248,24 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
SVC_I3C_MCTRL_RDTERM(*actual_len),
master->regs + SVC_I3C_MCTRL);
+ /*
+ * The entire transaction can consist of multiple write transfers.
+ * Prefilling before EmitStartAddr causes the data to be emitted
+ * immediately, becoming part of the previous transfer.
+ * The only way to work around this hardware issue is to let the
+ * FIFO start filling as soon as possible after EmitStartAddr.
+ */
+ if (svc_has_quirk(master, SVC_I3C_QUIRK_FIFO_EMPTY) && !rnw && xfer_len) {
+ u32 end = xfer_len > SVC_I3C_FIFO_SIZE ? 0 : SVC_I3C_MWDATAB_END;
+ u32 len = min_t(u32, xfer_len, SVC_I3C_FIFO_SIZE);
+
+ writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1);
+ /* Mark END bit if this is the last byte */
+ writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB);
+ xfer_len -= len;
+ out += len;
+ }
+
ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
SVC_I3C_MSTATUS_MCTRLDONE(reg), 0, 1000);
if (ret)
@@ -1304,6 +1352,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
emit_stop:
svc_i3c_master_emit_stop(master);
svc_i3c_master_clear_merrwarn(master);
+ svc_i3c_master_flush_fifo(master);
return ret;
}
@@ -1958,7 +2007,9 @@ static const struct dev_pm_ops svc_i3c_pm_ops = {
svc_i3c_runtime_resume, NULL)
};
-static const struct svc_i3c_drvdata npcm845_drvdata = {};
+static const struct svc_i3c_drvdata npcm845_drvdata = {
+ .quirks = SVC_I3C_QUIRK_FIFO_EMPTY,
+};
static const struct svc_i3c_drvdata svc_default_drvdata = {};
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 760/869] i3c: master: svc: Fix npcm845 invalid slvstart event
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (758 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 759/869] i3c: master: svc: Fix npcm845 FIFO empty issue Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 761/869] i3c: master: svc: Prevent IRQ storm from false SLVSTART on NPCM845 Greg Kroah-Hartman
` (109 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Frank Li, Stanley Chu,
Alexandre Belloni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanley Chu <yschu@nuvoton.com>
[ Upstream commit 4dd12e944f07013ac280d7f46463c19157898bd1 ]
I3C HW may generate an invalid SlvStart event when emitting a STOP.
If it is a true SlvStart, the MSTATUS state is SLVREQ. Check the
MSTATUS state to ignore the false event.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Stanley Chu <yschu@nuvoton.com>
Link: https://lore.kernel.org/r/20250306075429.2265183-5-yschu@nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Stable-dep-of: 1effa3adfe53 ("i3c: master: svc: Prevent IRQ storm from false SLVSTART on NPCM845")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/i3c/master/svc-i3c-master.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index a9107aef1eefe..0b709be2544c2 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -58,6 +58,7 @@
#define SVC_I3C_MSTATUS 0x088
#define SVC_I3C_MSTATUS_STATE(x) FIELD_GET(GENMASK(2, 0), (x))
#define SVC_I3C_MSTATUS_STATE_DAA(x) (SVC_I3C_MSTATUS_STATE(x) == 5)
+#define SVC_I3C_MSTATUS_STATE_SLVREQ(x) (SVC_I3C_MSTATUS_STATE(x) == 1)
#define SVC_I3C_MSTATUS_STATE_IDLE(x) (SVC_I3C_MSTATUS_STATE(x) == 0)
#define SVC_I3C_MSTATUS_BETWEEN(x) FIELD_GET(BIT(4), (x))
#define SVC_I3C_MSTATUS_NACKED(x) FIELD_GET(BIT(5), (x))
@@ -143,6 +144,12 @@
* Fill the FIFO in advance to prevent FIFO from becoming empty.
*/
#define SVC_I3C_QUIRK_FIFO_EMPTY BIT(0)
+/*
+ * SVC_I3C_QUIRK_FLASE_SLVSTART:
+ * I3C HW may generate an invalid SlvStart event when emitting a STOP.
+ * If it is a true SlvStart, the MSTATUS state is SLVREQ.
+ */
+#define SVC_I3C_QUIRK_FALSE_SLVSTART BIT(1)
struct svc_i3c_cmd {
u8 addr;
@@ -584,6 +591,11 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
/* Clear the interrupt status */
writel(SVC_I3C_MINT_SLVSTART, master->regs + SVC_I3C_MSTATUS);
+ /* Ignore the false event */
+ if (svc_has_quirk(master, SVC_I3C_QUIRK_FALSE_SLVSTART) &&
+ !SVC_I3C_MSTATUS_STATE_SLVREQ(active))
+ return IRQ_HANDLED;
+
svc_i3c_master_disable_interrupts(master);
/* Handle the interrupt in a non atomic context */
@@ -2008,7 +2020,8 @@ static const struct dev_pm_ops svc_i3c_pm_ops = {
};
static const struct svc_i3c_drvdata npcm845_drvdata = {
- .quirks = SVC_I3C_QUIRK_FIFO_EMPTY,
+ .quirks = SVC_I3C_QUIRK_FIFO_EMPTY |
+ SVC_I3C_QUIRK_FALSE_SLVSTART,
};
static const struct svc_i3c_drvdata svc_default_drvdata = {};
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 761/869] i3c: master: svc: Prevent IRQ storm from false SLVSTART on NPCM845
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (759 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 760/869] i3c: master: svc: Fix npcm845 invalid slvstart event Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 762/869] hwmon: (asus_rog_ryujin) Rely on subsystem locking Greg Kroah-Hartman
` (108 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Stanley Chu, Frank Li,
Alexandre Belloni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanley Chu <yschu@nuvoton.com>
[ Upstream commit 1effa3adfe53cb2bb28bf5640a676b791d5ab405 ]
On NPCM845, when a target on the I3C bus gets stuck holding SDA low,
the controller reports a false Master Request (MR) in-band interrupt
event. The driver handles this by emitting a STOP condition to restore
the bus.
However, the hardware quirk SVC_I3C_QUIRK_FALSE_SLVSTART indicates that
emitting a STOP condition may spuriously set the SLVSTART interrupt
status bit. In the Master Request case, this creates a feedback loop:
the STOP triggers a new SLVSTART event, the IRQ handler fires again,
the controller still reports an MR type, another STOP is emitted, and
the cycle repeats indefinitely, resulting in an IRQ storm that can lock
up the CPU.
Clear the SLVSTART status bit explicitly after emitting the STOP in the
Master Request IBI handler when the SVC_I3C_QUIRK_FALSE_SLVSTART quirk
is set. This breaks the feedback loop without affecting normal SLVSTART
processing, which is already guarded in the top-level IRQ handler by
checking that MSTATUS is in SLVREQ state.
Signed-off-by: Stanley Chu <yschu@nuvoton.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260413005040.1211107-3-yschu@nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/i3c/master/svc-i3c-master.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 0b709be2544c2..1948d398ce503 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -570,6 +570,15 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
break;
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
svc_i3c_master_emit_stop(master);
+
+ /*
+ * If a target gets stuck holding SDA low, the controller reports a MR.
+ * On NPCM845, emitting STOP may spuriously set SLVSTART, retriggering
+ * the interrupt and re-entering MR handling, leading to an IRQ storm.
+ * Clear SLVSTART after STOP to break the loop.
+ */
+ if (svc_has_quirk(master, SVC_I3C_QUIRK_FALSE_SLVSTART))
+ writel(SVC_I3C_MINT_SLVSTART, master->regs + SVC_I3C_MSTATUS);
break;
default:
break;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 762/869] hwmon: (asus_rog_ryujin) Rely on subsystem locking
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (760 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 761/869] i3c: master: svc: Prevent IRQ storm from false SLVSTART on NPCM845 Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 763/869] hwmon: (asus_rog_ryujin) Add per-device configuration Greg Kroah-Hartman
` (107 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Guenter Roeck, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <linux@roeck-us.net>
[ Upstream commit b4306c0c8e24f9e031185fb87de45391bc8c7fe9 ]
Attribute access is now serialized in the hardware monitoring core,
so locking in the driver code is no longer necessary. Drop it.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Stable-dep-of: 8042312e73c5 ("hwmon: (asus_rog_ryujin) Validate HID report lengths")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hwmon/asus_rog_ryujin.c | 48 +++++++--------------------------
1 file changed, 9 insertions(+), 39 deletions(-)
diff --git a/drivers/hwmon/asus_rog_ryujin.c b/drivers/hwmon/asus_rog_ryujin.c
index e5e93a20723c4..10a1f5aca988d 100644
--- a/drivers/hwmon/asus_rog_ryujin.c
+++ b/drivers/hwmon/asus_rog_ryujin.c
@@ -81,10 +81,6 @@ static const char *const rog_ryujin_speed_label[] = {
struct rog_ryujin_data {
struct hid_device *hdev;
struct device *hwmon_dev;
- /* For locking access to buffer */
- struct mutex buffer_lock;
- /* For queueing multiple readers */
- struct mutex status_report_request_mutex;
/* For reinitializing the completions below */
spinlock_t status_report_request_lock;
struct completion cooler_status_received;
@@ -153,18 +149,10 @@ static umode_t rog_ryujin_is_visible(const void *data,
/* Writes the command to the device with the rest of the report filled with zeroes */
static int rog_ryujin_write_expanded(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length)
{
- int ret;
-
- mutex_lock(&priv->buffer_lock);
-
memcpy_and_pad(priv->buffer, MAX_REPORT_LENGTH, cmd, cmd_length, 0x00);
- ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
-
- mutex_unlock(&priv->buffer_lock);
- return ret;
+ return hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
}
-/* Assumes priv->status_report_request_mutex is locked */
static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length,
struct completion *status_completion)
{
@@ -196,14 +184,11 @@ static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, i
static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
{
- int ret = mutex_lock_interruptible(&priv->status_report_request_mutex);
-
- if (ret < 0)
- return ret;
+ int ret;
if (!time_after(jiffies, priv->updated + msecs_to_jiffies(STATUS_VALIDITY))) {
/* Data is up to date */
- goto unlock_and_return;
+ return 0;
}
/* Retrieve cooler status */
@@ -211,36 +196,30 @@ static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
rog_ryujin_execute_cmd(priv, get_cooler_status_cmd, GET_CMD_LENGTH,
&priv->cooler_status_received);
if (ret < 0)
- goto unlock_and_return;
+ return ret;
/* Retrieve controller status (speeds) */
ret =
rog_ryujin_execute_cmd(priv, get_controller_speed_cmd, GET_CMD_LENGTH,
&priv->controller_status_received);
if (ret < 0)
- goto unlock_and_return;
+ return ret;
/* Retrieve cooler duty */
ret =
rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH,
&priv->cooler_duty_received);
if (ret < 0)
- goto unlock_and_return;
+ return ret;
/* Retrieve controller duty */
ret =
rog_ryujin_execute_cmd(priv, get_controller_duty_cmd, GET_CMD_LENGTH,
&priv->controller_duty_received);
- if (ret < 0)
- goto unlock_and_return;
-
- priv->updated = jiffies;
-
-unlock_and_return:
- mutex_unlock(&priv->status_report_request_mutex);
if (ret < 0)
return ret;
+ priv->updated = jiffies;
return 0;
}
@@ -303,14 +282,11 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel
* Retrieve cooler duty since both pump and internal fan are set
* together, then write back with one of them modified.
*/
- ret = mutex_lock_interruptible(&priv->status_report_request_mutex);
- if (ret < 0)
- return ret;
ret =
rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH,
&priv->cooler_duty_received);
if (ret < 0)
- goto unlock_and_return;
+ return ret;
memcpy(set_cmd, set_cooler_duty_cmd, SET_CMD_LENGTH);
@@ -329,11 +305,7 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel
set_cmd[RYUJIN_SET_COOLER_FAN_DUTY_OFFSET] = val;
}
- ret = rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
-unlock_and_return:
- mutex_unlock(&priv->status_report_request_mutex);
- if (ret < 0)
- return ret;
+ return rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
} else {
/*
* Controller fan duty (channel == 2). No need to retrieve current
@@ -538,8 +510,6 @@ static int rog_ryujin_probe(struct hid_device *hdev, const struct hid_device_id
goto fail_and_close;
}
- mutex_init(&priv->status_report_request_mutex);
- mutex_init(&priv->buffer_lock);
spin_lock_init(&priv->status_report_request_lock);
init_completion(&priv->cooler_status_received);
init_completion(&priv->controller_status_received);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 763/869] hwmon: (asus_rog_ryujin) Add per-device configuration
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (761 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 762/869] hwmon: (asus_rog_ryujin) Rely on subsystem locking Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 764/869] hwmon: (asus_rog_ryujin) Validate HID report lengths Greg Kroah-Hartman
` (106 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Arie Miller, Aleksa Savic,
Guenter Roeck, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arie Miller <renari@arimil.com>
[ Upstream commit b20ee9aee8779427d2f9de99cbb578b048bf7c04 ]
Move model-specific report offsets and capabilities into a device
information structure. This prepares the driver for coolers which use
a different report layout or do not include the external fan
controller, while preserving the existing Ryujin II 360 behavior.
Handles an issue reported by Sashiko where an id could
be missing driver_data.
Link: https://lore.kernel.org/r/5a817284-a9f4-48b2-9f0f-802c5dc6963c@roeck-us.net
Assisted-by: Codex:gpt-5.6-sol sparse
Signed-off-by: Arie Miller <renari@arimil.com>
Reviewed-by: Aleksa Savic <savicaleksa83@gmail.com>
Link: https://lore.kernel.org/r/20260812103532.395049-2-renari@arimil.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Stable-dep-of: 8042312e73c5 ("hwmon: (asus_rog_ryujin) Validate HID report lengths")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hwmon/asus_rog_ryujin.c | 75 +++++++++++++++++++++++----------
1 file changed, 52 insertions(+), 23 deletions(-)
diff --git a/drivers/hwmon/asus_rog_ryujin.c b/drivers/hwmon/asus_rog_ryujin.c
index 10a1f5aca988d..80563ce38519d 100644
--- a/drivers/hwmon/asus_rog_ryujin.c
+++ b/drivers/hwmon/asus_rog_ryujin.c
@@ -18,15 +18,25 @@
#define USB_VENDOR_ID_ASUS_ROG 0x0b05
#define USB_PRODUCT_ID_RYUJIN_AIO 0x1988 /* ASUS ROG RYUJIN II 360 */
+struct rog_ryujin_device_info {
+ u8 temp_offset;
+ u8 pump_speed_offset;
+ u8 fan_speed_offset;
+ u8 duty_channel;
+ bool has_controller;
+};
+
+static const struct rog_ryujin_device_info rog_ryujin_ii_360_info = {
+ .temp_offset = 3,
+ .pump_speed_offset = 5,
+ .fan_speed_offset = 7,
+ .duty_channel = 0,
+ .has_controller = true,
+};
+
#define STATUS_VALIDITY 1500 /* ms */
#define MAX_REPORT_LENGTH 65
-/* Cooler status report offsets */
-#define RYUJIN_TEMP_SENSOR_1 3
-#define RYUJIN_TEMP_SENSOR_2 4
-#define RYUJIN_PUMP_SPEED 5
-#define RYUJIN_INTERNAL_FAN_SPEED 7
-
/* Cooler duty report offsets */
#define RYUJIN_PUMP_DUTY 4
#define RYUJIN_INTERNAL_FAN_DUTY 5
@@ -81,6 +91,7 @@ static const char *const rog_ryujin_speed_label[] = {
struct rog_ryujin_data {
struct hid_device *hdev;
struct device *hwmon_dev;
+ const struct rog_ryujin_device_info *info;
/* For reinitializing the completions below */
spinlock_t status_report_request_lock;
struct completion cooler_status_received;
@@ -112,6 +123,8 @@ static int rog_ryujin_pwm_to_percent(long val)
static umode_t rog_ryujin_is_visible(const void *data,
enum hwmon_sensor_types type, u32 attr, int channel)
{
+ const struct rog_ryujin_data *priv = data;
+
switch (type) {
case hwmon_temp:
switch (attr) {
@@ -123,6 +136,8 @@ static umode_t rog_ryujin_is_visible(const void *data,
}
break;
case hwmon_fan:
+ if (channel >= 2 && !priv->info->has_controller)
+ return 0;
switch (attr) {
case hwmon_fan_label:
case hwmon_fan_input:
@@ -132,6 +147,8 @@ static umode_t rog_ryujin_is_visible(const void *data,
}
break;
case hwmon_pwm:
+ if (channel >= 2 && !priv->info->has_controller)
+ return 0;
switch (attr) {
case hwmon_pwm_input:
return 0644;
@@ -198,12 +215,14 @@ static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
if (ret < 0)
return ret;
- /* Retrieve controller status (speeds) */
- ret =
- rog_ryujin_execute_cmd(priv, get_controller_speed_cmd, GET_CMD_LENGTH,
- &priv->controller_status_received);
- if (ret < 0)
- return ret;
+ if (priv->info->has_controller) {
+ /* Retrieve controller status (speeds) */
+ ret = rog_ryujin_execute_cmd(priv, get_controller_speed_cmd,
+ GET_CMD_LENGTH,
+ &priv->controller_status_received);
+ if (ret < 0)
+ return ret;
+ }
/* Retrieve cooler duty */
ret =
@@ -212,12 +231,14 @@ static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
if (ret < 0)
return ret;
- /* Retrieve controller duty */
- ret =
- rog_ryujin_execute_cmd(priv, get_controller_duty_cmd, GET_CMD_LENGTH,
- &priv->controller_duty_received);
- if (ret < 0)
- return ret;
+ if (priv->info->has_controller) {
+ /* Retrieve controller duty */
+ ret = rog_ryujin_execute_cmd(priv, get_controller_duty_cmd,
+ GET_CMD_LENGTH,
+ &priv->controller_duty_received);
+ if (ret < 0)
+ return ret;
+ }
priv->updated = jiffies;
return 0;
@@ -289,6 +310,7 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel
return ret;
memcpy(set_cmd, set_cooler_duty_cmd, SET_CMD_LENGTH);
+ set_cmd[2] = priv->info->duty_channel;
/* Cooler duties are set as 0-100% */
val = rog_ryujin_pwm_to_percent(val);
@@ -394,10 +416,12 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
if (data[1] == RYUJIN_GET_COOLER_STATUS_CMD_RESPONSE) {
/* Received coolant temp and speeds of pump and internal fan */
- priv->temp_input[0] =
- data[RYUJIN_TEMP_SENSOR_1] * 1000 + data[RYUJIN_TEMP_SENSOR_2] * 100;
- priv->speed_input[0] = get_unaligned_le16(data + RYUJIN_PUMP_SPEED);
- priv->speed_input[1] = get_unaligned_le16(data + RYUJIN_INTERNAL_FAN_SPEED);
+ priv->temp_input[0] = data[priv->info->temp_offset] * 1000 +
+ data[priv->info->temp_offset + 1] * 100;
+ priv->speed_input[0] =
+ get_unaligned_le16(data + priv->info->pump_speed_offset);
+ priv->speed_input[1] =
+ get_unaligned_le16(data + priv->info->fan_speed_offset);
if (!completion_done(&priv->cooler_status_received))
complete_all(&priv->cooler_status_received);
@@ -471,11 +495,15 @@ static int rog_ryujin_probe(struct hid_device *hdev, const struct hid_device_id
struct rog_ryujin_data *priv;
int ret;
+ if (!id->driver_data)
+ return -EINVAL;
+
priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->hdev = hdev;
+ priv->info = (const struct rog_ryujin_device_info *)id->driver_data;
hid_set_drvdata(hdev, priv);
/*
@@ -546,7 +574,8 @@ static void rog_ryujin_remove(struct hid_device *hdev)
}
static const struct hid_device_id rog_ryujin_table[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_AIO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_AIO),
+ .driver_data = (kernel_ulong_t)&rog_ryujin_ii_360_info },
{ }
};
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 764/869] hwmon: (asus_rog_ryujin) Validate HID report lengths
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (762 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 763/869] hwmon: (asus_rog_ryujin) Add per-device configuration Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 765/869] smb: client: avoid using uninitialized SIDs in cifs_posix_to_fattr() Greg Kroah-Hartman
` (105 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Arie Miller, Guenter Roeck,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arie Miller <renari@arimil.com>
[ Upstream commit 8042312e73c50de82634ce63eae7cf219464b481 ]
rog_ryujin_raw_event() parses response headers and payload fields without
first checking that they are present in the received report. A short report
can therefore make the driver consume uninitialized bytes from the HID
transport buffer and expose them as sensor values through sysfs.
Validate the response header and the fields used by each response type
before parsing them.
Fixes: ed3e03790c5c ("hwmon: Add driver for ASUS ROG RYUJIN II 360 AIO cooler")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/linux-hwmon/20260812104617.858D01F000E9@smtp.kernel.org/
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.6-sol sparse
Signed-off-by: Arie Miller <renari@arimil.com>
Link: https://patch.msgid.link/20260904022129.97896-2-renari@arimil.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hwmon/asus_rog_ryujin.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/drivers/hwmon/asus_rog_ryujin.c b/drivers/hwmon/asus_rog_ryujin.c
index 80563ce38519d..593950802b39d 100644
--- a/drivers/hwmon/asus_rog_ryujin.c
+++ b/drivers/hwmon/asus_rog_ryujin.c
@@ -411,10 +411,15 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
{
struct rog_ryujin_data *priv = hid_get_drvdata(hdev);
- if (data[0] != RYUJIN_CMD_PREFIX)
+ if (size < 2 || data[0] != RYUJIN_CMD_PREFIX)
return 0;
if (data[1] == RYUJIN_GET_COOLER_STATUS_CMD_RESPONSE) {
+ if (size <= priv->info->temp_offset + 1 ||
+ size <= priv->info->pump_speed_offset + 1 ||
+ size <= priv->info->fan_speed_offset + 1)
+ return 0;
+
/* Received coolant temp and speeds of pump and internal fan */
priv->temp_input[0] = data[priv->info->temp_offset] * 1000 +
data[priv->info->temp_offset + 1] * 100;
@@ -426,6 +431,9 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
if (!completion_done(&priv->cooler_status_received))
complete_all(&priv->cooler_status_received);
} else if (data[1] == RYUJIN_GET_CONTROLLER_SPEED_CMD_RESPONSE) {
+ if (size <= RYUJIN_CONTROLLER_SPEED_3 + 1)
+ return 0;
+
/* Received speeds of four fans attached to the controller */
priv->speed_input[2] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_1);
priv->speed_input[3] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_2);
@@ -435,6 +443,9 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
if (!completion_done(&priv->controller_status_received))
complete_all(&priv->controller_status_received);
} else if (data[1] == RYUJIN_GET_COOLER_DUTY_CMD_RESPONSE) {
+ if (size <= RYUJIN_INTERNAL_FAN_DUTY)
+ return 0;
+
/* Received report for pump and internal fan duties (in %) */
if (data[RYUJIN_PUMP_DUTY] == 0 && data[RYUJIN_INTERNAL_FAN_DUTY] == 0) {
/*
@@ -461,6 +472,9 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
if (!completion_done(&priv->cooler_duty_received))
complete_all(&priv->cooler_duty_received);
} else if (data[1] == RYUJIN_GET_CONTROLLER_DUTY_CMD_RESPONSE) {
+ if (size <= RYUJIN_CONTROLLER_DUTY)
+ return 0;
+
/* Received report for controller duty for fans (in PWM) */
if (data[RYUJIN_CONTROLLER_DUTY] == 0) {
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 765/869] smb: client: avoid using uninitialized SIDs in cifs_posix_to_fattr()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (763 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 764/869] hwmon: (asus_rog_ryujin) Validate HID report lengths Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 766/869] smb: client: honor forceuid/forcegid when mapping SIDs to uid/gid Greg Kroah-Hartman
` (104 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Namjae Jeon, Paulo Alcantara,
Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <pc@manguebit.org>
[ Upstream commit da6e25842431982d5a53cf00d925b98c690f4467 ]
cifs_posix_to_fattr() ignores the return value of posix_info_parse().
When a malformed POSIX directory entry is encountered (e.g. invalid
SID lengths from an untrusted server), posix_info_parse() returns -1
without populating the 'parsed' struct. The uninitialized stack
memory in parsed.owner and parsed.group is then passed to
sid_to_id(), which processes the garbage bytes and passes them to
request_key() to construct a SID string, potentially leaking kernel
stack contents to the userspace idmap daemon.
Fix this by checking the return value and skipping the SID-to-id
mapping when parsing fails. The remaining fattr fields (timestamps,
mode, etc.) are populated directly from the 'info' pointer so they
are unaffected.
Closes: https://sashiko.dev/#/patchset/20260906172005.627163-1-pc%40manguebit.org
Closes: https://sashiko.dev/#/patchset/20260906181540.647469-1-pc%40manguebit.org
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Cc: Shyam Prasad N <sprasad@microsoft.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Bharath SM <bharathsm@microsoft.com>
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/readdir.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c
index 6b619506b7a1c..bdf91737b46ff 100644
--- a/fs/smb/client/readdir.c
+++ b/fs/smb/client/readdir.c
@@ -242,8 +242,9 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
struct cifs_sb_info *cifs_sb)
{
struct smb2_posix_info_parsed parsed;
+ int rc;
- posix_info_parse(info, NULL, &parsed);
+ rc = posix_info_parse(info, NULL, &parsed);
memset(fattr, 0, sizeof(*fattr));
fattr->cf_uniqueid = le64_to_cpu(info->Inode);
@@ -280,8 +281,15 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
le32_to_cpu(info->ReparseTag),
le32_to_cpu(info->Mode));
- sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER);
- sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP);
+ fattr->cf_uid = cifs_sb->ctx->linux_uid;
+ fattr->cf_gid = cifs_sb->ctx->linux_gid;
+ if (rc < 0) {
+ cifs_dbg(VFS, "%s: failed to parse SIDs: %d\n",
+ __func__, rc);
+ } else {
+ sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER);
+ sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP);
+ }
}
static void __dir_info_to_fattr(struct cifs_fattr *fattr, const void *info)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 766/869] smb: client: honor forceuid/forcegid when mapping SIDs to uid/gid
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (764 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 765/869] smb: client: avoid using uninitialized SIDs in cifs_posix_to_fattr() Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 767/869] drm/amdgpu: skip the VMID 0 flush for VRAM Greg Kroah-Hartman
` (103 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Namjae Jeon, Paulo Alcantara,
Ronnie Sahlberg, Shyam Prasad N, Tom Talpey, Bharath SM,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paulo Alcantara <pc@manguebit.org>
[ Upstream commit 18a72975e9f35aadecc75b031f693f2d1f49308f ]
When the administrator mounts with forceuid or forcegid (uid=/gid=
mount options), they expect all files to appear owned by the specified
user/group. However, several code paths unconditionally called
sid_to_id() to overwrite cf_uid/cf_gid with server-provided values,
ignoring the administrator's explicit override:
- smb311_posix_info_to_fattr() (stat via POSIX extensions)
- cifs_posix_to_fattr() (readdir via POSIX extensions)
- parse_sec_desc() (CIFS ACL ownership mapping)
This allowed an untrusted server to dictate local file ownership even
when the mount was configured to force specific uid/gid values.
Fix all three call sites to check CIFS_MOUNT_OVERR_UID and
CIFS_MOUNT_OVERR_GID before calling sid_to_id(), following the
same pattern already used by cifs_unix_basic_to_fattr() for unix
extensions.
Closes: https://sashiko.dev/#/patchset/20260906155816.603278-1-pc%40manguebit.org
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Cc: Shyam Prasad N <sprasad@microsoft.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Bharath SM <bharathsm@microsoft.com>
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/cifsacl.c | 28 ++++++++++++++++++----------
fs/smb/client/inode.c | 9 +++++++--
fs/smb/client/readdir.c | 7 +++++--
3 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
index 102a7abd72748..a9157dbc40bb5 100644
--- a/fs/smb/client/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -1315,6 +1315,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
{
int rc = 0;
struct smb_sid *owner_sid_ptr, *group_sid_ptr;
+ unsigned int sbflags = cifs_sb->mnt_cifs_flags;
struct smb_acl *dacl_ptr; /* no need for SACL ptr */
char *end_of_acl = ((char *)pntsd) + acl_len;
__u32 dacloffset;
@@ -1332,16 +1333,21 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
le32_to_cpu(pntsd->gsidoffset),
le32_to_cpu(pntsd->sacloffset), dacloffset);
/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
+ fattr->cf_uid = cifs_sb->ctx->linux_uid;
+ fattr->cf_gid = cifs_sb->ctx->linux_gid;
+
rc = parse_sid(owner_sid_ptr, end_of_acl);
if (rc) {
cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
return rc;
}
- rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
- if (rc) {
- cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
- __func__, rc);
- return rc;
+ if (!(sbflags & CIFS_MOUNT_OVERR_UID)) {
+ rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
+ if (rc) {
+ cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
+ __func__, rc);
+ return rc;
+ }
}
rc = parse_sid(group_sid_ptr, end_of_acl);
@@ -1350,11 +1356,13 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
__func__, rc);
return rc;
}
- rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
- if (rc) {
- cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
- __func__, rc);
- return rc;
+ if (!(sbflags & CIFS_MOUNT_OVERR_GID)) {
+ rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
+ if (rc) {
+ cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
+ __func__, rc);
+ return rc;
+ }
}
if (dacloffset) {
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index e75ac895d3b4a..05f525621e0f6 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -833,6 +833,7 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
struct smb311_posix_qinfo *info = &data->posix_fi;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+ unsigned int sbflags = cifs_sb->mnt_cifs_flags;
memset(fattr, 0, sizeof(*fattr));
@@ -877,8 +878,12 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
fattr->cf_symlink_target = data->symlink_target;
data->symlink_target = NULL;
}
- sid_to_id(cifs_sb, &data->posix_owner, fattr, SIDOWNER);
- sid_to_id(cifs_sb, &data->posix_group, fattr, SIDGROUP);
+ fattr->cf_uid = cifs_sb->ctx->linux_uid;
+ fattr->cf_gid = cifs_sb->ctx->linux_gid;
+ if (!(sbflags & CIFS_MOUNT_OVERR_UID))
+ sid_to_id(cifs_sb, &data->posix_owner, fattr, SIDOWNER);
+ if (!(sbflags & CIFS_MOUNT_OVERR_GID))
+ sid_to_id(cifs_sb, &data->posix_group, fattr, SIDGROUP);
cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n",
fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c
index bdf91737b46ff..f1f7a718f5d58 100644
--- a/fs/smb/client/readdir.c
+++ b/fs/smb/client/readdir.c
@@ -241,6 +241,7 @@ static void
cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
struct cifs_sb_info *cifs_sb)
{
+ unsigned int sbflags = cifs_sb->mnt_cifs_flags;
struct smb2_posix_info_parsed parsed;
int rc;
@@ -287,8 +288,10 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
cifs_dbg(VFS, "%s: failed to parse SIDs: %d\n",
__func__, rc);
} else {
- sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER);
- sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP);
+ if (!(sbflags & CIFS_MOUNT_OVERR_UID))
+ sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER);
+ if (!(sbflags & CIFS_MOUNT_OVERR_GID))
+ sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 767/869] drm/amdgpu: skip the VMID 0 flush for VRAM
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (765 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 766/869] smb: client: honor forceuid/forcegid when mapping SIDs to uid/gid Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 768/869] perf/x86/intel: Prevent drain_pebs() reentry Greg Kroah-Hartman
` (102 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian König,
Arunpravin Paneer Selvam, Timur Kristóf, Alex Deucher,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
[ Upstream commit 87ceb8cba73d0b3c4025ff42495bccd8164acaed ]
Clear-on-release only runs on VRAM, which amdgpu_ttm_map_buffer() reaches
via its direct MC address without programming a GART window, yet the wipe
still forces a VMID 0 flush. On GFX11 (e.g. Navi33) that spurious SDMA
flush can wedge the engine; only flush when a GART window is actually used.
v2: Let amdgpu_ttm_map_buffer() return whether the VMID 0 flush is needed,
and drive the clear and copy paths from that. (Christian)
v3: Make the vm_needs_flush output parameter mandatory instead of
allowing NULL. (Christian)
Fixes: a68c7eaa7a8f ("drm/amdgpu: Enable clear page functionality")
Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/5413
Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Timur Kristóf <timur.kristof@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit a306e406e570b74318ff7d80e5b07b540ca1d3a9)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 60c5e8803f60c..93da39a5ce492 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -174,6 +174,8 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo,
* @tmz: if we should setup a TMZ enabled mapping
* @size: in number of bytes to map, out number of bytes mapped
* @addr: resulting address inside the MC address space
+ * @vm_needs_flush: out, set true if a GART window was programmed (VMID 0 flush
+ * needed) or false for a direct address
*
* Setup one of the GART windows to access a specific piece of memory or return
* the physical address for local memory.
@@ -182,7 +184,8 @@ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
struct ttm_resource *mem,
struct amdgpu_res_cursor *mm_cur,
unsigned int window, struct amdgpu_ring *ring,
- bool tmz, uint64_t *size, uint64_t *addr)
+ bool tmz, uint64_t *size, uint64_t *addr,
+ bool *vm_needs_flush)
{
struct amdgpu_device *adev = ring->adev;
unsigned int offset, num_pages, num_dw, num_bytes;
@@ -203,9 +206,12 @@ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
if (!tmz && mem->start != AMDGPU_BO_INVALID_OFFSET) {
*addr = amdgpu_ttm_domain_start(adev, mem->mem_type) +
mm_cur->start;
+ *vm_needs_flush = false;
return 0;
}
+ /* A GART window is programmed below, so its VMID 0 TLB needs a flush */
+ *vm_needs_flush = true;
/*
* If start begins at an offset inside the page, then adjust the size
@@ -314,6 +320,7 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
while (src_mm.remaining) {
uint64_t from, to, cur_size, tiling_flags;
uint32_t num_type, data_format, max_com, write_compress_disable;
+ bool src_vm_flush, dst_vm_flush;
struct dma_fence *next;
/* Never copy more than 256MiB at once to avoid a timeout */
@@ -321,12 +328,12 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
/* Map src to window 0 and dst to window 1. */
r = amdgpu_ttm_map_buffer(src->bo, src->mem, &src_mm,
- 0, ring, tmz, &cur_size, &from);
+ 0, ring, tmz, &cur_size, &from, &src_vm_flush);
if (r)
goto error;
r = amdgpu_ttm_map_buffer(dst->bo, dst->mem, &dst_mm,
- 1, ring, tmz, &cur_size, &to);
+ 1, ring, tmz, &cur_size, &to, &dst_vm_flush);
if (r)
goto error;
@@ -354,7 +361,7 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
}
r = amdgpu_copy_buffer(ring, from, to, cur_size, resv,
- &next, false, true, copy_flags);
+ &next, false, src_vm_flush || dst_vm_flush, copy_flags);
if (r)
goto error;
@@ -2311,6 +2318,7 @@ int amdgpu_ttm_clear_buffer(struct amdgpu_bo *bo,
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
struct amdgpu_res_cursor cursor;
+ bool vm_needs_flush = false;
u64 addr;
int r = 0;
@@ -2338,12 +2346,12 @@ int amdgpu_ttm_clear_buffer(struct amdgpu_bo *bo,
size = min(cursor.size, 256ULL << 20);
r = amdgpu_ttm_map_buffer(&bo->tbo, bo->tbo.resource, &cursor,
- 1, ring, false, &size, &addr);
+ 1, ring, false, &size, &addr, &vm_needs_flush);
if (r)
goto err;
r = amdgpu_ttm_fill_mem(ring, 0, addr, size, resv,
- &next, true, true,
+ &next, vm_needs_flush, true,
AMDGPU_KERNEL_JOB_ID_TTM_CLEAR_BUFFER);
if (r)
goto err;
@@ -2370,6 +2378,7 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
struct dma_fence *fence = NULL;
struct amdgpu_res_cursor dst;
+ bool vm_needs_flush = false;
int r;
if (!adev->mman.buffer_funcs_enabled) {
@@ -2388,12 +2397,12 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
cur_size = min(dst.size, 256ULL << 20);
r = amdgpu_ttm_map_buffer(&bo->tbo, bo->tbo.resource, &dst,
- 1, ring, false, &cur_size, &to);
+ 1, ring, false, &cur_size, &to, &vm_needs_flush);
if (r)
goto error;
r = amdgpu_ttm_fill_mem(ring, src_data, to, cur_size, resv,
- &next, true, delayed, k_job_id);
+ &next, vm_needs_flush, delayed, k_job_id);
if (r)
goto error;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 768/869] perf/x86/intel: Prevent drain_pebs() reentry
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (766 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 767/869] drm/amdgpu: skip the VMID 0 flush for VRAM Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 769/869] net/mlx5e: Move representor vnic reporter to eswitch devlink port Greg Kroah-Hartman
` (101 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dapeng Mi, Peter Zijlstra (Intel),
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dapeng Mi <dapeng1.mi@linux.intel.com>
[ Upstream commit a56c03a397e2cd0c4cf8da96dcd6214f7d0e7d8c ]
The PEBS buffer is shared by all events on a CPU, so drain_pebs() must
not be reentered. If so, one instance may observe stale buffer state and
potentially access out-of-bound memory.
Most invocations happen in NMI context, which naturally prevents reentry.
However, drain_pebs() is also reachable from process context via
intel_pmu_drain_pebs_buffer().
In those paths, the PMU is often already disabled, but not guaranteed.
For example, __intel_pmu_pebs_disable() only disables the target counter,
so other active counters can still raise a PMI and interrupt an in-flight
drain_pebs(). Here is an example,
__perf_addr_filters_adjust()
perf_event_stop()
__perf_event_stop()
x86_pmu_stop() (event->pmu->stop)
intel_pmu_disable_event()
intel_pmu_pebs_disable()
__intel_pmu_pebs_disable()
intel_pmu_drain_large_pebs()
intel_pmu_drain_pebs_buffer()
Introduce __intel_pmu_quiesce() and __intel_pmu_resume() helpers and
use them in intel_pmu_drain_large_pebs() to disable the full PMU
around the intel_pmu_drain_pebs_buffer() call, preventing reentry.
Also add a warning in intel_pmu_drain_pebs_buffer() when the full PMU is
not disabled.
Fixes: b752ea0c28e3 ("perf/x86/intel/ds: Flush PEBS DS when changing PEBS_DATA_CFG")
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260813064346.335458-1-dapeng1.mi@linux.intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/events/intel/core.c | 32 ++++++++++++++++++++++++--------
arch/x86/events/intel/ds.c | 8 +++++++-
arch/x86/events/perf_event.h | 3 +++
3 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 2efb414959e1f..35b6c340001db 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -2606,6 +2606,27 @@ static void intel_pmu_del_event(struct perf_event *event)
intel_pmu_pebs_del(event);
}
+int __intel_pmu_quiesce(void)
+{
+ struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+ int pmu_enabled = cpuc->enabled;
+
+ cpuc->enabled = 0;
+ if (pmu_enabled)
+ intel_pmu_disable_all();
+
+ return pmu_enabled;
+}
+
+void __intel_pmu_resume(int pmu_enabled)
+{
+ struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+ cpuc->enabled = pmu_enabled;
+ if (pmu_enabled)
+ intel_pmu_enable_all(0);
+}
+
static int icl_set_topdown_event_period(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
@@ -2784,24 +2805,19 @@ static void intel_pmu_read_event(struct perf_event *event)
{
if (event->hw.flags & (PERF_X86_EVENT_AUTO_RELOAD | PERF_X86_EVENT_TOPDOWN)) {
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
- bool pmu_enabled = cpuc->enabled;
+ int pmu_enabled;
/* Only need to call update_topdown_event() once for group read. */
if (is_metric_event(event) && (cpuc->txn_flags & PERF_PMU_TXN_READ))
return;
- cpuc->enabled = 0;
- if (pmu_enabled)
- intel_pmu_disable_all();
+ pmu_enabled = __intel_pmu_quiesce();
if (is_topdown_count(event))
static_call(intel_pmu_update_topdown_event)(event);
else
intel_pmu_drain_pebs_buffer();
-
- cpuc->enabled = pmu_enabled;
- if (pmu_enabled)
- intel_pmu_enable_all(0);
+ __intel_pmu_resume(pmu_enabled);
return;
}
diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c
index 4eac316932108..44c041c6a29b7 100644
--- a/arch/x86/events/intel/ds.c
+++ b/arch/x86/events/intel/ds.c
@@ -949,8 +949,11 @@ int intel_pmu_drain_bts_buffer(void)
void intel_pmu_drain_pebs_buffer(void)
{
+ struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
struct perf_sample_data data;
+ WARN_ON_ONCE(cpuc->enabled);
+
static_call(x86_pmu_drain_pebs)(NULL, &data);
}
@@ -1448,8 +1451,11 @@ static void intel_pmu_pebs_via_pt_enable(struct perf_event *event)
static inline void intel_pmu_drain_large_pebs(struct cpu_hw_events *cpuc)
{
if (cpuc->n_pebs == cpuc->n_large_pebs &&
- cpuc->n_pebs != cpuc->n_pebs_via_pt)
+ cpuc->n_pebs != cpuc->n_pebs_via_pt) {
+ int enabled = __intel_pmu_quiesce();
intel_pmu_drain_pebs_buffer();
+ __intel_pmu_resume(enabled);
+ }
}
void intel_pmu_pebs_enable(struct perf_event *event)
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index 3878173933be6..85afab67414a8 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -1560,6 +1560,9 @@ static __always_inline void __intel_pmu_lbr_disable(void)
wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
}
+extern int __intel_pmu_quiesce(void);
+extern void __intel_pmu_resume(int pmu_enabled);
+
int intel_pmu_save_and_restart(struct perf_event *event);
struct event_constraint *
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 769/869] net/mlx5e: Move representor vnic reporter to eswitch devlink port
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (767 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 768/869] perf/x86/intel: Prevent drain_pebs() reentry Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 770/869] Bluetooth: hci_sysfs: Fix NULL pointer dereference in device_del() Greg Kroah-Hartman
` (100 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Carolina Jubran, Cosmin Ratiu,
Tariq Toukan, Simon Horman, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carolina Jubran <cjubran@nvidia.com>
[ Upstream commit 7f26a5e8040b4957ef4dbdfcde6cc7ba2db53937 ]
The representor vnic devlink health reporter is created and destroyed
along the representor netdev (un)load path, which is not serialized by
the devlink instance lock. Destroying the reporter from there triggers
a devl_assert_locked() splat on driver unbind:
WARNING: net/devlink/core.c:259 at devl_assert_locked+0x54/0x70, CPU#2: bash/3758
Modules linked in: mlx5_vdpa vringh vdpa mlx5_ib mlx5_fwctl mlx5_core ...
CPU: 2 UID: 0 PID: 3758 Comm: bash Tainted: G W 6.19.0+ #1 PREEMPT
Tainted: [W]=WARN
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), ...
RIP: 0010:devl_assert_locked+0x54/0x70
Call Trace:
<TASK>
devl_health_reporter_destroy+0x3a/0x1b0
mlx5e_vport_rep_unload+0x12d/0x2b0 [mlx5_core]
mlx5_eswitch_unregister_vport_reps+0x1b8/0x220 [mlx5_core]
? __esw_offloads_unload_rep+0x190/0x190 [mlx5_core]
? kernfs_remove_by_name_ns+0xc3/0xf0
device_release_driver_internal+0x3b2/0x560
unbind_store+0xce/0xf0
Move the reporter's lifecycle to the eswitch devlink port (un)register
paths, which are already serialized by the devlink instance lock, and
store the handle on mlx5_devlink_port. Use the port's mlx5_vport as the
reporter priv since the diagnose callback only needs a device handle and
a vport number, and mlx5_vport carries both and is initialized before
any representor driver probes.
Fixes: cf14af140a5a ("net/mlx5e: Add vnic devlink health reporter to representors")
Signed-off-by: Carolina Jubran <cjubran@nvidia.com>
Reviewed-by: Cosmin Ratiu <cratiu@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260906090700.3761260-1-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../net/ethernet/mellanox/mlx5/core/en_rep.c | 52 +------------------
.../net/ethernet/mellanox/mlx5/core/en_rep.h | 1 -
.../mellanox/mlx5/core/esw/devlink_port.c | 36 +++++++++++++
.../net/ethernet/mellanox/mlx5/core/eswitch.h | 1 +
4 files changed, 38 insertions(+), 52 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 763b264721af1..82ef5d252161e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -56,7 +56,6 @@
#include "lib/vxlan.h"
#define CREATE_TRACE_POINTS
#include "diag/en_rep_tracepoint.h"
-#include "diag/reporter_vnic.h"
#include "en_accel/ipsec.h"
#include "en/tc/int_port.h"
#include "en/ptp.h"
@@ -1412,51 +1411,6 @@ static unsigned int mlx5e_ul_rep_stats_grps_num(struct mlx5e_priv *priv)
return ARRAY_SIZE(mlx5e_ul_rep_stats_grps);
}
-static int
-mlx5e_rep_vnic_reporter_diagnose(struct devlink_health_reporter *reporter,
- struct devlink_fmsg *fmsg,
- struct netlink_ext_ack *extack)
-{
- struct mlx5e_rep_priv *rpriv = devlink_health_reporter_priv(reporter);
- struct mlx5_eswitch_rep *rep = rpriv->rep;
-
- mlx5_reporter_vnic_diagnose_counters(rep->esw->dev, fmsg, rep->vport,
- true);
- return 0;
-}
-
-static const struct devlink_health_reporter_ops mlx5_rep_vnic_reporter_ops = {
- .name = "vnic",
- .diagnose = mlx5e_rep_vnic_reporter_diagnose,
-};
-
-static void mlx5e_rep_vnic_reporter_create(struct mlx5e_priv *priv,
- struct devlink_port *dl_port)
-{
- struct mlx5e_rep_priv *rpriv = priv->ppriv;
- struct devlink_health_reporter *reporter;
-
- reporter = devl_port_health_reporter_create(dl_port,
- &mlx5_rep_vnic_reporter_ops,
- 0, rpriv);
- if (IS_ERR(reporter)) {
- mlx5_core_err(priv->mdev,
- "Failed to create representor vnic reporter, err = %ld\n",
- PTR_ERR(reporter));
- return;
- }
-
- rpriv->rep_vnic_reporter = reporter;
-}
-
-static void mlx5e_rep_vnic_reporter_destroy(struct mlx5e_priv *priv)
-{
- struct mlx5e_rep_priv *rpriv = priv->ppriv;
-
- if (!IS_ERR_OR_NULL(rpriv->rep_vnic_reporter))
- devl_health_reporter_destroy(rpriv->rep_vnic_reporter);
-}
-
static const struct mlx5e_profile mlx5e_rep_profile = {
.init = mlx5e_init_rep,
.cleanup = mlx5e_cleanup_rep,
@@ -1580,10 +1534,8 @@ mlx5e_vport_vf_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
dl_port = mlx5_esw_offloads_devlink_port(dev->priv.eswitch,
rpriv->rep->vport);
- if (!IS_ERR(dl_port)) {
+ if (!IS_ERR(dl_port))
SET_NETDEV_DEVLINK_PORT(netdev, dl_port);
- mlx5e_rep_vnic_reporter_create(priv, dl_port);
- }
err = register_netdev(netdev);
if (err) {
@@ -1596,7 +1548,6 @@ mlx5e_vport_vf_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
return 0;
err_detach_netdev:
- mlx5e_rep_vnic_reporter_destroy(priv);
mlx5e_detach_netdev(netdev_priv(netdev));
err_cleanup_profile:
priv->profile->cleanup(priv);
@@ -1654,7 +1605,6 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep)
}
unregister_netdev(netdev);
- mlx5e_rep_vnic_reporter_destroy(priv);
mlx5e_detach_netdev(priv);
priv->profile->cleanup(priv);
mlx5e_destroy_netdev(netdev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
index 70640fa1ad7bc..bcd7b4e814d06 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
@@ -118,7 +118,6 @@ struct mlx5e_rep_priv {
struct rtnl_link_stats64 prev_vf_vport_stats;
struct mlx5_flow_handle *send_to_vport_meta_rule;
struct rhashtable tc_ht;
- struct devlink_health_reporter *rep_vnic_reporter;
};
static inline
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c
index b0c97648ffc71..9283b7c46e50c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c
@@ -3,6 +3,26 @@
#include <linux/mlx5/driver.h>
#include "eswitch.h"
+#include "diag/reporter_vnic.h"
+
+static int
+mlx5_esw_rep_vnic_reporter_diagnose(struct devlink_health_reporter *reporter,
+ struct devlink_fmsg *fmsg,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_vport *vport = devlink_health_reporter_priv(reporter);
+
+ mlx5_reporter_vnic_diagnose_counters(vport->dev, fmsg, vport->vport,
+ true);
+
+ return 0;
+}
+
+static const
+struct devlink_health_reporter_ops mlx5_esw_rep_vnic_reporter_ops = {
+ .name = "vnic",
+ .diagnose = mlx5_esw_rep_vnic_reporter_diagnose,
+};
static void
mlx5_esw_get_port_parent_id(struct mlx5_core_dev *dev, struct netdev_phys_item_id *ppid)
@@ -153,6 +173,7 @@ static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = {
int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
{
+ struct devlink_health_reporter *reporter;
struct mlx5_core_dev *dev = esw->dev;
const struct devlink_port_ops *ops;
struct mlx5_devlink_port *dl_port;
@@ -182,6 +203,16 @@ int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx
if (err)
goto rate_err;
+ reporter = devl_port_health_reporter_create(
+ &dl_port->dl_port, &mlx5_esw_rep_vnic_reporter_ops,
+ 0, vport);
+ if (IS_ERR(reporter))
+ mlx5_core_err(dev,
+ "Failed to create vnic health reporter for vport %d: %ld\n",
+ vport_num, PTR_ERR(reporter));
+ else
+ dl_port->vnic_reporter = reporter;
+
return 0;
rate_err:
@@ -197,6 +228,11 @@ void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, struct
return;
dl_port = vport->dl_port;
+ if (dl_port->vnic_reporter) {
+ devl_health_reporter_destroy(dl_port->vnic_reporter);
+ dl_port->vnic_reporter = NULL;
+ }
+
mlx5_esw_qos_vport_update_group(esw, vport, NULL, NULL);
devl_rate_leaf_destroy(&dl_port->dl_port);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 63c2b36ce967b..af25da01181d8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -179,6 +179,7 @@ struct mlx5_vport;
struct mlx5_devlink_port {
struct devlink_port dl_port;
struct mlx5_vport *vport;
+ struct devlink_health_reporter *vnic_reporter;
};
static inline void mlx5_devlink_port_init(struct mlx5_devlink_port *dl_port,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 770/869] Bluetooth: hci_sysfs: Fix NULL pointer dereference in device_del()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (768 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 769/869] net/mlx5e: Move representor vnic reporter to eswitch devlink port Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 771/869] vhost: invalidate vring access on IOTLB transitions Greg Kroah-Hartman
` (99 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+6df45dd3d03e1a9aca96,
Krystian Kaniewski, Luiz Augusto von Dentz, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krystian Kaniewski <krystianmkaniewski@gmail.com>
[ Upstream commit 9b851b09b392da68bd715601f10a5adb2d8d19b8 ]
A NULL pointer dereference in klist_put() occurs when a child device (such
as a BNEP network device in bnep_session) is concurrently being
unregistered while hci_conn_del_sysfs() reparents child devices.
This is caused by a race condition between hci_conn_del_sysfs() and
concurrent child device unregistration (e.g. bnep_session calling
unregister_netdev()). During device unregistration, device_del() snapshots
a non-NULL parent pointer. Concurrently, hci_conn_del_sysfs() finds the
child device using device_find_any_child() and calls device_move() to
reparent it to NULL, which removes the node from its parent's klist and
clears knode_parent. Subsequently, device_del() calls
klist_del(&dev->p->knode_parent) using the stale parent snapshot, causing
klist_put() to dereference knode_klist(n)->put on an already removed node,
resulting in a NULL pointer dereference.
This race was introduced by commit 27aabf27fd01 ("Bluetooth: fix
use-after-free in device_for_each_child()"), which replaced
device_find_child(..., __match_tty) with device_find_any_child() in
hci_conn_del_sysfs(). That change was intended to avoid a use-after-free
where conn->dev outlived its parent hdev->dev when child devices held
references to conn->dev, because conn->dev only held a reference to
hdev->dev while registered in sysfs.
Fix the issue properly by taking an explicit reference to the parent device
with get_device(&hdev->dev) in hci_conn_init_sysfs() and dropping it with
put_device(parent) in bt_link_release() when the conn device is freed. This
ensures that hdev->dev remains valid for the entire lifecycle of conn->dev,
resolving the underlying use-after-free. With the parent reference held
properly, restore the __match_tty filter in hci_conn_del_sysfs() so that
device_move() is only invoked on persistent RFCOMM TTY devices as
originally intended, eliminating the race condition with unregistering
network devices.
Fixes: 27aabf27fd01 ("Bluetooth: fix use-after-free in device_for_each_child()")
Assisted-by: Gemini:gemini-3.7-flash syzbot
Reported-by: syzbot+6df45dd3d03e1a9aca96@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=6df45dd3d03e1a9aca96
Link: https://syzkaller.appspot.com/ai_job?id=f1c0e740-db21-40af-a9ff-84db0fd8b8bd
Signed-off-by: Krystian Kaniewski <krystianmkaniewski@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/bluetooth/hci_sysfs.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 60350c6723cb7..feb4f1302b375 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -13,7 +13,10 @@ static const struct class bt_class = {
static void bt_link_release(struct device *dev)
{
struct hci_conn *conn = to_hci_conn(dev);
+ struct device *parent = dev->parent;
+
kfree(conn);
+ put_device(parent);
}
static const struct device_type bt_link = {
@@ -21,6 +24,16 @@ static const struct device_type bt_link = {
.release = bt_link_release,
};
+/*
+ * The rfcomm tty device will possibly retain even when conn
+ * is down, and sysfs doesn't support move zombie device,
+ * so we should move the device before conn device is destroyed.
+ */
+static int __match_tty(struct device *dev, void *data)
+{
+ return !strncmp(dev_name(dev), "rfcomm", 6);
+}
+
void hci_conn_init_sysfs(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
@@ -29,7 +42,7 @@ void hci_conn_init_sysfs(struct hci_conn *conn)
conn->dev.type = &bt_link;
conn->dev.class = &bt_class;
- conn->dev.parent = &hdev->dev;
+ conn->dev.parent = get_device(&hdev->dev);
device_initialize(&conn->dev);
}
@@ -69,7 +82,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
while (1) {
struct device *dev;
- dev = device_find_any_child(&conn->dev);
+ dev = device_find_child(&conn->dev, NULL, __match_tty);
if (!dev)
break;
device_move(dev, NULL, DPM_ORDER_DEV_LAST);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 771/869] vhost: invalidate vring access on IOTLB transitions
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (769 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 770/869] Bluetooth: hci_sysfs: Fix NULL pointer dereference in device_del() Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 772/869] vduse: validate virtqueue alignment Greg Kroah-Hartman
` (98 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Michael S. Tsirkin, Jia Jia,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jia Jia <physicalmtea@gmail.com>
[ Upstream commit e4f4761879a230aa59e569102a6ab9851847d833 ]
When VIRTIO_F_ACCESS_PLATFORM changes, cached vring pointers and IOTLB
metadata are interpreted in a different address space. Keeping them
across the transition can leave stale ring mappings in use.
Clearing d->iotlb before taking the VQ locks also lets a worker observe
a transient NULL d->iotlb and fall back to d->umem while translating a
descriptor.
Add a common vhost_clear_device_iotlb() helper for vhost-net and
vhost-vsock. Take all VQ mutexes in index order before dropping the
device-wide IOTLB, invalidate each VQ's cached ring access and metadata,
clear pending IOTLB messages, and free the old table after the handoff.
This serializes the transition with workers and prevents mixed address
space mappings.
On the first direct-to-IOTLB transition, invalidate the cached vring
addresses. When an existing device IOTLB is replaced, preserve the
GIOVA ring addresses and reset only the metadata cache. After clearing
ACCESS_PLATFORM, userspace must configure the vring addresses for the
new address mode.
vhost_vq_invalidate_access() clears desc, avail, and used together.
Treat the VQ as invalidated only when all three are NULL, since a single
GIOVA address may legitimately be zero.
Fixes: 6b1e6cc7855b ("vhost: new device IOTLB API")
Fixes: e13a6915a03f ("vhost/vsock: add IOTLB API support")
Suggested-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jia Jia <physicalmtea@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260828085721.57816-1-physicalmtea@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/vhost/net.c | 2 ++
drivers/vhost/vhost.c | 57 ++++++++++++++++++++++++++++++++++++++++++-
drivers/vhost/vhost.h | 1 +
drivers/vhost/vsock.c | 2 ++
4 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index c4c0139605479..e64e3a663366f 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -1637,6 +1637,8 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features)
if ((features & (1ULL << VIRTIO_F_ACCESS_PLATFORM))) {
if (vhost_init_device_iotlb(&n->dev))
goto out_unlock;
+ } else {
+ vhost_clear_device_iotlb(&n->dev);
}
for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 22119ec7fd9b7..9d5ea96f67ce2 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -344,6 +344,17 @@ static void __vhost_vq_meta_reset(struct vhost_virtqueue *vq)
vq->meta_iotlb[j] = NULL;
}
+/* Caller must hold the virtqueue mutex. */
+static void vhost_vq_invalidate_access(struct vhost_virtqueue *vq)
+{
+ vq->desc = NULL;
+ vq->avail = NULL;
+ vq->used = NULL;
+ vq->log_used = false;
+ vq->log_addr = -1ull;
+ __vhost_vq_meta_reset(vq);
+}
+
static void vhost_vq_meta_reset(struct vhost_dev *d)
{
int i;
@@ -1912,6 +1923,13 @@ int vq_meta_prefetch(struct vhost_virtqueue *vq)
{
unsigned int num = vq->num;
+ /*
+ * vhost_vq_invalidate_access() clears all three addresses together.
+ * A single zero address may be a valid GIOVA in IOTLB mode.
+ */
+ if (!vq->desc && !vq->avail && !vq->used)
+ return 0;
+
if (!vq->iotlb)
return 1;
@@ -2281,6 +2299,40 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
}
EXPORT_SYMBOL_GPL(vhost_vring_ioctl);
+/* Caller must hold the device mutex. */
+void vhost_clear_device_iotlb(struct vhost_dev *d)
+{
+ struct vhost_iotlb *iotlb;
+ int i;
+
+ iotlb = d->iotlb;
+ if (!iotlb)
+ return;
+
+ vhost_dev_lock_vqs(d);
+
+ /*
+ * vhost_dev_lock_vqs() takes all VQ mutexes in index order. Drop the
+ * device-wide view while they are held, then clear each per-VQ view
+ * and its cached ring access before releasing the locks. Workers
+ * cannot observe a mixed address-space state during this handoff.
+ */
+ d->iotlb = NULL;
+
+ for (i = 0; i < d->nvqs; ++i) {
+ struct vhost_virtqueue *vq = d->vqs[i];
+
+ vq->iotlb = NULL;
+ vhost_vq_invalidate_access(vq);
+ }
+
+ vhost_dev_unlock_vqs(d);
+ vhost_clear_msg(d);
+ vhost_iotlb_free(iotlb);
+ wake_up_interruptible_poll(&d->wait, EPOLLIN | EPOLLRDNORM);
+}
+EXPORT_SYMBOL_GPL(vhost_clear_device_iotlb);
+
int vhost_init_device_iotlb(struct vhost_dev *d)
{
struct vhost_iotlb *niotlb, *oiotlb;
@@ -2301,7 +2353,10 @@ int vhost_init_device_iotlb(struct vhost_dev *d)
mutex_lock(&vq->mutex);
vq->iotlb = niotlb;
- __vhost_vq_meta_reset(vq);
+ if (oiotlb)
+ __vhost_vq_meta_reset(vq);
+ else
+ vhost_vq_invalidate_access(vq);
mutex_unlock(&vq->mutex);
}
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index ab704d84fb344..2bab74fe08070 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -264,6 +264,7 @@ ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to,
int noblock);
ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
struct iov_iter *from);
+void vhost_clear_device_iotlb(struct vhost_dev *d);
int vhost_init_device_iotlb(struct vhost_dev *d);
void vhost_iotlb_map_free(struct vhost_iotlb *iotlb,
diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 78cc66fbb3dd6..65297f245b272 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -819,6 +819,8 @@ static int vhost_vsock_set_features(struct vhost_vsock *vsock, u64 features)
if ((features & (1ULL << VIRTIO_F_ACCESS_PLATFORM))) {
if (vhost_init_device_iotlb(&vsock->dev))
goto err;
+ } else {
+ vhost_clear_device_iotlb(&vsock->dev);
}
vsock->seqpacket_allow = features & (1ULL << VIRTIO_VSOCK_F_SEQPACKET);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 772/869] vduse: validate virtqueue alignment
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (770 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 771/869] vhost: invalidate vring access on IOTLB transitions Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 773/869] virtio_ring: fix stale descriptor flags after a failed packed add Greg Kroah-Hartman
` (97 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jia Jia, Michael S. Tsirkin,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jia Jia <physicalmtea@gmail.com>
[ Upstream commit fa2c25b4add57888acfa89e398389e267bff3dcf ]
vduse_validate_config() only checks the upper bound of vq_align. Invalid
values can therefore reach vring_create_virtqueue_map(). The split-ring
helpers use align - 1 as a bit mask, so the alignment must be a non-zero
power of two. A zero value makes vring_size() drop the descriptor and
available-ring part and vring_init() leave the used ring pointer NULL.
The VIRTIO spec requires the used ring to start at an address
aligned to at least 4 bytes. Reject values below VRING_USED_ALIGN_SIZE as
well as non-power-of-two values before they reach the virtio ring helpers.
Opening a virtio-net device created with vq_align=0 triggered:
BUG: KASAN: null-ptr-deref in virtqueue_kick_prepare_split+0xe3/0x100
Read of size 2 at addr 0000000000000000 by task systemd-network/1062
Call Trace (relevant frames):
dump_stack_lvl
print_report
kasan_report
__asan_load2
virtqueue_kick_prepare_split+0xe3/0x100
virtqueue_kick_prepare+0x40/0x60
try_fill_recv+0x857/0x1250
virtnet_open+0x189/0x460
__dev_open+0x225/0x390
__dev_change_flags+0x368/0x3b0
netif_change_flags+0x56/0xc0
do_setlink.isra.0+0x68c/0x1e30
Validate the value before it reaches the virtio ring helpers.
Fixes: c8a6153b6c59 ("vduse: Introduce VDUSE - vDPA Device in Userspace")
Signed-off-by: Jia Jia <physicalmtea@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260830023354.115333-1-physicalmtea@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/vdpa/vdpa_user/vduse_dev.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
index 4fbfc51407a31..fa391515bab2f 100644
--- a/drivers/vdpa/vdpa_user/vduse_dev.c
+++ b/drivers/vdpa/vdpa_user/vduse_dev.c
@@ -1756,7 +1756,9 @@ static bool vduse_validate_config(struct vduse_dev_config *config)
sizeof(config->reserved)))
return false;
- if (config->vq_align > PAGE_SIZE)
+ if (config->vq_align < VRING_USED_ALIGN_SIZE ||
+ !is_power_of_2(config->vq_align) ||
+ config->vq_align > PAGE_SIZE)
return false;
if (config->config_size > PAGE_SIZE)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 773/869] virtio_ring: fix stale descriptor flags after a failed packed add
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (771 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 772/869] vduse: validate virtqueue alignment Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 774/869] iommu/amd: Do not reallocate GA log buffers on resume Greg Kroah-Hartman
` (96 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Alexander Graf, Michael S. Tsirkin,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Graf <graf@amazon.com>
[ Upstream commit 75d276e5bb68778b2916f98a2bc30f142ebadc64 ]
In a packed ring the AVAIL and USED bits sit in the descriptor itself,
so writing them makes that descriptor available. Those bit combinations
flip meaning on every round of the ring, tracked by a wrap counter, so
invalidating or validating a descriptor means inverting both bits.
Commit 1ce9e6055fa0 ("virtio_ring: introduce packed ring support") has
virtqueue_add_packed() make every descriptor of a chain available as it
maps the chain, and write the head last. The device consumes the ring in
order and stops at a head that is not available yet, so it never reaches
the rest.
When vring_map_one_sg() fails partway, unmap_release unmaps the segments
and restores avail_used_flags, but the descriptors it wrote to in the
ring stay marked with AVAIL and USED bits. The head is now the only
entry that keeps the device from consuming these stale entries.
For example, the ring would look like this now.
Z - pre-previous command
A - previous command
B - aborted command
C - current command
[A1 DONE] [A2 DONE] <C1 EMPTY> [B2] [B3] [Z1 DONE]
When the driver now attempts to issue the C command, the next add starts
at the same head as B. If C spans less descriptors than B, there is no
end marker because AVAIL and USED bits were still in place. And that
means the device will start interpreting these stale entries (B2/B3) as
another command entry, which then blocks the queue.
This effect typically happens in swiotlb configurations under memory
pressure, because vring_map_one_sg() can then fail with larger I/O
requests which then leads to command abortions.
There are broadly 2 ways to avoid leaving those flags behind:
1) Defer those flags too until the chain is complete.
2) Rewrite those flags for the previous wrap counter.
Implement the second option in both packed add paths. The first option
traverses the chain a second time on every successful add. The second
option invalidates all added descriptors when any add fails.
With this patch applied, a packed virtqueue keeps completing requests
after a failed add.
Fixes: 1ce9e6055fa0 ("virtio_ring: introduce packed ring support")
Fixes: f6a15d854986 ("virtio_ring: add in order support")
Assisted-by: Kiro:claude-opus-5 checkpatch sparse
Signed-off-by: Alexander Graf <graf@amazon.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260817223229.28954-1-graf@amazon.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/virtio/virtio_ring.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index c0276979675df..2dfc815c54f68 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -1412,7 +1412,7 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
struct scatterlist *sg;
unsigned int i, n, c, descs_used, err_idx;
__le16 head_flags, flags;
- u16 head, id, prev, curr, avail_used_flags;
+ u16 head, id, prev, curr, avail_used_flags, unpub_flags;
int err;
START_USE(vq);
@@ -1535,15 +1535,30 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
curr = vq->free_head;
vq->packed.avail_used_flags = avail_used_flags;
+ unpub_flags = avail_used_flags ^ (1 << VRING_PACKED_DESC_F_AVAIL |
+ 1 << VRING_PACKED_DESC_F_USED);
for (n = 0; n < total_sg; n++) {
if (i == err_idx)
break;
+ /*
+ * The mapping loop made every descriptor but the head
+ * available. Stamp the previous wrap counter's AVAIL and USED
+ * bits on those, so that a later and shorter chain at this head
+ * does not leave one of them available beyond its own last
+ * descriptor. Marking them used instead would hand
+ * is_used_desc_packed() a completion we never made.
+ */
+ if (i != head)
+ desc[i].flags = cpu_to_le16(unpub_flags);
vring_unmap_extra_packed(vq, &vq->packed.desc_extra[curr]);
curr = vq->packed.desc_extra[curr].next;
i++;
- if (i >= vq->packed.vring.num)
+ if (i >= vq->packed.vring.num) {
i = 0;
+ unpub_flags ^= 1 << VRING_PACKED_DESC_F_AVAIL |
+ 1 << VRING_PACKED_DESC_F_USED;
+ }
}
END_USE(vq);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 774/869] iommu/amd: Do not reallocate GA log buffers on resume
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (772 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 773/869] virtio_ring: fix stale descriptor flags after a failed packed add Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 775/869] bpf: mark a NULL call argument precise Greg Kroah-Hartman
` (95 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Karl Mehltretter, Vasant Hegde,
Ankit Soni, Joerg Roedel, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <kmehltretter@gmail.com>
[ Upstream commit 00a7dd64888d6dd72110b40e2824a088cf7b7386 ]
Commit c5e1a1eb9279 ("iommu/amd: Simplify and Consolidate Virtual APIC
(AVIC) Enablement") moved the GA log allocation from iommu_init_pci()
to enable_iommus_vapic(), which is called on every resume.
iommu_init_ga_log() assigns iommu->ga_log and iommu->ga_log_tail
unconditionally. Each resume therefore replaces the boot-time pointers
and leaks both old allocations. The function also uses GFP_KERNEL from a
syscore resume callback, where interrupts are disabled and the non-boot
CPUs are offline.
Return early if both buffers are already allocated. Clear the pointers
in free_ga_log() so a partial allocation failure cannot leave ga_log
dangling.
Fixes: c5e1a1eb9279 ("iommu/amd: Simplify and Consolidate Virtual APIC (AVIC) Enablement")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
Reviewed-by: Ankit Soni <Ankit.Soni@amd.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/iommu/amd/init.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 57d0e37f6c2bd..54aa09e1174d3 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -912,7 +912,9 @@ static void free_ga_log(struct amd_iommu *iommu)
{
#ifdef CONFIG_IRQ_REMAP
iommu_free_pages(iommu->ga_log, get_order(GA_LOG_SIZE));
+ iommu->ga_log = NULL;
iommu_free_pages(iommu->ga_log_tail, get_order(8));
+ iommu->ga_log_tail = NULL;
#endif
}
@@ -957,6 +959,9 @@ static int iommu_init_ga_log(struct amd_iommu *iommu)
if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir))
return 0;
+ if (iommu->ga_log && iommu->ga_log_tail)
+ return 0;
+
iommu->ga_log = iommu_alloc_pages(GFP_KERNEL, get_order(GA_LOG_SIZE));
if (!iommu->ga_log)
goto err_out;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 775/869] bpf: mark a NULL call argument precise
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (773 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 774/869] iommu/amd: Do not reallocate GA log buffers on resume Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 776/869] tracing: Fix subbuf resize races with trace_pipe_raw readers Greg Kroah-Hartman
` (94 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eduard Zingerman, Alexei Starovoitov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <eddyz87@gmail.com>
[ Upstream commit 1a3a10b030c96ea88868ccc060a16827c01eaa5a ]
check_func_arg() allows bpf_register_is_null() for nullable arguments
w/o marking the underlying scalar register precise. Hence a checkpoint
created on such a path would prune against arbitrary scalar value.
check_helper_call() enforces second parameter of the
bpf_get_local_storage() to be zero, w/o marking the underlying scalar
register precise. Hence a checkpoint created on such a path would
prune against arbitrary scalar value.
Grouping these two into one patch, as they share the same fixes tag.
Fixes: b5dc0163d8fd ("bpf: precise scalar_value tracking")
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260904-register-is-null-precise-fixes-v1-1-0f5a360ff15d@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 9 ++++++++-
.../selftests/bpf/progs/verifier_subprog_precision.c | 12 ++++++------
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 9f5eed4a7290a..67a250c439035 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -9172,11 +9172,15 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
return err;
}
- if (register_is_null(reg) && type_may_be_null(arg_type))
+ if (register_is_null(reg) && type_may_be_null(arg_type)) {
/* A NULL register has a SCALAR_VALUE type, so skip
* type checking.
*/
+ err = mark_chain_precision(env, regno);
+ if (err)
+ return err;
goto skip_type_check;
+ }
/* arg_btf_id and arg_size are in a union. */
if (base_type(arg_type) == ARG_PTR_TO_BTF_ID ||
@@ -10961,6 +10965,9 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
verbose(env, "get_local_storage() doesn't support non-zero flags\n");
return -EINVAL;
}
+ err = mark_chain_precision(env, BPF_REG_2);
+ if (err)
+ return err;
break;
case BPF_FUNC_for_each_map_elem:
err = push_callback_call(env, insn, insn_idx, meta.subprogno,
diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
index 9d415f7ce599b..8fcbb2ef5a533 100644
--- a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
+++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
@@ -287,9 +287,9 @@ __msg("17: (b7) r0 = 0")
__msg("18: (95) exit")
__msg("returning from callee:")
__msg("to caller at 9:")
-__msg("frame 0: propagating r1,r4")
+__msg("frame 0: propagating r1,r3,r4")
__msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1")
-__msg("mark_precise: frame0: regs=r1,r4 stack= before 18: (95) exit")
+__msg("mark_precise: frame0: regs=r1,r3,r4 stack= before 18: (95) exit")
__msg("from 18 to 9: safe")
__naked int callback_result_precise(void)
{
@@ -419,9 +419,9 @@ __msg("to caller at 9:")
/* r1, r4 are always precise for bpf_loop(),
* r6 was marked before backtracking to callback body.
*/
-__msg("frame 0: propagating r1,r4,r6")
+__msg("frame 0: propagating r1,r3,r4,r6")
__msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1")
-__msg("mark_precise: frame0: regs=r1,r4,r6 stack= before 16: (95) exit")
+__msg("mark_precise: frame0: regs=r1,r3,r4,r6 stack= before 16: (95) exit")
__msg("mark_precise: frame1: regs= stack= before 15: (b7) r0 = 0")
__msg("mark_precise: frame1: regs= stack= before 9: (85) call bpf_loop")
__msg("mark_precise: frame0: parent state regs= stack=:")
@@ -575,9 +575,9 @@ __msg("to caller at 10:")
/* r1, r4 are always precise for bpf_loop(),
* fp-8 was marked before backtracking to callback body.
*/
-__msg("frame 0: propagating r1,r4,fp-8")
+__msg("frame 0: propagating r1,r3,r4,fp-8")
__msg("mark_precise: frame0: last_idx 10 first_idx 10 subseq_idx -1")
-__msg("mark_precise: frame0: regs=r1,r4 stack=-8 before 18: (95) exit")
+__msg("mark_precise: frame0: regs=r1,r3,r4 stack=-8 before 18: (95) exit")
__msg("mark_precise: frame1: regs= stack= before 17: (b7) r0 = 0")
__msg("mark_precise: frame1: regs= stack= before 10: (85) call bpf_loop#181")
__msg("mark_precise: frame0: parent state regs= stack=:")
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 776/869] tracing: Fix subbuf resize races with trace_pipe_raw readers
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (774 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 775/869] bpf: mark a NULL call argument precise Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 777/869] bpf: Preserve inner map identity in callback frames Greg Kroah-Hartman
` (93 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vincent Donnefort, Steven Rostedt,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vincent Donnefort <vdonnefort@google.com>
[ Upstream commit dae8dda341d2d9034a90d59e8a7d502e1263813f ]
Concurrent subbuffer resizes may crash trace_pipe_raw readers or leak
uninitialized memory to userspace due to stale size values.
Modify ring_buffer_alloc_read_page() to handle the resizing of an
existing buffer_data_read_page if necessary and add a new
ring_buffer_read_page_size(). This new function enables ring-buffer
buffer_data_read_page users to not call the racy
ring_buffer_subbuf_size_get(). This makes the spare_size member of
ftrace_buffer_info redundant.
Finally, handle buffer_data_read_page/reader_page order discrepancy in
ring_buffer_read_page(). On a mismatch simply copy manually the data to
the buffer_data_read_page.
Link: https://lore.kernel.org/all/20260817140812.2C7D41F00A3A@smtp.kernel.org/
Link: https://patch.msgid.link/20260904164450.1345852-3-vdonnefort@google.com
Fixes: bce761d75745 ("ring-buffer: Read and write to ring buffers with custom sub buffer size")
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/ring_buffer.h | 5 +-
kernel/trace/ring_buffer.c | 135 ++++++++++++++++++---------
kernel/trace/ring_buffer_benchmark.c | 6 +-
kernel/trace/trace.c | 106 +++++++++------------
4 files changed, 144 insertions(+), 108 deletions(-)
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 03934249b91e6..f39289bce1a08 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -214,14 +214,15 @@ bool ring_buffer_time_stamp_abs(struct trace_buffer *buffer);
size_t ring_buffer_nr_dirty_pages(struct trace_buffer *buffer, int cpu);
struct buffer_data_read_page;
-struct buffer_data_read_page *
-ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu);
+int ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu,
+ struct buffer_data_read_page **rpage);
void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu,
struct buffer_data_read_page *page);
int ring_buffer_read_page(struct trace_buffer *buffer,
struct buffer_data_read_page *data_page,
size_t len, int cpu, int full);
void *ring_buffer_read_page_data(struct buffer_data_read_page *page);
+unsigned int ring_buffer_read_page_size(struct buffer_data_read_page *rpage);
struct trace_seq;
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index ca6a4d0f3ef37..c89f4f8a33b0e 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -347,6 +347,11 @@ struct buffer_data_read_page {
struct buffer_data_page *data; /* actual data, stored in this page */
};
+static __always_inline unsigned int rb_read_page_capacity(struct buffer_data_read_page *rpage)
+{
+ return (PAGE_SIZE << rpage->order) - BUF_PAGE_HDR_SIZE;
+}
+
/*
* Note, the buffer_page list must be first. The buffer pages
* are allocated in cache lines, which means that each buffer
@@ -6391,56 +6396,78 @@ EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu);
* ring_buffer_alloc_read_page - allocate a page to read from buffer
* @buffer: the buffer to allocate for.
* @cpu: the cpu buffer to allocate.
+ * @rpage: pointer to pass in an already allocated page (can be NULL)
+ * and returns the allocated page.
*
- * This function is used in conjunction with ring_buffer_read_page.
+ * This function is used in conjunction with ring_buffer_read_page().
* When reading a full page from the ring buffer, these functions
* can be used to speed up the process. The calling function should
* allocate a few pages first with this function. Then when it
* needs to get pages from the ring buffer, it passes the result
- * of this function into ring_buffer_read_page, which will swap
+ * of this function into ring_buffer_read_page(), which will swap
* the page that was allocated, with the read page of the buffer.
*
+ * If @rpage is provided, and it has a different order than the current
+ * subbuffer order, its payload will be freed and re-allocated. If it
+ * already matches the order, it is simply returned.
+ *
* Returns:
- * The page allocated, or ERR_PTR
+ * 0 on success, < 0 on error
*/
-struct buffer_data_read_page *
-ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu)
+int ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu,
+ struct buffer_data_read_page **rpage)
{
struct ring_buffer_per_cpu *cpu_buffer;
- struct buffer_data_read_page *bpage = NULL;
unsigned long flags;
+ unsigned int order;
if (!cpumask_test_cpu(cpu, buffer->cpumask))
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
- bpage = kzalloc(sizeof(*bpage), GFP_KERNEL);
- if (!bpage)
- return ERR_PTR(-ENOMEM);
+ if (!rpage)
+ return -EINVAL;
+
+ order = READ_ONCE(buffer->subbuf_order);
- bpage->order = buffer->subbuf_order;
+ if (*rpage) {
+ if ((*rpage)->order == order)
+ return 0;
+
+ /* We can reuse rpage, but we discard the payload */
+ free_pages((unsigned long)(*rpage)->data, (*rpage)->order);
+ (*rpage)->data = NULL;
+ } else {
+ *rpage = kzalloc_obj(**rpage);
+ if (!*rpage)
+ return -ENOMEM;
+ }
+
+ (*rpage)->order = order;
cpu_buffer = buffer->buffers[cpu];
+
local_irq_save(flags);
arch_spin_lock(&cpu_buffer->lock);
if (cpu_buffer->free_page.data) {
- *bpage = cpu_buffer->free_page;
+ **rpage = cpu_buffer->free_page;
cpu_buffer->free_page.data = NULL;
}
arch_spin_unlock(&cpu_buffer->lock);
local_irq_restore(flags);
- if (bpage->data) {
- rb_init_data_page(bpage->data);
+ if ((*rpage)->data) {
+ rb_init_data_page((*rpage)->data);
} else {
- bpage->data = alloc_cpu_data(cpu, bpage->order);
- if (!bpage->data) {
- kfree(bpage);
- return ERR_PTR(-ENOMEM);
+ (*rpage)->data = alloc_cpu_data(cpu, (*rpage)->order);
+ if (!(*rpage)->data) {
+ kfree(*rpage);
+ *rpage = NULL;
+ return -ENOMEM;
}
}
- return bpage;
+ return 0;
}
EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page);
@@ -6448,21 +6475,30 @@ EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page);
* ring_buffer_free_read_page - free an allocated read page
* @buffer: the buffer the page was allocate for
* @cpu: the cpu buffer the page came from
- * @data_page: the page to free
+ * @rpage: the buffer_data_read_page to free
*
* Free a page allocated from ring_buffer_alloc_read_page.
*/
void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu,
- struct buffer_data_read_page *data_page)
+ struct buffer_data_read_page *rpage)
{
struct ring_buffer_per_cpu *cpu_buffer;
- struct buffer_data_page *bpage = data_page->data;
- struct page *page = virt_to_page(bpage);
+ struct buffer_data_page *bpage;
unsigned long flags;
+ struct page *page;
if (!buffer || !buffer->buffers || !buffer->buffers[cpu])
return;
+ if (!rpage)
+ return;
+
+ bpage = rpage->data;
+ if (!bpage)
+ goto out;
+
+ page = virt_to_page(bpage);
+
cpu_buffer = buffer->buffers[cpu];
/*
@@ -6470,14 +6506,14 @@ void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu,
* is different from the subbuffer order of the buffer -
* we can't reuse it
*/
- if (page_ref_count(page) > 1 || data_page->order != buffer->subbuf_order)
+ if (page_ref_count(page) > 1 || rpage->order != READ_ONCE(buffer->subbuf_order))
goto out;
local_irq_save(flags);
arch_spin_lock(&cpu_buffer->lock);
if (!cpu_buffer->free_page.data) {
- cpu_buffer->free_page = *data_page;
+ cpu_buffer->free_page = *rpage;
bpage = NULL;
}
@@ -6485,8 +6521,8 @@ void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu,
local_irq_restore(flags);
out:
- free_pages((unsigned long)bpage, data_page->order);
- kfree(data_page);
+ free_pages((unsigned long)bpage, rpage->order);
+ kfree(rpage);
}
EXPORT_SYMBOL_GPL(ring_buffer_free_read_page);
@@ -6557,10 +6593,9 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
if (!bpage)
return -1;
- guard(raw_spinlock_irqsave)(&cpu_buffer->reader_lock);
+ len = min_t(size_t, len, rb_read_page_capacity(data_page));
- if (data_page->order != cpu_buffer->reader_page->order)
- return -1;
+ guard(raw_spinlock_irqsave)(&cpu_buffer->reader_lock);
reader = rb_get_reader_page(cpu_buffer);
if (!reader)
@@ -6575,16 +6610,18 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
/* Check if any events were dropped */
missed_events = cpu_buffer->lost_events;
- /*
- * If this page has been partially read or
- * if len is not big enough to read the rest of the page or
- * a writer is still on the page, then
- * we must copy the data from the page to the buffer.
- * Otherwise, we can simply swap the page with the one passed in.
- */
+ /*
+ * It is not possible to swap the reader page if:
+ * - It has been partially read
+ * - len is not big enough to read it entirely
+ * - A writer is still on it
+ * - The ring buffer is static
+ * - The order doesn't match
+ */
if (read || (len < (size - read)) ||
cpu_buffer->reader_page == cpu_buffer->commit_page ||
- cpu_buffer->mapped) {
+ cpu_buffer->mapped ||
+ data_page->order != reader->order) {
struct buffer_data_page *rpage = cpu_buffer->reader_page->page;
unsigned int rpos = read;
unsigned int pos = 0;
@@ -6676,7 +6713,7 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
/* If there is room at the end of the page to save the
* missed events, then record it there.
*/
- if (rb_page_capacity(reader) - size >= sizeof(missed_events)) {
+ if (rb_read_page_capacity(data_page) - size >= sizeof(missed_events)) {
memcpy(&bpage->data[size], &missed_events,
sizeof(missed_events));
commit |= RB_MISSED_STORED;
@@ -6688,8 +6725,8 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
/*
* This page may be off to user land. Zero it out here.
*/
- if (size < rb_page_capacity(reader))
- memset(&bpage->data[size], 0, rb_page_capacity(reader) - size);
+ if (size < rb_read_page_capacity(data_page))
+ memset(&bpage->data[size], 0, rb_read_page_capacity(data_page) - size);
return read;
}
@@ -6707,6 +6744,18 @@ void *ring_buffer_read_page_data(struct buffer_data_read_page *page)
}
EXPORT_SYMBOL_GPL(ring_buffer_read_page_data);
+/**
+ * ring_buffer_read_page_size - get size of the read page.
+ * @page: the page to get the size from
+ *
+ * Returns size of the page in bytes.
+ */
+unsigned int ring_buffer_read_page_size(struct buffer_data_read_page *rpage)
+{
+ return rpage ? PAGE_SIZE << rpage->order : 0;
+}
+EXPORT_SYMBOL_GPL(ring_buffer_read_page_size);
+
/**
* ring_buffer_subbuf_size_get - get size of the sub buffer.
* @buffer: the buffer to get the sub buffer size from
@@ -6800,7 +6849,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
/* Make sure all commits have finished */
synchronize_rcu();
- buffer->subbuf_order = order;
+ WRITE_ONCE(buffer->subbuf_order, order);
/* Make sure all new buffers are allocated, before deleting the old ones */
for_each_buffer_cpu(buffer, cpu) {
@@ -6904,7 +6953,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
return 0;
error:
- buffer->subbuf_order = old_order;
+ WRITE_ONCE(buffer->subbuf_order, old_order);
atomic_dec(&buffer->record_disabled);
diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c
index 008187ebd7fe6..56f4082e14c84 100644
--- a/kernel/trace/ring_buffer_benchmark.c
+++ b/kernel/trace/ring_buffer_benchmark.c
@@ -104,7 +104,7 @@ static enum event_status read_event(int cpu)
static enum event_status read_page(int cpu)
{
- struct buffer_data_read_page *bpage;
+ struct buffer_data_read_page *bpage = NULL;
struct ring_buffer_event *event;
struct rb_page *rpage;
unsigned long commit;
@@ -114,8 +114,8 @@ static enum event_status read_page(int cpu)
int inc;
int i;
- bpage = ring_buffer_alloc_read_page(buffer, cpu);
- if (IS_ERR(bpage))
+ ret = ring_buffer_alloc_read_page(buffer, cpu, &bpage);
+ if (ret < 0)
return EVENT_DROPPED;
page_size = ring_buffer_subbuf_size_get(buffer);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index ed1014292c089..8af0fe8233433 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -7177,11 +7177,10 @@ int tracing_set_filter_buffering(struct trace_array *tr, bool set)
}
struct ftrace_buffer_info {
- struct trace_iterator iter;
- void *spare;
- unsigned int spare_cpu;
- unsigned int spare_size;
- unsigned int read;
+ struct trace_iterator iter;
+ struct buffer_data_read_page *spare;
+ unsigned int spare_cpu;
+ unsigned int read;
};
#ifdef CONFIG_TRACER_SNAPSHOT
@@ -7890,8 +7889,8 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
{
struct ftrace_buffer_info *info = filp->private_data;
struct trace_iterator *iter = &info->iter;
+ unsigned int spare_size;
void *trace_data;
- int page_size;
ssize_t ret = 0;
ssize_t size;
@@ -7903,36 +7902,22 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
return -EBUSY;
#endif
- page_size = ring_buffer_subbuf_size_get(iter->array_buffer->buffer);
+ spare_size = ring_buffer_read_page_size(info->spare);
- /* Make sure the spare matches the current sub buffer size */
- if (info->spare) {
- if (page_size != info->spare_size) {
- ring_buffer_free_read_page(iter->array_buffer->buffer,
- info->spare_cpu, info->spare);
- info->spare = NULL;
- }
- }
+again:
+ /* Do we have previous read data to read? */
+ if (info->read < spare_size)
+ goto read;
- if (!info->spare) {
- info->spare = ring_buffer_alloc_read_page(iter->array_buffer->buffer,
- iter->cpu_file);
- if (IS_ERR(info->spare)) {
- ret = PTR_ERR(info->spare);
- info->spare = NULL;
- } else {
- info->spare_cpu = iter->cpu_file;
- info->spare_size = page_size;
- }
- }
- if (!info->spare)
+ ret = ring_buffer_alloc_read_page(iter->array_buffer->buffer, iter->cpu_file,
+ &info->spare);
+ if (ret)
return ret;
- /* Do we have previous read data to read? */
- if (info->read < page_size)
- goto read;
+ spare_size = ring_buffer_read_page_size(info->spare);
+ info->read = spare_size;
+ info->spare_cpu = iter->cpu_file;
- again:
trace_access_lock(iter->cpu_file);
ret = ring_buffer_read_page(iter->array_buffer->buffer,
info->spare,
@@ -7955,8 +7940,9 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
}
info->read = 0;
+
read:
- size = page_size - info->read;
+ size = spare_size - info->read;
if (size > count)
size = count;
trace_data = ring_buffer_read_page_data(info->spare);
@@ -7997,9 +7983,7 @@ static int tracing_buffers_release(struct inode *inode, struct file *file)
__trace_array_put(iter->tr);
- if (info->spare)
- ring_buffer_free_read_page(iter->array_buffer->buffer,
- info->spare_cpu, info->spare);
+ ring_buffer_free_read_page(iter->array_buffer->buffer, info->spare_cpu, info->spare);
kvfree(info);
mutex_unlock(&trace_types_lock);
@@ -8008,17 +7992,17 @@ static int tracing_buffers_release(struct inode *inode, struct file *file)
}
struct buffer_ref {
- struct trace_buffer *buffer;
- void *page;
- int cpu;
- refcount_t refcount;
+ struct trace_buffer *buffer;
+ struct buffer_data_read_page *rpage;
+ int cpu;
+ refcount_t refcount;
};
static void buffer_ref_release(struct buffer_ref *ref)
{
if (!refcount_dec_and_test(&ref->refcount))
return;
- ring_buffer_free_read_page(ref->buffer, ref->cpu, ref->page);
+ ring_buffer_free_read_page(ref->buffer, ref->cpu, ref->rpage);
kfree(ref);
}
@@ -8078,9 +8062,9 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
.ops = &buffer_pipe_buf_ops,
.spd_release = buffer_spd_release,
};
+ unsigned int page_size = 0;
struct buffer_ref *ref;
bool woken = false;
- int page_size;
int entries, i;
ssize_t ret = 0;
@@ -8089,16 +8073,6 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
return -EBUSY;
#endif
- page_size = ring_buffer_subbuf_size_get(iter->array_buffer->buffer);
- if (*ppos & (page_size - 1))
- return -EINVAL;
-
- if (len & (page_size - 1)) {
- if (len < page_size)
- return -EINVAL;
- len &= (~(page_size - 1));
- }
-
if (splice_grow_spd(pipe, &spd))
return -ENOMEM;
@@ -8118,25 +8092,37 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
refcount_set(&ref->refcount, 1);
ref->buffer = iter->array_buffer->buffer;
- ref->page = ring_buffer_alloc_read_page(ref->buffer, iter->cpu_file);
- if (IS_ERR(ref->page)) {
- ret = PTR_ERR(ref->page);
- ref->page = NULL;
+
+ ret = ring_buffer_alloc_read_page(ref->buffer, iter->cpu_file, &ref->rpage);
+ if (ret) {
kfree(ref);
break;
}
ref->cpu = iter->cpu_file;
- r = ring_buffer_read_page(ref->buffer, ref->page,
- len, iter->cpu_file, 1);
+ page_size = ring_buffer_read_page_size(ref->rpage);
+
+ r = -EINVAL;
+ if (IS_ALIGNED(*ppos, page_size) && len >= page_size) {
+ r = ring_buffer_read_page(ref->buffer, ref->rpage, len, iter->cpu_file, 1);
+ } else if (!i) {
+ /*
+ * We failed to read because the length is too small
+ * or unaligned. If this is the first iteration, it's
+ * an invalid userspace input. Otherwise, this is due
+ * to a subbuf order change. Do not report an error
+ * and just finish the read.
+ */
+ ret = -EINVAL;
+ }
+
if (r < 0) {
- ring_buffer_free_read_page(ref->buffer, ref->cpu,
- ref->page);
+ ring_buffer_free_read_page(ref->buffer, ref->cpu, ref->rpage);
kfree(ref);
break;
}
- page = virt_to_page(ring_buffer_read_page_data(ref->page));
+ page = virt_to_page(ring_buffer_read_page_data(ref->rpage));
spd.pages[i] = page;
spd.partial[i].len = page_size;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 777/869] bpf: Preserve inner map identity in callback frames
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (775 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 776/869] tracing: Fix subbuf resize races with trace_pipe_raw readers Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 778/869] bpf: Mark NULL kptr stores precise Greg Kroah-Hartman
` (92 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini,
Kumar Kartikeya Dwivedi, Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
[ Upstream commit b90c5d770dad910fb89e6c1b15052a8a1e8db752 ]
Callback frame constructors initialize map-typed argument registers with
__mark_reg_known_zero() and then restore map_ptr. This clears map_uid,
which is the only field distinguishing inner maps that share an
inner_map_meta template.
When a timer callback invokes bpf_for_each_map_elem() on a second inner
map, both the saved first map and the second map value can reach the nested
callback as the same template with map_uid zero. bpf_timer_init() then
accepts pairing the timer from the second map with the first map.
The runtime records the first map in the timer without taking a reference.
Freeing that map does not find the timer stored in the second map, so a
later timer callback dereferences the freed map.
Copy map_uid from the same caller register as map_ptr when constructing
for-each, timer/workqueue, and task-work callback arguments. The existing
identity check can then reject mismatched inner maps while allowing a
callback value to be paired with its actual map.
Fixes: 3e8ce29850f1 ("bpf: Prevent pointer mismatch in bpf_timer_init.")
Fixes: 69c087ba6225 ("bpf: Add bpf_for_each_map_elem() helper")
Fixes: 5c8fd7e2b5b0 ("bpf: bpf task work plumbing")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260904104203.345917-8-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 67a250c439035..75f8d73e6eb7d 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -10203,10 +10203,12 @@ int map_set_for_each_callback_args(struct bpf_verifier_env *env,
callee->regs[BPF_REG_2].type = PTR_TO_MAP_KEY;
__mark_reg_known_zero(&callee->regs[BPF_REG_2]);
callee->regs[BPF_REG_2].map_ptr = caller->regs[BPF_REG_1].map_ptr;
+ callee->regs[BPF_REG_2].map_uid = caller->regs[BPF_REG_1].map_uid;
callee->regs[BPF_REG_3].type = PTR_TO_MAP_VALUE;
__mark_reg_known_zero(&callee->regs[BPF_REG_3]);
callee->regs[BPF_REG_3].map_ptr = caller->regs[BPF_REG_1].map_ptr;
+ callee->regs[BPF_REG_3].map_uid = caller->regs[BPF_REG_1].map_uid;
/* pointer to stack or null */
callee->regs[BPF_REG_4] = caller->regs[BPF_REG_3];
@@ -10284,6 +10286,7 @@ static int set_timer_callback_state(struct bpf_verifier_env *env,
int insn_idx)
{
struct bpf_map *map_ptr = caller->regs[BPF_REG_1].map_ptr;
+ u32 map_uid = caller->regs[BPF_REG_1].map_uid;
/* bpf_timer_set_callback(struct bpf_timer *timer, void *callback_fn);
* callback_fn(struct bpf_map *map, void *key, void *value);
@@ -10291,14 +10294,17 @@ static int set_timer_callback_state(struct bpf_verifier_env *env,
callee->regs[BPF_REG_1].type = CONST_PTR_TO_MAP;
__mark_reg_known_zero(&callee->regs[BPF_REG_1]);
callee->regs[BPF_REG_1].map_ptr = map_ptr;
+ callee->regs[BPF_REG_1].map_uid = map_uid;
callee->regs[BPF_REG_2].type = PTR_TO_MAP_KEY;
__mark_reg_known_zero(&callee->regs[BPF_REG_2]);
callee->regs[BPF_REG_2].map_ptr = map_ptr;
+ callee->regs[BPF_REG_2].map_uid = map_uid;
callee->regs[BPF_REG_3].type = PTR_TO_MAP_VALUE;
__mark_reg_known_zero(&callee->regs[BPF_REG_3]);
callee->regs[BPF_REG_3].map_ptr = map_ptr;
+ callee->regs[BPF_REG_3].map_uid = map_uid;
/* unused */
__mark_reg_not_init(env, &callee->regs[BPF_REG_4]);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 778/869] bpf: Mark NULL kptr stores precise
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (776 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 777/869] bpf: Preserve inner map identity in callback frames Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 779/869] bpf: Keep refcount_acquire nullable for borrowed RCU kptrs Greg Kroah-Hartman
` (91 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini,
Kumar Kartikeya Dwivedi, Eduard Zingerman, Alexei Starovoitov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
[ Upstream commit ecdc5043794c9184aa8e6c814603899479c46b35 ]
check_map_kptr_access() permits a scalar store into an untrusted kptr
field only when the register is known to contain zero. Unlike other
verifier checks whose outcome depends on a scalar value, it does not mark
that register precise.
A state checkpoint reached with an imprecise zero can therefore prune a
second path that reaches the store with an arbitrary nonzero scalar. The
program can write attacker-controlled bits into the kptr field and load
them back as a PTR_TO_BTF_ID.
Call mark_chain_precision() before accepting a known-zero register. This
forces state equivalence to compare its scalar range and makes the verifier
visit and reject a path carrying a nonzero value.
Fixes: 61df10c7799e ("bpf: Allow storing unreferenced kptr in map")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260904104203.345917-6-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 75f8d73e6eb7d..ebce193173ce7 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5704,8 +5704,15 @@ static int check_map_kptr_access(struct bpf_verifier_env *env, u32 regno,
kptr_field->kptr.btf_id, btf_ld_kptr_type(env, kptr_field));
} else if (class == BPF_STX) {
val_reg = reg_state(env, value_regno);
- if (!register_is_null(val_reg) &&
- map_kptr_match_type(env, kptr_field, val_reg, value_regno))
+ if (register_is_null(val_reg)) {
+ /*
+ * This store is valid only because the scalar is known to be
+ * zero. Mark it precise so another scalar cannot be pruned
+ * against this state.
+ */
+ return mark_chain_precision(env, value_regno);
+ }
+ if (map_kptr_match_type(env, kptr_field, val_reg, value_regno))
return -EACCES;
} else if (class == BPF_ST) {
if (insn->imm) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 779/869] bpf: Keep refcount_acquire nullable for borrowed RCU kptrs
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (777 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 778/869] bpf: Mark NULL kptr stores precise Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 780/869] bpf: Dont infer non-NULL from a pointer with an unbounded offset Greg Kroah-Hartman
` (90 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini, Ning Ding,
Kumar Kartikeya Dwivedi, Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ning Ding <dingning04@gmail.com>
[ Upstream commit dc36739e5cc9f60485418a910b42bc95339218d2 ]
bpf_refcount_acquire() is fallible for a borrowed reference because the
object may have reached a zero refcount. The verifier therefore keeps
KF_RET_NULL on the return value unless the argument is an owning reference.
An RCU-protected load of a local kptr is marked MEM_ALLOC, but it only
receives NON_OWN_REF when the pointee contains a graph node. A refcounted
object without a graph node consequently looks like an owning reference
even though the loaded register has no acquired reference state. If the
program drops the last real reference while remaining in the RCU critical
section, refcount_inc_not_zero() returns NULL while the verifier treats the
result as non-NULL.
Only classify the argument as owning when it is backed by a verifier-tracked
reference. This retains the non-NULL return for pointers from bpf_obj_new(),
bpf_kptr_xchg(), or an earlier successful acquisition, while requiring a
NULL check for borrowed RCU kptrs.
Fixes: 1b12171533a9 ("bpf: Mark direct ld of stashed bpf_{rb,list}_node as non-owning ref")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Ning Ding <dingning04@gmail.com>
[ kkd: Rewrote commit log ]
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260904084325.52250-4-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index ebce193173ce7..c1957d03f9d23 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -12732,7 +12732,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
verbose(env, "arg#%d is neither owning or non-owning ref\n", i);
return -EINVAL;
}
- if (!type_is_non_owning_ref(reg->type))
+ if (!type_is_non_owning_ref(reg->type) && reg->ref_obj_id)
meta->arg_owning_ref = true;
rec = reg_btf_record(reg);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 780/869] bpf: Dont infer non-NULL from a pointer with an unbounded offset
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (778 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 779/869] bpf: Keep refcount_acquire nullable for borrowed RCU kptrs Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 781/869] bpf: Reject legacy packet loads from callbacks Greg Kroah-Hartman
` (89 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini, Eduard Zingerman,
Kumar Kartikeya Dwivedi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <eddyz87@gmail.com>
[ Upstream commit 67b529f521a6676cdfc78b91b0217d7eaa84216b ]
reg_not_null() decides that a register holds a non-NULL value by
looking at its type alone. For pointer types that allow arithmetic the
type only guarantees a non-NULL base, in case of an unbound offset
the runtime offset value might still add up to NULL.
Consider the followng program:
r6 = bpf_map_lookup_elem(map, &0); /* present */
if (r6 == 0) return 0;
r7 = bpf_map_lookup_elem(map, &1); /* absent, NULL at runtime */
r8 = r7;
r8 -= r6; /* pointer - pointer: unknown scalar, -r6 */
r8 <<= 1;
r8 >>= 1; /* any non-negative offset is accepted by */
/* check_reg_sane_offset_ptr() */
r6 += r8; /* verifier: map value; runtime: zero */
if (r7 != r6) return 0;
*(u8 *)(r7 + 0); /* r7 is inferred non-NULL, both are zero */
At runtime both registers are zero, the comparison is true and the
load faults with NULL pointer dereference.
Require the offset to be within +-BPF_MAX_VAR_OFF in reg_not_null().
Fixes: cac616db39c2 ("bpf: Verifier track null pointer branch_taken with JNE and JEQ")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/bpf/20260904083325.2083493-1-eddyz87@gmail.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index c1957d03f9d23..61df484f39ff2 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -395,6 +395,13 @@ static bool reg_not_null(const struct bpf_reg_state *reg)
if (type_may_be_null(type))
return false;
+ /*
+ * The types below guarantee a non-NULL base, an unbounded offset can
+ * still wrap base + offset to zero.
+ */
+ if (reg->smin_value <= -BPF_MAX_VAR_OFF || reg->smax_value >= BPF_MAX_VAR_OFF)
+ return false;
+
type = base_type(type);
return type == PTR_TO_SOCKET ||
type == PTR_TO_TCP_SOCK ||
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 781/869] bpf: Reject legacy packet loads from callbacks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (779 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 780/869] bpf: Dont infer non-NULL from a pointer with an unbounded offset Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 782/869] bpf: Check ancestor frames for rbtree callbacks Greg Kroah-Hartman
` (88 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko, Kumar Kartikeya Dwivedi,
Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
[ Upstream commit e7d28823c662128caae63f14e16bd394916c139b ]
check_ld_abs() models a failed BPF_LD_ABS or BPF_LD_IND in a
subprogram as an implicit return with R0 set to zero. It calls
prepare_func_exit() to explore this synthesized path.
When the load is reached directly from a synchronous callback,
prepare_func_exit() enforces the callback return contract and marks R0
precise. R0 is not derived from a real instruction on this path, so
precision backtracking reaches the callback call with R0 still requested
and triggers the "callback unexpected regs" verifier bug. A privileged
program loader can therefore cause a verifier warning and an -EFAULT
BPF_PROG_LOAD.
These legacy packet-load instructions are deprecated. Reject them from
callbacks rather than complicating their implicit-return model. Check all
active frames before constructing the implicit return so nested static
subprograms cannot hide the callback context.
Global functions are verified independently with a fresh frame zero, so
an active-frame check cannot identify a global function called from a
callback. Also check the complete subprogram call graph during stack-depth
validation and reject a function containing a legacy load when any caller
is a callback. This covers global and static descendants without making
has_ld_abs transitive, preserving its per-function BTF return-type check.
Ordinary uses outside callbacks remain supported.
Fixes: ee861486e377 ("bpf: Fix ld_{abs,ind} failure path analysis in subprogs")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://lore.kernel.org/bpf/20260903152147.C0E241F00A3A@smtp.kernel.org
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260903214758.2727663-8-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 61df484f39ff2..424cf2b196f27 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -6257,6 +6257,17 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,
if (!priv_stack_supported)
subprog[idx].priv_stack_mode = NO_PRIV_STACK;
process_func:
+ if (subprog[idx].has_ld_abs) {
+ bool in_cb = subprog[idx].is_cb;
+
+ for (j = 0; j < frame && !in_cb; j++)
+ in_cb = subprog[ret_prog[j]].is_cb;
+ if (in_cb) {
+ verbose(env, "cannot use BPF_LD_[ABS|IND] within callback\n");
+ return -EINVAL;
+ }
+ }
+
/* protect against potential stack overflow that might happen when
* bpf2bpf calls get combined with tailcalls. Limit the caller's stack
* depth for such case down to 256 so that the worst case scenario
@@ -16202,6 +16213,7 @@ static bool may_access_skb(enum bpf_prog_type type)
*/
static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
{
+ struct bpf_verifier_state *state = env->cur_state;
struct bpf_reg_state *regs = cur_regs(env);
static const int ctx_reg = BPF_REG_6;
u8 mode = BPF_MODE(insn->code);
@@ -16212,6 +16224,13 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
return -EINVAL;
}
+ for (i = state->curframe; i; i--) {
+ if (state->frame[i]->in_callback_fn) {
+ verbose(env, "cannot use BPF_LD_[ABS|IND] within callback\n");
+ return -EINVAL;
+ }
+ }
+
if (!env->ops->gen_ld_abs) {
verbose(env, "bpf verifier is misconfigured\n");
return -EINVAL;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 782/869] bpf: Check ancestor frames for rbtree callbacks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (780 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 781/869] bpf: Reject legacy packet loads from callbacks Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 783/869] bpf: dont rewrite bpf_fastcall patterns entered by a jump Greg Kroah-Hartman
` (87 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini,
Kumar Kartikeya Dwivedi, Eduard Zingerman, Alexei Starovoitov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
[ Upstream commit 369f4ce734570bdfedaa4b5ca50e2a3f6a892728 ]
bpf_rbtree_add() invokes its comparator while the caller holds the root
lock. The native insertion code retains raw parent and link pointers across
the callback, so the verifier prohibits unlocking, consuming tree nodes,
or changing RCU state from that callback.
in_rbtree_lock_required_cb() only checks the innermost verifier frame.
Static subprogram calls are permitted while holding a spin lock, and such a
call pushes a frame without in_callback_fn set. Consequently, all callback
restrictions disappear in the nested frame. The subprogram can unlock the
tree, remove and drop the node being compared, then relock. Native insertion
resumes with the stale parent pointer and links freed memory into the tree.
Walk all active frames for the rbtree callback instead. Benign static
subprograms remain permitted, while callback restrictions follow execution
into nested frames.
Fixes: a44b1334aadd ("bpf: Allow calling static subprogs while holding a bpf_spin_lock")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260903214758.2727663-2-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 424cf2b196f27..106547524c563 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -10424,9 +10424,10 @@ static int set_rbtree_add_callback_state(struct bpf_verifier_env *env,
static bool is_rbtree_lock_required_kfunc(u32 btf_id);
-/* Are we currently verifying the callback for a rbtree helper that must
- * be called with lock held? If so, no need to complain about unreleased
- * lock
+/*
+ * Are we currently verifying the callback for an rbtree kfunc that must
+ * be called with a lock held, or one of that callback's subprogs? If so,
+ * no need to complain about an unreleased lock.
*/
static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env)
{
@@ -10434,17 +10435,19 @@ static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env)
struct bpf_insn *insn = env->prog->insnsi;
struct bpf_func_state *callee;
int kfunc_btf_id;
+ u32 frame;
- if (!state->curframe)
- return false;
-
- callee = state->frame[state->curframe];
+ for (frame = state->curframe; frame; frame--) {
+ callee = state->frame[frame];
+ if (!callee->in_callback_fn)
+ continue;
- if (!callee->in_callback_fn)
- return false;
+ kfunc_btf_id = insn[callee->callsite].imm;
+ if (is_rbtree_lock_required_kfunc(kfunc_btf_id))
+ return true;
+ }
- kfunc_btf_id = insn[callee->callsite].imm;
- return is_rbtree_lock_required_kfunc(kfunc_btf_id);
+ return false;
}
static bool retval_range_within(struct bpf_retval_range range, const struct bpf_reg_state *reg,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 783/869] bpf: dont rewrite bpf_fastcall patterns entered by a jump
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (781 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 782/869] bpf: Check ancestor frames for rbtree callbacks Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 784/869] bpf: zero extend the result of an arena 32-bit cmpxchg Greg Kroah-Hartman
` (86 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini, Eduard Zingerman,
Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <eddyz87@gmail.com>
[ Upstream commit 0b1c83dc3c4401cd7e846548f62e3caf3d06742e ]
mark_fastcall_pattern_for_call() must ensure that matched
"spill; call; fill" instruction series is not interrupted by a jump.
Otherwise the rewrite applied by bpf_remove_fastcall_spills_fills()
is not sound.
Record the instructions targeted by jumps in
insn_aux_data[*].jump_target when the CFG is built and use this flag
to stop growing a pattern at such an instruction. Jumps to the first
spill are fine.
Note that existing insn_aux_data[*].jmp_point field can't be reused,
as it marks subprogram return instructions.
Fixes: 5b5f51bff1b6 ("bpf: no_caller_saved_registers attribute for helper calls")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260903205820.1743087-1-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/bpf_verifier.h | 2 ++
kernel/bpf/verifier.c | 20 ++++++++++++++++++++
2 files changed, 22 insertions(+)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 48581c4def02c..a0468b6f40b37 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -604,6 +604,8 @@ struct bpf_insn_aux_data {
* accepts callback function as a parameter.
*/
bool calls_callback;
+ /* true if some jump or call instruction targets this instruction */
+ bool jump_target;
};
#define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 106547524c563..1becf8f07415e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3531,6 +3531,16 @@ static bool is_jmp_point(struct bpf_verifier_env *env, int insn_idx)
return env->insn_aux_data[insn_idx].jmp_point;
}
+static void mark_jump_target(struct bpf_verifier_env *env, int idx)
+{
+ env->insn_aux_data[idx].jump_target = true;
+}
+
+static bool bpf_is_jump_target(struct bpf_verifier_env *env, int insn_idx)
+{
+ return env->insn_aux_data[insn_idx].jump_target;
+}
+
#define LR_FRAMENO_BITS 3
#define LR_SPI_BITS 6
#define LR_ENTRY_BITS (LR_SPI_BITS + LR_FRAMENO_BITS + 1)
@@ -16629,6 +16639,7 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env)
/* mark branch target for state pruning */
mark_prune_point(env, w);
mark_jmp_point(env, w);
+ mark_jump_target(env, w);
}
if (insn_state[w] == 0) {
@@ -16817,6 +16828,10 @@ static bool is_fastcall_kfunc_call(struct bpf_kfunc_call_arg_meta *meta)
* r0 = *(u64 *)(r10 - 8); r0 += r1;
* r0 += r1; exit;
* exit;
+ *
+ * Both uses of the marks assume that a pattern is entered at its first
+ * spill and thus executes as a unit, hence a pattern is not grown past
+ * an instruction targeted by a jump.
*/
static void mark_fastcall_pattern_for_call(struct bpf_verifier_env *env,
struct bpf_subprog_info *subprog,
@@ -16871,6 +16886,10 @@ static void mark_fastcall_pattern_for_call(struct bpf_verifier_env *env,
for (i = 1, off = lowest_off; i <= ARRAY_SIZE(caller_saved); ++i, off += BPF_REG_SIZE) {
if (insn_idx - i < 0 || insn_idx + i >= env->prog->len)
break;
+ /* stx/ldx/call must not be a jump targets, a jump to the first stx is fine */
+ if (bpf_is_jump_target(env, insn_idx - i + 1) ||
+ bpf_is_jump_target(env, insn_idx + i))
+ break;
stx = &insns[insn_idx - i];
ldx = &insns[insn_idx + i];
/* must be a stack spill/fill pair */
@@ -17036,6 +17055,7 @@ static int visit_insn(int t, struct bpf_verifier_env *env)
mark_prune_point(env, t + off + 1);
mark_jmp_point(env, t + off + 1);
+ mark_jump_target(env, t + off + 1);
return ret;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 784/869] bpf: zero extend the result of an arena 32-bit cmpxchg
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (782 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 783/869] bpf: dont rewrite bpf_fastcall patterns entered by a jump Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 785/869] ASoC: Intel: avs: Refactor and fix init_config access Greg Kroah-Hartman
` (85 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini, Eduard Zingerman,
Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <eddyz87@gmail.com>
[ Upstream commit 4814ed6406f3493bd554ad046da5f7fc04833571 ]
bpf_convert_ctx_accesses() rewrites an atomic on an arena pointer from
BPF_STX | BPF_ATOMIC to BPF_STX | BPF_PROBE_ATOMIC, and it runs before
bpf_opt_subreg_zext_lo32_rnd_hi32().
That pass emits an explicit zero extension for a 32-bit cmpxchg even
when bpf_jit_needs_zext() is false. This is done because on some
architectures 32-bit cmpxchg requires explicit zero extension for the
dst register. E.g. on x86-64 'lock cmpxchg' does not change the %eax
if comparison is successful, while BPF semantics declare that each
operation on a 32-bit register zero extends it's upper half.
is_cmpxchg_insn() matches BPF_MODE == BPF_ATOMIC only, so an arena
cmpxchg misses said zero extension adjustment. This patch adjusts
is_cmpxchg_insn() to match BPF_PROBE_ATOMIC alongside BPF_ATOMIC.
Fixes: d503a04f8bc0 ("bpf: Add support for certain atomics in bpf_arena to x86 JIT")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260903171542.1438050-1-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 1becf8f07415e..60fc4935288c8 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -578,10 +578,15 @@ static bool helper_multiple_ref_obj_use(enum bpf_func_id func_id,
return ref_obj_uses > 1;
}
+/*
+ * Matches BPF_PROBE_ATOMIC too: convert_ctx_accesses() rewrites arena
+ * atomics before opt_subreg_zext_lo32_rnd_hi32() runs.
+ */
static bool is_cmpxchg_insn(const struct bpf_insn *insn)
{
return BPF_CLASS(insn->code) == BPF_STX &&
- BPF_MODE(insn->code) == BPF_ATOMIC &&
+ (BPF_MODE(insn->code) == BPF_ATOMIC ||
+ BPF_MODE(insn->code) == BPF_PROBE_ATOMIC) &&
insn->imm == BPF_CMPXCHG;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 785/869] ASoC: Intel: avs: Refactor and fix init_config access
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (783 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 784/869] bpf: zero extend the result of an arena 32-bit cmpxchg Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 786/869] bpf: Mark syscall helpers as sleepable Greg Kroah-Hartman
` (84 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Cezary Rojewski, Mark Brown,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cezary Rojewski <cezary.rojewski@intel.com>
[ Upstream commit 681e91035dc794896a904852040837190e5041f5 ]
Existing code accesses enties found in ->init_configs array through
indexes that are part of ->config_ids array. Those two are limited by:
->num_init_configs and ->num_config_ids respectively. Using ID larger
or equal to ->num_init_configs leads to out-of-bounds access:
avs_path_module_send_init_configs()
loop:
(...) &acomp->tplg->init_configs[ids[i]]
^ out-of-bounds candidate
Rather than adding another if-statement, refactor the code. There is no
need to store the IDs, have a list of pointers to actual config-entries
instead. As the verification of ->init_config entries does not differ from
verification of other types that are part of the topology.c file, simply
reuse the code.
Fixes: 8a49ef789b1b ("ASoC: Intel: avs: Send initial config to module if present")
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
Link: https://patch.msgid.link/20260902081814.1590883-10-cezary.rojewski@intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/soc/intel/avs/path.c | 11 +++-----
sound/soc/intel/avs/topology.c | 47 +++++++++++++++++++---------------
sound/soc/intel/avs/topology.h | 4 +--
3 files changed, 32 insertions(+), 30 deletions(-)
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c
index f31d5e2caa7b0..05892b0176acc 100644
--- a/sound/soc/intel/avs/path.c
+++ b/sound/soc/intel/avs/path.c
@@ -548,15 +548,10 @@ static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_mod
static int avs_path_module_send_init_configs(struct avs_dev *adev, struct avs_path_module *mod)
{
- struct avs_soc_component *acomp;
-
- acomp = to_avs_soc_component(mod->template->owner->owner->owner->owner->comp);
-
- u32 num_ids = mod->template->num_config_ids;
- u32 *ids = mod->template->config_ids;
+ struct avs_tplg_module *template = mod->template;
- for (int i = 0; i < num_ids; i++) {
- struct avs_tplg_init_config *config = &acomp->tplg->init_configs[ids[i]];
+ for (int i = 0; i < template->num_init_configs; i++) {
+ struct avs_tplg_init_config *config = template->init_configs[i];
size_t len = config->length;
void *data = config->data;
u32 param = config->param;
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index 9d49e248cfb22..88618351b75e6 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -350,6 +350,7 @@ AVS_DEFINE_PTR_PARSER(modcfg_base, struct avs_tplg_modcfg_base, modcfgs_base);
AVS_DEFINE_PTR_PARSER(modcfg_ext, struct avs_tplg_modcfg_ext, modcfgs_ext);
AVS_DEFINE_PTR_PARSER(pplcfg, struct avs_tplg_pplcfg, pplcfgs);
AVS_DEFINE_PTR_PARSER(binding, struct avs_tplg_binding, bindings);
+AVS_DEFINE_PTR_PARSER(init_config, struct avs_tplg_init_config, init_configs);
static int
parse_audio_format_bitfield(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
@@ -1121,7 +1122,7 @@ static const struct avs_tplg_token_parser module_parsers[] = {
{
.token = AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
- .offset = offsetof(struct avs_tplg_module, num_config_ids),
+ .offset = offsetof(struct avs_tplg_module, num_init_configs),
.parse = avs_parse_byte_token,
},
};
@@ -1131,10 +1132,32 @@ static const struct avs_tplg_token_parser init_config_parsers[] = {
.token = AVS_TKN_MOD_INIT_CONFIG_ID_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = 0,
- .parse = avs_parse_word_token,
+ .parse = avs_parse_init_config_ptr,
},
};
+static int avs_tplg_module_init_configs(struct snd_soc_component *comp,
+ struct avs_tplg_module *module,
+ struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
+{
+ struct avs_tplg_init_config **cfgs;
+ int ret;
+
+ if (!module->num_init_configs)
+ return -EINVAL;
+
+ cfgs = devm_kcalloc(comp->card->dev, module->num_init_configs, sizeof(*cfgs), GFP_KERNEL);
+ if (!cfgs)
+ return -ENOMEM;
+
+ ret = parse_dictionary_entries(comp, tuples, block_size, cfgs, module->num_init_configs,
+ sizeof(*cfgs), AVS_TKN_MOD_INIT_CONFIG_ID_U32,
+ init_config_parsers, ARRAY_SIZE(init_config_parsers));
+ if (!ret)
+ module->init_configs = cfgs;
+ return ret;
+}
+
static struct avs_tplg_module *
avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline *owner,
struct snd_soc_tplg_vendor_array *tuples, u32 block_size)
@@ -1161,27 +1184,11 @@ avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline
block_size -= esize;
/* Parse trailing config ids if any. */
if (block_size) {
- u32 num_config_ids = module->num_config_ids;
- u32 *config_ids;
-
- if (!num_config_ids)
- return ERR_PTR(-EINVAL);
-
- config_ids = devm_kcalloc(comp->card->dev, num_config_ids, sizeof(*config_ids),
- GFP_KERNEL);
- if (!config_ids)
- return ERR_PTR(-ENOMEM);
-
tuples = avs_tplg_vendor_array_at(tuples, esize);
- ret = parse_dictionary_entries(comp, tuples, block_size,
- config_ids, num_config_ids, sizeof(*config_ids),
- AVS_TKN_MOD_INIT_CONFIG_ID_U32,
- init_config_parsers,
- ARRAY_SIZE(init_config_parsers));
+
+ ret = avs_tplg_module_init_configs(comp, module, tuples, block_size);
if (ret)
return ERR_PTR(ret);
-
- module->config_ids = config_ids;
}
module->owner = owner;
diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h
index 409abdb239779..5d68418da8d8a 100644
--- a/sound/soc/intel/avs/topology.h
+++ b/sound/soc/intel/avs/topology.h
@@ -194,8 +194,8 @@ struct avs_tplg_module {
u8 domain;
struct avs_tplg_modcfg_ext *cfg_ext;
u32 ctl_id;
- u32 num_config_ids;
- u32 *config_ids;
+ u32 num_init_configs;
+ struct avs_tplg_init_config **init_configs;
struct avs_tplg_pipeline *owner;
/* Pipeline modules management. */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 786/869] bpf: Mark syscall helpers as sleepable
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (784 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 785/869] ASoC: Intel: avs: Refactor and fix init_config access Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 787/869] bpf: Mark signal tracepoint siginfo arguments as scalar Greg Kroah-Hartman
` (83 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini,
Kumar Kartikeya Dwivedi, Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
[ Upstream commit d05524794240b52fdc3b6c1220dd05505715824d ]
bpf_sys_bpf() executes the bpf(2) syscall body, which can take mutexes,
allocate with GFP_KERNEL, and wait for an RCU grace period.
bpf_sys_close() reaches close_fd() and filp_close(), which can sleep as
well.
Both helpers are limited to BPF_PROG_TYPE_SYSCALL, whose main program is
sleepable. That does not make every callback sleepable: a syscall program
can register a bpf_timer callback, and the verifier checks that callback
in a non-sleepable context while retaining the syscall helper set.
Without .might_sleep on the prototypes, such a callback can invoke
bpf_sys_bpf() from hrtimer softirq context and trigger a
scheduling-while-atomic failure. bpf_sys_close() is exposed through the
same missing context check.
Set .might_sleep on both prototypes so the existing helper-context check
rejects them from timer callbacks and other atomic regions. Calls from the
sleepable main body remain valid.
Fixes: 79a7f8bdb159 ("bpf: Introduce bpf_sys_bpf() helper and program type.")
Fixes: 3abea089246f ("bpf: Add bpf_sys_close() helper.")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260903144433.1716731-10-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/syscall.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 43081a7fb283a..9b3d067e47420 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -5899,6 +5899,7 @@ EXPORT_SYMBOL_NS(kern_sys_bpf, BPF_INTERNAL);
static const struct bpf_func_proto bpf_sys_bpf_proto = {
.func = bpf_sys_bpf,
.gpl_only = false,
+ .might_sleep = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_ANYTHING,
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
@@ -5924,6 +5925,7 @@ BPF_CALL_1(bpf_sys_close, u32, fd)
static const struct bpf_func_proto bpf_sys_close_proto = {
.func = bpf_sys_close,
.gpl_only = false,
+ .might_sleep = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_ANYTHING,
};
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 787/869] bpf: Mark signal tracepoint siginfo arguments as scalar
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (785 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 786/869] bpf: Mark syscall helpers as sleepable Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 788/869] erofs: disable LZ4 rolling decompression for now Greg Kroah-Hartman
` (82 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini,
Kumar Kartikeya Dwivedi, Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
[ Upstream commit 77515ab12e4983e6416f8c35039a3f0c0822ac70 ]
The signal_generate and signal_deliver tracepoints declare their info
argument as a struct kernel_siginfo pointer. btf_ctx_access() therefore
treats it as a trusted pointer for tp_btf programs.
Signal delivery also uses SEND_SIG_NOINFO and SEND_SIG_PRIV as special
values for this argument. Those values are zero and one respectively,
and are not pointers. A tp_btf program can currently dereference either
value and fault the kernel. In particular, signal_generate can run from
timer interrupt context, turning the fault into a kernel panic.
Record both tracepoints in raw_tp_null_args[] and mark argument one as
a non-pointer. This preserves scalar access to the cookie while rejecting
direct and helper-mediated pointer use. Merely marking it nullable would
not suffice because SEND_SIG_PRIV is nonzero.
Fixes: 838a10bd2ebf ("bpf: Augment raw_tp arguments with PTR_MAYBE_NULL")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260903144433.1716731-2-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/btf.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index cd63c1e27f601..e8a79d92d4afa 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -6558,6 +6558,9 @@ static const struct bpf_raw_tp_null_args raw_tp_null_args[] = {
/* rxrpc */
{ "rxrpc_recvdata", 0x1 },
{ "rxrpc_resend", 0x10 },
+ /* signal */
+ { "signal_generate", 0x20 },
+ { "signal_deliver", 0x20 },
/* skb */
{"kfree_skb", 0x1000},
/* sunrpc */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 788/869] erofs: disable LZ4 rolling decompression for now
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (786 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 787/869] bpf: Mark signal tracepoint siginfo arguments as scalar Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 789/869] net: rename netns_local to netns_immutable Greg Kroah-Hartman
` (81 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Walther, Jens-Uwe, Yann Collet,
Gao Xiang, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gao Xiang <xiang@kernel.org>
[ Upstream commit 82e664cf1219c459c33aae931b222cf951af9cb7 ]
LZ4 rolling decompression [1] was introduced to reduce the memory
footprint of temporary pages:
For many cases, it is needed for users to read small data within
a compressed extent (pcluster), either due to random small read, or
since uptodate folios (typically order-0) cannot be reused for
decompression again since decompression algorithm refills
already-uptodate folios.
Rolling decompression works because LZ4 is LZ77-based and only refers
to the most recent 64 KiB of decompressed data, so in theory only a
bounded rolling window of temporary pages is needed when decompressing.
It can save a lot of temporary memory, e.g.
601,960-byte data can be compressed into a 256k LZ4 compressed extent,
which means it needs 146 extra pages per request in the worst case if
rolling decompression is disabled.
However, the upstream LZ4 implementation is not under EROFS' control:
For example, the literal copy memmove() may still **copy long literals
backward** on x86 based on the address comparison even when the source
and destination ranges do not overlap (IOWs, inline decompression
doesn't need to be considered here). That breaks the rolling assumption
and makes the optimization broken.
Disable it for now to make sure the data correctness first since EROFS
is used everywhere now: The rolling window approach can be revived once
we either ensure that the official LZ4 code always copies forward for
non-overlapping ranges or maintain our own LZ4 implementation in EROFS.
The main impact is a higher runtime memory footprint; However, recent
commit 0f6273ab4637 ("erofs: add a reserved buffer pool for lz4
decompression") helps mitigate this when enabled but it's still not
perfect.
[1] https://www.usenix.org/conference/atc19/presentation/gao
§ 3.3 Decompression
Reported-by: "Walther, Jens-Uwe" <waltju@amazon.de>
Closes: https://lore.kernel.org/r/BEZP281MB2102E57CD31862B8D958B33DD2AC2@BEZP281MB2102.DEUP281.PROD.OUTLOOK.COM
Fixes: 8e6c8fa9f2e9 ("erofs: enable big pcluster feature")
Cc: Yann Collet <yann.collet.73@gmail.com>
Signed-off-by: Gao Xiang <xiang@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/erofs/decompressor.c | 60 +++++++++--------------------------------
fs/erofs/internal.h | 6 +----
fs/erofs/zdata.c | 18 +++----------
3 files changed, 16 insertions(+), 68 deletions(-)
diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
index d965a3f3073b7..933347416513b 100644
--- a/fs/erofs/decompressor.c
+++ b/fs/erofs/decompressor.c
@@ -7,11 +7,6 @@
#include "compress.h"
#include <linux/lz4.h>
-#ifndef LZ4_DISTANCE_MAX /* history window size */
-#define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */
-#endif
-
-#define LZ4_MAX_DISTANCE_PAGES (DIV_ROUND_UP(LZ4_DISTANCE_MAX, PAGE_SIZE) + 1)
#ifndef LZ4_DECOMPRESS_INPLACE_MARGIN
#define LZ4_DECOMPRESS_INPLACE_MARGIN(srcsize) (((srcsize) >> 8) + 32)
#endif
@@ -21,15 +16,12 @@ static int z_erofs_load_lz4_config(struct super_block *sb,
{
struct erofs_sb_info *sbi = EROFS_SB(sb);
struct z_erofs_lz4_cfgs *lz4 = data;
- u16 distance;
if (lz4) {
if (size < sizeof(struct z_erofs_lz4_cfgs)) {
erofs_err(sb, "invalid lz4 cfgs, size=%u", size);
return -EINVAL;
}
- distance = le16_to_cpu(lz4->max_distance);
-
sbi->lz4.max_pclusterblks = le16_to_cpu(lz4->max_pclusterblks);
if (!sbi->lz4.max_pclusterblks) {
sbi->lz4.max_pclusterblks = 1; /* reserved case */
@@ -40,48 +32,27 @@ static int z_erofs_load_lz4_config(struct super_block *sb,
return -EINVAL;
}
} else {
- distance = le16_to_cpu(dsb->u1.lz4_max_distance);
sbi->lz4.max_pclusterblks = 1;
}
-
- sbi->lz4.max_distance_pages = distance ?
- DIV_ROUND_UP(distance, PAGE_SIZE) + 1 :
- LZ4_MAX_DISTANCE_PAGES;
return z_erofs_gbuf_growsize(sbi->lz4.max_pclusterblks);
}
/*
- * Fill all gaps with bounce pages if it's a sparse page list. Also check if
- * all physical pages are consecutive, which can be seen for moderate CR.
+ * Fill all gaps with bounce pages if it's a sparse page list (for example some
+ * folios are already uptodate and thus can be mapped into userspace). Also
+ * check if pages are physically consecutive, which can be seen for moderate CR.
*/
-static int z_erofs_lz4_prepare_dstpages(struct z_erofs_decompress_req *rq,
- struct page **pagepool)
+static int z_erofs_oneshot_prepare_dstpages(struct z_erofs_decompress_req *rq,
+ struct page **pagepool)
{
- struct page *availables[LZ4_MAX_DISTANCE_PAGES] = { NULL };
- unsigned long bounced[DIV_ROUND_UP(LZ4_MAX_DISTANCE_PAGES,
- BITS_PER_LONG)] = { 0 };
- unsigned int lz4_max_distance_pages =
- EROFS_SB(rq->sb)->lz4.max_distance_pages;
void *kaddr = NULL;
- unsigned int i, j, top;
-
- top = 0;
- for (i = j = 0; i < rq->outpages; ++i, ++j) {
- struct page *const page = rq->out[i];
- struct page *victim;
-
- if (j >= lz4_max_distance_pages)
- j = 0;
+ unsigned int i;
- /* 'valid' bounced can only be tested after a complete round */
- if (!rq->fillgaps && test_bit(j, bounced)) {
- DBG_BUGON(i < lz4_max_distance_pages);
- DBG_BUGON(top >= lz4_max_distance_pages);
- availables[top++] = rq->out[i - lz4_max_distance_pages];
- }
+ for (i = 0; i < rq->outpages; ++i) {
+ struct page *page, *victim;
+ page = rq->out[i];
if (page) {
- __clear_bit(j, bounced);
if (!PageHighMem(page)) {
if (!i) {
kaddr = page_address(page);
@@ -93,21 +64,14 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_decompress_req *rq,
continue;
}
}
- kaddr = NULL;
- continue;
- }
- kaddr = NULL;
- __set_bit(j, bounced);
-
- if (top) {
- victim = availables[--top];
} else {
victim = __erofs_allocpage(pagepool, rq->gfp, true);
if (!victim)
return -ENOMEM;
set_page_private(victim, Z_EROFS_SHORTLIVED_PAGE);
+ rq->out[i] = victim;
}
- rq->out[i] = victim;
+ kaddr = NULL;
}
return kaddr ? 1 : 0;
}
@@ -279,7 +243,7 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
dst_maptype = 0;
} else {
/* general decoding path which can be used for all cases */
- ret = z_erofs_lz4_prepare_dstpages(rq, pagepool);
+ ret = z_erofs_oneshot_prepare_dstpages(rq, pagepool);
if (ret < 0)
return ret;
if (ret > 0) {
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 89dfb3736daa4..ed023f14acd3c 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -77,12 +77,8 @@ struct erofs_dev_context {
bool flatdev;
};
-/* all filesystem-wide lz4 configurations */
struct erofs_sb_lz4_info {
- /* # of pages needed for EROFS lz4 rolling decompression */
- u16 max_distance_pages;
- /* maximum possible blocks for pclusters in the filesystem */
- u16 max_pclusterblks;
+ u16 max_pclusterblks; /* maximum physical blocks for LZ4 pclusters */
};
struct erofs_domain {
diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
index d36562c4afff7..08720efbb1a17 100644
--- a/fs/erofs/zdata.c
+++ b/fs/erofs/zdata.c
@@ -1237,7 +1237,7 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, bool eio)
unsigned int pclusterpages = z_erofs_pclusterpages(pcl);
const struct z_erofs_decompressor *decomp =
z_erofs_decomp[pcl->algorithmformat];
- int i, j, jtop, err2, err = eio ? -EIO : 0;
+ int i, err2, err = eio ? -EIO : 0;
struct page *page;
bool overlapped;
bool try_free = true;
@@ -1314,7 +1314,6 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, bool eio)
be->compressed_pages >= be->onstack_pages + Z_EROFS_ONSTACK_PAGES)
kvfree(be->compressed_pages);
- jtop = 0;
z_erofs_fill_other_copies(be, err);
for (i = 0; i < be->nr_pages; ++i) {
page = be->decompressed_pages[i];
@@ -1322,22 +1321,11 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, bool eio)
continue;
DBG_BUGON(z_erofs_page_is_invalidated(page));
- if (!z_erofs_is_shortlived_page(page)) {
+ if (!z_erofs_is_shortlived_page(page))
erofs_onlinefolio_end(page_folio(page), err, true);
- continue;
- }
- if (pcl->algorithmformat != Z_EROFS_COMPRESSION_LZ4) {
+ else
erofs_pagepool_add(be->pagepool, page);
- continue;
- }
- for (j = 0; j < jtop && be->decompressed_pages[j] != page; ++j)
- ;
- if (j >= jtop) /* this bounce page is newly detected */
- be->decompressed_pages[jtop++] = page;
}
- while (jtop)
- erofs_pagepool_add(be->pagepool,
- be->decompressed_pages[--jtop]);
if (be->decompressed_pages != be->onstack_pages)
kvfree(be->decompressed_pages);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 789/869] net: rename netns_local to netns_immutable
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (787 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 788/869] erofs: disable LZ4 rolling decompression for now Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 790/869] net: plumb extack in __dev_change_net_namespace() Greg Kroah-Hartman
` (80 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Dumazet, Kuniyuki Iwashima,
Nicolas Dichtel, Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolas Dichtel <nicolas.dichtel@6wind.com>
[ Upstream commit 0c493da86374dffff7505e67289ad75b21f5b301 ]
The name 'netns_local' is confusing. A following commit will export it via
netlink, so let's use a more explicit name.
Reported-by: Eric Dumazet <edumazet@google.com>
Suggested-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Adapted to the older tree: the net_cachelines documentation is in the older
format and only the netns_local row is renamed there, the ieee802154
switch_netns hunk keeps the existing WARN_ON condition, and the missed
ip6_vti user of the flag is converted as well.
Stable-dep-of: debac3a20dec ("net: Remove conflicting altnames for dying netns in __dev_change_net_namespace().")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
Documentation/networking/net_cachelines/net_device.rst | 2 +-
Documentation/networking/switchdev.rst | 2 +-
drivers/net/amt.c | 2 +-
drivers/net/bonding/bond_main.c | 2 +-
drivers/net/ethernet/adi/adin1110.c | 2 +-
drivers/net/ethernet/marvell/prestera/prestera_main.c | 2 +-
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 ++--
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 2 +-
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 +-
drivers/net/ethernet/rocker/rocker_main.c | 2 +-
drivers/net/ethernet/ti/cpsw_new.c | 2 +-
drivers/net/loopback.c | 2 +-
drivers/net/net_failover.c | 2 +-
drivers/net/team/team_core.c | 2 +-
drivers/net/vrf.c | 2 +-
include/linux/netdevice.h | 4 ++--
net/batman-adv/soft-interface.c | 2 +-
net/bridge/br_device.c | 2 +-
net/core/dev.c | 4 ++--
net/hsr/hsr_device.c | 2 +-
net/ieee802154/6lowpan/core.c | 2 +-
net/ieee802154/core.c | 10 +++++-----
net/ipv4/ip_tunnel.c | 2 +-
net/ipv4/ipmr.c | 2 +-
net/ipv6/ip6_gre.c | 2 +-
net/ipv6/ip6_tunnel.c | 2 +-
net/ipv6/ip6_vti.c | 2 +-
net/ipv6/ip6mr.c | 2 +-
net/ipv6/sit.c | 2 +-
net/openvswitch/vport-internal_dev.c | 2 +-
net/wireless/core.c | 10 +++++-----
tools/testing/selftests/net/forwarding/README | 2 +-
32 files changed, 43 insertions(+), 43 deletions(-)
diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst
index 22b07c814f4a4..ce8666529fc58 100644
--- a/Documentation/networking/net_cachelines/net_device.rst
+++ b/Documentation/networking/net_cachelines/net_device.rst
@@ -166,7 +166,7 @@ unsigned:1 wol_enabled
unsigned:1 threaded - - napi_poll(napi_enable,dev_set_threaded)
unsigned_long:1 see_all_hwtstamp_requests
unsigned_long:1 change_proto_down
-unsigned_long:1 netns_local
+unsigned_long:1 netns_immutable
unsigned_long:1 fcoe_mtu
struct_list_head net_notifier_list
struct_macsec_ops* macsec_ops
diff --git a/Documentation/networking/switchdev.rst b/Documentation/networking/switchdev.rst
index f355f0166f1b4..2966b7122f050 100644
--- a/Documentation/networking/switchdev.rst
+++ b/Documentation/networking/switchdev.rst
@@ -137,7 +137,7 @@ would be sub-port 0 on port 1 on switch 1.
Port Features
^^^^^^^^^^^^^
-dev->netns_local
+dev->netns_immutable
If the switchdev driver (and device) only supports offloading of the default
network namespace (netns), the driver should set this private flag to prevent
diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index bf890f90f51e2..54199c3babccb 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -3126,7 +3126,7 @@ static void amt_link_setup(struct net_device *dev)
dev->addr_len = 0;
dev->priv_flags |= IFF_NO_QUEUE;
dev->lltx = true;
- dev->netns_local = true;
+ dev->netns_immutable = true;
dev->features |= NETIF_F_GSO_SOFTWARE;
dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM;
dev->hw_features |= NETIF_F_FRAGLIST | NETIF_F_RXCSUM;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index d10bbe4c35718..a6f3ed0bd86a3 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -6088,7 +6088,7 @@ void bond_setup(struct net_device *bond_dev)
bond_dev->lltx = true;
/* Don't allow bond devices to change network namespaces. */
- bond_dev->netns_local = true;
+ bond_dev->netns_immutable = true;
/* By default, we declare the bond to be fully
* VLAN hardware accelerated capable. Special
diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c
index 4352444ec6f6f..71a2397edf2bb 100644
--- a/drivers/net/ethernet/adi/adin1110.c
+++ b/drivers/net/ethernet/adi/adin1110.c
@@ -1602,7 +1602,7 @@ static int adin1110_probe_netdevs(struct adin1110_priv *priv)
netdev->netdev_ops = &adin1110_netdev_ops;
netdev->ethtool_ops = &adin1110_ethtool_ops;
netdev->priv_flags |= IFF_UNICAST_FLT;
- netdev->netns_local = true;
+ netdev->netns_immutable = true;
port_priv->phydev = get_phy_device(priv->mii_bus, i + 1, false);
if (IS_ERR(port_priv->phydev)) {
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_main.c b/drivers/net/ethernet/marvell/prestera/prestera_main.c
index 3f7cc04a873b2..ebd42fc263fce 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_main.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_main.c
@@ -634,7 +634,7 @@ static int prestera_port_create(struct prestera_switch *sw, u32 id)
goto err_dl_port_register;
dev->features |= NETIF_F_HW_TC;
- dev->netns_local = true;
+ dev->netns_immutable = true;
dev->netdev_ops = &prestera_netdev_ops;
dev->ethtool_ops = &prestera_ethtool_ops;
SET_NETDEV_DEV(dev, sw->dev->dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index fd3cf53ff17a9..1f46eae73319d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -4401,9 +4401,9 @@ static netdev_features_t mlx5e_fix_features(struct net_device *netdev,
if (mlx5e_is_uplink_rep(priv)) {
features = mlx5e_fix_uplink_rep_features(netdev, features);
- netdev->netns_local = true;
+ netdev->netns_immutable = true;
} else {
- netdev->netns_local = false;
+ netdev->netns_immutable = false;
}
mutex_unlock(&priv->state_lock);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 82ef5d252161e..e07e2f5f84435 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -903,7 +903,7 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev,
netdev->features |= netdev->hw_features;
- netdev->netns_local = true;
+ netdev->netns_immutable = true;
}
static int mlx5e_init_rep(struct mlx5_core_dev *mdev,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 81164f12cad36..12377cb1669a4 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -1680,7 +1680,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u16 local_port,
NETIF_F_HW_TC;
dev->hw_features |= NETIF_F_HW_TC | NETIF_F_LOOPBACK;
dev->lltx = true;
- dev->netns_local = true;
+ dev->netns_immutable = true;
dev->min_mtu = ETH_MIN_MTU;
dev->max_mtu = MLXSW_PORT_MAX_MTU - MLXSW_PORT_ETH_FRAME_HDR;
diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c
index 23b20d5fd0168..2794f75df8fcb 100644
--- a/drivers/net/ethernet/rocker/rocker_main.c
+++ b/drivers/net/ethernet/rocker/rocker_main.c
@@ -2575,7 +2575,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
rocker_carrier_init(rocker_port);
dev->features |= NETIF_F_SG;
- dev->netns_local = true;
+ dev->netns_immutable = true;
/* MTU range: 68 - 9000 */
dev->min_mtu = ROCKER_PORT_MIN_MTU;
diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c
index c2041e46b83d6..d6f19cfd10b75 100644
--- a/drivers/net/ethernet/ti/cpsw_new.c
+++ b/drivers/net/ethernet/ti/cpsw_new.c
@@ -1427,7 +1427,7 @@ static int cpsw_create_ports(struct cpsw_common *cpsw)
ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER |
NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_TC;
- ndev->netns_local = true;
+ ndev->netns_immutable = true;
ndev->xdp_features = NETDEV_XDP_ACT_BASIC |
NETDEV_XDP_ACT_REDIRECT |
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 491e56b3263fd..63b236efb3b70 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -172,7 +172,7 @@ static void gen_lo_setup(struct net_device *dev,
dev->flags = IFF_LOOPBACK;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
dev->lltx = true;
- dev->netns_local = true;
+ dev->netns_immutable = true;
netif_keep_dst(dev);
dev->hw_features = NETIF_F_GSO_SOFTWARE;
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
diff --git a/drivers/net/net_failover.c b/drivers/net/net_failover.c
index 54c8b9d5b5fcf..5b50d9186f121 100644
--- a/drivers/net/net_failover.c
+++ b/drivers/net/net_failover.c
@@ -734,7 +734,7 @@ struct failover *net_failover_create(struct net_device *standby_dev)
failover_dev->lltx = true;
/* Don't allow failover devices to change network namespaces. */
- failover_dev->netns_local = true;
+ failover_dev->netns_immutable = true;
failover_dev->hw_features = FAILOVER_VLAN_FEATURES |
NETIF_F_HW_VLAN_CTAG_TX |
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index a83f996f0f2e7..1645a7a2e0767 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -2305,7 +2305,7 @@ static void team_setup(struct net_device *dev)
dev->lltx = true;
/* Don't allow team devices to change network namespaces. */
- dev->netns_local = true;
+ dev->netns_immutable = true;
dev->features |= NETIF_F_GRO;
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index c071b3ccd8cb9..e48a15ad4a16a 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -1624,7 +1624,7 @@ static void vrf_setup(struct net_device *dev)
dev->lltx = true;
/* don't allow vrf devices to change network namespaces. */
- dev->netns_local = true;
+ dev->netns_immutable = true;
/* does not make sense for a VLAN to be added to a vrf device */
dev->features |= NETIF_F_VLAN_CHALLENGED;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 58e2f366dfe4d..97db4c477170d 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1976,7 +1976,7 @@ enum netdev_reg_state {
* regardless of source, even if those aren't
* HWTSTAMP_SOURCE_NETDEV
* @change_proto_down: device supports setting carrier via IFLA_PROTO_DOWN
- * @netns_local: interface can't change network namespaces
+ * @netns_immutable: interface can't change network namespaces
* @fcoe_mtu: device supports maximum FCoE MTU, 2158 bytes
*
* @net_notifier_list: List of per-net netdev notifier block
@@ -2373,7 +2373,7 @@ struct net_device {
/* priv_flags_slow, ungrouped to save space */
unsigned long see_all_hwtstamp_requests:1;
unsigned long change_proto_down:1;
- unsigned long netns_local:1;
+ unsigned long netns_immutable:1;
unsigned long fcoe_mtu:1;
struct list_head net_notifier_list;
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 47715a612320a..72fbf415dc2b5 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -1031,7 +1031,7 @@ static void batadv_softif_init_early(struct net_device *dev)
dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
dev->priv_flags |= IFF_NO_QUEUE;
dev->lltx = true;
- dev->netns_local = true;
+ dev->netns_immutable = true;
/* can't call min_mtu, because the needed variables
* have not been initialized yet
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 446761da4e549..339b9be9653d3 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -488,7 +488,7 @@ void br_dev_setup(struct net_device *dev)
SET_NETDEV_DEVTYPE(dev, &br_type);
dev->priv_flags = IFF_EBRIDGE | IFF_NO_QUEUE;
dev->lltx = true;
- dev->netns_local = true;
+ dev->netns_immutable = true;
dev->features = COMMON_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_STAG_TX;
diff --git a/net/core/dev.c b/net/core/dev.c
index 8f507292f8ba4..1c406b150477f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -11749,7 +11749,7 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net,
/* Don't allow namespace local devices to be moved. */
err = -EINVAL;
- if (dev->netns_local)
+ if (dev->netns_immutable)
goto out;
/* Ensure the device has been registered */
@@ -12219,7 +12219,7 @@ static void __net_exit default_device_exit_net(struct net *net)
char fb_name[IFNAMSIZ];
/* Ignore unmoveable devices (i.e. loopback) */
- if (dev->netns_local)
+ if (dev->netns_immutable)
continue;
/* Leave virtual devices for the generic cleanup */
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
index 988d35866d043..3ef9e8e8f3a97 100644
--- a/net/hsr/hsr_device.c
+++ b/net/hsr/hsr_device.c
@@ -653,7 +653,7 @@ void hsr_dev_setup(struct net_device *dev)
/* Not sure about this. Taken from bridge code. netdevice.h says
* it means "Does not change network namespaces".
*/
- dev->netns_local = true;
+ dev->netns_immutable = true;
dev->needs_free_netdev = true;
diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c
index b200e1a03c17e..75ad8638c2d78 100644
--- a/net/ieee802154/6lowpan/core.c
+++ b/net/ieee802154/6lowpan/core.c
@@ -116,7 +116,7 @@ static void lowpan_setup(struct net_device *ldev)
ldev->netdev_ops = &lowpan_netdev_ops;
ldev->header_ops = &lowpan_header_ops;
ldev->needs_free_netdev = true;
- ldev->netns_local = true;
+ ldev->netns_immutable = true;
}
static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[],
diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
index 9b807f78a3105..edfbd57aebc2c 100644
--- a/net/ieee802154/core.c
+++ b/net/ieee802154/core.c
@@ -226,11 +226,11 @@ int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
if (!wpan_dev->netdev)
continue;
- wpan_dev->netdev->netns_local = false;
+ wpan_dev->netdev->netns_immutable = false;
err = dev_change_net_namespace(wpan_dev->netdev, net, "wpan%d");
if (err)
break;
- wpan_dev->netdev->netns_local = true;
+ wpan_dev->netdev->netns_immutable = true;
}
if (err) {
@@ -242,11 +242,11 @@ int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
list) {
if (!wpan_dev->netdev)
continue;
- wpan_dev->netdev->netns_local = false;
+ wpan_dev->netdev->netns_immutable = false;
err = dev_change_net_namespace(wpan_dev->netdev, net,
"wpan%d");
WARN_ON(err && err != -ENOMEM);
- wpan_dev->netdev->netns_local = true;
+ wpan_dev->netdev->netns_immutable = true;
}
return err;
@@ -291,7 +291,7 @@ static int cfg802154_netdev_notifier_call(struct notifier_block *nb,
switch (state) {
/* TODO NETDEV_DEVTYPE */
case NETDEV_REGISTER:
- dev->netns_local = true;
+ dev->netns_immutable = true;
wpan_dev->identifier = ++rdev->wpan_dev_id;
list_add_rcu(&wpan_dev->list, &rdev->wpan_dev_list);
rdev->devlist_generation++;
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 87cc6dca894cc..ed7bcd70f0c84 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -1148,7 +1148,7 @@ int ip_tunnel_init_net(struct net *net, unsigned int ip_tnl_net_id,
* Allowing to move it to another netns is clearly unsafe.
*/
if (!IS_ERR(itn->fb_tunnel_dev)) {
- itn->fb_tunnel_dev->netns_local = true;
+ itn->fb_tunnel_dev->netns_immutable = true;
itn->fb_tunnel_dev->mtu = ip_tunnel_bind_dev(itn->fb_tunnel_dev);
ip_tunnel_add(itn, netdev_priv(itn->fb_tunnel_dev));
itn->type = itn->fb_tunnel_dev->type;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index e37853d70db61..c3aa025362510 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -549,7 +549,7 @@ static void reg_vif_setup(struct net_device *dev)
dev->flags = IFF_NOARP;
dev->netdev_ops = ®_vif_netdev_ops;
dev->needs_free_netdev = true;
- dev->netns_local = true;
+ dev->netns_immutable = true;
}
static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 0cc0e1113845a..b737731dbcba4 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -1624,7 +1624,7 @@ static int __net_init ip6gre_init_net(struct net *net)
/* FB netdevice is special: we have one, and only one per netns.
* Allowing to move it to another netns is clearly unsafe.
*/
- ign->fb_tunnel_dev->netns_local = true;
+ ign->fb_tunnel_dev->netns_immutable = true;
ip6gre_fb_tunnel_init(ign->fb_tunnel_dev);
ign->fb_tunnel_dev->rtnl_link_ops = &ip6gre_link_ops;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 7eb2e67842f4a..4053ba5b1a139 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -2264,7 +2264,7 @@ static int __net_init ip6_tnl_init_net(struct net *net)
/* FB netdevice is special: we have one, and only one per netns.
* Allowing to move it to another netns is clearly unsafe.
*/
- ip6n->fb_tnl_dev->netns_local = true;
+ ip6n->fb_tnl_dev->netns_immutable = true;
err = ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
if (err < 0)
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index 3880662b6bc38..a5ad9fb38966d 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -1162,7 +1162,7 @@ static int __net_init vti6_init_net(struct net *net)
goto err_alloc_dev;
dev_net_set(ip6n->fb_tnl_dev, net);
ip6n->fb_tnl_dev->rtnl_link_ops = &vti6_link_ops;
- ip6n->fb_tnl_dev->netns_local = true;
+ ip6n->fb_tnl_dev->netns_immutable = true;
err = vti6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
if (err < 0)
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index d95b988be4afe..47afc8cef6880 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -654,7 +654,7 @@ static void reg_vif_setup(struct net_device *dev)
dev->flags = IFF_NOARP;
dev->netdev_ops = ®_vif_netdev_ops;
dev->needs_free_netdev = true;
- dev->netns_local = true;
+ dev->netns_immutable = true;
}
static struct net_device *ip6mr_reg_vif(struct net *net, struct mr_table *mrt)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 1f980e827d042..614f7267dc9f8 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1861,7 +1861,7 @@ static int __net_init sit_init_net(struct net *net)
/* FB netdevice is special: we have one, and only one per netns.
* Allowing to move it to another netns is clearly unsafe.
*/
- sitn->fb_tunnel_dev->netns_local = true;
+ sitn->fb_tunnel_dev->netns_immutable = true;
t = netdev_priv(sitn->fb_tunnel_dev);
t->net = net;
diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c
index 5858d65ea1a9b..7b05a423a9ab9 100644
--- a/net/openvswitch/vport-internal_dev.c
+++ b/net/openvswitch/vport-internal_dev.c
@@ -149,7 +149,7 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
/* Restrict bridge port to current netns. */
if (vport->port_no == OVSP_LOCAL)
- vport->dev->netns_local = true;
+ vport->dev->netns_immutable = true;
rtnl_lock();
err = register_netdevice(vport->dev);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index c485cd6fbc825..a0c0de4948428 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -165,11 +165,11 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->netdev)
continue;
- wdev->netdev->netns_local = false;
+ wdev->netdev->netns_immutable = false;
err = dev_change_net_namespace(wdev->netdev, net, "wlan%d");
if (err)
break;
- wdev->netdev->netns_local = true;
+ wdev->netdev->netns_immutable = true;
}
if (err) {
@@ -181,11 +181,11 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
list) {
if (!wdev->netdev)
continue;
- wdev->netdev->netns_local = false;
+ wdev->netdev->netns_immutable = false;
err = dev_change_net_namespace(wdev->netdev, net,
"wlan%d");
WARN_ON(err);
- wdev->netdev->netns_local = true;
+ wdev->netdev->netns_immutable = true;
}
return err;
@@ -1549,7 +1549,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
SET_NETDEV_DEVTYPE(dev, &wiphy_type);
wdev->netdev = dev;
/* can only change netns with wiphy */
- dev->netns_local = true;
+ dev->netns_immutable = true;
cfg80211_init_wdev(wdev);
break;
diff --git a/tools/testing/selftests/net/forwarding/README b/tools/testing/selftests/net/forwarding/README
index a652429bfd53c..7b41cff993adb 100644
--- a/tools/testing/selftests/net/forwarding/README
+++ b/tools/testing/selftests/net/forwarding/README
@@ -6,7 +6,7 @@ to easily create and test complex environments.
Unfortunately, these namespaces can not be used with actual switching
ASICs, as their ports can not be migrated to other network namespaces
-(dev->netns_local) and most of them probably do not support the
+(dev->netns_immutable) and most of them probably do not support the
L1-separation provided by namespaces.
However, a similar kind of flexibility can be achieved by using VRFs and
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 790/869] net: plumb extack in __dev_change_net_namespace()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (788 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 789/869] net: rename netns_local to netns_immutable Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 791/869] net: Remove conflicting altnames for dying netns " Greg Kroah-Hartman
` (79 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicolas Dichtel, Eric Dumazet,
Kuniyuki Iwashima, Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolas Dichtel <nicolas.dichtel@6wind.com>
[ Upstream commit 12b6f7069ba5aa160f3332916408b34ae8e0b0f6 ]
It could be hard to understand why the netlink command fails. For example,
if dev->netns_immutable is set, the error is "Invalid argument".
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: debac3a20dec ("net: Remove conflicting altnames for dying netns in __dev_change_net_namespace().")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/netdevice.h | 5 +++--
net/core/dev.c | 43 +++++++++++++++++++++++++++++++--------
net/core/rtnetlink.c | 2 +-
3 files changed, 38 insertions(+), 12 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 97db4c477170d..4d1e0b91402d1 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -4022,12 +4022,13 @@ int dev_change_flags(struct net_device *dev, unsigned int flags,
int dev_set_alias(struct net_device *, const char *, size_t);
int dev_get_alias(const struct net_device *, char *, size_t);
int __dev_change_net_namespace(struct net_device *dev, struct net *net,
- const char *pat, int new_ifindex);
+ const char *pat, int new_ifindex,
+ struct netlink_ext_ack *extack);
static inline
int dev_change_net_namespace(struct net_device *dev, struct net *net,
const char *pat)
{
- return __dev_change_net_namespace(dev, net, pat, 0);
+ return __dev_change_net_namespace(dev, net, pat, 0, NULL);
}
int __dev_set_mtu(struct net_device *, int);
int dev_set_mtu(struct net_device *, int);
diff --git a/net/core/dev.c b/net/core/dev.c
index 1c406b150477f..e6d907a685f64 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -11729,6 +11729,7 @@ EXPORT_SYMBOL(unregister_netdev);
* is already taken in the destination network namespace.
* @new_ifindex: If not zero, specifies device index in the target
* namespace.
+ * @extack: netlink extended ack
*
* This function shuts down a device interface and moves it
* to a new network namespace. On success 0 is returned, on
@@ -11738,7 +11739,8 @@ EXPORT_SYMBOL(unregister_netdev);
*/
int __dev_change_net_namespace(struct net_device *dev, struct net *net,
- const char *pat, int new_ifindex)
+ const char *pat, int new_ifindex,
+ struct netlink_ext_ack *extack)
{
struct netdev_name_node *name_node;
struct net *net_old = dev_net(dev);
@@ -11749,12 +11751,16 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net,
/* Don't allow namespace local devices to be moved. */
err = -EINVAL;
- if (dev->netns_immutable)
+ if (dev->netns_immutable) {
+ NL_SET_ERR_MSG(extack, "The interface netns is immutable");
goto out;
+ }
/* Ensure the device has been registered */
- if (dev->reg_state != NETREG_REGISTERED)
+ if (dev->reg_state != NETREG_REGISTERED) {
+ NL_SET_ERR_MSG(extack, "The interface isn't registered");
goto out;
+ }
/* Get out if there is nothing todo */
err = 0;
@@ -11767,30 +11773,49 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net,
err = -EEXIST;
if (netdev_name_in_use(net, dev->name)) {
/* We get here if we can't use the current device name */
- if (!pat)
+ if (!pat) {
+ NL_SET_ERR_MSG(extack,
+ "An interface with the same name exists in the target netns");
goto out;
+ }
err = dev_prep_valid_name(net, dev, pat, new_name, EEXIST);
- if (err < 0)
+ if (err < 0) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "Unable to use '%s' for the new interface name in the target netns",
+ pat);
goto out;
+ }
}
/* Check that none of the altnames conflicts. */
err = -EEXIST;
- netdev_for_each_altname(dev, name_node)
- if (netdev_name_in_use(net, name_node->name))
+ netdev_for_each_altname(dev, name_node) {
+ if (netdev_name_in_use(net, name_node->name)) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "An interface with the altname %s exists in the target netns",
+ name_node->name);
goto out;
+ }
+ }
/* Check that new_ifindex isn't used yet. */
if (new_ifindex) {
err = dev_index_reserve(net, new_ifindex);
- if (err < 0)
+ if (err < 0) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "The ifindex %d is not available in the target netns",
+ new_ifindex);
goto out;
+ }
} else {
/* If there is an ifindex conflict assign a new one */
err = dev_index_reserve(net, dev->ifindex);
if (err == -EBUSY)
err = dev_index_reserve(net, 0);
- if (err < 0)
+ if (err < 0) {
+ NL_SET_ERR_MSG(extack,
+ "Unable to allocate a new ifindex in the target netns");
goto out;
+ }
new_ifindex = err;
}
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 23b0e673fd83f..159a6270d5fb8 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2932,7 +2932,7 @@ static int do_setlink(const struct sk_buff *skb,
else
new_ifindex = 0;
- err = __dev_change_net_namespace(dev, net, pat, new_ifindex);
+ err = __dev_change_net_namespace(dev, net, pat, new_ifindex, extack);
put_net(net);
if (err)
goto errout;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 791/869] net: Remove conflicting altnames for dying netns in __dev_change_net_namespace().
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (789 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 790/869] net: plumb extack in __dev_change_net_namespace() Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 792/869] btrfs: zstd: fix lost wakeup when waiting for a workspace Greg Kroah-Hartman
` (78 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+74f338e09f1ef3ee6457,
Kuniyuki Iwashima, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit debac3a20dec524a59625cf10fa2f18571127824 ]
syzbot reported the warning in cfg80211_pernet_exit(). [0]
The repro does the following:
1. create two device in root netns and non-root netns
2. assign the same altname for the two devices
3. remove the non-root netns
Since commit 7663d522099e ("net: check for altname conflicts
when changing netdev's netns"), cfg80211_switch_netns() and
cfg802154_switch_netns() fail if init_net has a device with the
conflicting altname.
default_device_exit_net() had the same issue and commit d09486a04f5d
("net: fix removing a namespace with conflicting altnames") fixed it.
cfg80211_pernet_exit() and cfg802154_pernet_exit() need the same fix.
Let's generalise the fix by removing conflicting altnames for dying
netns in __dev_change_net_namespace().
[0]:
cfg80211_switch_netns(rdev, &init_net)
WARNING: net/wireless/core.c:1871 at cfg80211_pernet_exit+0xd5/0x120 net/wireless/core.c:1871, CPU#1: kworker/u8:9/1160
Modules linked in:
CPU: 1 UID: 0 PID: 1160 Comm: kworker/u8:9 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/24/2026
Workqueue: netns cleanup_net
RIP: 0010:cfg80211_pernet_exit+0xd5/0x120 net/wireless/core.c:1871
Code: e8 03 42 80 3c 20 00 74 08 4c 89 f7 e8 b4 ef 0e f7 4d 8b 36 49 81 fe 20 10 4a 90 74 12 e8 03 3d 9f f6 eb 85 e8 fc 3c 9f f6 90 <0f> 0b 90 eb cc e8 f1 3c 9f f6 eb 05 e8 ea 3c 9f f6 5b 41 5c 41 5e
RSP: 0018:ffffc900057a78f0 EFLAGS: 00010293
RAX: ffffffff8b287154 RBX: ffff88807ba72780 RCX: ffff8880213e8000
RDX: 0000000000000000 RSI: 00000000ffffffef RDI: 0000000000000000
RBP: 00000000ffffffef R08: ffffffff9024cc67 R09: 0000000000000000
R10: fffff52000af4eb0 R11: fffffbfff204998d R12: dffffc0000000000
R13: ffffffff904a1080 R14: ffff888144ed0008 R15: ffff888144ed0e20
FS: 0000000000000000(0000) GS:ffff888124de6000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00005642de0a8a70 CR3: 000000007a40c000 CR4: 00000000003526f0
Call Trace:
<TASK>
ops_exit_list net/core/net_namespace.c:200 [inline]
ops_undo_list+0x43d/0x8d0 net/core/net_namespace.c:253
cleanup_net+0x572/0x810 net/core/net_namespace.c:706
process_one_work kernel/workqueue.c:3387 [inline]
process_scheduled_works+0xc3d/0x1630 kernel/workqueue.c:3470
worker_thread+0xa47/0xfb0 kernel/workqueue.c:3551
kthread+0x38b/0x480 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
Fixes: 36fbf1e52bd3 ("net: rtnetlink: add linkprop commands to add and delete alternative ifnames")
Reported-by: syzbot+74f338e09f1ef3ee6457@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/all/6a96219e.04428c52.29b18.0001.GAE@google.com/T/
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260901005550.2042357-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/core/dev.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index e6d907a685f64..397fd0f9cc7a2 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -11742,7 +11742,7 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net,
const char *pat, int new_ifindex,
struct netlink_ext_ack *extack)
{
- struct netdev_name_node *name_node;
+ struct netdev_name_node *name_node, *tmp;
struct net *net_old = dev_net(dev);
char new_name[IFNAMSIZ] = {};
int err, new_nsid;
@@ -11788,13 +11788,19 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net,
}
/* Check that none of the altnames conflicts. */
err = -EEXIST;
- netdev_for_each_altname(dev, name_node) {
- if (netdev_name_in_use(net, name_node->name)) {
- NL_SET_ERR_MSG_FMT(extack,
- "An interface with the altname %s exists in the target netns",
- name_node->name);
- goto out;
+ netdev_for_each_altname_safe(dev, name_node, tmp) {
+ if (!netdev_name_in_use(net, name_node->name))
+ continue;
+
+ if (!check_net(net_old)) {
+ __netdev_name_node_alt_destroy(name_node);
+ continue;
}
+
+ NL_SET_ERR_MSG_FMT(extack,
+ "An interface with the altname %s exists in the target netns",
+ name_node->name);
+ goto out;
}
/* Check that new_ifindex isn't used yet. */
@@ -12232,7 +12238,6 @@ static struct pernet_operations __net_initdata netdev_net_ops = {
static void __net_exit default_device_exit_net(struct net *net)
{
- struct netdev_name_node *name_node, *tmp;
struct net_device *dev, *aux;
/*
* Push all migratable network devices back to the
@@ -12256,10 +12261,6 @@ static void __net_exit default_device_exit_net(struct net *net)
if (netdev_name_in_use(&init_net, fb_name))
snprintf(fb_name, IFNAMSIZ, "dev%%d");
- netdev_for_each_altname_safe(dev, name_node, tmp)
- if (netdev_name_in_use(&init_net, name_node->name))
- __netdev_name_node_alt_destroy(name_node);
-
err = dev_change_net_namespace(dev, &init_net, fb_name);
if (err) {
pr_emerg("%s: failed to move %s to init_net: %d\n",
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 792/869] btrfs: zstd: fix lost wakeup when waiting for a workspace
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (790 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 791/869] net: Remove conflicting altnames for dying netns " Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 793/869] bpf: backtracking shouldnt clear outer frame R1-R5 for callbacks Greg Kroah-Hartman
` (77 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Qu Wenruo, FAN YE, David Sterba,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: FAN YE <fy15309206903@gmail.com>
[ Upstream commit 2acb9f3d1cc8f65dc81ed55e238cbf8e5b60bff7 ]
A writer can sleep forever in zstd_get_workspace() even though a workspace
is free. When zstd_alloc_workspace() fails, the task is queued on
zwsm->wait and schedules unconditionally, never re-testing the pool.
zstd_put_workspace() publishes the workspace and then calls cond_wake_up(),
which only wakes when a sleeper is already visible, so a workspace returned
between the failed allocation and prepare_to_wait() wakes nobody. The
window is wide: zstd_alloc_workspace() goes through kvmalloc() and may
enter reclaim.
Only a max level workspace triggers the wakeup and one is deliberately kept
allocated as the fallback every waiter waits for, so once its wakeup is
lost the writer stays in TASK_UNINTERRUPTIBLE until some other task happens
to return one. Re-check the pool after prepare_to_wait() has published the
waiter, and use the workspace if one turned up.
Fixes: 3f93aef535c8 ("btrfs: add zstd compression level support")
Assisted-by: Claude:claude-opus-5
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: FAN YE <fy15309206903@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/zstd.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/zstd.c b/fs/btrfs/zstd.c
index c9ea37fabf659..732a84c0f6b1e 100644
--- a/fs/btrfs/zstd.c
+++ b/fs/btrfs/zstd.c
@@ -290,8 +290,17 @@ struct list_head *zstd_get_workspace(unsigned int level)
DEFINE_WAIT(wait);
prepare_to_wait(&wsm.wait, &wait, TASK_UNINTERRUPTIBLE);
- schedule();
+ /*
+ * Re-check after being queued: zstd_put_workspace() only wakes
+ * a queue that already has a sleeper, so a workspace returned
+ * since the failed allocation woke nobody.
+ */
+ ws = zstd_find_workspace(level);
+ if (!ws)
+ schedule();
finish_wait(&wsm.wait, &wait);
+ if (ws)
+ return ws;
goto again;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 793/869] bpf: backtracking shouldnt clear outer frame R1-R5 for callbacks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (791 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 792/869] btrfs: zstd: fix lost wakeup when waiting for a workspace Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 794/869] bpf: backtrack_insn(): Handle ld_{abs,ind} subprog exit edge Greg Kroah-Hartman
` (76 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini, Eduard Zingerman,
Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <eddyz87@gmail.com>
[ Upstream commit e3e4f66cc4b72333d0886ae2673c360248987889 ]
When processing calls to bpf_loop() verifier marks R1 (and R4) as
precise. R1 tracks loop iterations number and because of the
'callback_depth < R1' mechanics in check_helper_call() must be marked
precise. However, precision propagation for R1 was broken,
when bpf_loop() call was verified on a second iteration.
Consider the following verification trace:
- main: bpf_loop(nr_loops, callback ...)
- callback: BPF_EXIT
- main: bpf_loop(nr_loops, callback ...)
- ...
While the first visit of the call to bpf_loop() propagated R1
precision as expected, the second call to mark_chain_precision() in
the check_helper_call() set R1, but it was immediately reset when
backtrack_insn() processed preceding BPF_EXIT in the loop deleted in
this patch.
Because of that, the second visit of the call to bpf_loop() injected
checkpoint with R1 not marked as precise. Which could trick the
verifier into accepting unsafe programs. See the next patch for an
example of such program.
Commit is structured in a way to minimize conflicts when
'bpf' would be eventually merged with 'bpf-next'.
Fixes: ab5cfac139ab ("bpf: verify callbacks as if they are called unknown number of times")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260831-bug-015-backtrack-cb-args-precise-v1-1-68a8e2a821e0@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 37 +++++++++++++++++--------------------
1 file changed, 17 insertions(+), 20 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 60fc4935288c8..76868b01727f5 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -4148,37 +4148,34 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
return -EFAULT;
}
} else if (opcode == BPF_EXIT) {
- bool r0_precise;
+ bool from_subprog_call, r0_precise;
+
+ /* BPF_EXIT in subprog or callback always returns
+ * right after the call instruction, so by checking
+ * whether the instruction at subseq_idx-1 is subprog
+ * call or not we can distinguish actual exit from
+ * *subprog* from exit from *callback*. In the former
+ * case, we need to propagate r0 precision, if
+ * necessary. In the former we never do that.
+ */
+ from_subprog_call = subseq_idx - 1 >= 0 &&
+ bpf_pseudo_call(&env->prog->insnsi[subseq_idx - 1]);
+
+ r0_precise = from_subprog_call && bt_is_reg_set(bt, BPF_REG_0);
/* Backtracking to a nested function call, 'idx' is a part of
* the inner frame 'subseq_idx' is a part of the outer frame.
* In case of a regular function call, instructions giving
* precision to registers R1-R5 should have been found already.
- * In case of a callback, it is ok to have R1-R5 marked for
- * backtracking, as these registers are set by the function
- * invoking callback.
+ * In case of a callback from bpf_loop(), R{1,4} in the calling
+ * frame would be set as precise and that is correct.
*/
- if (subseq_idx >= 0 && calls_callback(env, subseq_idx))
- for (i = BPF_REG_1; i <= BPF_REG_5; i++)
- bt_clear_reg(bt, i);
- if (bt_reg_mask(bt) & BPF_REGMASK_ARGS) {
+ if (from_subprog_call && (bt_reg_mask(bt) & BPF_REGMASK_ARGS)) {
verbose(env, "BUG regs %x\n", bt_reg_mask(bt));
WARN_ONCE(1, "verifier backtracking bug");
return -EFAULT;
}
- /* BPF_EXIT in subprog or callback always returns
- * right after the call instruction, so by checking
- * whether the instruction at subseq_idx-1 is subprog
- * call or not we can distinguish actual exit from
- * *subprog* from exit from *callback*. In the former
- * case, we need to propagate r0 precision, if
- * necessary. In the former we never do that.
- */
- r0_precise = subseq_idx - 1 >= 0 &&
- bpf_pseudo_call(&env->prog->insnsi[subseq_idx - 1]) &&
- bt_is_reg_set(bt, BPF_REG_0);
-
bt_clear_reg(bt, BPF_REG_0);
if (bt_subprog_enter(bt))
return -EFAULT;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 794/869] bpf: backtrack_insn(): Handle ld_{abs,ind} subprog exit edge
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (792 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 793/869] bpf: backtracking shouldnt clear outer frame R1-R5 for callbacks Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 795/869] ipv6: mcast: use rcu_assign_pointer() for __rcu list updates Greg Kroah-Hartman
` (75 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini, Eduard Zingerman,
Daniel Borkmann, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <eddyz87@gmail.com>
[ Upstream commit 387b1baefbb776e3f48dc2261e77a49213f470f7 ]
Nicholas Carlini reported a bug in precision backtracking mechanism
for BPF_LD | BPF_{IND,ABS} instructions. These instructions are
modelled as two branches:
- fallthrough;
- implicit exit from current subprogram.
The implicit exit case was not handled by the backtrack_insn()
function. When backtracking such a path backtrack_insn() did not
call bt_subprog_enter(), which meant that backtracking continued
manipulating precision marks in a caller frame, while looking at
instructions in a callee frame.
This lead to segmentation faults during verification (see the
selftest), or unsound state pruning.
Fixes: ee861486e377 ("bpf: Fix ld_{abs,ind} failure path analysis in subprogs")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20260901-bug-016-backtrack-ld-abs-v1-1-59368f1be435@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 76868b01727f5..dd766eefbf027 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -4207,16 +4207,29 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
*/
}
} else if (class == BPF_LD) {
- if (!bt_is_reg_set(bt, dreg))
- return 0;
- bt_clear_reg(bt, dreg);
/* It's ld_imm64 or ld_abs or ld_ind.
* For ld_imm64 no further tracking of precision
* into parent is necessary
*/
- if (mode == BPF_IND || mode == BPF_ABS)
- /* to be analyzed */
- return -ENOTSUPP;
+ if (mode == BPF_IMM) {
+ bt_clear_reg(bt, dreg);
+ return 0;
+ }
+ /*
+ * BPF_{IND,ABS} are modelled as two branches:
+ * - fallthrough;
+ * - implicit subprogram exit.
+ * It is necessary to switch current frame if
+ * implicit subprogram exit branch is backtracked.
+ */
+ if (mode == BPF_IND || mode == BPF_ABS) {
+ if (bt_is_reg_set(bt, dreg))
+ return -ENOTSUPP;
+ if (subseq_idx != idx + 1)
+ if (bt_subprog_enter(bt))
+ return -EFAULT;
+ return 0;
+ }
}
/* Propagate precision marks to linked registers, to account for
* registers marked as precise in this function.
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 795/869] ipv6: mcast: use rcu_assign_pointer() for __rcu list updates
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (793 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 794/869] bpf: backtrack_insn(): Handle ld_{abs,ind} subprog exit edge Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 796/869] smb/client: invalidate fscache for fallocate range operations Greg Kroah-Hartman
` (74 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Dumazet, Taehee Yoo,
Ido Schimmel, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 0c8f56c583c3250408367880c98e4d6fbc929315 ]
Several places in net/ipv6/mcast.c update RCU-protected lists
(np->ipv6_mc_list, idev->mc_list, idev->mc_tomb) using direct pointer
assignments instead of rcu_assign_pointer():
1. In __ipv6_dev_mc_dec(), unlinking a group from idev->mc_list did:
*map = ma->next;
without rcu_assign_pointer() while concurrent readers traverse
idev->mc_list locklessly under rcu_read_lock().
2. In ipv6_sock_mc_drop() and __ipv6_sock_mc_close(), unlinking a group
from np->ipv6_mc_list directly assigned *lnk = mc_lst->next and
np->ipv6_mc_list = mc_lst->next without rcu_assign_pointer(), racing
with lockless readers in inet6_mc_check().
3. In __ipv6_sock_mc_join(), mc_lst->next was initialized to
np->ipv6_mc_list via raw assignment before publishing mc_lst.
4. In mld_del_delrec() and __ipv6_dev_mc_inc(), __rcu source pointers
passed into rcu_assign_pointer() lacked explicit dereference helpers.
Fix these by consistently using rcu_assign_pointer() along with
mc_dereference() / sock_dereference().
Fixes: 456b61bca8ee ("ipv6: mcast: RCU conversion")
Fixes: 88e2ca308094 ("mld: convert ifmcaddr6 to RCU")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Taehee Yoo <ap420073@gmail.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260828084531.1826790-5-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv6/mcast.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index d0eefadea5c33..9326dd3976bf8 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -229,7 +229,8 @@ static int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
return err;
}
- mc_lst->next = np->ipv6_mc_list;
+ rcu_assign_pointer(mc_lst->next,
+ sock_dereference(np->ipv6_mc_list, sk));
rcu_assign_pointer(np->ipv6_mc_list, mc_lst);
return 0;
@@ -289,7 +290,8 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
lnk = &mc_lst->next) {
if ((ifindex == 0 || mc_lst->ifindex == ifindex) &&
ipv6_addr_equal(&mc_lst->addr, addr)) {
- *lnk = mc_lst->next;
+ rcu_assign_pointer(*lnk,
+ sock_dereference(mc_lst->next, sk));
__ipv6_sock_mc_drop(sk, mc_lst);
return 0;
}
@@ -343,7 +345,8 @@ void __ipv6_sock_mc_close(struct sock *sk)
while ((mc_lst = sock_dereference(np->ipv6_mc_list, sk)) != NULL) {
struct net_device *dev;
- np->ipv6_mc_list = mc_lst->next;
+ rcu_assign_pointer(np->ipv6_mc_list,
+ sock_dereference(mc_lst->next, sk));
dev = __dev_get_by_index(net, mc_lst->ifindex);
if (dev) {
@@ -826,9 +829,11 @@ static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
}
if (pmc) {
if (pmc_prev)
- rcu_assign_pointer(pmc_prev->next, pmc->next);
+ rcu_assign_pointer(pmc_prev->next,
+ mc_dereference(pmc->next, idev));
else
- rcu_assign_pointer(idev->mc_tomb, pmc->next);
+ rcu_assign_pointer(idev->mc_tomb,
+ mc_dereference(pmc->next, idev));
}
if (pmc) {
@@ -986,7 +991,7 @@ static int __ipv6_dev_mc_inc(struct net_device *dev,
return -ENOMEM;
}
- rcu_assign_pointer(mc->next, idev->mc_list);
+ rcu_assign_pointer(mc->next, mc_dereference(idev->mc_list, idev));
rcu_assign_pointer(idev->mc_list, mc);
mca_get(mc);
@@ -1018,7 +1023,8 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr)
map = &ma->next) {
if (ipv6_addr_equal(&ma->mca_addr, addr)) {
if (--ma->mca_users == 0) {
- *map = ma->next;
+ rcu_assign_pointer(*map,
+ mc_dereference(ma->next, idev));
igmp6_group_dropped(ma);
ip6_mc_clear_src(ma);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 796/869] smb/client: invalidate fscache for fallocate range operations
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (794 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 795/869] ipv6: mcast: use rcu_assign_pointer() for __rcu list updates Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 797/869] net: stmmac: fix dma mapping leak in stmmac_tso_xmit() Greg Kroah-Hartman
` (73 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Huiwen He, Namjae Jeon, ChenXiaoSong,
Paulo Alcantara, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huiwen He <hehuiwen@kylinos.cn>
[ Upstream commit 448ba0ae65ca61064183564d2983c9aa59bd6ba7 ]
smb3_zero_range(), smb3_punch_hole(), smb3_insert_range(), and
smb3_collapse_range() modify file contents through server-side range
operations. These operations discard the affected page cache, but leave
the FS-Cache cookie valid, so a later read may return data cached before
the range operation.
Fix this by invalidating FS-Cache after outstanding I/O has completed
and before modifying the file on the server.
Run the following as root on a CIFS mount with fsc enabled and an active
CacheFiles backend:
bash -c '
MNT=/mnt/cifs
FILE="$MNT/repro"
# Generate four 1 MiB random blocks: [A][B][C][D].
dd if=/dev/urandom of=/tmp/src bs=1M count=4 status=none
# Expected contents after zeroing B: [A][zero][C][D].
cp /tmp/src /tmp/expected
dd if=/dev/zero of=/tmp/expected bs=1M seek=1 count=1 \
conv=notrunc status=none
cp /tmp/src "$FILE"
# Populate FS-Cache, then discard the page cache.
sync
echo 1 > /proc/sys/vm/drop_caches
cat "$FILE" > /dev/null
sync
echo 1 > /proc/sys/vm/drop_caches
fallocate --zero-range -o 1M -l 1M "$FILE"
if cmp -s /tmp/expected "$FILE"; then
echo "readback: OK"
else
echo "readback: STALE DATA"
fi
'
Before this change, the readback differs from /tmp/expected:
readback: STALE DATA
After this change, it matches:
readback: OK
Fixes: 30175628bf7f ("[SMB3] Enable fallocate -z support for SMB3 mounts")
Fixes: 31742c5a3317 ("enable fallocate punch hole ("fallocate -p") for SMB3")
Fixes: 5476b5dd82c8 ("cifs: add support for FALLOC_FL_COLLAPSE_RANGE")
Fixes: 7fe6fe95b936 ("cifs: add FALLOC_FL_INSERT_RANGE support")
Signed-off-by: Huiwen He <hehuiwen@kylinos.cn>
Suggested-by: Namjae Jeon <linkinjeon@kernel.org>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/smb2ops.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 3bf0b25feed9e..6ef0fcd9a05c2 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -3524,6 +3524,9 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
if (keep_size == false && !CIFS_CACHE_READ(cifsi))
goto zero_range_exit;
+ fscache_invalidate(cifs_inode_cookie(inode), NULL,
+ i_size_read(inode), 0);
+
rc = smb3_zero_data(file, tcon, offset, len, xid);
if (rc < 0)
goto zero_range_exit;
@@ -3591,6 +3594,8 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
*/
truncate_pagecache_range(inode, offset, offset + len - 1);
netfs_wait_for_outstanding_io(inode);
+ fscache_invalidate(cifs_inode_cookie(inode), NULL,
+ i_size_read(inode), 0);
cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
@@ -3936,6 +3941,7 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
truncate_pagecache_range(inode, off, old_eof);
ictx->zero_point = old_eof;
netfs_wait_for_outstanding_io(inode);
+ fscache_invalidate(cifs_inode_cookie(inode), NULL, old_eof, 0);
rc = __smb2_copychunk_range(xid, cfile, cfile, off + len,
old_eof - off - len, off);
@@ -3998,6 +4004,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
goto out_2;
truncate_pagecache_range(inode, off, old_eof);
netfs_wait_for_outstanding_io(inode);
+ fscache_invalidate(cifs_inode_cookie(inode), NULL, old_eof, 0);
rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid, cfile->pid, new_eof);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 797/869] net: stmmac: fix dma mapping leak in stmmac_tso_xmit()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (795 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 796/869] smb/client: invalidate fscache for fallocate range operations Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 798/869] bpf: check_cond_jmp_op(): properly infer if register is null Greg Kroah-Hartman
` (72 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lorenzo Bianconi, Jakub Kicinski,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
[ Upstream commit a5d946466a95621fa2769720d59ea336003aa1a5 ]
In stmmac_tso_xmit(), if the DMA mapping of an skb fragment fails, the
frame is dropped but the DMA mappings already created for the linear
part and for the fragments mapped before the failure are never
unmapped, leaking DMA mappings.
Fix the leak by walking back over the descriptors used by the frame and
releasing each of them with stmmac_free_tx_buffer(). Moreover, release
the descriptors with stmmac_release_tx_desc() unmapping the DMA buffers.
Fixes: f748be531d70 ("stmmac: support new GMAC4")
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Link: https://patch.msgid.link/20260826-stmmac_dma_unmap_tso-v1-1-a2753d1576ba@oss.qualcomm.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 67 ++++++++++++-------
1 file changed, 43 insertions(+), 24 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 73f079a7cb537..057d23c8d8906 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4087,6 +4087,7 @@ static bool stmmac_vlan_insert(struct stmmac_priv *priv, struct sk_buff *skb,
/**
* stmmac_tso_allocator - close entry point of the driver
* @priv: driver private structure
+ * @entry: TX queue buffer index
* @des: buffer start address
* @total_len: total length to fill in descriptors
* @last_segment: condition for the last descriptor
@@ -4095,8 +4096,9 @@ static bool stmmac_vlan_insert(struct stmmac_priv *priv, struct sk_buff *skb,
* This function fills descriptor and request new descriptors according to
* buffer length to fill
*/
-static void stmmac_tso_allocator(struct stmmac_priv *priv, dma_addr_t des,
- int total_len, bool last_segment, u32 queue)
+static void stmmac_tso_allocator(struct stmmac_priv *priv, u32 *entry,
+ dma_addr_t des, int total_len,
+ bool last_segment, u32 queue)
{
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
struct dma_desc *desc;
@@ -4108,14 +4110,13 @@ static void stmmac_tso_allocator(struct stmmac_priv *priv, dma_addr_t des,
while (tmp_len > 0) {
dma_addr_t curr_addr;
- tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx,
- priv->dma_conf.dma_tx_size);
- WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]);
+ *entry = STMMAC_NEXT_ENTRY(*entry, priv->dma_conf.dma_tx_size);
+ WARN_ON(tx_q->tx_skbuff[*entry]);
if (tx_q->tbs & STMMAC_TBS_AVAIL)
- desc = &tx_q->dma_entx[tx_q->cur_tx].basic;
+ desc = &tx_q->dma_entx[*entry].basic;
else
- desc = &tx_q->dma_tx[tx_q->cur_tx];
+ desc = &tx_q->dma_tx[*entry];
curr_addr = des + (total_len - tmp_len);
stmmac_set_desc_addr(priv, desc, curr_addr);
@@ -4240,7 +4241,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct dma_desc *desc, *first, *mss_desc = NULL;
struct stmmac_priv *priv = netdev_priv(dev);
- unsigned int first_entry, tx_packets;
+ unsigned int first_entry, entry, tx_packets;
struct stmmac_txq_stats *txq_stats;
int i, first_tx, nfrags, ndesc;
struct stmmac_tx_queue *tx_q;
@@ -4315,22 +4316,24 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
}
first_entry = tx_q->cur_tx;
- WARN_ON(tx_q->tx_skbuff[first_entry]);
+ entry = first_entry;
+
+ WARN_ON(tx_q->tx_skbuff[entry]);
if (tx_q->tbs & STMMAC_TBS_AVAIL)
- desc = &tx_q->dma_entx[first_entry].basic;
+ desc = &tx_q->dma_entx[entry].basic;
else
- desc = &tx_q->dma_tx[first_entry];
+ desc = &tx_q->dma_tx[entry];
first = desc;
/* first descriptor: fill Headers on Buf1 */
des = dma_map_single(priv->device, skb->data, skb_headlen(skb),
DMA_TO_DEVICE);
if (dma_mapping_error(priv->device, des))
- goto dma_map_err;
+ goto error;
stmmac_set_desc_addr(priv, first, des);
- stmmac_tso_allocator(priv, des + proto_hdr_len, pay_len,
+ stmmac_tso_allocator(priv, &entry, des + proto_hdr_len, pay_len,
(nfrags == 0), queue);
/* In case two or more DMA transmit descriptors are allocated for this
@@ -4345,10 +4348,10 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
* this DMA buffer right after the DMA engine completely finishes the
* full buffer transmission.
*/
- tx_q->tx_skbuff_dma[tx_q->cur_tx].buf = des;
- tx_q->tx_skbuff_dma[tx_q->cur_tx].len = skb_headlen(skb);
- tx_q->tx_skbuff_dma[tx_q->cur_tx].map_as_page = false;
- tx_q->tx_skbuff_dma[tx_q->cur_tx].buf_type = STMMAC_TXBUF_T_SKB;
+ tx_q->tx_skbuff_dma[entry].buf = des;
+ tx_q->tx_skbuff_dma[entry].len = skb_headlen(skb);
+ tx_q->tx_skbuff_dma[entry].map_as_page = false;
+ tx_q->tx_skbuff_dma[entry].buf_type = STMMAC_TXBUF_T_SKB;
/* Prepare fragments */
for (i = 0; i < nfrags; i++) {
@@ -4358,16 +4361,17 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
skb_frag_size(frag),
DMA_TO_DEVICE);
if (dma_mapping_error(priv->device, des))
- goto dma_map_err;
+ goto error_dma_unmap;
- stmmac_tso_allocator(priv, des, skb_frag_size(frag),
+ stmmac_tso_allocator(priv, &entry, des, skb_frag_size(frag),
(i == nfrags - 1), queue);
- tx_q->tx_skbuff_dma[tx_q->cur_tx].buf = des;
- tx_q->tx_skbuff_dma[tx_q->cur_tx].len = skb_frag_size(frag);
- tx_q->tx_skbuff_dma[tx_q->cur_tx].map_as_page = true;
- tx_q->tx_skbuff_dma[tx_q->cur_tx].buf_type = STMMAC_TXBUF_T_SKB;
+ tx_q->tx_skbuff_dma[entry].buf = des;
+ tx_q->tx_skbuff_dma[entry].len = skb_frag_size(frag);
+ tx_q->tx_skbuff_dma[entry].map_as_page = true;
+ tx_q->tx_skbuff_dma[entry].buf_type = STMMAC_TXBUF_T_SKB;
}
+ tx_q->cur_tx = entry;
tx_q->tx_skbuff_dma[tx_q->cur_tx].last_segment = true;
@@ -4464,7 +4468,22 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
-dma_map_err:
+error_dma_unmap:
+ for (;;) {
+ if (tx_q->tbs & STMMAC_TBS_AVAIL)
+ desc = &tx_q->dma_entx[first_entry].basic;
+ else
+ desc = &tx_q->dma_tx[first_entry];
+ stmmac_release_tx_desc(priv, desc, priv->mode);
+ stmmac_free_tx_buffer(priv, &priv->dma_conf, queue,
+ first_entry);
+ if (first_entry == entry)
+ break;
+
+ first_entry = STMMAC_NEXT_ENTRY(first_entry,
+ priv->dma_conf.dma_tx_size);
+ }
+error:
dev_err(priv->device, "Tx dma map failed\n");
dev_kfree_skb(skb);
priv->xstats.tx_dropped++;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 798/869] bpf: check_cond_jmp_op(): properly infer if register is null
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (796 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 797/869] net: stmmac: fix dma mapping leak in stmmac_tso_xmit() Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 799/869] printk: Dont WARN on kthread_run failure Greg Kroah-Hartman
` (71 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Nicholas Carlini, Eduard Zingerman,
Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <eddyz87@gmail.com>
[ Upstream commit d3ef6c097ba078e1f8c7239d76a0ce8b61e75095 ]
Nicholas Carlini reported a bug when verifier can incorrectly infer
that a pointer is non-null. The bug occurs when two pointers are
compared and one of them has a type w/o PTR_MAYBE_NULL flag,
but which allows a value to be NULL at runtime.
Here is an example:
// `a` is PTR_TO_MEM | MEM_RDONLY | PTR_UNTRUSTED
// `a` is 0 at runtime.
// `b` is PTR_TO_MAP_VALUE | PTR_MAYBE_NULL
void *a = bpf_rdonly_cast(0, 0);
int *b = bpf_map_lookup_elem(...);
if (a == b)
*b = 42; // verifier does not catch null pointer dereference
This happens because of a special case in check_cond_jmp_op(),
which attempts to strip PTR_MAYBE_NULL flags from pointer types,
when processing comparisons like `rA == rB`, if either rA or rB can't
be null.
The non-null property is derived based on the absence of
PTR_MAYBE_NULL flag on rA's or rB's type. But that is not sufficient
for types like PTR_TO_MEM, as in the example.
This patch replaces type_may_be_null() call with reg_not_null(),
which contains an allowlist of types for which absence of
PTR_MAYBE_NULL actually means that the value can't be NULL at runtime.
At the moment, the list in the reg_not_null() omits two types for
which PTR_MAYBE_NULL is applicable: PTR_TO_XDP_SOCK and PTR_TO_BUF.
In order to remain backward compatible, and assuming that only
comparison between pointers of the same type makes sense,
this commit extends reg_not_null(). W/o such an extension e.g.
verifier_jeq_infer_not_null/null_ptr_to_map_value fails.
reg_not_null() can be extended further, but I deem that out of scope
for the fix at hand. Explicit base_type(...) != PTR_TO_BTF_ID
checks in the check_cond_jmp_op() can be removed with migration to
reg_not_null(), but that is a behavioural change, as the special case
would start matching for PTR_TO_BTF_ID that is also is_trusted_reg().
I omit the behavioural change from this commit.
Fixes: befae75856ab ("bpf: propagate nullness information for reg to reg comparisons")
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260826-bug-029-bad-non-null-inference-v2-1-136789ace9e9@localhost
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/verifier.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index dd766eefbf027..ecd8595bd5450 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -405,6 +405,8 @@ static bool reg_not_null(const struct bpf_reg_state *reg)
type = base_type(type);
return type == PTR_TO_SOCKET ||
type == PTR_TO_TCP_SOCK ||
+ type == PTR_TO_XDP_SOCK ||
+ type == PTR_TO_BUF ||
type == PTR_TO_MAP_VALUE ||
type == PTR_TO_MAP_KEY ||
type == PTR_TO_SOCK_COMMON ||
@@ -16057,7 +16059,6 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
*/
if (!is_jmp32 && BPF_SRC(insn->code) == BPF_X &&
__is_pointer_value(false, src_reg) && __is_pointer_value(false, dst_reg) &&
- type_may_be_null(src_reg->type) != type_may_be_null(dst_reg->type) &&
base_type(src_reg->type) != PTR_TO_BTF_ID &&
base_type(dst_reg->type) != PTR_TO_BTF_ID) {
eq_branch_regs = NULL;
@@ -16073,9 +16074,11 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
break;
}
if (eq_branch_regs) {
- if (type_may_be_null(src_reg->type))
+ /* src == dst && dst != NULL => src != NULL */
+ if (reg_not_null(dst_reg) && type_may_be_null(src_reg->type))
mark_ptr_not_null_reg(&eq_branch_regs[insn->src_reg]);
- else
+ /* src == dst && src != NULL => dst != NULL */
+ if (reg_not_null(src_reg) && type_may_be_null(dst_reg->type))
mark_ptr_not_null_reg(&eq_branch_regs[insn->dst_reg]);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 799/869] printk: Dont WARN on kthread_run failure.
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (797 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 798/869] bpf: check_cond_jmp_op(): properly infer if register is null Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 800/869] drm/gud: validate GUD_ROTATION_0 is present in supported rotations Greg Kroah-Hartman
` (70 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+1ebbc20f223b99446034,
Tetsuo Handa, John Ogness, Petr Mladek, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
[ Upstream commit 72dd0ec09e7cc98ed58ddeac26575e5d1ab8a93d ]
Since __kthread_create_on_node() returns -EINTR upon SIGKILL,
we should not use WARN_ON() in order to catch kthread_run() failure.
Reported-by: syzbot+1ebbc20f223b99446034@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=1ebbc20f223b99446034
Fixes: 5f53ca3ff83b ("printk: Implement legacy printer kthread for PREEMPT_RT")
Fixes: 76f258bf3f2a ("printk: nbcon: Introduce printer kthreads")
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Reviewed-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://patch.msgid.link/76bb4c1c-5d85-4635-b3bb-fc06f292c59e@I-love.SAKURA.ne.jp
Signed-off-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/printk/nbcon.c | 2 +-
kernel/printk/printk.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index df7769c4fb0f2..a947b1a75cce3 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1333,7 +1333,7 @@ bool nbcon_kthread_create(struct console *con)
return true;
kt = kthread_run(nbcon_kthread_func, con, "pr/%s%d", con->name, con->index);
- if (WARN_ON(IS_ERR(kt))) {
+ if (IS_ERR(kt)) {
con_printk(KERN_ERR, con, "failed to start printing thread\n");
return false;
}
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 1c5c26168cefd..d5c1dff1617c4 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3638,7 +3638,7 @@ static bool legacy_kthread_create(void)
lockdep_assert_console_list_lock_held();
kt = kthread_run(legacy_kthread_func, NULL, "pr/legacy");
- if (WARN_ON(IS_ERR(kt))) {
+ if (IS_ERR(kt)) {
pr_err("failed to start legacy printing thread\n");
return false;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 800/869] drm/gud: validate GUD_ROTATION_0 is present in supported rotations
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (798 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 799/869] printk: Dont WARN on kthread_run failure Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 801/869] drm/virtio: Use drm_gem_plane_helper_prepare_fb() Greg Kroah-Hartman
` (69 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+efe2810681f1b065d3a8,
Sajal Gupta, Ruben Wauters, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sajal Gupta <sajal2005gupta@gmail.com>
[ Upstream commit cb732d027aa18e1fcf9d2797f47d20b179ebc59c ]
The rotation argument to drm_plane_create_rotation_property() is set to
DRM_MODE_ROTATE_0, and the device reported rotation bitmask is used as
the supported_rotations argument. The driver never validates that
GUD_ROTATION_0 is present, so a device that omits it from its
GUD_PROPERTY_ROTATION triggers the
WARN_ON(rotation & ~supported_rotations) in
drm_plane_create_rotation_property()
Fix this by skipping the creation of rotation property if the device
doesn't have the GUD_ROTATION_0 bit
Fixes: 40e1a70b4aed ("drm: Add GUD USB Display driver")
Reported-by: syzbot+efe2810681f1b065d3a8@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=efe2810681f1b065d3a8
Tested-by: syzbot+efe2810681f1b065d3a8@syzkaller.appspotmail.com
Signed-off-by: Sajal Gupta <sajal2005gupta@gmail.com>
Acked-by: Ruben Wauters <rubenru09@aol.com>
Signed-off-by: Ruben Wauters <rubenru09@aol.com>
Link: https://patch.msgid.link/20260821071812.16500-1-sajal2005gupta@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/gud/gud_drv.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c
index f1200a2ef8801..065d52895bfb7 100644
--- a/drivers/gpu/drm/gud/gud_drv.c
+++ b/drivers/gpu/drm/gud/gud_drv.c
@@ -288,6 +288,8 @@ static int gud_get_properties(struct gud_device *gdrm)
* but mask out any additions on future devices.
*/
val &= GUD_ROTATION_MASK;
+ if (!(val & GUD_ROTATION_0))
+ continue;
ret = drm_plane_create_rotation_property(&gdrm->pipe.plane,
DRM_MODE_ROTATE_0, val);
break;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 801/869] drm/virtio: Use drm_gem_plane_helper_prepare_fb()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (799 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 800/869] drm/gud: validate GUD_ROTATION_0 is present in supported rotations Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 802/869] drm/virtio: Add a helper to map and note the dma addrs and lengths Greg Kroah-Hartman
` (68 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dongwon Kim, Dmitry Osipenko,
Vivek Kasireddy, Rob Clark, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dongwon Kim <dongwon.kim@intel.com>
[ Upstream commit 30f86b8f86ada845fbd0d853b3a3d238567ac2c2 ]
Use drm_gem_plane_helper_prepare_fb() helper for explicit framebuffer
synchronization. We need to wait for explicit fences in a case of
Venus and native contexts when guest user space uses explicit fencing.
Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
[dmitry.osipenko@collabora.com: edit commit message]
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Acked-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
Reviewed-by: Rob Clark <robdclark@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241020230803.247419-1-dmitry.osipenko@collabora.com
Stable-dep-of: 6a736d2f9d0c ("drm/virtio: use the DMA API for resource backing on Xen")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/virtio/virtgpu_plane.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c
index 7a091beddaef9..d59f11b781866 100644
--- a/drivers/gpu/drm/virtio/virtgpu_plane.c
+++ b/drivers/gpu/drm/virtio/virtgpu_plane.c
@@ -26,6 +26,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_gem_atomic_helper.h>
#include "virtgpu_drv.h"
@@ -276,6 +277,9 @@ static int virtio_gpu_plane_prepare_fb(struct drm_plane *plane,
vgfb = to_virtio_gpu_framebuffer(new_state->fb);
vgplane_st = to_virtio_gpu_plane_state(new_state);
bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
+
+ drm_gem_plane_helper_prepare_fb(plane, new_state);
+
if (!bo || (plane->type == DRM_PLANE_TYPE_PRIMARY && !bo->guest_blob))
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 802/869] drm/virtio: Add a helper to map and note the dma addrs and lengths
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (800 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 801/869] drm/virtio: Use drm_gem_plane_helper_prepare_fb() Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 803/869] drm/virtio: use the DMA API for resource backing on Xen Greg Kroah-Hartman
` (67 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Gerd Hoffmann, Dmitry Osipenko,
Rob Clark, Gurchetan Singh, Chia-I Wu, Vivek Kasireddy,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vivek Kasireddy <vivek.kasireddy@intel.com>
[ Upstream commit 25c3fd1183c0631d67cd126b2ba3e48388e15204 ]
This helper would be used when first initializing the object as
part of import and also when updating the plane where we need to
ensure that the imported object's backing is valid.
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Cc: Rob Clark <robdclark@gmail.com>
Cc: Gurchetan Singh <gurchetansingh@chromium.org>
Cc: Chia-I Wu <olvaffe@gmail.com>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
Tested-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Reviewed-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241126031643.3490496-3-vivek.kasireddy@intel.com
Stable-dep-of: 6a736d2f9d0c ("drm/virtio: use the DMA API for resource backing on Xen")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/virtio/virtgpu_drv.h | 5 +++
drivers/gpu/drm/virtio/virtgpu_prime.c | 42 ++++++++++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index ca0f7dcc99a25..c73fbb239ddc4 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -89,6 +89,7 @@ struct virtio_gpu_object_params {
struct virtio_gpu_object {
struct drm_gem_shmem_object base;
+ struct sg_table *sgt;
uint32_t hw_res_handle;
bool dumb;
bool created;
@@ -476,6 +477,10 @@ struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev,
struct drm_gem_object *virtgpu_gem_prime_import_sg_table(
struct drm_device *dev, struct dma_buf_attachment *attach,
struct sg_table *sgt);
+int virtgpu_dma_buf_import_sgt(struct virtio_gpu_mem_entry **ents,
+ unsigned int *nents,
+ struct virtio_gpu_object *bo,
+ struct dma_buf_attachment *attach);
/* virtgpu_debugfs.c */
void virtio_gpu_debugfs_init(struct drm_minor *minor);
diff --git a/drivers/gpu/drm/virtio/virtgpu_prime.c b/drivers/gpu/drm/virtio/virtgpu_prime.c
index 44425f20d91aa..8e63aa67270af 100644
--- a/drivers/gpu/drm/virtio/virtgpu_prime.c
+++ b/drivers/gpu/drm/virtio/virtgpu_prime.c
@@ -27,6 +27,8 @@
#include "virtgpu_drv.h"
+MODULE_IMPORT_NS(DMA_BUF);
+
static int virtgpu_virtio_get_uuid(struct dma_buf *buf,
uuid_t *uuid)
{
@@ -142,6 +144,46 @@ struct dma_buf *virtgpu_gem_prime_export(struct drm_gem_object *obj,
return buf;
}
+int virtgpu_dma_buf_import_sgt(struct virtio_gpu_mem_entry **ents,
+ unsigned int *nents,
+ struct virtio_gpu_object *bo,
+ struct dma_buf_attachment *attach)
+{
+ struct scatterlist *sl;
+ struct sg_table *sgt;
+ long i, ret;
+
+ dma_resv_assert_held(attach->dmabuf->resv);
+
+ ret = dma_resv_wait_timeout(attach->dmabuf->resv,
+ DMA_RESV_USAGE_KERNEL,
+ false, MAX_SCHEDULE_TIMEOUT);
+ if (ret <= 0)
+ return ret < 0 ? ret : -ETIMEDOUT;
+
+ sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sgt))
+ return PTR_ERR(sgt);
+
+ *ents = kvmalloc_array(sgt->nents,
+ sizeof(struct virtio_gpu_mem_entry),
+ GFP_KERNEL);
+ if (!(*ents)) {
+ dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+ return -ENOMEM;
+ }
+
+ *nents = sgt->nents;
+ for_each_sgtable_dma_sg(sgt, sl, i) {
+ (*ents)[i].addr = cpu_to_le64(sg_dma_address(sl));
+ (*ents)[i].length = cpu_to_le32(sg_dma_len(sl));
+ (*ents)[i].padding = 0;
+ }
+
+ bo->sgt = sgt;
+ return 0;
+}
+
struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev,
struct dma_buf *buf)
{
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 803/869] drm/virtio: use the DMA API for resource backing on Xen
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (801 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 802/869] drm/virtio: Add a helper to map and note the dma addrs and lengths Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 804/869] functionfs: fix the open/removal races Greg Kroah-Hartman
` (66 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ben Leggett, Dmitry Osipenko,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Leggett <benjamin@edera.io>
[ Upstream commit 6a736d2f9d0c6e6217fe7532bc4c50ceca71db78 ]
On a Xen PV domain page addresses bear no relation to the real machine
addresses the host would have to use to reach it.
virtio_ring.c handles this correctly, vring_use_map_api() returns true
for any xen_domain() regardless of VIRTIO_F_ACCESS_PLATFORM.
virtio-gpu makes the same decision independently, but its copy
looks only at the feature bit:
bool use_dma_api = !virtio_has_dma_quirk(vgdev->vdev);
QEMU does not set iommu_platform on virtio-vga by default, so
VIRTIO_F_ACCESS_PLATFORM is not negotiated, use_dma_api is false, and
virtio_gpu_object_shmem_init() describes the framebuffer's backing pages
to the host with sg_phys(). Those are guest-physical addresses. In a PV
domain they resolve, on the host side, to pages belonging to some other
domain, so the host scans out unrelated memory.
Move the decision into virtio_gpu_use_dma_api() and give it the
xen_domain() check, like vring_use_map_api() has. This
additionally enables the dma_sync_sgtable_for_device() calls in
virtgpu_vq.c, which are required for correctness whenever swiotlb
is in play.
Reproduced with a Xen 4.21 PV dom0 nested inside QEMU 8.2 with
virtio-vga, on both a distro 6.8 kernel and 6.18 LTS. A PVH dom0
works fine and doesn't need this fix because it is identity-mapped,
only PV dom0s are affected.
Fixes: a3b815f09bb8 ("drm/virtio: add iommu support.")
Signed-off-by: Ben Leggett <benjamin@edera.io>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Link: https://patch.msgid.link/20260806-virtgpu-xen-dma-v1-1-e499b345bbad@edera.io
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpu/drm/virtio/virtgpu_drv.h | 20 ++++++++++++++++++++
drivers/gpu/drm/virtio/virtgpu_object.c | 2 +-
drivers/gpu/drm/virtio/virtgpu_vq.c | 4 ++--
3 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index c73fbb239ddc4..a597c73a2bf1a 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -43,6 +43,8 @@
#include <drm/drm_probe_helper.h>
#include <drm/virtgpu_drm.h>
+#include <xen/xen.h>
+
#define DRIVER_NAME "virtio_gpu"
#define DRIVER_DESC "virtio GPU"
#define DRIVER_DATE "0"
@@ -61,6 +63,24 @@
/* See virtio_gpu_ctx_create. One additional character for NULL terminator. */
#define DEBUG_NAME_MAX_LEN 65
+/*
+ * Whether the host must be told about resource backing pages by DMA address
+ * rather than guest-physical address.
+ *
+ * This mirrors vring_use_map_api() in drivers/virtio/virtio_ring.c, including
+ * its xen_domain() case.
+ */
+static inline bool virtio_gpu_use_dma_api(const struct virtio_device *vdev)
+{
+ if (!virtio_has_dma_quirk(vdev))
+ return true;
+
+ if (xen_domain())
+ return true;
+
+ return false;
+}
+
struct virtio_gpu_object_params {
unsigned long size;
bool dumb;
diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
index c7e74cf130221..c4f8cdf85f60a 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -137,7 +137,7 @@ static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev,
struct virtio_gpu_mem_entry **ents,
unsigned int *nents)
{
- bool use_dma_api = !virtio_has_dma_quirk(vgdev->vdev);
+ bool use_dma_api = virtio_gpu_use_dma_api(vgdev->vdev);
struct scatterlist *sg;
struct sg_table *pages;
int si;
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
index 4369275cb56b5..9bf7e69b85aa6 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -601,7 +601,7 @@ void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev,
struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(objs->objs[0]);
struct virtio_gpu_transfer_to_host_2d *cmd_p;
struct virtio_gpu_vbuffer *vbuf;
- bool use_dma_api = !virtio_has_dma_quirk(vgdev->vdev);
+ bool use_dma_api = virtio_gpu_use_dma_api(vgdev->vdev);
if (virtio_gpu_is_shmem(bo) && use_dma_api)
dma_sync_sgtable_for_device(vgdev->vdev->dev.parent,
@@ -1020,7 +1020,7 @@ void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev,
struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(objs->objs[0]);
struct virtio_gpu_transfer_host_3d *cmd_p;
struct virtio_gpu_vbuffer *vbuf;
- bool use_dma_api = !virtio_has_dma_quirk(vgdev->vdev);
+ bool use_dma_api = virtio_gpu_use_dma_api(vgdev->vdev);
if (virtio_gpu_is_shmem(bo) && use_dma_api)
dma_sync_sgtable_for_device(vgdev->vdev->dev.parent,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 804/869] functionfs: fix the open/removal races
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (802 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 803/869] drm/virtio: use the DMA API for resource backing on Xen Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 805/869] ACPI: platform: Use acpi_bus_get_primary_device() Greg Kroah-Hartman
` (65 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Al Viro, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Al Viro <viro@zeniv.linux.org.uk>
[ Upstream commit e5bf5ee266633cb18fff6f98f0b7d59a62819eee ]
ffs_epfile_open() can race with removal, ending up with file->private_data
pointing to freed object.
There is a total count of opened files on functionfs (both ep0 and
dynamic ones) and when it hits zero, dynamic files get removed.
Unfortunately, that removal can happen while another thread is
in ffs_epfile_open(), but has not incremented the count yet.
In that case open will succeed, leaving us with UAF on any subsequent
read() or write().
The root cause is that ffs->opened is misused; atomic_dec_and_test() vs.
atomic_add_return() is not a good idea, when object remains visible all
along.
To untangle that
* serialize openers on ffs->mutex (both for ep0 and for dynamic files)
* have dynamic ones use atomic_inc_not_zero() and fail if we had
zero ->opened; in that case the file we are opening is doomed.
* have the inodes of dynamic files marked on removal (from the
callback of simple_recursive_removal()) - clear ->i_private there.
* have open of dynamic ones verify they hadn't been already removed,
along with checking that state is FFS_ACTIVE.
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/usb/gadget/function/f_fs.c | 55 ++++++++++++++++++++++++------
1 file changed, 44 insertions(+), 11 deletions(-)
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 489054d369537..8bad59b4242c6 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -649,13 +649,22 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
static int ffs_ep0_open(struct inode *inode, struct file *file)
{
- struct ffs_data *ffs = inode->i_private;
+ struct ffs_data *ffs = inode->i_sb->s_fs_info;
+ int ret;
- if (ffs->state == FFS_CLOSING)
- return -EBUSY;
+ /* Acquire mutex */
+ ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
+ if (ret < 0)
+ return ret;
- file->private_data = ffs;
ffs_data_opened(ffs);
+ if (ffs->state == FFS_CLOSING) {
+ ffs_data_closed(ffs);
+ mutex_unlock(&ffs->mutex);
+ return -EBUSY;
+ }
+ mutex_unlock(&ffs->mutex);
+ file->private_data = ffs;
return stream_open(inode, file);
}
@@ -1212,14 +1221,34 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
static int
ffs_epfile_open(struct inode *inode, struct file *file)
{
- struct ffs_epfile *epfile = inode->i_private;
+ struct ffs_data *ffs = inode->i_sb->s_fs_info;
+ struct ffs_epfile *epfile;
+ int ret;
- if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+ /* Acquire mutex */
+ ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
+ if (ret < 0)
+ return ret;
+
+ if (!atomic_inc_not_zero(&ffs->opened)) {
+ mutex_unlock(&ffs->mutex);
return -ENODEV;
+ }
+ ffs_data_get(ffs);
+ /*
+ * we want the state to be FFS_ACTIVE; FFS_ACTIVE alone is
+ * not enough, though - we might have been through FFS_CLOSING
+ * and back to FFS_ACTIVE, with our file already removed.
+ */
+ epfile = smp_load_acquire(&inode->i_private);
+ if (unlikely(ffs->state != FFS_ACTIVE || !epfile)) {
+ mutex_unlock(&ffs->mutex);
+ ffs_data_closed(ffs);
+ return -ENODEV;
+ }
+ mutex_unlock(&ffs->mutex);
file->private_data = epfile;
- ffs_data_opened(epfile->ffs);
-
return stream_open(inode, file);
}
@@ -1368,7 +1397,7 @@ static void ffs_dmabuf_put(struct dma_buf_attachment *attach)
static int
ffs_epfile_release(struct inode *inode, struct file *file)
{
- struct ffs_epfile *epfile = inode->i_private;
+ struct ffs_epfile *epfile = file->private_data;
struct ffs_dmabuf_priv *priv, *tmp;
struct ffs_data *ffs = epfile->ffs;
@@ -2413,6 +2442,11 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
return 0;
}
+static void clear_one(struct dentry *dentry)
+{
+ smp_store_release(&dentry->d_inode->i_private, NULL);
+}
+
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
{
struct ffs_epfile *epfile = epfiles;
@@ -2421,8 +2455,7 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
BUG_ON(mutex_is_locked(&epfile->mutex));
__ffs_epfile_read_buffer_free(epfile);
if (epfile->dentry) {
- d_delete(epfile->dentry);
- dput(epfile->dentry);
+ simple_recursive_removal(epfile->dentry, clear_one);
epfile->dentry = NULL;
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 805/869] ACPI: platform: Use acpi_bus_get_primary_device()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (803 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 804/869] functionfs: fix the open/removal races Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 806/869] KVM: nSVM: Triple fault if restore host CR3 fails on nested #VMEXIT Greg Kroah-Hartman
` (64 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Rafael J. Wysocki, Andy Shevchenko,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
[ Upstream commit a9ba4dd2f18bf3f439d9ef0d8f375f90360ba1bd ]
The acpi_get_first_physical_node() usage in acpi_platform_fill_resource()
and acpi_create_platform_device() is generally unsafe because in theory
the device returned by it may be freed at any time [1].
It is also inefficient because acpi_get_first_physical_node() is called
multiple times for the same argument which can be avoided.
Address these issues by using acpi_bus_get_primary_device() instead of
acpi_get_first_physical_node() and adjusting the code to call it just
once at the beginning of and acpi_create_platform_device() and drop
the device reference acquired by it upon the return from that function.
Fixes: 3b95bd160547 ("ACPI: introduce a function to find the first physical device")
Fixes: a252d881c558 ("ACPI / platform: Pay attention to parent device's resources")
Link: https://sashiko.dev/#/patchset/12955541.O9o76ZdvQC%40rafael.j.wysocki [1]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://patch.msgid.link/3436112.aeNJFYEL58@rafael.j.wysocki
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/acpi/acpi_platform.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 48d15dd785f6e..affa076a211da 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -71,18 +71,15 @@ static struct notifier_block acpi_platform_notifier = {
.notifier_call = acpi_platform_device_remove_notify,
};
-static void acpi_platform_fill_resource(struct acpi_device *adev,
- const struct resource *src, struct resource *dest)
+static void acpi_platform_fill_resource(struct device *parent,
+ const struct resource *src,
+ struct resource *dest)
{
- struct device *parent;
-
*dest = *src;
-
/*
* If the device has parent we need to take its resources into
* account as well because this device might consume part of those.
*/
- parent = acpi_get_first_physical_node(acpi_dev_parent(adev));
if (parent && dev_is_pci(parent))
dest->parent = pci_find_resource(to_pci_dev(parent), dest);
}
@@ -110,7 +107,8 @@ static unsigned int acpi_platform_resource_count(struct acpi_resource *ares, voi
struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
const struct property_entry *properties)
{
- struct acpi_device *parent = acpi_dev_parent(adev);
+ struct acpi_device *p = acpi_dev_parent(adev);
+ struct device *parent __free(put_device) = acpi_bus_get_primary_device(p);
struct platform_device *pdev = NULL;
struct platform_device_info pdevinfo;
const struct acpi_device_id *match;
@@ -149,7 +147,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
}
count = 0;
list_for_each_entry(rentry, &resource_list, node)
- acpi_platform_fill_resource(adev, rentry->res,
+ acpi_platform_fill_resource(parent, rentry->res,
&resources[count++]);
acpi_dev_free_resource_list(&resource_list);
@@ -161,7 +159,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
* attached to it, that physical device should be the parent of the
* platform device we are about to create.
*/
- pdevinfo.parent = parent ? acpi_get_first_physical_node(parent) : NULL;
+ pdevinfo.parent = parent;
pdevinfo.name = dev_name(&adev->dev);
pdevinfo.id = PLATFORM_DEVID_NONE;
pdevinfo.res = resources;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 806/869] KVM: nSVM: Triple fault if restore host CR3 fails on nested #VMEXIT
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (804 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 805/869] ACPI: platform: Use acpi_bus_get_primary_device() Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 807/869] greybus: raw: fix use-after-free if write is called after disconnect Greg Kroah-Hartman
` (63 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yosry Ahmed, Sean Christopherson,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yosry Ahmed <yosry@kernel.org>
[ Upstream commit 5d291ef0585ed880ed4dd71ea1a5965e0a65fb53 ]
If loading L1's CR3 fails on a nested #VMEXIT, nested_svm_vmexit()
returns an error code that is ignored by most callers, and continues to
run L1 with corrupted state. A sane recovery is not possible in this
case, and HW behavior is to cause a shutdown. Inject a triple fault
instead, and do not return early from nested_svm_vmexit(). Continue
cleaning up the vCPU state (e.g. clear pending exceptions), to handle
the failure as gracefully as possible.
>From the APM:
Upon #VMEXIT, the processor performs the following actions in order to
return to the host execution context:
...
if (illegal host state loaded, or exception while loading host state)
shutdown
else
execute first host instruction following the VMRUN
Remove the return value of nested_svm_vmexit(), which is mostly
unchecked anyway.
Fixes: d82aaef9c88a ("KVM: nSVM: use nested_svm_load_cr3() on guest->host switch")
CC: stable@vger.kernel.org
Signed-off-by: Yosry Ahmed <yosry@kernel.org>
Link: https://patch.msgid.link/20260303003421.2185681-10-yosry@kernel.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/svm/nested.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index 636f0354fa815..4aee865718fe3 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -1163,9 +1163,8 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
nested_svm_uninit_mmu_context(vcpu);
- rc = nested_svm_load_cr3(vcpu, vmcb01->save.cr3, false, true);
- if (rc)
- return 1;
+ if (nested_svm_load_cr3(vcpu, vmcb01->save.cr3, false, true))
+ kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
/*
* Drop what we picked up for L2 via svm_complete_interrupts() so it
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 807/869] greybus: raw: fix use-after-free if write is called after disconnect
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (805 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 806/869] KVM: nSVM: Triple fault if restore host CR3 fails on nested #VMEXIT Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 808/869] firmware: arm_ffa: Add support for IMPDEF value in the memory access descriptor Greg Kroah-Hartman
` (62 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Johan Hovold, Damien Riégel,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Damien Riégel <damien.riegel@silabs.com>
[ Upstream commit 84265cbd96b97058ef67e3f8be3933667a000835 ]
If a user writes to the chardev after disconnect has been called, the
kernel panics with the following trace (with
CONFIG_INIT_ON_FREE_DEFAULT_ON=y):
BUG: kernel NULL pointer dereference, address: 0000000000000218
...
Call Trace:
<TASK>
gb_operation_create_common+0x61/0x180
gb_operation_create_flags+0x28/0xa0
gb_operation_sync_timeout+0x6f/0x100
raw_write+0x7b/0xc7 [gb_raw]
vfs_write+0xcf/0x420
? task_mm_cid_work+0x136/0x220
ksys_write+0x63/0xe0
do_syscall_64+0xa4/0x290
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Disconnect calls gb_connection_destroy, which ends up freeing the
connection object. When gb_operation_sync is called in the write file
operations, its gets a freed connection as parameter and the kernel
panics.
The gb_connection_destroy cannot be moved out of the disconnect
function, as the Greybus subsystem expect all connections belonging to a
bundle to be destroyed when disconnect returns.
To prevent this bug, use a rw lock to synchronize access between write
and disconnect. This guarantees that the write function doesn't try
to use a disconnected connection.
Fixes: e806c7fb8e9b ("greybus: raw: add raw greybus kernel driver")
Reviewed-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Damien Riégel <damien.riegel@silabs.com>
Link: https://patch.msgid.link/20260324140039.40001-2-damien.riegel@silabs.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/staging/greybus/raw.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/greybus/raw.c b/drivers/staging/greybus/raw.c
index e668438e1a2c4..d0fd15af22baa 100644
--- a/drivers/staging/greybus/raw.c
+++ b/drivers/staging/greybus/raw.c
@@ -21,6 +21,8 @@ struct gb_raw {
struct list_head list;
int list_data;
struct mutex list_lock;
+ struct rw_semaphore disconnect_lock;
+ bool disconnected;
struct cdev cdev;
struct device dev;
};
@@ -200,6 +202,7 @@ static int gb_raw_probe(struct gb_bundle *bundle,
INIT_LIST_HEAD(&raw->list);
mutex_init(&raw->list_lock);
+ init_rwsem(&raw->disconnect_lock);
raw->connection = connection;
greybus_set_drvdata(bundle, raw);
@@ -235,6 +238,11 @@ static void gb_raw_disconnect(struct gb_bundle *bundle)
struct raw_data *temp;
cdev_device_del(&raw->cdev, &raw->dev);
+
+ down_write(&raw->disconnect_lock);
+ raw->disconnected = true;
+ up_write(&raw->disconnect_lock);
+
gb_connection_disable(connection);
gb_connection_destroy(connection);
@@ -277,11 +285,22 @@ static ssize_t raw_write(struct file *file, const char __user *buf,
if (count > MAX_PACKET_SIZE)
return -E2BIG;
+ down_read(&raw->disconnect_lock);
+
+ if (raw->disconnected) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
retval = gb_raw_send(raw, count, buf);
if (retval)
- return retval;
+ goto exit;
- return count;
+ retval = count;
+exit:
+ up_read(&raw->disconnect_lock);
+
+ return retval;
}
static ssize_t raw_read(struct file *file, char __user *buf, size_t count,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 808/869] firmware: arm_ffa: Add support for IMPDEF value in the memory access descriptor
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (806 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 807/869] greybus: raw: fix use-after-free if write is called after disconnect Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 809/869] firmware: arm_ffa: Fix Endpoint Memory Access Descriptor offset calculation Greg Kroah-Hartman
` (61 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Lixiang Mao, Sudeep Holla,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sudeep Holla <sudeep.holla@arm.com>
[ Upstream commit 11fb1a82aefa6f7fea6ac82334edb5639b9927df ]
FF-A v1.2 introduced 16 byte IMPLEMENTATION DEFINED value in the endpoint
memory access descriptor to allow any sender could to specify an its any
custom value for each receiver. Also this value must be specified by the
receiver when retrieving the memory region. The sender must ensure it
informs the receiver of this value via an IMPLEMENTATION DEFINED mechanism
such as a partition message.
So the FF-A driver can use the message interfaces to communicate the value
and set the same in the ffa_mem_region_attributes structures when using
the memory interfaces.
The driver ensure that the size of the endpoint memory access descriptors
is set correctly based on the FF-A version.
Fixes: 9fac08d9d985 ("firmware: arm_ffa: Upgrade FF-A version to v1.2 in the driver")
Reported-by: Lixiang Mao <liximao@qti.qualcomm.com>
Tested-by: Lixiang Mao <liximao@qti.qualcomm.com>
Message-Id: <20250923150927.1218364-1-sudeep.holla@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Stable-dep-of: b4d961351aa8 ("firmware: arm_ffa: Fix Endpoint Memory Access Descriptor offset calculation")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/firmware/arm_ffa/driver.c | 39 ++++++++++++++++++++++---------
include/linux/arm_ffa.h | 22 +++++++++++++++--
2 files changed, 48 insertions(+), 13 deletions(-)
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index 58939ca2d7dfa..8216c8e233844 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -613,6 +613,26 @@ static u16 ffa_memory_attributes_get(u32 func_id)
return FFA_MEM_NORMAL | FFA_MEM_WRITE_BACK | FFA_MEM_INNER_SHAREABLE;
}
+static void ffa_emad_impdef_value_init(u32 version, void *dst, void *src)
+{
+ struct ffa_mem_region_attributes *ep_mem_access;
+
+ if (FFA_EMAD_HAS_IMPDEF_FIELD(version))
+ memcpy(dst, src, sizeof(ep_mem_access->impdef_val));
+}
+
+static void
+ffa_mem_region_additional_setup(u32 version, struct ffa_mem_region *mem_region)
+{
+ if (!FFA_MEM_REGION_HAS_EP_MEM_OFFSET(version)) {
+ mem_region->ep_mem_size = 0;
+ } else {
+ mem_region->ep_mem_size = ffa_emad_size_get(version);
+ mem_region->ep_mem_offset = sizeof(*mem_region);
+ memset(mem_region->reserved, 0, 12);
+ }
+}
+
static int
ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
struct ffa_mem_ops_args *args)
@@ -631,26 +651,23 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
mem_region->flags = args->flags;
mem_region->sender_id = drv_info->vm_id;
mem_region->attributes = ffa_memory_attributes_get(func_id);
- ep_mem_access = buffer +
- ffa_mem_desc_offset(buffer, 0, drv_info->version);
composite_offset = ffa_mem_desc_offset(buffer, args->nattrs,
drv_info->version);
- for (idx = 0; idx < args->nattrs; idx++, ep_mem_access++) {
- memset(ep_mem_access, 0, sizeof(*ep_mem_access));
+ for (idx = 0; idx < args->nattrs; idx++) {
+ ep_mem_access = buffer +
+ ffa_mem_desc_offset(buffer, idx, drv_info->version);
+ memset(ep_mem_access, 0, ffa_emad_size_get(drv_info->version));
ep_mem_access->receiver = args->attrs[idx].receiver;
ep_mem_access->attrs = args->attrs[idx].attrs;
ep_mem_access->composite_off = composite_offset;
+ ffa_emad_impdef_value_init(drv_info->version,
+ ep_mem_access->impdef_val,
+ args->attrs[idx].impdef_val);
}
mem_region->handle = 0;
mem_region->ep_count = args->nattrs;
- if (drv_info->version <= FFA_VERSION_1_0) {
- mem_region->ep_mem_size = 0;
- } else {
- mem_region->ep_mem_size = sizeof(*ep_mem_access);
- mem_region->ep_mem_offset = sizeof(*mem_region);
- memset(mem_region->reserved, 0, 12);
- }
+ ffa_mem_region_additional_setup(drv_info->version, mem_region);
composite = buffer + composite_offset;
composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg);
diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h
index 53f2837ce7df4..ef84fb843610c 100644
--- a/include/linux/arm_ffa.h
+++ b/include/linux/arm_ffa.h
@@ -112,6 +112,7 @@
FIELD_PREP(FFA_MINOR_VERSION_MASK, (minor)))
#define FFA_VERSION_1_0 FFA_PACK_VERSION_INFO(1, 0)
#define FFA_VERSION_1_1 FFA_PACK_VERSION_INFO(1, 1)
+#define FFA_VERSION_1_2 FFA_PACK_VERSION_INFO(1, 2)
/**
* FF-A specification mentions explicitly about '4K pages'. This should
@@ -326,6 +327,7 @@ struct ffa_mem_region_attributes {
* an `struct ffa_mem_region_addr_range`.
*/
u32 composite_off;
+ u8 impdef_val[16];
u64 reserved;
};
@@ -405,15 +407,31 @@ struct ffa_mem_region {
#define CONSTITUENTS_OFFSET(x) \
(offsetof(struct ffa_composite_mem_region, constituents[x]))
+#define FFA_EMAD_HAS_IMPDEF_FIELD(version) ((version) >= FFA_VERSION_1_2)
+#define FFA_MEM_REGION_HAS_EP_MEM_OFFSET(version) ((version) > FFA_VERSION_1_0)
+
+static inline u32 ffa_emad_size_get(u32 ffa_version)
+{
+ u32 sz;
+ struct ffa_mem_region_attributes *ep_mem_access;
+
+ if (FFA_EMAD_HAS_IMPDEF_FIELD(ffa_version))
+ sz = sizeof(*ep_mem_access);
+ else
+ sz = sizeof(*ep_mem_access) - sizeof(ep_mem_access->impdef_val);
+
+ return sz;
+}
+
static inline u32
ffa_mem_desc_offset(struct ffa_mem_region *buf, int count, u32 ffa_version)
{
- u32 offset = count * sizeof(struct ffa_mem_region_attributes);
+ u32 offset = count * ffa_emad_size_get(ffa_version);
/*
* Earlier to v1.1, the endpoint memory descriptor array started at
* offset 32(i.e. offset of ep_mem_offset in the current structure)
*/
- if (ffa_version <= FFA_VERSION_1_0)
+ if (!FFA_MEM_REGION_HAS_EP_MEM_OFFSET(ffa_version))
offset += offsetof(struct ffa_mem_region, ep_mem_offset);
else
offset += sizeof(struct ffa_mem_region);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 809/869] firmware: arm_ffa: Fix Endpoint Memory Access Descriptor offset calculation
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (807 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 808/869] firmware: arm_ffa: Add support for IMPDEF value in the memory access descriptor Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 810/869] pmdomain: imx93-blk-ctrl: Extract PHY as shared domain for DSI/CSI Greg Kroah-Hartman
` (60 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sudeep Holla, Mostafa Saleh,
Sebastian Ene, Marc Zyngier, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sebastian Ene <sebastianene@google.com>
[ Upstream commit b4d961351aa84fdf0148783fb1f3a1391b8a0adb ]
Use the descriptor's `ep_mem_offset` to calculate the start of the endpoint
memory access array and to comply with the FF-A spec instead of defaulting
to `sizeof(struct ffa_mem_region)`.
This requires moving `ffa_mem_region_additional_setup()` earlier in the setup
flow.
Also, add sanity checks to ensure the calculated descriptor offsets do not
exceed `max_fragsize`.
Fixes: 113580530ee7 ("firmware: arm_ffa: Update memory descriptor to support v1.1 format")
Reviewed-by: Sudeep Holla <sudeep.holla@kernel.org>
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
Link: https://patch.msgid.link/20260702103848.1647249-3-sebastianene@google.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/firmware/arm_ffa/driver.c | 20 +++++++++++++++-----
include/linux/arm_ffa.h | 2 +-
2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index 8216c8e233844..04a4a58cb68b7 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -645,19 +645,30 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
struct ffa_composite_mem_region *composite;
struct ffa_mem_region_addr_range *constituents;
struct ffa_mem_region_attributes *ep_mem_access;
- u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg);
+ u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg), ep_offset;
+ u32 emad_end, emad_size = ffa_emad_size_get(drv_info->version);
mem_region->tag = args->tag;
mem_region->flags = args->flags;
mem_region->sender_id = drv_info->vm_id;
mem_region->attributes = ffa_memory_attributes_get(func_id);
+
+ ffa_mem_region_additional_setup(drv_info->version, mem_region);
composite_offset = ffa_mem_desc_offset(buffer, args->nattrs,
drv_info->version);
+ if (composite_offset + sizeof(*composite) > max_fragsize)
+ return -ENXIO;
for (idx = 0; idx < args->nattrs; idx++) {
- ep_mem_access = buffer +
- ffa_mem_desc_offset(buffer, idx, drv_info->version);
- memset(ep_mem_access, 0, ffa_emad_size_get(drv_info->version));
+ ep_offset = ffa_mem_desc_offset(buffer, idx, drv_info->version);
+ if (check_add_overflow(ep_offset, emad_size, &emad_end))
+ return -ENXIO;
+
+ if (emad_end > max_fragsize)
+ return -ENXIO;
+
+ ep_mem_access = buffer + ep_offset;
+ memset(ep_mem_access, 0, emad_size);
ep_mem_access->receiver = args->attrs[idx].receiver;
ep_mem_access->attrs = args->attrs[idx].attrs;
ep_mem_access->composite_off = composite_offset;
@@ -667,7 +678,6 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
}
mem_region->handle = 0;
mem_region->ep_count = args->nattrs;
- ffa_mem_region_additional_setup(drv_info->version, mem_region);
composite = buffer + composite_offset;
composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg);
diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h
index ef84fb843610c..c1d511e85a799 100644
--- a/include/linux/arm_ffa.h
+++ b/include/linux/arm_ffa.h
@@ -434,7 +434,7 @@ ffa_mem_desc_offset(struct ffa_mem_region *buf, int count, u32 ffa_version)
if (!FFA_MEM_REGION_HAS_EP_MEM_OFFSET(ffa_version))
offset += offsetof(struct ffa_mem_region, ep_mem_offset);
else
- offset += sizeof(struct ffa_mem_region);
+ offset += buf->ep_mem_offset;
return offset;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 810/869] pmdomain: imx93-blk-ctrl: Extract PHY as shared domain for DSI/CSI
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (808 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 809/869] firmware: arm_ffa: Fix Endpoint Memory Access Descriptor offset calculation Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 811/869] cxl/region: Resolve region deletion races Greg Kroah-Hartman
` (59 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Guoniu Zhou, Frank Li, Peng Fan,
Ulf Hansson, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
[ Upstream commit 99611233f8cda833169fa6487d5dacdf189e5cb0 ]
The MIPI DSI and CSI domains share control bits for clock and reset, which
can lead to incorrect behavior if one domain disables the shared resource
while the other is still active.
To fix the issue, introduce a shared MIPI PHY power domain to own the
common resources and make DSI and CSI its subdomains. This ensures the
shared bits are properly managed and not disabled while still in use.
Fixes: e9aa77d413c9 ("soc: imx: add i.MX93 media blk ctrl driver")
Cc: stable@vger.kernel.org
Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Ulf Hansson <ulfh@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pmdomain/imx/imx93-blk-ctrl.c | 60 +++++++++++++++++++++++++--
1 file changed, 57 insertions(+), 3 deletions(-)
diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
index b10348ac10f06..89886bdeb6cd3 100644
--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
@@ -47,6 +47,8 @@
#define PRIO(X) (X)
+#define BLK_CTRL_NO_PARENT UINT_MAX
+
struct imx93_blk_ctrl_domain;
struct imx93_blk_ctrl {
@@ -73,6 +75,7 @@ struct imx93_blk_ctrl_domain_data {
int num_clks;
u32 rst_mask;
u32 clk_mask;
+ u32 parent;
int num_qos;
struct imx93_blk_ctrl_qos qos[DOMAIN_MAX_QOS];
};
@@ -287,18 +290,46 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
bc->onecell_data.domains[i] = &domain->genpd;
}
+ for (i = 0; i < bc_data->num_domains; i++) {
+ struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
+ const struct imx93_blk_ctrl_domain_data *data = domain->data;
+
+ if (data->parent == BLK_CTRL_NO_PARENT)
+ continue;
+
+ ret = pm_genpd_add_subdomain(&bc->domains[data->parent].genpd,
+ &domain->genpd);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to add subdomain %s\n",
+ domain->genpd.name);
+ goto cleanup_subdomains;
+ }
+ }
+
pm_runtime_enable(dev);
ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
if (ret) {
dev_err_probe(dev, ret, "failed to add power domain provider\n");
- goto cleanup_pds;
+ goto cleanup_subdomains;
}
dev_set_drvdata(dev, bc);
return 0;
+cleanup_subdomains:
+ for (i--; i >= 0; i--) {
+ const struct imx93_blk_ctrl_domain_data *data = bc->domains[i].data;
+
+ if (data->parent == BLK_CTRL_NO_PARENT)
+ continue;
+
+ pm_genpd_remove_subdomain(&bc->domains[data->parent].genpd,
+ &bc->domains[i].genpd);
+ }
+ i = bc_data->num_domains;
+
cleanup_pds:
for (i--; i >= 0; i--)
pm_genpd_remove(&bc->domains[i].genpd);
@@ -315,6 +346,16 @@ static void imx93_blk_ctrl_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
+ for (i = 0; i < bc->onecell_data.num_domains; i++) {
+ struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
+
+ if (domain->data->parent == BLK_CTRL_NO_PARENT)
+ continue;
+
+ pm_genpd_remove_subdomain(&bc->domains[domain->data->parent].genpd,
+ &domain->genpd);
+ }
+
for (i = 0; i < bc->onecell_data.num_domains; i++) {
struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
@@ -327,8 +368,9 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.name = "mediablk-mipi-dsi",
.clk_names = (const char *[]){ "dsi" },
.num_clks = 1,
- .rst_mask = BIT(11) | BIT(12),
- .clk_mask = BIT(11) | BIT(12),
+ .rst_mask = BIT(11),
+ .clk_mask = BIT(11),
+ .parent = IMX93_MEDIABLK_PD_MIPI_PHY,
},
[IMX93_MEDIABLK_PD_MIPI_CSI] = {
.name = "mediablk-mipi-csi",
@@ -336,6 +378,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.num_clks = 2,
.rst_mask = BIT(9) | BIT(10),
.clk_mask = BIT(9) | BIT(10),
+ .parent = IMX93_MEDIABLK_PD_MIPI_PHY,
},
[IMX93_MEDIABLK_PD_PXP] = {
.name = "mediablk-pxp",
@@ -343,6 +386,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.num_clks = 1,
.rst_mask = BIT(7) | BIT(8),
.clk_mask = BIT(7) | BIT(8),
+ .parent = BLK_CTRL_NO_PARENT,
.num_qos = 2,
.qos = {
{
@@ -364,6 +408,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.num_clks = 2,
.rst_mask = BIT(4) | BIT(5) | BIT(6),
.clk_mask = BIT(4) | BIT(5) | BIT(6),
+ .parent = BLK_CTRL_NO_PARENT,
.num_qos = 1,
.qos = {
{
@@ -380,6 +425,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.num_clks = 1,
.rst_mask = BIT(2) | BIT(3),
.clk_mask = BIT(2) | BIT(3),
+ .parent = BLK_CTRL_NO_PARENT,
.num_qos = 4,
.qos = {
{
@@ -405,6 +451,14 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
}
}
},
+ [IMX93_MEDIABLK_PD_MIPI_PHY] = {
+ .name = "mediablk-mipi-phy",
+ .clk_names = NULL,
+ .num_clks = 0,
+ .rst_mask = BIT(12),
+ .clk_mask = BIT(12),
+ .parent = BLK_CTRL_NO_PARENT,
+ },
};
static const struct regmap_range imx93_media_blk_ctl_yes_ranges[] = {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 811/869] cxl/region: Resolve region deletion races
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (809 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 810/869] pmdomain: imx93-blk-ctrl: Extract PHY as shared domain for DSI/CSI Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 812/869] bpf: Remove migrate_{disable|enable} in bpf_obj_free_fields() Greg Kroah-Hartman
` (58 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sungwoo Kim, Dan Williams,
Alejandro Lucero, Dave Jiang, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Williams <djbw@kernel.org>
[ Upstream commit 4dd86ca99ffcc413cbf79063fd9956ef54e0ca91 ]
Sungwoo noticed that the sysfs trigger to delete a region may try to delete
a region multiple times. It also has no exclusion relative to the kernel
releasing the region via CXL root device teardown.
Instead of installing new cxl root devres actions per region, use the
existing root decoder unregistration event to remove all remaining regions.
An xarray of regions replaces a devres list of regions.
This handles 3 separate issues with the old approach:
1/ sysfs users racing to delete the same region: no longer possible now
that the regions_lock is held over the lookup and deletion.
2/ multiple actions triggering deletion of the same region: solved by
erasing regions while holding @regions_lock, and only proceeding on
successful erasure.
3/ userspace racing devres_release_all() to trigger the devres not found
warning: solved by sysfs unregistration not requiring a release action
Fixes: 779dd20cfb56 ("cxl/region: Add region creation support")
Reported-by: Sungwoo Kim <iam@sung-woo.kim>
Closes: http://lore.kernel.org/20260427032010.916681-2-iam@sung-woo.kim
Signed-off-by: Dan Williams <djbw@kernel.org>
Reviewed-by: Alejandro Lucero <alucerop@amd.com>
Tested-by: ALejandro Lucero <alucerop@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://patch.msgid.link/20260519210158.1499795-3-djbw@kernel.org
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/cxl/core/core.h | 2 ++
drivers/cxl/core/port.c | 5 ++++
drivers/cxl/core/region.c | 62 ++++++++++++++++++++++-----------------
drivers/cxl/cxl.h | 4 +++
4 files changed, 46 insertions(+), 27 deletions(-)
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 1c11bd5f0df00..d95206ed6ab8d 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -32,6 +32,7 @@ int cxl_get_poison_by_endpoint(struct cxl_port *port);
struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa);
u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
u64 dpa);
+void kill_regions(struct cxl_root_decoder *cxlrd);
#else
static inline u64 cxl_dpa_to_hpa(struct cxl_region *cxlr,
@@ -58,6 +59,7 @@ static inline int cxl_region_init(void)
static inline void cxl_region_exit(void)
{
}
+static inline void kill_regions(struct cxl_root_decoder *cxlrd) { };
#define CXL_REGION_ATTR(x) NULL
#define CXL_REGION_TYPE(x) NULL
#define SET_CXL_REGION_ATTR(x)
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 217a24a2f56e3..35aceb7b38040 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -445,6 +445,8 @@ static void cxl_root_decoder_release(struct device *dev)
if (atomic_read(&cxlrd->region_id) >= 0)
memregion_free(atomic_read(&cxlrd->region_id));
+ mutex_destroy(&cxlrd->regions_lock);
+ xa_destroy(&cxlrd->regions);
__cxl_decoder_release(&cxlrd->cxlsd.cxld);
kfree(cxlrd);
}
@@ -1826,6 +1828,7 @@ struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
}
mutex_init(&cxlrd->regions_lock);
+ xa_init(&cxlrd->regions);
cxld = &cxlsd->cxld;
cxld->dev.type = &cxl_decoder_root_type;
@@ -2009,6 +2012,8 @@ static void cxld_unregister(void *dev)
cxled = to_cxl_endpoint_decoder(dev);
cxl_decoder_kill_region(cxled);
}
+ if (is_root_decoder(dev))
+ kill_regions(to_cxl_root_decoder(dev));
device_unregister(dev);
}
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 00c9c60d9a246..15253e5c28d60 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -2327,12 +2327,13 @@ static struct cxl_region *to_cxl_region(struct device *dev)
return container_of(dev, struct cxl_region, dev);
}
-static void unregister_region(void *_cxlr)
+static void unregister_region(struct cxl_region *cxlr)
{
- struct cxl_region *cxlr = _cxlr;
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
struct cxl_region_params *p = &cxlr->params;
int i;
+ xa_erase(&cxlrd->regions, cxlr->id);
device_del(&cxlr->dev);
/*
@@ -2460,6 +2461,19 @@ static int cxl_region_calculate_adistance(struct notifier_block *nb,
return NOTIFY_STOP;
}
+/* unwind all remaining regions */
+void kill_regions(struct cxl_root_decoder *cxlrd)
+{
+ unsigned long index;
+ struct cxl_region *cxlr;
+
+ guard(mutex)(&cxlrd->regions_lock);
+ /* no more region creation */
+ cxlrd->dead = true;
+ xa_for_each(&cxlrd->regions, index, cxlr)
+ unregister_region(cxlr);
+}
+
/**
* devm_cxl_add_region - Adds a region to a decoder
* @cxlrd: root decoder
@@ -2498,14 +2512,15 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd,
if (rc)
goto err;
- rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr);
- if (rc)
+ rc = xa_insert(&cxlrd->regions, cxlr->id, cxlr, GFP_KERNEL);
+ if (rc) {
+ unregister_region(cxlr);
return ERR_PTR(rc);
+ }
dev_dbg(port->uport_dev, "%s: created %s\n",
dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev));
return cxlr;
-
err:
put_device(dev);
return ERR_PTR(rc);
@@ -2533,6 +2548,9 @@ static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd,
{
int rc;
+ if (cxlrd->dead)
+ return ERR_PTR(-ENXIO);
+
switch (mode) {
case CXL_DECODER_RAM:
case CXL_DECODER_PMEM:
@@ -2624,40 +2642,31 @@ static ssize_t region_show(struct device *dev, struct device_attribute *attr,
}
DEVICE_ATTR_RO(region);
-static struct cxl_region *
-cxl_find_region_by_name(struct cxl_root_decoder *cxlrd, const char *name)
-{
- struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
- struct device *region_dev;
-
- region_dev = device_find_child_by_name(&cxld->dev, name);
- if (!region_dev)
- return ERR_PTR(-ENODEV);
-
- return to_cxl_region(region_dev);
-}
-
static ssize_t delete_region_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
- struct cxl_port *port = to_cxl_port(dev->parent);
struct cxl_region *cxlr;
- int rc;
+ int rc, id;
rc = mutex_lock_interruptible(&cxlrd->regions_lock);
if (rc)
return rc;
- cxlr = cxl_find_region_by_name(cxlrd, buf);
- if (IS_ERR(cxlr)) {
+ rc = sscanf(buf, "region%d\n", &id);
+ if (rc != 1) {
mutex_unlock(&cxlrd->regions_lock);
- return PTR_ERR(cxlr);
+ return -EINVAL;
}
- devm_release_action(port->uport_dev, unregister_region, cxlr);
- put_device(&cxlr->dev);
+ cxlr = xa_load(&cxlrd->regions, id);
+ if (!cxlr || !sysfs_streq(buf, dev_name(&cxlr->dev))) {
+ mutex_unlock(&cxlrd->regions_lock);
+ return -ENODEV;
+ }
+
+ unregister_region(cxlr);
mutex_unlock(&cxlrd->regions_lock);
return len;
@@ -3256,7 +3265,6 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
struct cxl_endpoint_decoder *cxled)
{
struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
- struct cxl_port *port = cxlrd_to_port(cxlrd);
struct range *hpa = &cxled->cxld.hpa_range;
struct cxl_region_params *p;
struct cxl_region *cxlr;
@@ -3331,7 +3339,7 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
err:
up_write(&cxl_region_rwsem);
- devm_release_action(port->uport_dev, unregister_region, cxlr);
+ unregister_region(cxlr);
return ERR_PTR(rc);
}
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index bcd1d140fa0f2..e2b7e398d4d57 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -453,6 +453,8 @@ typedef u64 (*cxl_hpa_to_spa_fn)(struct cxl_root_decoder *cxlrd, u64 hpa);
* @hpa_to_spa: translate CXL host-physical-address to Platform system-physical-address
* @platform_data: platform specific configuration data
* @regions_lock: sync region discovery, construction, and deletion
+ * @regions: regions to remove at root decoder destruct time
+ * @dead: root decoder dead to region creation
* @qos_class: QoS performance class cookie
* @cxlsd: base cxl switch decoder
*/
@@ -462,6 +464,8 @@ struct cxl_root_decoder {
cxl_hpa_to_spa_fn hpa_to_spa;
void *platform_data;
struct mutex regions_lock;
+ struct xarray regions;
+ bool dead;
int qos_class;
struct cxl_switch_decoder cxlsd;
};
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 812/869] bpf: Remove migrate_{disable|enable} in bpf_obj_free_fields()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (810 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 811/869] cxl/region: Resolve region deletion races Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 813/869] bpf: Clear rb node linkage when freeing bpf_rb_root Greg Kroah-Hartman
` (57 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Hou Tao, Alexei Starovoitov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hou Tao <houtao1@huawei.com>
[ Upstream commit 1d2dbe7120e89090ed4f6be03d6fbadfbfff59bf ]
The callers of bpf_obj_free_fields() have already guaranteed that the
migration is disabled, therefore, there is no need to invoke
migrate_{disable,enable} pair in bpf_obj_free_fields()'s underly
implementation.
This patch removes unnecessary migrate_{disable|enable} pairs from
bpf_obj_free_fields() and its callees: bpf_list_head_free() and
bpf_rb_root_free().
Signed-off-by: Hou Tao <houtao1@huawei.com>
Link: https://lore.kernel.org/r/20250108010728.207536-12-houtao@huaweicloud.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Stable-dep-of: 4a7910ee060d ("bpf: Clear rb node linkage when freeing bpf_rb_root")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/helpers.c | 4 ----
kernel/bpf/syscall.c | 2 --
2 files changed, 6 deletions(-)
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 3126ec5097f15..e8417cd67decb 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -2100,9 +2100,7 @@ void bpf_list_head_free(const struct btf_field *field, void *list_head,
/* The contained type can also have resources, including a
* bpf_list_head which needs to be freed.
*/
- migrate_disable();
__bpf_obj_drop_impl(obj, field->graph_root.value_rec, false);
- migrate_enable();
}
}
@@ -2139,9 +2137,7 @@ void bpf_rb_root_free(const struct btf_field *field, void *rb_root,
obj -= field->graph_root.node_offset;
- migrate_disable();
__bpf_obj_drop_impl(obj, field->graph_root.value_rec, false);
- migrate_enable();
}
}
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 9b3d067e47420..854cc29b47c8f 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -707,11 +707,9 @@ void bpf_obj_free_fields(const struct btf_record *rec, void *obj)
if (!btf_is_kernel(field->kptr.btf)) {
pointee_struct_meta = btf_find_struct_meta(field->kptr.btf,
field->kptr.btf_id);
- migrate_disable();
__bpf_obj_drop_impl(xchgd_field, pointee_struct_meta ?
pointee_struct_meta->record : NULL,
fields[i].type == BPF_KPTR_PERCPU);
- migrate_enable();
} else {
field->kptr.dtor(xchgd_field);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 813/869] bpf: Clear rb node linkage when freeing bpf_rb_root
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (811 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 812/869] bpf: Remove migrate_{disable|enable} in bpf_obj_free_fields() Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 814/869] ocfs2: validate external xattr entries when reading metadata Greg Kroah-Hartman
` (56 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Kaitao Cheng, Yonghong Song,
Alexei Starovoitov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kaitao Cheng <chengkaitao@kylinos.cn>
[ Upstream commit 4a7910ee060d8ce55612f5b3cc267f3a265a3cec ]
bpf_rb_root_free() detaches the root by copying the current rb_root_cached
and then replacing the live root with RB_ROOT_CACHED. It then walks the
copied root and drops each object contained in the tree.
This leaves the rb node state intact while dropping the object. If the
object is refcounted and survives the drop, its bpf_rb_node_kern still
contains an owner pointer to the freed root and stale rb tree linkage. If
a later bpf_rb_root allocation reuses the same address, bpf_rbtree_remove()
can incorrectly pass the owner check and call rb_erase_cached() on a node
whose rb pointers belong to the old tree.
Mirror the list draining behavior by marking nodes as busy while the root
is being detached, then clear the rb node and release the owner before
dropping the containing object. This makes surviving nodes unowned and
safe to reject from remove or accept for a later add.
Fixes: 9c395c1b99bd ("bpf: Add basic bpf_rb_{root,node} support")
Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
Acked-by: Yonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/r/20260605094143.5509-1-kaitao.cheng@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/bpf/helpers.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index e8417cd67decb..617f1b8c36703 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -2121,6 +2121,7 @@ void bpf_rb_root_free(const struct btf_field *field, void *rb_root,
struct bpf_spin_lock *spin_lock)
{
struct rb_root_cached orig_root, *root = rb_root;
+ struct bpf_rb_node_kern *node;
struct rb_node *pos, *n;
void *obj;
@@ -2129,14 +2130,20 @@ void bpf_rb_root_free(const struct btf_field *field, void *rb_root,
__bpf_spin_lock_irqsave(spin_lock);
orig_root = *root;
+ bpf_rbtree_postorder_for_each_entry_safe(pos, n, &orig_root.rb_root) {
+ node = rb_entry(pos, struct bpf_rb_node_kern, rb_node);
+ WRITE_ONCE(node->owner, BPF_PTR_POISON);
+ }
*root = RB_ROOT_CACHED;
__bpf_spin_unlock_irqrestore(spin_lock);
bpf_rbtree_postorder_for_each_entry_safe(pos, n, &orig_root.rb_root) {
obj = pos;
obj -= field->graph_root.node_offset;
-
-
+ node = rb_entry(pos, struct bpf_rb_node_kern, rb_node);
+ RB_CLEAR_NODE(pos);
+ /* Ensure __bpf_rbtree_add() sees the node as unlinked. */
+ smp_store_release(&node->owner, NULL);
__bpf_obj_drop_impl(obj, field->graph_root.value_rec, false);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 814/869] ocfs2: validate external xattr entries when reading metadata
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (812 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 813/869] bpf: Clear rb node linkage when freeing bpf_rb_root Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 815/869] dm-integrity: replace forgeable discard filler with a keyed sector marker Greg Kroah-Hartman
` (55 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Cen Zhang, Joseph Qi, Mark Fasheh,
Joel Becker, Junxiao Bi, Changwei Ge, Jun Piao, Heming Zhao,
Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <zzzccc427@gmail.com>
[ Upstream commit 2cf82b46d5e43be0dfbaac7fa1073cec2fc1f5e6 ]
ocfs2_validate_xattr_block() checks the xattr block header before the
block reaches higher-level xattr users, but it does not verify that a
non-indexed block's xh_count and entry offsets fit inside the block.
Indexed buckets likewise reach list/get consumers after ECC without an
entry-bounds check.
Use the flat xattr entry validator for non-indexed external xattr blocks,
and use a bucket-specific validator for indexed buckets at metadata read
time. The bucket validator keeps the entry array bounded by the first
bucket block while checking name/value offsets against the bucket block
they target.
Reject corrupted external xattr metadata before listxattr() or getxattr()
can walk out-of-range entry arrays or name/value offsets.
Validation reproduced this kernel report:
BUG: KASAN: use-after-free in ocfs2_xattr_list_entries+0xd7/0x190
Read of size 1 at addr ffff88810a654007 by task ocfs2_xattr_lis/630
Call Trace:
dump_stack_lvl+0x66/0xa0
print_report+0xce/0x630
kasan_report+0xe0/0x110
ocfs2_xattr_list_entries+0xd7/0x190
ocfs2_listxattr+0x3f6/0x610
listxattr+0x90/0xe0
path_listxattrat+0xed/0x220
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Link: https://lore.kernel.org/20260705025311.3429854-3-zzzccc427@gmail.com
Fixes: cf1d6c763fbc ("ocfs2: Add extended attribute support")
Fixes: 0c044f0b24b9 ("ocfs2: Add xattr bucket iteration for large numbers of EAs")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Assisted-by: Codex:gpt-5.5
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/xattr.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 97 insertions(+)
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index 1cad9a386705e..5c88f6f800852 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -386,6 +386,12 @@ static int ocfs2_init_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
return rc;
}
+static int ocfs2_validate_xattr_entries_flat(struct super_block *sb, u64 blkno,
+ struct ocfs2_xattr_header *xh,
+ size_t region_size);
+static int ocfs2_validate_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
+ u64 blkno);
+
/* Read the xattr bucket at xb_blkno */
static int ocfs2_read_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
u64 xb_blkno)
@@ -404,6 +410,8 @@ static int ocfs2_read_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
spin_unlock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock);
if (rc)
mlog_errno(rc);
+ else
+ rc = ocfs2_validate_xattr_bucket(bucket, xb_blkno);
}
if (rc)
@@ -505,6 +513,22 @@ static int ocfs2_validate_xattr_block(struct super_block *sb,
le32_to_cpu(xb->xb_fs_generation));
}
+ if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+ size_t region_offset =
+ offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header);
+
+ if (bh->b_size < region_offset)
+ return ocfs2_error(sb,
+ "Invalid xattr block %llu: block size %zu is too small\n",
+ (unsigned long long)bh->b_blocknr,
+ bh->b_size);
+
+ return ocfs2_validate_xattr_entries_flat(sb, bh->b_blocknr,
+ &xb->xb_attrs.xb_header,
+ bh->b_size -
+ region_offset);
+ }
+
return 0;
}
@@ -1071,6 +1095,79 @@ int ocfs2_validate_inode_xattr(struct super_block *sb, u64 blkno,
return ocfs2_validate_xattr_entries_flat(sb, blkno, xh, inline_size);
}
+static int ocfs2_validate_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
+ u64 blkno)
+{
+ struct super_block *sb = bucket->bu_inode->i_sb;
+ struct ocfs2_xattr_header *xh = bucket_xh(bucket);
+ u16 xattr_count = le16_to_cpu(xh->xh_count);
+ size_t region_size = (size_t)sb->s_blocksize * bucket->bu_blocks;
+ size_t entries_limit = sb->s_blocksize;
+ size_t nv_limit = sb->s_blocksize;
+ size_t max_entries;
+ int i;
+
+ if (region_size < sizeof(*xh))
+ return ocfs2_error(sb,
+ "Invalid xattr bucket %llu: region size %zu is too small\n",
+ (unsigned long long)blkno, region_size);
+
+ if (entries_limit < sizeof(*xh))
+ return ocfs2_error(sb,
+ "Invalid xattr bucket %llu: entries limit %zu is too small\n",
+ (unsigned long long)blkno,
+ entries_limit);
+
+ max_entries = (entries_limit - sizeof(*xh)) /
+ sizeof(struct ocfs2_xattr_entry);
+
+ if (xattr_count > max_entries)
+ return ocfs2_error(sb,
+ "Invalid xattr bucket %llu: entry count %u exceeds maximum %zu\n",
+ (unsigned long long)blkno,
+ xattr_count, max_entries);
+
+ for (i = 0; i < xattr_count; i++) {
+ struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
+ size_t name_offset = le16_to_cpu(xe->xe_name_offset);
+ size_t block_off = name_offset >> sb->s_blocksize_bits;
+ size_t block_offset = name_offset % nv_limit;
+ size_t value_offset;
+
+ if (name_offset >= region_size || block_off >= bucket->bu_blocks)
+ return ocfs2_error(sb,
+ "Invalid xattr bucket %llu: entry %d name is out of bounds\n",
+ (unsigned long long)blkno, i);
+
+ if (xe->xe_name_len > nv_limit - block_offset)
+ return ocfs2_error(sb,
+ "Invalid xattr bucket %llu: entry %d name crosses block boundary\n",
+ (unsigned long long)blkno, i);
+
+ value_offset = block_offset + OCFS2_XATTR_SIZE(xe->xe_name_len);
+ if (value_offset > nv_limit)
+ return ocfs2_error(sb,
+ "Invalid xattr bucket %llu: entry %d value starts out of bounds\n",
+ (unsigned long long)blkno, i);
+
+ if (ocfs2_xattr_is_local(xe)) {
+ if (le64_to_cpu(xe->xe_value_size) >
+ nv_limit - value_offset)
+ return ocfs2_error(sb,
+ "Invalid xattr bucket %llu: entry %d value is out of bounds\n",
+ (unsigned long long)blkno,
+ i);
+ } else if (sizeof(struct ocfs2_xattr_value_root) >
+ nv_limit - value_offset) {
+ return ocfs2_error(sb,
+ "Invalid xattr bucket %llu: entry %d value root is out of bounds\n",
+ (unsigned long long)blkno, i);
+ }
+ }
+
+ return 0;
+}
+
int ocfs2_has_inline_xattr_value_outside(struct inode *inode,
struct ocfs2_dinode *di)
{
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 815/869] dm-integrity: replace forgeable discard filler with a keyed sector marker
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (813 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 814/869] ocfs2: validate external xattr entries when reading metadata Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 816/869] perf/x86/intel/uncore: Fix uncore_box ref/unref ordering Greg Kroah-Hartman
` (54 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jo Van Bulck, Shukai Ni,
Mikulas Patocka, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shukai Ni <shukai.ni@kuleuven.be>
[ Upstream commit 68c5c42567bc462139128968ebbfadd0aefff519 ]
The discard-block check in dm_integrity_rw_tag() treats a stored tag
of all 0xf6 bytes (DISCARD_FILLER) as proof a block was discarded and
skips HMAC verification. allow_discards is only accepted in
dm-integrity's standalone mode. An attacker with raw write access to
the backing device, but without the integrity key, can stamp any block
with an all-0xf6 tag and have it served as authentic.
Add a new "allow_discards_keyed" target argument that marks discarded
blocks with a keyed checksum of (salt || sector) instead, computed by
integrity_discard_checksum().
Fixes: 84597a44a9d8 ("dm integrity: add optional discard support")
Co-developed-by: Jo Van Bulck <jo.vanbulck@cs.kuleuven.be>
Signed-off-by: Jo Van Bulck <jo.vanbulck@cs.kuleuven.be>
Signed-off-by: Shukai Ni <shukai.ni@kuleuven.be>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../admin-guide/device-mapper/dm-ima.rst | 7 +-
.../device-mapper/dm-integrity.rst | 13 +++
drivers/md/dm-integrity.c | 110 +++++++++++++++---
3 files changed, 114 insertions(+), 16 deletions(-)
diff --git a/Documentation/admin-guide/device-mapper/dm-ima.rst b/Documentation/admin-guide/device-mapper/dm-ima.rst
index a4aa50a828e00..2a3b50ffbee4e 100644
--- a/Documentation/admin-guide/device-mapper/dm-ima.rst
+++ b/Documentation/admin-guide/device-mapper/dm-ima.rst
@@ -424,7 +424,8 @@ section above) has the following data format for 'integrity' target.
target_attributes := <target_name> "," <target_version> "," <dev_name> "," <start>
<tag_size> "," <mode> "," [<meta_device> ","] [<block_size> ","] <recalculate> ","
- <allow_discards> "," <fix_padding> "," <fix_hmac> "," <legacy_recalculate> ","
+ <allow_discards> "," <allow_discards_keyed> "," <fix_padding> "," <fix_hmac> ","
+ <legacy_recalculate> ","
<journal_sectors> "," <interleave_sectors> "," <buffer_sectors> ";"
target_name := "target_name=integrity"
@@ -438,6 +439,7 @@ section above) has the following data format for 'integrity' target.
block_size := "block_size=" <N>
recalculate := "recalculate=" <yes_no>
allow_discards := "allow_discards=" <yes_no>
+ allow_discards_keyed := "allow_discards_keyed=" <yes_no>
fix_padding := "fix_padding=" <yes_no>
fix_hmac := "fix_hmac=" <yes_no>
legacy_recalculate := "legacy_recalculate=" <yes_no>
@@ -455,7 +457,8 @@ section above) has the following data format for 'integrity' target.
dm_version=4.45.0;
name=integrity1,uuid=,major=253,minor=1,minor_count=1,num_targets=1;
target_index=0,target_begin=0,target_len=7856,target_name=integrity,target_version=1.10.0,
- dev_name=253:0,start=0,tag_size=32,mode=J,recalculate=n,allow_discards=n,fix_padding=n,
+ dev_name=253:0,start=0,tag_size=32,mode=J,recalculate=n,allow_discards=n,
+ allow_discards_keyed=n,fix_padding=n,
fix_hmac=n,legacy_recalculate=n,journal_sectors=88,interleave_sectors=32768,buffer_sectors=128;
diff --git a/Documentation/admin-guide/device-mapper/dm-integrity.rst b/Documentation/admin-guide/device-mapper/dm-integrity.rst
index d8a5f14d0e3c4..38fe5c70603be 100644
--- a/Documentation/admin-guide/device-mapper/dm-integrity.rst
+++ b/Documentation/admin-guide/device-mapper/dm-integrity.rst
@@ -185,6 +185,19 @@ allow_discards
Allow block discard requests (a.k.a. TRIM) for the integrity device.
Discards are only allowed to devices using internal hash.
+ A discarded block is marked with a constant filler tag that anyone
+ with raw write access to the backing device can forge without the
+ key. Use allow_discards_keyed instead on new volumes.
+
+allow_discards_keyed
+ Like allow_discards, but marks a discarded block with a keyed
+ checksum of the sector number, HMAC_key(salt || sector), instead of
+ the constant filler tag, so it can't be forged without the
+ integrity key.
+
+ Not compatible with volumes that already have discarded blocks
+ marked the old way; only use on a freshly formatted volume.
+
fix_padding
Use a smaller padding of the tag area that is more
space-efficient. If this option is not present, large padding is
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index e43892d1619db..513c6d5fd74e1 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -65,6 +65,7 @@
#define SB_VERSION_4 4
#define SB_VERSION_5 5
#define SB_VERSION_6 6
+#define SB_VERSION_7 7
#define SB_SECTORS 8
#define MAX_SECTORS_PER_BLOCK 8
@@ -90,6 +91,7 @@ struct superblock {
#define SB_FLAG_FIXED_PADDING 0x8
#define SB_FLAG_FIXED_HMAC 0x10
#define SB_FLAG_INLINE 0x20
+#define SB_FLAG_DISCARD_KEYED 0x40
#define JOURNAL_ENTRY_ROUNDUP 8
@@ -275,6 +277,7 @@ struct dm_integrity_c {
bool recalculate_flag;
bool reset_recalculate_flag;
bool discard;
+ bool discard_keyed;
bool fix_padding;
bool fix_hmac;
bool legacy_recalculate;
@@ -475,7 +478,9 @@ static void wraparound_section(struct dm_integrity_c *ic, unsigned int *sec_ptr)
static void sb_set_version(struct dm_integrity_c *ic)
{
- if (ic->sb->flags & cpu_to_le32(SB_FLAG_INLINE))
+ if (ic->sb->flags & cpu_to_le32(SB_FLAG_DISCARD_KEYED))
+ ic->sb->version = SB_VERSION_7;
+ else if (ic->sb->flags & cpu_to_le32(SB_FLAG_INLINE))
ic->sb->version = SB_VERSION_6;
else if (ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_HMAC))
ic->sb->version = SB_VERSION_5;
@@ -1406,7 +1411,7 @@ static int dm_integrity_rw_tag(struct dm_integrity_c *ic, unsigned char *tag, se
{
unsigned int hash_offset = 0;
unsigned char mismatch_hash = 0;
- unsigned char mismatch_filler = !ic->discard;
+ unsigned char mismatch_filler = !ic->discard || ic->discard_keyed;
do {
unsigned char *data, *dp;
@@ -1458,7 +1463,7 @@ static int dm_integrity_rw_tag(struct dm_integrity_c *ic, unsigned char *tag, se
}
hash_offset = 0;
mismatch_hash = 0;
- mismatch_filler = !ic->discard;
+ mismatch_filler = !ic->discard || ic->discard_keyed;
}
}
}
@@ -1662,10 +1667,12 @@ static void integrity_sector_checksum(struct dm_integrity_c *ic, sector_t sector
goto failed;
}
- r = crypto_shash_update(req, data, ic->sectors_per_block << SECTOR_SHIFT);
- if (unlikely(r < 0)) {
- dm_integrity_io_error(ic, "crypto_shash_update", r);
- goto failed;
+ if (likely(data)) {
+ r = crypto_shash_update(req, data, ic->sectors_per_block << SECTOR_SHIFT);
+ if (unlikely(r < 0)) {
+ dm_integrity_io_error(ic, "crypto_shash_update", r);
+ goto failed;
+ }
}
r = crypto_shash_final(req, result);
@@ -1685,6 +1692,53 @@ static void integrity_sector_checksum(struct dm_integrity_c *ic, sector_t sector
get_random_bytes(result, ic->tag_size);
}
+/*
+ * Authenticated marker for a discarded block: HMAC_key(salt || sector), with
+ * no data payload. Because a real data tag's input always covers a full
+ * block, its length differs from this marker's, so the two can never
+ * collide structurally, regardless of block content.
+ */
+static void integrity_discard_checksum(struct dm_integrity_c *ic, sector_t sector, char *result)
+{
+ integrity_sector_checksum(ic, sector, NULL, result);
+}
+
+static void integrity_discard_fill_tags(struct dm_integrity_c *ic, unsigned char *checksums,
+ sector_t *sector, unsigned int blocks)
+{
+ char digest[MAX_T(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
+ unsigned int i;
+
+ for (i = 0; i < blocks; i++) {
+ integrity_discard_checksum(ic, *sector, digest);
+ memcpy(checksums + i * ic->tag_size, digest, ic->tag_size);
+ *sector += ic->sectors_per_block;
+ }
+}
+
+static int integrity_recheck_verify_tag(struct dm_integrity_io *dio, char *checksum,
+ char *on_disk_tag, sector_t logical_sector)
+{
+ struct dm_integrity_c *ic = dio->ic;
+ int r;
+
+ if (!ic->discard_keyed)
+ return dm_integrity_rw_tag(ic, checksum, &dio->metadata_block,
+ &dio->metadata_offset, ic->tag_size, TAG_CMP);
+
+ r = dm_integrity_rw_tag(ic, on_disk_tag, &dio->metadata_block,
+ &dio->metadata_offset, ic->tag_size, TAG_READ);
+ if (unlikely(r))
+ return r;
+
+ r = crypto_memneq(on_disk_tag, checksum, ic->tag_size);
+ if (unlikely(r)) {
+ integrity_discard_checksum(ic, logical_sector, checksum);
+ r = crypto_memneq(on_disk_tag, checksum, ic->tag_size);
+ }
+ return r;
+}
+
static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checksum)
{
struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
@@ -1709,6 +1763,7 @@ static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checks
sector_t alignment;
char *mem;
char *buffer = page_to_virt(page);
+ char on_disk_tag[MAX_T(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
int r;
struct dm_io_request io_req;
struct dm_io_region io_loc;
@@ -1736,8 +1791,8 @@ static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checks
}
integrity_sector_checksum(ic, logical_sector, buffer, checksum);
- r = dm_integrity_rw_tag(ic, checksum, &dio->metadata_block,
- &dio->metadata_offset, ic->tag_size, TAG_CMP);
+ r = integrity_recheck_verify_tag(dio, checksum, on_disk_tag,
+ logical_sector);
if (r) {
if (r > 0) {
DMERR_LIMIT("%pg: Checksum failed at sector 0x%llx",
@@ -1803,13 +1858,18 @@ static void integrity_metadata(struct work_struct *w)
unsigned int bi_size = dio->bio_details.bi_iter.bi_size;
unsigned int max_size = likely(checksums != checksums_onstack) ? PAGE_SIZE : HASH_MAX_DIGESTSIZE;
unsigned int max_blocks = max_size / ic->tag_size;
+ sector_t sector = dio->range.logical_sector;
- memset(checksums, DISCARD_FILLER, max_size);
+ if (!ic->discard_keyed)
+ memset(checksums, DISCARD_FILLER, max_size);
while (bi_size) {
unsigned int this_step_blocks = bi_size >> (SECTOR_SHIFT + ic->sb->log2_sectors_per_block);
this_step_blocks = min(this_step_blocks, max_blocks);
+ if (ic->discard_keyed)
+ integrity_discard_fill_tags(ic, checksums, §or,
+ this_step_blocks);
r = dm_integrity_rw_tag(ic, checksums, &dio->metadata_block, &dio->metadata_offset,
this_step_blocks * ic->tag_size, TAG_WRITE);
if (unlikely(r)) {
@@ -3658,6 +3718,8 @@ static void dm_integrity_resume(struct dm_target *ti)
ic->wrote_to_journal = false;
flags = ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING);
+ if (ic->discard_keyed)
+ flags |= cpu_to_le32(SB_FLAG_DISCARD_KEYED);
r = sync_rw_sb(ic, REQ_OP_READ);
if (r)
dm_integrity_io_error(ic, "reading superblock", r);
@@ -3805,7 +3867,8 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
arg_count += ic->sectors_per_block != 1;
arg_count += !!(ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING));
arg_count += ic->reset_recalculate_flag;
- arg_count += ic->discard;
+ arg_count += ic->discard && !ic->discard_keyed;
+ arg_count += ic->discard_keyed;
arg_count += ic->mode == 'J';
arg_count += ic->mode == 'J';
arg_count += ic->mode == 'B';
@@ -3826,8 +3889,10 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
DMEMIT(" recalculate");
if (ic->reset_recalculate_flag)
DMEMIT(" reset_recalculate");
- if (ic->discard)
+ if (ic->discard && !ic->discard_keyed)
DMEMIT(" allow_discards");
+ if (ic->discard_keyed)
+ DMEMIT(" allow_discards_keyed");
DMEMIT(" journal_sectors:%u", ic->initial_sectors - SB_SECTORS);
DMEMIT(" interleave_sectors:%u", 1U << ic->sb->log2_interleave_sectors);
DMEMIT(" buffer_sectors:%u", 1U << ic->log2_buffer_sectors);
@@ -3876,6 +3941,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
DMEMIT(",recalculate=%c", (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) ?
'y' : 'n');
DMEMIT(",allow_discards=%c", ic->discard ? 'y' : 'n');
+ DMEMIT(",allow_discards_keyed=%c", ic->discard_keyed ? 'y' : 'n');
DMEMIT(",fix_padding=%c",
((ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0) ? 'y' : 'n');
DMEMIT(",fix_hmac=%c",
@@ -4037,6 +4103,9 @@ static int initialize_superblock(struct dm_integrity_c *ic,
get_random_bytes(ic->sb->salt, SALT_SIZE);
}
+ if (ic->discard_keyed)
+ ic->sb->flags |= cpu_to_le32(SB_FLAG_DISCARD_KEYED);
+
if (!ic->meta_dev) {
if (ic->fix_padding)
ic->sb->flags |= cpu_to_le32(SB_FLAG_FIXED_PADDING);
@@ -4673,6 +4742,9 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
ic->reset_recalculate_flag = true;
} else if (!strcmp(opt_string, "allow_discards")) {
ic->discard = true;
+ } else if (!strcmp(opt_string, "allow_discards_keyed")) {
+ ic->discard = true;
+ ic->discard_keyed = true;
} else if (!strcmp(opt_string, "fix_padding")) {
ic->fix_padding = true;
} else if (!strcmp(opt_string, "fix_hmac")) {
@@ -4791,6 +4863,11 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
ti->error = "Discard can be only used with internal hash";
goto bad;
}
+ if (ic->discard_keyed && !ic->internal_hash_alg.key) {
+ r = -EINVAL;
+ ti->error = "Keyed discard can only be used with keyed internal hash";
+ goto bad;
+ }
ic->autocommit_jiffies = msecs_to_jiffies(sync_msec);
ic->autocommit_msec = sync_msec;
@@ -4917,7 +4994,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
should_write_sb = true;
}
- if (!ic->sb->version || ic->sb->version > SB_VERSION_6) {
+ if (!ic->sb->version || ic->sb->version > SB_VERSION_7) {
r = -EINVAL;
ti->error = "Unknown version";
goto bad;
@@ -4965,6 +5042,11 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv
goto bad;
}
}
+ if (!ic->discard_keyed && (ic->sb->flags & cpu_to_le32(SB_FLAG_DISCARD_KEYED))) {
+ r = -EINVAL;
+ ti->error = "Keyed discard cannot be disabled once enabled";
+ goto bad;
+ }
if (!!(ic->sb->flags & cpu_to_le32(SB_FLAG_HAVE_JOURNAL_MAC)) != !!ic->journal_mac_alg.alg_string) {
r = -EINVAL;
ti->error = "Journal mac mismatch";
@@ -5260,7 +5342,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
static struct target_type integrity_target = {
.name = "integrity",
- .version = {1, 13, 0},
+ .version = {1, 14, 0},
.module = THIS_MODULE,
.features = DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY,
.ctr = dm_integrity_ctr,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 816/869] perf/x86/intel/uncore: Fix uncore_box ref/unref ordering
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (814 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 815/869] dm-integrity: replace forgeable discard filler with a keyed sector marker Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 817/869] i3c: master: Fix recursive locking during device registration Greg Kroah-Hartman
` (53 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Zide Chen, Peter Zijlstra (Intel),
Ian Rogers, Dapeng Mi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zide Chen <zide.chen@intel.com>
[ Upstream commit 174f0582e38abe03b88e15f04bfe58490f88cb19 ]
In uncore_event_cpu_online(), uncore_box_ref() was called before
uncore_change_context(). uncore_box_ref() gates on box->cpu >= 0,
but box->cpu is still -1 at that point because uncore_change_context()
has not run yet. As a result, the box is never initialized on the
first CPU to come online in a die, leaving it permanently
uninitialized in the single-CPU-per-die case.
Thus, box->refcnt is one count below the true value, and in the CPU
offline path, the box will be torn down on the second-to-last CPU.
In uncore_event_cpu_offline(), uncore_box_unref() was called after
uncore_change_context(), so box->cpu is already -1 when the collector
CPU goes offline, which prevents it from tearing down the box.
Fix by swapping the call order in both paths so that
uncore_box_{ref,unref}() runs at the point where box->cpu reflects
the correct context.
Move allocate_boxes() out of uncore_box_ref() to enable this
reordering.
Fixes: c74443d92f68 ("perf/x86/uncore: Support per PMU cpumask")
Signed-off-by: Zide Chen <zide.chen@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Reviewed-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Link: https://patch.msgid.link/20260611160033.66760-8-zide.chen@intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/events/intel/uncore.c | 46 +++++++++++++++-------------------
1 file changed, 20 insertions(+), 26 deletions(-)
diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c
index 2736815e651c7..2cc80848e3188 100644
--- a/arch/x86/events/intel/uncore.c
+++ b/arch/x86/events/intel/uncore.c
@@ -1535,9 +1535,15 @@ static int uncore_event_cpu_offline(unsigned int cpu)
{
int die, target;
+ /* Clear the references */
+ die = topology_logical_die_id(cpu);
+ uncore_box_unref(uncore_msr_uncores, die);
+ uncore_box_unref(uncore_mmio_uncores, die);
+
/* Check if exiting cpu is used for collecting uncore events */
if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask))
- goto unref;
+ return 0;
+
/* Find a new cpu to collect uncore events */
target = cpumask_any_but(topology_die_cpumask(cpu), cpu);
@@ -1550,16 +1556,10 @@ static int uncore_event_cpu_offline(unsigned int cpu)
uncore_change_context(uncore_msr_uncores, cpu, target);
uncore_change_context(uncore_mmio_uncores, cpu, target);
uncore_change_context(uncore_pci_uncores, cpu, target);
-
-unref:
- /* Clear the references */
- die = topology_logical_die_id(cpu);
- uncore_box_unref(uncore_msr_uncores, die);
- uncore_box_unref(uncore_mmio_uncores, die);
return 0;
}
-static int allocate_boxes(struct intel_uncore_type **types,
+static void allocate_boxes(struct intel_uncore_type **types,
unsigned int die, unsigned int cpu)
{
struct intel_uncore_box *box, *tmp;
@@ -1588,14 +1588,13 @@ static int allocate_boxes(struct intel_uncore_type **types,
list_del_init(&box->active_list);
box->pmu->boxes[die] = box;
}
- return 0;
+ return;
cleanup:
list_for_each_entry_safe(box, tmp, &allocated, active_list) {
list_del_init(&box->active_list);
kfree(box);
}
- return -ENOMEM;
}
static int uncore_box_ref(struct intel_uncore_type **types,
@@ -1604,11 +1603,7 @@ static int uncore_box_ref(struct intel_uncore_type **types,
struct intel_uncore_type *type;
struct intel_uncore_pmu *pmu;
struct intel_uncore_box *box;
- int i, ret;
-
- ret = allocate_boxes(types, id, cpu);
- if (ret)
- return ret;
+ int i;
for (; *types; types++) {
type = *types;
@@ -1624,27 +1619,26 @@ static int uncore_box_ref(struct intel_uncore_type **types,
static int uncore_event_cpu_online(unsigned int cpu)
{
- int die, target, msr_ret, mmio_ret;
+ int die, target;
die = topology_logical_die_id(cpu);
- msr_ret = uncore_box_ref(uncore_msr_uncores, die, cpu);
- mmio_ret = uncore_box_ref(uncore_mmio_uncores, die, cpu);
+ allocate_boxes(uncore_msr_uncores, die, cpu);
+ allocate_boxes(uncore_mmio_uncores, die, cpu);
/*
* Check if there is an online cpu in the package
* which collects uncore events already.
*/
target = cpumask_any_and(&uncore_cpu_mask, topology_die_cpumask(cpu));
- if (target < nr_cpu_ids)
- return 0;
-
- cpumask_set_cpu(cpu, &uncore_cpu_mask);
-
- if (!msr_ret)
+ if (target >= nr_cpu_ids) {
+ cpumask_set_cpu(cpu, &uncore_cpu_mask);
uncore_change_context(uncore_msr_uncores, -1, cpu);
- if (!mmio_ret)
uncore_change_context(uncore_mmio_uncores, -1, cpu);
- uncore_change_context(uncore_pci_uncores, -1, cpu);
+ uncore_change_context(uncore_pci_uncores, -1, cpu);
+ }
+
+ uncore_box_ref(uncore_msr_uncores, die, cpu);
+ uncore_box_ref(uncore_mmio_uncores, die, cpu);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 817/869] i3c: master: Fix recursive locking during device registration
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (815 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 816/869] perf/x86/intel/uncore: Fix uncore_box ref/unref ordering Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 818/869] xfs: remove unused trace event xfs_dqreclaim_dirty Greg Kroah-Hartman
` (52 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Adrian Hunter, Frank Li,
Alexandre Belloni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <adrian.hunter@intel.com>
[ Upstream commit 456f832e5fc26fbfd3b8200fd4553eee520cc377 ]
i3c_master_register_new_i3c_devs() registers newly discovered devices
while holding i3c_bus_normaluse_lock(), a down_read(). device_register()
can immediately probe the device, and probe callbacks typically invoke
I3C helpers that take i3c_bus_normaluse_lock() again, leading to a
recursive acquisition of the same rwsem. rwsems do not support recursive
read locking and can deadlock when a writer is waiting. See the
"Recursive read locks" section of Documentation/locking/lockdep-design.rst.
For example, with Intel LPSS I3C, LOCKDEP generates a WARNING like:
# echo intel-lpss-i3c.0 > /sys/bus/platform/drivers/mipi-i3c-hci/unbind
# echo intel-lpss-i3c.0 > /sys/bus/platform/drivers/mipi-i3c-hci/bind
WARNING: possible recursive locking detected
kworker/5:1/94 is trying to acquire lock:
ffff88811c810d78 (&i3cbus->lock){++++}-{4:4}, at: i3c_device_match_id+0x45/0x370
but task is already holding lock:
ffff88811c810d78 (&i3cbus->lock){++++}-{4:4}, at: i3c_master_reg_work_fn+0x21/0x5f0
Fix this by separating device creation from device registration.
Populate desc->dev under the maintenance lock, collect the devices that
still need registration into a local list, then release the lock before
calling device_register(). Finally retake the lock and clean up any
devices that failed to register.
Use the maintenance lock rather than the normal-use lock while adding
device objects. A write-side maintenance lock prevents readers from
observing a partially initialized desc->dev during initial device
population, or desc->dev disappearing if registration fails.
The local list requires a list node, so add a list node member to struct
i3c_device.
Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure")
Cc: stable@vger.kernel.org
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260807145638.168865-2-adrian.hunter@intel.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/i3c/master.c | 39 ++++++++++++++++++++++++++------------
include/linux/i3c/master.h | 3 +++
2 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 4b23fe33329b0..bb15b621c067b 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -1661,12 +1661,16 @@ static int i3c_master_early_i3c_dev_add(struct i3c_master_controller *master,
static void
i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
{
+ struct i3c_device *i3cdev, *tmp;
struct i3c_dev_desc *desc;
+ LIST_HEAD(i3c_unreg_devs);
int ret;
if (!master->init_done)
return;
+ i3c_bus_maintenance_lock(&master->bus);
+
i3c_bus_for_each_i3cdev(&master->bus, desc) {
if (desc->dev || !desc->info.dyn_addr || desc == master->this)
continue;
@@ -1687,15 +1691,30 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)
if (desc->boardinfo)
desc->dev->dev.of_node = desc->boardinfo->of_node;
- ret = device_register(&desc->dev->dev);
- if (ret) {
- dev_err(&master->dev,
- "Failed to add I3C device (err = %d)\n", ret);
- desc->dev->desc = NULL;
- put_device(&desc->dev->dev);
- desc->dev = NULL;
- }
+ list_add_tail(&desc->dev->node, &i3c_unreg_devs);
+ }
+
+ i3c_bus_maintenance_unlock(&master->bus);
+
+ list_for_each_entry_safe(i3cdev, tmp, &i3c_unreg_devs, node) {
+ ret = device_register(&i3cdev->dev);
+ if (ret)
+ dev_err(&master->dev, "Failed to add I3C device (err = %d)\n", ret);
+ else
+ list_del_init(&i3cdev->node);
}
+
+ i3c_bus_maintenance_lock(&master->bus);
+
+ list_for_each_entry_safe(i3cdev, tmp, &i3c_unreg_devs, node) {
+ list_del(&i3cdev->node);
+ desc = i3cdev->desc;
+ i3cdev->desc = NULL;
+ put_device(&i3cdev->dev);
+ desc->dev = NULL;
+ }
+
+ i3c_bus_maintenance_unlock(&master->bus);
}
/**
@@ -1724,9 +1743,7 @@ int i3c_master_do_daa(struct i3c_master_controller *master)
if (ret)
return ret;
- i3c_bus_normaluse_lock(&master->bus);
i3c_master_register_new_i3c_devs(master);
- i3c_bus_normaluse_unlock(&master->bus);
return 0;
}
@@ -2904,9 +2921,7 @@ int i3c_master_register(struct i3c_master_controller *master,
* register I3C devices discovered during the initial DAA.
*/
master->init_done = true;
- i3c_bus_normaluse_lock(&master->bus);
i3c_master_register_new_i3c_devs(master);
- i3c_bus_normaluse_unlock(&master->bus);
return 0;
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index 414a8acde0183..a17433c2458a3 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -228,6 +228,8 @@ struct i3c_dev_desc {
* every time the I3C device is rediscovered with a different dynamic
* address assigned
* @bus: I3C bus this device is attached to
+ * @node: unregistered device list node, only for use by
+ * i3c_master_register_new_i3c_devs(), it is not protected by a lock
*
* I3C device object exposed to I3C device drivers. The takes care of linking
* this object to the relevant &struct_i3c_dev_desc one.
@@ -238,6 +240,7 @@ struct i3c_device {
struct device dev;
struct i3c_dev_desc *desc;
struct i3c_bus *bus;
+ struct list_head node;
};
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 818/869] xfs: remove unused trace event xfs_dqreclaim_dirty
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (816 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 817/869] i3c: master: Fix recursive locking during device registration Greg Kroah-Hartman
@ 2026-10-17 16:00 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 819/869] ublk: fix dead loop when canceling io command Greg Kroah-Hartman
` (51 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:00 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Steven Rostedt (Google),
Christoph Hellwig, Darrick J. Wong, Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <rostedt@goodmis.org>
[ Upstream commit b9adb86b9045e6e912035e5991d370ac769be0b8 ]
The tracepoint trace_xfs_dqreclaim_dirty was removed with other code
removed from xfs_qm_dquot_isolate() but the defined tracepoint was not.
Fixes: d62016b1a2df ("xfs: avoid dquot buffer pin deadlock")
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
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_trace.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 526920b41766b..af12e4c7ecd2d 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -1097,7 +1097,6 @@ DEFINE_EVENT(xfs_dquot_class, name, \
TP_ARGS(dqp))
DEFINE_DQUOT_EVENT(xfs_dqadjust);
DEFINE_DQUOT_EVENT(xfs_dqreclaim_want);
-DEFINE_DQUOT_EVENT(xfs_dqreclaim_dirty);
DEFINE_DQUOT_EVENT(xfs_dqreclaim_busy);
DEFINE_DQUOT_EVENT(xfs_dqreclaim_done);
DEFINE_DQUOT_EVENT(xfs_dqattach_found);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 819/869] ublk: fix dead loop when canceling io command
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (817 preceding siblings ...)
2026-10-17 16:00 ` [PATCH 6.12 818/869] xfs: remove unused trace event xfs_dqreclaim_dirty Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 820/869] riscv: uaccess: Only restore the CSR_STATUS SUM bit Greg Kroah-Hartman
` (50 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Shinichiro Kawasaki, Ming Lei,
Jens Axboe, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Lei <ming.lei@redhat.com>
[ Upstream commit dd24f87f65c957f30e605e44961d2fd53a44c780 ]
Commit:
f40139fde527 ("ublk: fix race between io_uring_cmd_complete_in_task and
ublk_cancel_cmd")
adds a request state check in ublk_cancel_cmd(), and if the request is
started, skips canceling this uring_cmd.
However, the current uring_cmd may be in ACTIVE state, without block
request coming to the uring command. Meantime, if the cached request in
tag_set.tags[tag] has been delivered to ublk server and reycycled, then
this uring_cmd can't be canceled.
ublk requests are aborted in ublk char device release handler, which
depends on canceling all ACTIVE uring_cmd. So it causes a dead loop.
Fix this issue by not taking a stale request into account when canceling
uring_cmd in ublk_cancel_cmd().
Reported-by: Shinichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Closes: https://lore.kernel.org/linux-block/mruqwpf4tqenkbtgezv5oxwq7ngyq24jzeyqy4ixzvivatbbxv@4oh2wzz4e6qn/
Fixes: f40139fde527 ("ublk: fix race between io_uring_cmd_complete_in_task and ublk_cancel_cmd")
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250515162601.77346-1-ming.lei@redhat.com
[axboe: rewording of commit message]
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/block/ublk_drv.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 7fd286d8aadb2..085a4d624659f 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -1580,7 +1580,7 @@ static void ublk_cancel_cmd(struct ublk_queue *ubq, unsigned tag,
* that ublk_dispatch_req() is always called
*/
req = blk_mq_tag_to_rq(ub->tag_set.tags[ubq->q_id], tag);
- if (req && blk_mq_request_started(req))
+ if (req && blk_mq_request_started(req) && req->tag == tag)
return;
spin_lock(&ubq->cancel_lock);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 820/869] riscv: uaccess: Only restore the CSR_STATUS SUM bit
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (818 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 819/869] ublk: fix dead loop when canceling io command Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 821/869] s390/kvm: Initialize uninitialized flags variable Greg Kroah-Hartman
` (49 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Cyril Bur, Alexandre Ghiti,
Palmer Dabbelt, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cyril Bur <cyrilbur@tenstorrent.com>
[ Upstream commit 265d6aba165c500389c80d394ac247460c443ef5 ]
During switch to csrs will OR the value of the register into the
corresponding csr. In this case we're only interested in restoring the
SUM bit not the entire register.
Signed-off-by: Cyril Bur <cyrilbur@tenstorrent.com>
Link: https://lore.kernel.org/r/20250522160954.429333-1-cyrilbur@tenstorrent.com
Co-developed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Fixes: 788aa64c01f1 ("riscv: save the SR_SUM status over switches")
Link: https://lore.kernel.org/r/20250602121543.1544278-1-alexghiti@rivosinc.com
Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/riscv/include/asm/processor.h | 2 +-
arch/riscv/kernel/asm-offsets.c | 6 +++---
arch/riscv/kernel/entry.S | 9 +++++----
3 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 8b00833d24937..25a1385dcd3fd 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -103,7 +103,7 @@ struct thread_struct {
struct __riscv_d_ext_state fstate;
unsigned long bad_cause;
unsigned long envcfg;
- unsigned long status;
+ unsigned long sum;
u32 riscv_v_flags;
u32 vstate_ctrl;
struct __riscv_v_ext_state vstate;
diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c
index 1b575ddcb26ac..1d93658825f77 100644
--- a/arch/riscv/kernel/asm-offsets.c
+++ b/arch/riscv/kernel/asm-offsets.c
@@ -35,7 +35,7 @@ void asm_offsets(void)
OFFSET(TASK_THREAD_S9, task_struct, thread.s[9]);
OFFSET(TASK_THREAD_S10, task_struct, thread.s[10]);
OFFSET(TASK_THREAD_S11, task_struct, thread.s[11]);
- OFFSET(TASK_THREAD_STATUS, task_struct, thread.status);
+ OFFSET(TASK_THREAD_SUM, task_struct, thread.sum);
OFFSET(TASK_TI_CPU, task_struct, thread_info.cpu);
OFFSET(TASK_TI_FLAGS, task_struct, thread_info.flags);
@@ -349,8 +349,8 @@ void asm_offsets(void)
offsetof(struct task_struct, thread.s[11])
- offsetof(struct task_struct, thread.ra)
);
- DEFINE(TASK_THREAD_STATUS_RA,
- offsetof(struct task_struct, thread.status)
+ DEFINE(TASK_THREAD_SUM_RA,
+ offsetof(struct task_struct, thread.sum)
- offsetof(struct task_struct, thread.ra)
);
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index c4d7a9ece593b..d8f74743134a7 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -404,14 +404,15 @@ SYM_FUNC_START(__switch_to)
REG_S s11, TASK_THREAD_S11_RA(a3)
/* save the user space access flag */
- li s0, SR_SUM
- csrr s1, CSR_STATUS
- REG_S s1, TASK_THREAD_STATUS_RA(a3)
+ csrr s0, CSR_STATUS
+ REG_S s0, TASK_THREAD_SUM_RA(a3)
/* Save the kernel shadow call stack pointer */
scs_save_current
/* Restore context from next->thread */
- REG_L s0, TASK_THREAD_STATUS_RA(a4)
+ REG_L s0, TASK_THREAD_SUM_RA(a4)
+ li s1, SR_SUM
+ and s0, s0, s1
csrs CSR_STATUS, s0
REG_L ra, TASK_THREAD_RA_RA(a4)
REG_L sp, TASK_THREAD_SP_RA(a4)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 821/869] s390/kvm: Initialize uninitialized flags variable
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (819 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 820/869] riscv: uaccess: Only restore the CSR_STATUS SUM bit Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 822/869] KVM: s390: wrapper for KVM_BUG Greg Kroah-Hartman
` (48 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Janosch Frank, Claudio Imbrenda,
Heiko Carstens, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
[ Upstream commit 64844729a608d308089510fc3bb23abf602f4e47 ]
The flags variable was being used uninitialized.
Initialize it to 0 as expected.
For some reason neither gcc nor clang reported a warning.
Fixes: 05066cafa925 ("s390/mm/fault: Handle guest-related program interrupts in KVM")
Reported-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Link: https://lore.kernel.org/r/20241030161906.85476-1-imbrenda@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Stable-dep-of: 5f9df945d4e8 ("KVM: s390: Fix FOLL_*/FAULT_FLAG_* confusion")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/kvm/kvm-s390.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 885eedfc0af63..768d3a6f69597 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -4737,8 +4737,8 @@ static int vcpu_post_run_addressing_exception(struct kvm_vcpu *vcpu)
static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
{
+ unsigned int flags = 0;
unsigned long gaddr;
- unsigned int flags;
int rc = 0;
gaddr = current->thread.gmap_teid.addr * PAGE_SIZE;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 822/869] KVM: s390: wrapper for KVM_BUG
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (820 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 821/869] s390/kvm: Initialize uninitialized flags variable Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 823/869] KVM: s390: move pv gmap functions into kvm Greg Kroah-Hartman
` (47 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Borntraeger,
Christoph Schlameuss, Steffen Eiden, David Hildenbrand,
Claudio Imbrenda, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
[ Upstream commit decff09adbeba4b75a1982b1dc3991761914e2df ]
Wrap the call to KVM_BUG; this reduces code duplication and improves
readability.
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Link: https://lore.kernel.org/r/20250123144627.312456-3-imbrenda@linux.ibm.com
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20250123144627.312456-3-imbrenda@linux.ibm.com>
Stable-dep-of: 5f9df945d4e8 ("KVM: s390: Fix FOLL_*/FAULT_FLAG_* confusion")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/kvm/kvm-s390.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 768d3a6f69597..b15d7a0ac012a 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -4735,6 +4735,13 @@ static int vcpu_post_run_addressing_exception(struct kvm_vcpu *vcpu)
return kvm_s390_inject_prog_irq(vcpu, &pgm_info);
}
+static void kvm_s390_assert_primary_as(struct kvm_vcpu *vcpu)
+{
+ KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm,
+ "Unexpected program interrupt 0x%x, TEID 0x%016lx",
+ current->thread.gmap_int_code, current->thread.gmap_teid.val);
+}
+
static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
{
unsigned int flags = 0;
@@ -4750,9 +4757,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
vcpu->stat.exit_null++;
break;
case PGM_NON_SECURE_STORAGE_ACCESS:
- KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm,
- "Unexpected program interrupt 0x%x, TEID 0x%016lx",
- current->thread.gmap_int_code, current->thread.gmap_teid.val);
+ kvm_s390_assert_primary_as(vcpu);
/*
* This is normal operation; a page belonging to a protected
* guest has not been imported yet. Try to import the page into
@@ -4763,9 +4768,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
break;
case PGM_SECURE_STORAGE_ACCESS:
case PGM_SECURE_STORAGE_VIOLATION:
- KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm,
- "Unexpected program interrupt 0x%x, TEID 0x%016lx",
- current->thread.gmap_int_code, current->thread.gmap_teid.val);
+ kvm_s390_assert_primary_as(vcpu);
/*
* This can happen after a reboot with asynchronous teardown;
* the new guest (normal or protected) will run on top of the
@@ -4794,9 +4797,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
case PGM_REGION_FIRST_TRANS:
case PGM_REGION_SECOND_TRANS:
case PGM_REGION_THIRD_TRANS:
- KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm,
- "Unexpected program interrupt 0x%x, TEID 0x%016lx",
- current->thread.gmap_int_code, current->thread.gmap_teid.val);
+ kvm_s390_assert_primary_as(vcpu);
if (vcpu->arch.gmap->pfault_enabled) {
rc = gmap_fault(vcpu->arch.gmap, gaddr, flags | FAULT_FLAG_RETRY_NOWAIT);
if (rc == -EFAULT)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 823/869] KVM: s390: move pv gmap functions into kvm
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (821 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 822/869] KVM: s390: wrapper for KVM_BUG Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 824/869] KVM: s390: use __kvm_faultin_pfn() Greg Kroah-Hartman
` (46 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Janosch Frank, Christoph Schlameuss,
Claudio Imbrenda, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
[ Upstream commit 5cbe24350b7d8ef6d466a37d56b07ae643c622ca ]
Move gmap related functions from kernel/uv into kvm.
Create a new file to collect gmap-related functions.
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
[fixed unpack_one(), thanks mhartmay@linux.ibm.com]
Link: https://lore.kernel.org/r/20250123144627.312456-6-imbrenda@linux.ibm.com
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20250123144627.312456-6-imbrenda@linux.ibm.com>
Stable-dep-of: 5f9df945d4e8 ("KVM: s390: Fix FOLL_*/FAULT_FLAG_* confusion")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/include/asm/gmap.h | 1 +
arch/s390/include/asm/uv.h | 6 +-
arch/s390/kernel/uv.c | 292 ++++-------------------------------
arch/s390/kvm/Makefile | 2 +-
arch/s390/kvm/gmap.c | 212 +++++++++++++++++++++++++
arch/s390/kvm/gmap.h | 17 ++
arch/s390/kvm/intercept.c | 3 +-
arch/s390/kvm/kvm-s390.c | 1 +
arch/s390/kvm/pv.c | 21 +++
arch/s390/mm/gmap.c | 28 ++++
10 files changed, 315 insertions(+), 268 deletions(-)
create mode 100644 arch/s390/kvm/gmap.c
create mode 100644 arch/s390/kvm/gmap.h
diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h
index 9725586f42597..22775b1ce7101 100644
--- a/arch/s390/include/asm/gmap.h
+++ b/arch/s390/include/asm/gmap.h
@@ -152,6 +152,7 @@ int s390_replace_asce(struct gmap *gmap);
void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns);
int __s390_uv_destroy_range(struct mm_struct *mm, unsigned long start,
unsigned long end, bool interruptible);
+int kvm_s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio, bool split);
/**
* s390_uv_destroy_range - Destroy a range of pages in the given mm.
diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h
index 153d93468b77c..5cd127654a860 100644
--- a/arch/s390/include/asm/uv.h
+++ b/arch/s390/include/asm/uv.h
@@ -476,12 +476,12 @@ static inline int is_prot_virt_host(void)
}
int uv_pin_shared(unsigned long paddr);
-int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb);
-int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr);
int uv_destroy_folio(struct folio *folio);
int uv_destroy_pte(pte_t pte);
int uv_convert_from_secure_pte(pte_t pte);
-int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr);
+int make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb);
+int uv_convert_from_secure(unsigned long paddr);
+int uv_convert_from_secure_folio(struct folio *folio);
void setup_uv(void);
diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c
index 9646f773208a1..23c3637f5014b 100644
--- a/arch/s390/kernel/uv.c
+++ b/arch/s390/kernel/uv.c
@@ -19,19 +19,6 @@
#include <asm/sections.h>
#include <asm/uv.h>
-#if !IS_ENABLED(CONFIG_KVM)
-unsigned long __gmap_translate(struct gmap *gmap, unsigned long gaddr)
-{
- return 0;
-}
-
-int gmap_fault(struct gmap *gmap, unsigned long gaddr,
- unsigned int fault_flags)
-{
- return 0;
-}
-#endif
-
/* the bootdata_preserved fields come from ones in arch/s390/boot/uv.c */
int __bootdata_preserved(prot_virt_guest);
EXPORT_SYMBOL(prot_virt_guest);
@@ -159,6 +146,7 @@ int uv_destroy_folio(struct folio *folio)
folio_put(folio);
return rc;
}
+EXPORT_SYMBOL(uv_destroy_folio);
/*
* The present PTE still indirectly holds a folio reference through the mapping.
@@ -175,7 +163,7 @@ int uv_destroy_pte(pte_t pte)
*
* @paddr: Absolute host address of page to be exported
*/
-static int uv_convert_from_secure(unsigned long paddr)
+int uv_convert_from_secure(unsigned long paddr)
{
struct uv_cb_cfs uvcb = {
.header.cmd = UVC_CMD_CONV_FROM_SEC_STOR,
@@ -187,11 +175,12 @@ static int uv_convert_from_secure(unsigned long paddr)
return -EINVAL;
return 0;
}
+EXPORT_SYMBOL_GPL(uv_convert_from_secure);
/*
* The caller must already hold a reference to the folio.
*/
-static int uv_convert_from_secure_folio(struct folio *folio)
+int uv_convert_from_secure_folio(struct folio *folio)
{
int rc;
@@ -206,6 +195,7 @@ static int uv_convert_from_secure_folio(struct folio *folio)
folio_put(folio);
return rc;
}
+EXPORT_SYMBOL_GPL(uv_convert_from_secure_folio);
/*
* The present PTE still indirectly holds a folio reference through the mapping.
@@ -237,13 +227,33 @@ static int expected_folio_refs(struct folio *folio)
return res;
}
-static int make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
+/**
+ * make_folio_secure() - make a folio secure
+ * @folio: the folio to make secure
+ * @uvcb: the uvcb that describes the UVC to be used
+ *
+ * The folio @folio will be made secure if possible, @uvcb will be passed
+ * as-is to the UVC.
+ *
+ * Return: 0 on success;
+ * -EBUSY if the folio is in writeback or has too many references;
+ * -E2BIG if the folio is large;
+ * -EAGAIN if the UVC needs to be attempted again;
+ * -ENXIO if the address is not mapped;
+ * -EINVAL if the UVC failed for other reasons.
+ *
+ * Context: The caller must hold exactly one extra reference on the folio
+ * (it's the same logic as split_folio())
+ */
+int make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
{
int expected, cc = 0;
+ if (folio_test_large(folio))
+ return -E2BIG;
if (folio_test_writeback(folio))
- return -EAGAIN;
- expected = expected_folio_refs(folio);
+ return -EBUSY;
+ expected = expected_folio_refs(folio) + 1;
if (!folio_ref_freeze(folio, expected))
return -EBUSY;
set_bit(PG_arch_1, &folio->flags);
@@ -267,251 +277,7 @@ static int make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
return -EAGAIN;
return uvcb->rc == 0x10a ? -ENXIO : -EINVAL;
}
-
-/**
- * should_export_before_import - Determine whether an export is needed
- * before an import-like operation
- * @uvcb: the Ultravisor control block of the UVC to be performed
- * @mm: the mm of the process
- *
- * Returns whether an export is needed before every import-like operation.
- * This is needed for shared pages, which don't trigger a secure storage
- * exception when accessed from a different guest.
- *
- * Although considered as one, the Unpin Page UVC is not an actual import,
- * so it is not affected.
- *
- * No export is needed also when there is only one protected VM, because the
- * page cannot belong to the wrong VM in that case (there is no "other VM"
- * it can belong to).
- *
- * Return: true if an export is needed before every import, otherwise false.
- */
-static bool should_export_before_import(struct uv_cb_header *uvcb, struct mm_struct *mm)
-{
- /*
- * The misc feature indicates, among other things, that importing a
- * shared page from a different protected VM will automatically also
- * transfer its ownership.
- */
- if (uv_has_feature(BIT_UV_FEAT_MISC))
- return false;
- if (uvcb->cmd == UVC_CMD_UNPIN_PAGE_SHARED)
- return false;
- return atomic_read(&mm->context.protected_count) > 1;
-}
-
-/*
- * Drain LRU caches: the local one on first invocation and the ones of all
- * CPUs on successive invocations. Returns "true" on the first invocation.
- */
-static bool drain_lru(bool *drain_lru_called)
-{
- /*
- * If we have tried a local drain and the folio refcount
- * still does not match our expected safe value, try with a
- * system wide drain. This is needed if the pagevecs holding
- * the page are on a different CPU.
- */
- if (*drain_lru_called) {
- lru_add_drain_all();
- /* We give up here, don't retry immediately. */
- return false;
- }
- /*
- * We are here if the folio refcount does not match the
- * expected safe value. The main culprits are usually
- * pagevecs. With lru_add_drain() we drain the pagevecs
- * on the local CPU so that hopefully the refcount will
- * reach the expected safe value.
- */
- lru_add_drain();
- *drain_lru_called = true;
- /* The caller should try again immediately */
- return true;
-}
-
-/*
- * Requests the Ultravisor to make a page accessible to a guest.
- * If it's brought in the first time, it will be cleared. If
- * it has been exported before, it will be decrypted and integrity
- * checked.
- */
-int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb)
-{
- struct vm_area_struct *vma;
- bool drain_lru_called = false;
- spinlock_t *ptelock;
- unsigned long uaddr;
- struct folio *folio;
- pte_t *ptep;
- int rc;
-
-again:
- rc = -EFAULT;
- mmap_read_lock(gmap->mm);
-
- uaddr = __gmap_translate(gmap, gaddr);
- if (IS_ERR_VALUE(uaddr))
- goto out;
- vma = vma_lookup(gmap->mm, uaddr);
- if (!vma)
- goto out;
- /*
- * Secure pages cannot be huge and userspace should not combine both.
- * In case userspace does it anyway this will result in an -EFAULT for
- * the unpack. The guest is thus never reaching secure mode. If
- * userspace is playing dirty tricky with mapping huge pages later
- * on this will result in a segmentation fault.
- */
- if (is_vm_hugetlb_page(vma))
- goto out;
-
- rc = -ENXIO;
- ptep = get_locked_pte(gmap->mm, uaddr, &ptelock);
- if (!ptep)
- goto out;
- if (pte_present(*ptep) && !(pte_val(*ptep) & _PAGE_INVALID) && pte_write(*ptep)) {
- folio = page_folio(pte_page(*ptep));
- rc = -EAGAIN;
- if (folio_test_large(folio)) {
- rc = -E2BIG;
- } else if (folio_trylock(folio)) {
- if (should_export_before_import(uvcb, gmap->mm))
- uv_convert_from_secure(PFN_PHYS(folio_pfn(folio)));
- rc = make_folio_secure(folio, uvcb);
- folio_unlock(folio);
- }
-
- /*
- * Once we drop the PTL, the folio may get unmapped and
- * freed immediately. We need a temporary reference.
- */
- if (rc == -EAGAIN || rc == -E2BIG)
- folio_get(folio);
- }
- pte_unmap_unlock(ptep, ptelock);
-out:
- mmap_read_unlock(gmap->mm);
-
- switch (rc) {
- case -E2BIG:
- folio_lock(folio);
- rc = split_folio(folio);
- folio_unlock(folio);
- folio_put(folio);
-
- switch (rc) {
- case 0:
- /* Splitting succeeded, try again immediately. */
- goto again;
- case -EAGAIN:
- /* Additional folio references. */
- if (drain_lru(&drain_lru_called))
- goto again;
- return -EAGAIN;
- case -EBUSY:
- /* Unexpected race. */
- return -EAGAIN;
- }
- WARN_ON_ONCE(1);
- return -ENXIO;
- case -EAGAIN:
- /*
- * If we are here because the UVC returned busy or partial
- * completion, this is just a useless check, but it is safe.
- */
- folio_wait_writeback(folio);
- folio_put(folio);
- return -EAGAIN;
- case -EBUSY:
- /* Additional folio references. */
- if (drain_lru(&drain_lru_called))
- goto again;
- return -EAGAIN;
- case -ENXIO:
- if (gmap_fault(gmap, gaddr, FAULT_FLAG_WRITE))
- return -EFAULT;
- return -EAGAIN;
- }
- return rc;
-}
-EXPORT_SYMBOL_GPL(gmap_make_secure);
-
-int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr)
-{
- struct uv_cb_cts uvcb = {
- .header.cmd = UVC_CMD_CONV_TO_SEC_STOR,
- .header.len = sizeof(uvcb),
- .guest_handle = gmap->guest_handle,
- .gaddr = gaddr,
- };
-
- return gmap_make_secure(gmap, gaddr, &uvcb);
-}
-EXPORT_SYMBOL_GPL(gmap_convert_to_secure);
-
-/**
- * gmap_destroy_page - Destroy a guest page.
- * @gmap: the gmap of the guest
- * @gaddr: the guest address to destroy
- *
- * An attempt will be made to destroy the given guest page. If the attempt
- * fails, an attempt is made to export the page. If both attempts fail, an
- * appropriate error is returned.
- */
-int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr)
-{
- struct vm_area_struct *vma;
- struct folio_walk fw;
- unsigned long uaddr;
- struct folio *folio;
- int rc;
-
- rc = -EFAULT;
- mmap_read_lock(gmap->mm);
-
- uaddr = __gmap_translate(gmap, gaddr);
- if (IS_ERR_VALUE(uaddr))
- goto out;
- vma = vma_lookup(gmap->mm, uaddr);
- if (!vma)
- goto out;
- /*
- * Huge pages should not be able to become secure
- */
- if (is_vm_hugetlb_page(vma))
- goto out;
-
- rc = 0;
- folio = folio_walk_start(&fw, vma, uaddr, 0);
- if (!folio)
- goto out;
- /*
- * See gmap_make_secure(): large folios cannot be secure. Small
- * folio implies FW_LEVEL_PTE.
- */
- if (folio_test_large(folio) || !pte_write(fw.pte))
- goto out_walk_end;
- rc = uv_destroy_folio(folio);
- /*
- * Fault handlers can race; it is possible that two CPUs will fault
- * on the same secure page. One CPU can destroy the page, reboot,
- * re-enter secure mode and import it, while the second CPU was
- * stuck at the beginning of the handler. At some point the second
- * CPU will be able to progress, and it will not be able to destroy
- * the page. In that case we do not want to terminate the process,
- * we instead try to export the page.
- */
- if (rc)
- rc = uv_convert_from_secure_folio(folio);
-out_walk_end:
- folio_walk_end(&fw, vma);
-out:
- mmap_read_unlock(gmap->mm);
- return rc;
-}
-EXPORT_SYMBOL_GPL(gmap_destroy_page);
+EXPORT_SYMBOL_GPL(make_folio_secure);
/*
* To be called with the folio locked or with an extra reference! This will
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile
index 02217fb4ae10f..d972dea657fd1 100644
--- a/arch/s390/kvm/Makefile
+++ b/arch/s390/kvm/Makefile
@@ -8,7 +8,7 @@ include $(srctree)/virt/kvm/Makefile.kvm
ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
kvm-y += kvm-s390.o intercept.o interrupt.o priv.o sigp.o
-kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o
+kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o gmap.o
kvm-$(CONFIG_VFIO_PCI_ZDEV_KVM) += pci.o
obj-$(CONFIG_KVM) += kvm.o
diff --git a/arch/s390/kvm/gmap.c b/arch/s390/kvm/gmap.c
new file mode 100644
index 0000000000000..02adf151d4de4
--- /dev/null
+++ b/arch/s390/kvm/gmap.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Guest memory management for KVM/s390
+ *
+ * Copyright IBM Corp. 2008, 2020, 2024
+ *
+ * Author(s): Claudio Imbrenda <imbrenda@linux.ibm.com>
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * David Hildenbrand <david@redhat.com>
+ * Janosch Frank <frankja@linux.vnet.ibm.com>
+ */
+
+#include <linux/compiler.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/pgtable.h>
+#include <linux/pagemap.h>
+
+#include <asm/lowcore.h>
+#include <asm/gmap.h>
+#include <asm/uv.h>
+
+#include "gmap.h"
+
+/**
+ * should_export_before_import - Determine whether an export is needed
+ * before an import-like operation
+ * @uvcb: the Ultravisor control block of the UVC to be performed
+ * @mm: the mm of the process
+ *
+ * Returns whether an export is needed before every import-like operation.
+ * This is needed for shared pages, which don't trigger a secure storage
+ * exception when accessed from a different guest.
+ *
+ * Although considered as one, the Unpin Page UVC is not an actual import,
+ * so it is not affected.
+ *
+ * No export is needed also when there is only one protected VM, because the
+ * page cannot belong to the wrong VM in that case (there is no "other VM"
+ * it can belong to).
+ *
+ * Return: true if an export is needed before every import, otherwise false.
+ */
+static bool should_export_before_import(struct uv_cb_header *uvcb, struct mm_struct *mm)
+{
+ /*
+ * The misc feature indicates, among other things, that importing a
+ * shared page from a different protected VM will automatically also
+ * transfer its ownership.
+ */
+ if (uv_has_feature(BIT_UV_FEAT_MISC))
+ return false;
+ if (uvcb->cmd == UVC_CMD_UNPIN_PAGE_SHARED)
+ return false;
+ return atomic_read(&mm->context.protected_count) > 1;
+}
+
+static int __gmap_make_secure(struct gmap *gmap, struct page *page, void *uvcb)
+{
+ struct folio *folio = page_folio(page);
+ int rc;
+
+ /*
+ * Secure pages cannot be huge and userspace should not combine both.
+ * In case userspace does it anyway this will result in an -EFAULT for
+ * the unpack. The guest is thus never reaching secure mode.
+ * If userspace plays dirty tricks and decides to map huge pages at a
+ * later point in time, it will receive a segmentation fault or
+ * KVM_RUN will return -EFAULT.
+ */
+ if (folio_test_hugetlb(folio))
+ return -EFAULT;
+ if (folio_test_large(folio)) {
+ mmap_read_unlock(gmap->mm);
+ rc = kvm_s390_wiggle_split_folio(gmap->mm, folio, true);
+ mmap_read_lock(gmap->mm);
+ if (rc)
+ return rc;
+ folio = page_folio(page);
+ }
+
+ if (!folio_trylock(folio))
+ return -EAGAIN;
+ if (should_export_before_import(uvcb, gmap->mm))
+ uv_convert_from_secure(folio_to_phys(folio));
+ rc = make_folio_secure(folio, uvcb);
+ folio_unlock(folio);
+
+ /*
+ * In theory a race is possible and the folio might have become
+ * large again before the folio_trylock() above. In that case, no
+ * action is performed and -EAGAIN is returned; the callers will
+ * have to try again later.
+ * In most cases this implies running the VM again, getting the same
+ * exception again, and make another attempt in this function.
+ * This is expected to happen extremely rarely.
+ */
+ if (rc == -E2BIG)
+ return -EAGAIN;
+ /* The folio has too many references, try to shake some off */
+ if (rc == -EBUSY) {
+ mmap_read_unlock(gmap->mm);
+ kvm_s390_wiggle_split_folio(gmap->mm, folio, false);
+ mmap_read_lock(gmap->mm);
+ return -EAGAIN;
+ }
+
+ return rc;
+}
+
+/**
+ * gmap_make_secure() - make one guest page secure
+ * @gmap: the guest gmap
+ * @gaddr: the guest address that needs to be made secure
+ * @uvcb: the UVCB specifying which operation needs to be performed
+ *
+ * Context: needs to be called with kvm->srcu held.
+ * Return: 0 on success, < 0 in case of error (see __gmap_make_secure()).
+ */
+int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb)
+{
+ struct kvm *kvm = gmap->private;
+ struct page *page;
+ int rc = 0;
+
+ lockdep_assert_held(&kvm->srcu);
+
+ page = gfn_to_page(kvm, gpa_to_gfn(gaddr));
+ mmap_read_lock(gmap->mm);
+ if (page)
+ rc = __gmap_make_secure(gmap, page, uvcb);
+ kvm_release_page_clean(page);
+ mmap_read_unlock(gmap->mm);
+
+ return rc;
+}
+
+int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr)
+{
+ struct uv_cb_cts uvcb = {
+ .header.cmd = UVC_CMD_CONV_TO_SEC_STOR,
+ .header.len = sizeof(uvcb),
+ .guest_handle = gmap->guest_handle,
+ .gaddr = gaddr,
+ };
+
+ return gmap_make_secure(gmap, gaddr, &uvcb);
+}
+
+/**
+ * __gmap_destroy_page() - Destroy a guest page.
+ * @gmap: the gmap of the guest
+ * @page: the page to destroy
+ *
+ * An attempt will be made to destroy the given guest page. If the attempt
+ * fails, an attempt is made to export the page. If both attempts fail, an
+ * appropriate error is returned.
+ *
+ * Context: must be called holding the mm lock for gmap->mm
+ */
+static int __gmap_destroy_page(struct gmap *gmap, struct page *page)
+{
+ struct folio *folio = page_folio(page);
+ int rc;
+
+ /*
+ * See gmap_make_secure(): large folios cannot be secure. Small
+ * folio implies FW_LEVEL_PTE.
+ */
+ if (folio_test_large(folio))
+ return -EFAULT;
+
+ rc = uv_destroy_folio(folio);
+ /*
+ * Fault handlers can race; it is possible that two CPUs will fault
+ * on the same secure page. One CPU can destroy the page, reboot,
+ * re-enter secure mode and import it, while the second CPU was
+ * stuck at the beginning of the handler. At some point the second
+ * CPU will be able to progress, and it will not be able to destroy
+ * the page. In that case we do not want to terminate the process,
+ * we instead try to export the page.
+ */
+ if (rc)
+ rc = uv_convert_from_secure_folio(folio);
+
+ return rc;
+}
+
+/**
+ * gmap_destroy_page() - Destroy a guest page.
+ * @gmap: the gmap of the guest
+ * @gaddr: the guest address to destroy
+ *
+ * An attempt will be made to destroy the given guest page. If the attempt
+ * fails, an attempt is made to export the page. If both attempts fail, an
+ * appropriate error is returned.
+ *
+ * Context: may sleep.
+ */
+int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr)
+{
+ struct page *page;
+ int rc = 0;
+
+ mmap_read_lock(gmap->mm);
+ page = gfn_to_page(gmap->private, gpa_to_gfn(gaddr));
+ if (page)
+ rc = __gmap_destroy_page(gmap, page);
+ kvm_release_page_clean(page);
+ mmap_read_unlock(gmap->mm);
+ return rc;
+}
diff --git a/arch/s390/kvm/gmap.h b/arch/s390/kvm/gmap.h
new file mode 100644
index 0000000000000..f2b52ce29be3d
--- /dev/null
+++ b/arch/s390/kvm/gmap.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * KVM guest address space mapping code
+ *
+ * Copyright IBM Corp. 2007, 2016, 2025
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Claudio Imbrenda <imbrenda@linux.ibm.com>
+ */
+
+#ifndef ARCH_KVM_S390_GMAP_H
+#define ARCH_KVM_S390_GMAP_H
+
+int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb);
+int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr);
+int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr);
+
+#endif
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 9c4304d484de7..deb2f2b3e5c33 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -21,6 +21,7 @@
#include "gaccess.h"
#include "trace.h"
#include "trace-s390.h"
+#include "gmap.h"
u8 kvm_s390_get_ilen(struct kvm_vcpu *vcpu)
{
@@ -549,7 +550,7 @@ static int handle_pv_uvc(struct kvm_vcpu *vcpu)
* If the unpin did not succeed, the guest will exit again for the UVC
* and we will retry the unpin.
*/
- if (rc == -EINVAL)
+ if (rc == -EINVAL || rc == -ENXIO)
return 0;
/*
* If we got -EAGAIN here, we simply return it. It will eventually
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index b15d7a0ac012a..49d967bde326a 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -49,6 +49,7 @@
#include "kvm-s390.h"
#include "gaccess.h"
#include "pci.h"
+#include "gmap.h"
#define CREATE_TRACE_POINTS
#include "trace.h"
diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c
index 75e81ba26d047..22c012aa5206b 100644
--- a/arch/s390/kvm/pv.c
+++ b/arch/s390/kvm/pv.c
@@ -17,6 +17,7 @@
#include <linux/sched/mm.h>
#include <linux/mmu_notifier.h>
#include "kvm-s390.h"
+#include "gmap.h"
bool kvm_s390_pv_is_protected(struct kvm *kvm)
{
@@ -638,10 +639,28 @@ static int unpack_one(struct kvm *kvm, unsigned long addr, u64 tweak,
.tweak[1] = offset,
};
int ret = gmap_make_secure(kvm->arch.gmap, addr, &uvcb);
+ unsigned long vmaddr;
+ bool unlocked;
*rc = uvcb.header.rc;
*rrc = uvcb.header.rrc;
+ if (ret == -ENXIO) {
+ mmap_read_lock(kvm->mm);
+ vmaddr = gfn_to_hva(kvm, gpa_to_gfn(addr));
+ if (kvm_is_error_hva(vmaddr)) {
+ ret = -EFAULT;
+ } else {
+ ret = fixup_user_fault(kvm->mm, vmaddr, FAULT_FLAG_WRITE, &unlocked);
+ if (!ret)
+ ret = __gmap_link(kvm->arch.gmap, addr, vmaddr);
+ }
+ mmap_read_unlock(kvm->mm);
+ if (!ret)
+ return -EAGAIN;
+ return ret;
+ }
+
if (ret && ret != -EAGAIN)
KVM_UV_EVENT(kvm, 3, "PROTVIRT VM UNPACK: failed addr %llx with rc %x rrc %x",
uvcb.gaddr, *rc, *rrc);
@@ -660,6 +679,8 @@ int kvm_s390_pv_unpack(struct kvm *kvm, unsigned long addr, unsigned long size,
KVM_UV_EVENT(kvm, 3, "PROTVIRT VM UNPACK: start addr %lx size %lx",
addr, size);
+ guard(srcu)(&kvm->srcu);
+
while (offset < size) {
ret = unpack_one(kvm, addr, tweak, offset, rc, rrc);
if (ret == -EAGAIN) {
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index eb0b51a36be01..2527c6574ad12 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -2982,3 +2982,31 @@ int s390_replace_asce(struct gmap *gmap)
return 0;
}
EXPORT_SYMBOL_GPL(s390_replace_asce);
+
+/**
+ * kvm_s390_wiggle_split_folio() - try to drain extra references to a folio and optionally split
+ * @mm: the mm containing the folio to work on
+ * @folio: the folio
+ * @split: whether to split a large folio
+ *
+ * Context: Must be called while holding an extra reference to the folio;
+ * the mm lock should not be held.
+ */
+int kvm_s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio, bool split)
+{
+ int rc;
+
+ lockdep_assert_not_held(&mm->mmap_lock);
+ folio_wait_writeback(folio);
+ lru_add_drain_all();
+ if (split) {
+ folio_lock(folio);
+ rc = split_folio(folio);
+ folio_unlock(folio);
+
+ if (rc != -EBUSY)
+ return rc;
+ }
+ return -EAGAIN;
+}
+EXPORT_SYMBOL_GPL(kvm_s390_wiggle_split_folio);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 824/869] KVM: s390: use __kvm_faultin_pfn()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (822 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 823/869] KVM: s390: move pv gmap functions into kvm Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 825/869] KVM: s390: move gmap_shadow_pgt_lookup() into kvm Greg Kroah-Hartman
` (45 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Janosch Frank, Christoph Schlameuss,
Claudio Imbrenda, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
[ Upstream commit 3762e905ec2e498c96464e094b7d46be98151d3b ]
Refactor the existing page fault handling code to use __kvm_faultin_pfn().
This possible now that memslots are always present.
Acked-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Link: https://lore.kernel.org/r/20250123144627.312456-7-imbrenda@linux.ibm.com
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20250123144627.312456-7-imbrenda@linux.ibm.com>
Stable-dep-of: 5f9df945d4e8 ("KVM: s390: Fix FOLL_*/FAULT_FLAG_* confusion")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/kvm/kvm-s390.c | 126 ++++++++++++++++++++++++++++++---------
arch/s390/kvm/kvm-s390.h | 6 ++
arch/s390/mm/gmap.c | 1 +
3 files changed, 106 insertions(+), 27 deletions(-)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 49d967bde326a..6224e4188c6d6 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -4743,11 +4743,104 @@ static void kvm_s390_assert_primary_as(struct kvm_vcpu *vcpu)
current->thread.gmap_int_code, current->thread.gmap_teid.val);
}
+/*
+ * __kvm_s390_handle_dat_fault() - handle a dat fault for the gmap of a vcpu
+ * @vcpu: the vCPU whose gmap is to be fixed up
+ * @gfn: the guest frame number used for memslots (including fake memslots)
+ * @gaddr: the gmap address, does not have to match @gfn for ucontrol gmaps
+ * @flags: FOLL_* flags
+ *
+ * Return: 0 on success, < 0 in case of error.
+ * Context: The mm lock must not be held before calling. May sleep.
+ */
+int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, unsigned int flags)
+{
+ struct kvm_memory_slot *slot;
+ unsigned int fault_flags;
+ bool writable, unlocked;
+ unsigned long vmaddr;
+ struct page *page;
+ kvm_pfn_t pfn;
+ int rc;
+
+ slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
+ if (!slot || slot->flags & KVM_MEMSLOT_INVALID)
+ return vcpu_post_run_addressing_exception(vcpu);
+
+ fault_flags = flags & FOLL_WRITE ? FAULT_FLAG_WRITE : 0;
+ if (vcpu->arch.gmap->pfault_enabled)
+ flags |= FOLL_NOWAIT;
+ vmaddr = __gfn_to_hva_memslot(slot, gfn);
+
+try_again:
+ pfn = __kvm_faultin_pfn(slot, gfn, flags, &writable, &page);
+
+ /* Access outside memory, inject addressing exception */
+ if (is_noslot_pfn(pfn))
+ return vcpu_post_run_addressing_exception(vcpu);
+ /* Signal pending: try again */
+ if (pfn == KVM_PFN_ERR_SIGPENDING)
+ return -EAGAIN;
+
+ /* Needs I/O, try to setup async pfault (only possible with FOLL_NOWAIT) */
+ if (pfn == KVM_PFN_ERR_NEEDS_IO) {
+ trace_kvm_s390_major_guest_pfault(vcpu);
+ if (kvm_arch_setup_async_pf(vcpu))
+ return 0;
+ vcpu->stat.pfault_sync++;
+ /* Could not setup async pfault, try again synchronously */
+ flags &= ~FOLL_NOWAIT;
+ goto try_again;
+ }
+ /* Any other error */
+ if (is_error_pfn(pfn))
+ return -EFAULT;
+
+ /* Success */
+ mmap_read_lock(vcpu->arch.gmap->mm);
+ /* Mark the userspace PTEs as young and/or dirty, to avoid page fault loops */
+ rc = fixup_user_fault(vcpu->arch.gmap->mm, vmaddr, fault_flags, &unlocked);
+ if (!rc)
+ rc = __gmap_link(vcpu->arch.gmap, gaddr, vmaddr);
+ scoped_guard(spinlock, &vcpu->kvm->mmu_lock) {
+ kvm_release_faultin_page(vcpu->kvm, page, false, writable);
+ }
+ mmap_read_unlock(vcpu->arch.gmap->mm);
+ return rc;
+}
+
+static int vcpu_dat_fault_handler(struct kvm_vcpu *vcpu, unsigned long gaddr, unsigned int flags)
+{
+ unsigned long gaddr_tmp;
+ gfn_t gfn;
+
+ gfn = gpa_to_gfn(gaddr);
+ if (kvm_is_ucontrol(vcpu->kvm)) {
+ /*
+ * This translates the per-vCPU guest address into a
+ * fake guest address, which can then be used with the
+ * fake memslots that are identity mapping userspace.
+ * This allows ucontrol VMs to use the normal fault
+ * resolution path, like normal VMs.
+ */
+ mmap_read_lock(vcpu->arch.gmap->mm);
+ gaddr_tmp = __gmap_translate(vcpu->arch.gmap, gaddr);
+ mmap_read_unlock(vcpu->arch.gmap->mm);
+ if (gaddr_tmp == -EFAULT) {
+ vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL;
+ vcpu->run->s390_ucontrol.trans_exc_code = gaddr;
+ vcpu->run->s390_ucontrol.pgm_code = PGM_SEGMENT_TRANSLATION;
+ return -EREMOTE;
+ }
+ gfn = gpa_to_gfn(gaddr_tmp);
+ }
+ return __kvm_s390_handle_dat_fault(vcpu, gfn, gaddr, flags);
+}
+
static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
{
unsigned int flags = 0;
unsigned long gaddr;
- int rc = 0;
gaddr = current->thread.gmap_teid.addr * PAGE_SIZE;
if (kvm_s390_cur_gmap_fault_is_write())
@@ -4799,37 +4892,14 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
case PGM_REGION_SECOND_TRANS:
case PGM_REGION_THIRD_TRANS:
kvm_s390_assert_primary_as(vcpu);
- if (vcpu->arch.gmap->pfault_enabled) {
- rc = gmap_fault(vcpu->arch.gmap, gaddr, flags | FAULT_FLAG_RETRY_NOWAIT);
- if (rc == -EFAULT)
- return vcpu_post_run_addressing_exception(vcpu);
- if (rc == -EAGAIN) {
- trace_kvm_s390_major_guest_pfault(vcpu);
- if (kvm_arch_setup_async_pf(vcpu))
- return 0;
- vcpu->stat.pfault_sync++;
- } else {
- return rc;
- }
- }
- rc = gmap_fault(vcpu->arch.gmap, gaddr, flags);
- if (rc == -EFAULT) {
- if (kvm_is_ucontrol(vcpu->kvm)) {
- vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL;
- vcpu->run->s390_ucontrol.trans_exc_code = gaddr;
- vcpu->run->s390_ucontrol.pgm_code = 0x10;
- return -EREMOTE;
- }
- return vcpu_post_run_addressing_exception(vcpu);
- }
- break;
+ return vcpu_dat_fault_handler(vcpu, gaddr, flags);
default:
KVM_BUG(1, vcpu->kvm, "Unexpected program interrupt 0x%x, TEID 0x%016lx",
current->thread.gmap_int_code, current->thread.gmap_teid.val);
send_sig(SIGSEGV, current, 0);
break;
}
- return rc;
+ return 0;
}
static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
@@ -5710,7 +5780,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
}
#endif
case KVM_S390_VCPU_FAULT: {
- r = gmap_fault(vcpu->arch.gmap, arg, 0);
+ idx = srcu_read_lock(&vcpu->kvm->srcu);
+ r = vcpu_dat_fault_handler(vcpu, arg, 0);
+ srcu_read_unlock(&vcpu->kvm->srcu, idx);
break;
}
case KVM_ENABLE_CAP:
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 597d7a71deebe..3f72a217ee995 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -408,6 +408,12 @@ void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu);
void kvm_s390_set_cpu_timer(struct kvm_vcpu *vcpu, __u64 cputm);
__u64 kvm_s390_get_cpu_timer(struct kvm_vcpu *vcpu);
int kvm_s390_cpus_from_pv(struct kvm *kvm, u16 *rc, u16 *rrc);
+int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, unsigned int flags);
+
+static inline int kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gpa_t gaddr, unsigned int flags)
+{
+ return __kvm_s390_handle_dat_fault(vcpu, gpa_to_gfn(gaddr), gaddr, flags);
+}
/* implemented in diag.c */
int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index 2527c6574ad12..fb975e72a81ae 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -635,6 +635,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr)
radix_tree_preload_end();
return rc;
}
+EXPORT_SYMBOL(__gmap_link);
/**
* gmap_fault - resolve a fault on a guest address
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 825/869] KVM: s390: move gmap_shadow_pgt_lookup() into kvm
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (823 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 824/869] KVM: s390: use __kvm_faultin_pfn() Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 826/869] KVM: s390: pv: fix race when making a page secure Greg Kroah-Hartman
` (44 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Steffen Eiden, Janosch Frank,
Christoph Schlameuss, Claudio Imbrenda, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
[ Upstream commit 43656f774a4b4a2841035947e89dcde8ee136caa ]
Move gmap_shadow_pgt_lookup() from mm/gmap.c into kvm/gaccess.c .
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Link: https://lore.kernel.org/r/20250123144627.312456-13-imbrenda@linux.ibm.com
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20250123144627.312456-13-imbrenda@linux.ibm.com>
Stable-dep-of: 5f9df945d4e8 ("KVM: s390: Fix FOLL_*/FAULT_FLAG_* confusion")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/include/asm/gmap.h | 3 +--
arch/s390/kvm/gaccess.c | 42 +++++++++++++++++++++++++++++++++-
arch/s390/kvm/gmap.h | 2 ++
arch/s390/mm/gmap.c | 44 ++----------------------------------
4 files changed, 46 insertions(+), 45 deletions(-)
diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h
index 22775b1ce7101..69eb2ef64034b 100644
--- a/arch/s390/include/asm/gmap.h
+++ b/arch/s390/include/asm/gmap.h
@@ -134,8 +134,6 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,
int fake);
int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,
int fake);
-int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,
- unsigned long *pgt, int *dat_protection, int *fake);
int gmap_shadow_page(struct gmap *sg, unsigned long saddr, pte_t pte);
void gmap_register_pte_notifier(struct gmap_notifier *);
@@ -153,6 +151,7 @@ void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns);
int __s390_uv_destroy_range(struct mm_struct *mm, unsigned long start,
unsigned long end, bool interruptible);
int kvm_s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio, bool split);
+unsigned long *gmap_table_walk(struct gmap *gmap, unsigned long gaddr, int level);
/**
* s390_uv_destroy_range - Destroy a range of pages in the given mm.
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index 7bc97ebd60d5d..448304e662fbb 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -16,6 +16,7 @@
#include <asm/gmap.h>
#include <asm/dat-bits.h>
#include "kvm-s390.h"
+#include "gmap.h"
#include "gaccess.h"
/*
@@ -1392,6 +1393,42 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr,
return 0;
}
+/**
+ * shadow_pgt_lookup() - find a shadow page table
+ * @sg: pointer to the shadow guest address space structure
+ * @saddr: the address in the shadow aguest address space
+ * @pgt: parent gmap address of the page table to get shadowed
+ * @dat_protection: if the pgtable is marked as protected by dat
+ * @fake: pgt references contiguous guest memory block, not a pgtable
+ *
+ * Returns 0 if the shadow page table was found and -EAGAIN if the page
+ * table was not found.
+ *
+ * Called with sg->mm->mmap_lock in read.
+ */
+static int shadow_pgt_lookup(struct gmap *sg, unsigned long saddr, unsigned long *pgt,
+ int *dat_protection, int *fake)
+{
+ unsigned long *table;
+ struct page *page;
+ int rc;
+
+ spin_lock(&sg->guest_table_lock);
+ table = gmap_table_walk(sg, saddr, 1); /* get segment pointer */
+ if (table && !(*table & _SEGMENT_ENTRY_INVALID)) {
+ /* Shadow page tables are full pages (pte+pgste) */
+ page = pfn_to_page(*table >> PAGE_SHIFT);
+ *pgt = page->index & ~GMAP_SHADOW_FAKE_TABLE;
+ *dat_protection = !!(*table & _SEGMENT_ENTRY_PROTECT);
+ *fake = !!(page->index & GMAP_SHADOW_FAKE_TABLE);
+ rc = 0;
+ } else {
+ rc = -EAGAIN;
+ }
+ spin_unlock(&sg->guest_table_lock);
+ return rc;
+}
+
/**
* kvm_s390_shadow_fault - handle fault on a shadow page table
* @vcpu: virtual cpu
@@ -1415,6 +1452,9 @@ int kvm_s390_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg,
int dat_protection, fake;
int rc;
+ if (KVM_BUG_ON(!gmap_is_shadow(sg), vcpu->kvm))
+ return -EFAULT;
+
mmap_read_lock(sg->mm);
/*
* We don't want any guest-2 tables to change - so the parent
@@ -1423,7 +1463,7 @@ int kvm_s390_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg,
*/
ipte_lock(vcpu->kvm);
- rc = gmap_shadow_pgt_lookup(sg, saddr, &pgt, &dat_protection, &fake);
+ rc = shadow_pgt_lookup(sg, saddr, &pgt, &dat_protection, &fake);
if (rc)
rc = kvm_s390_shadow_tables(sg, saddr, &pgt, &dat_protection,
&fake);
diff --git a/arch/s390/kvm/gmap.h b/arch/s390/kvm/gmap.h
index f2b52ce29be3d..14431ce978da2 100644
--- a/arch/s390/kvm/gmap.h
+++ b/arch/s390/kvm/gmap.h
@@ -10,6 +10,8 @@
#ifndef ARCH_KVM_S390_GMAP_H
#define ARCH_KVM_S390_GMAP_H
+#define GMAP_SHADOW_FAKE_TABLE 1ULL
+
int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb);
int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr);
int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr);
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index fb975e72a81ae..072e3fd01dd3c 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -804,8 +804,7 @@ static void gmap_call_notifier(struct gmap *gmap, unsigned long start,
*
* Note: Can also be called for shadow gmaps.
*/
-static inline unsigned long *gmap_table_walk(struct gmap *gmap,
- unsigned long gaddr, int level)
+unsigned long *gmap_table_walk(struct gmap *gmap, unsigned long gaddr, int level)
{
const int asce_type = gmap->asce & _ASCE_TYPE_MASK;
unsigned long *table = gmap->table;
@@ -856,6 +855,7 @@ static inline unsigned long *gmap_table_walk(struct gmap *gmap,
}
return table;
}
+EXPORT_SYMBOL(gmap_table_walk);
/**
* gmap_pte_op_walk - walk the gmap page table, get the page table lock
@@ -2003,46 +2003,6 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,
}
EXPORT_SYMBOL_GPL(gmap_shadow_sgt);
-/**
- * gmap_shadow_pgt_lookup - find a shadow page table
- * @sg: pointer to the shadow guest address space structure
- * @saddr: the address in the shadow aguest address space
- * @pgt: parent gmap address of the page table to get shadowed
- * @dat_protection: if the pgtable is marked as protected by dat
- * @fake: pgt references contiguous guest memory block, not a pgtable
- *
- * Returns 0 if the shadow page table was found and -EAGAIN if the page
- * table was not found.
- *
- * Called with sg->mm->mmap_lock in read.
- */
-int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,
- unsigned long *pgt, int *dat_protection,
- int *fake)
-{
- unsigned long *table;
- struct page *page;
- int rc;
-
- BUG_ON(!gmap_is_shadow(sg));
- spin_lock(&sg->guest_table_lock);
- table = gmap_table_walk(sg, saddr, 1); /* get segment pointer */
- if (table && !(*table & _SEGMENT_ENTRY_INVALID)) {
- /* Shadow page tables are full pages (pte+pgste) */
- page = pfn_to_page(*table >> PAGE_SHIFT);
- *pgt = page->index & ~GMAP_SHADOW_FAKE_TABLE;
- *dat_protection = !!(*table & _SEGMENT_ENTRY_PROTECT);
- *fake = !!(page->index & GMAP_SHADOW_FAKE_TABLE);
- rc = 0;
- } else {
- rc = -EAGAIN;
- }
- spin_unlock(&sg->guest_table_lock);
- return rc;
-
-}
-EXPORT_SYMBOL_GPL(gmap_shadow_pgt_lookup);
-
/**
* gmap_shadow_pgt - instantiate a shadow page table
* @sg: pointer to the shadow guest address space structure
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 826/869] KVM: s390: pv: fix race when making a page secure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (824 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 825/869] KVM: s390: move gmap_shadow_pgt_lookup() into kvm Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 827/869] KVM: s390: Fix FOLL_*/FAULT_FLAG_* confusion Greg Kroah-Hartman
` (43 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Hildenbrand, Claudio Imbrenda,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
[ Upstream commit d8dfda5af0be6e48178b6f4b46c6af30b06335b2 ]
Holding the pte lock for the page that is being converted to secure is
needed to avoid races. A previous commit removed the locking, which
caused issues. Fix by locking the pte again.
Fixes: 5cbe24350b7d ("KVM: s390: move pv gmap functions into kvm")
Reported-by: David Hildenbrand <david@redhat.com>
Tested-by: David Hildenbrand <david@redhat.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
[david@redhat.com: replace use of get_locked_pte() with folio_walk_start()]
Link: https://lore.kernel.org/r/20250312184912.269414-2-imbrenda@linux.ibm.com
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20250312184912.269414-2-imbrenda@linux.ibm.com>
Stable-dep-of: 5f9df945d4e8 ("KVM: s390: Fix FOLL_*/FAULT_FLAG_* confusion")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/include/asm/gmap.h | 1 -
arch/s390/include/asm/uv.h | 2 +-
arch/s390/kernel/uv.c | 136 +++++++++++++++++++++++++++++++++--
arch/s390/kvm/gmap.c | 103 ++------------------------
arch/s390/kvm/kvm-s390.c | 25 ++++---
arch/s390/mm/gmap.c | 28 --------
6 files changed, 151 insertions(+), 144 deletions(-)
diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h
index 69eb2ef64034b..b458957a383ec 100644
--- a/arch/s390/include/asm/gmap.h
+++ b/arch/s390/include/asm/gmap.h
@@ -150,7 +150,6 @@ int s390_replace_asce(struct gmap *gmap);
void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns);
int __s390_uv_destroy_range(struct mm_struct *mm, unsigned long start,
unsigned long end, bool interruptible);
-int kvm_s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio, bool split);
unsigned long *gmap_table_walk(struct gmap *gmap, unsigned long gaddr, int level);
/**
diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h
index 5cd127654a860..7e82dfb3c7aac 100644
--- a/arch/s390/include/asm/uv.h
+++ b/arch/s390/include/asm/uv.h
@@ -479,7 +479,7 @@ int uv_pin_shared(unsigned long paddr);
int uv_destroy_folio(struct folio *folio);
int uv_destroy_pte(pte_t pte);
int uv_convert_from_secure_pte(pte_t pte);
-int make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb);
+int make_hva_secure(struct mm_struct *mm, unsigned long hva, struct uv_cb_header *uvcb);
int uv_convert_from_secure(unsigned long paddr);
int uv_convert_from_secure_folio(struct folio *folio);
diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c
index 23c3637f5014b..785d396c5fdb2 100644
--- a/arch/s390/kernel/uv.c
+++ b/arch/s390/kernel/uv.c
@@ -206,6 +206,39 @@ int uv_convert_from_secure_pte(pte_t pte)
return uv_convert_from_secure_folio(pfn_folio(pte_pfn(pte)));
}
+/**
+ * should_export_before_import - Determine whether an export is needed
+ * before an import-like operation
+ * @uvcb: the Ultravisor control block of the UVC to be performed
+ * @mm: the mm of the process
+ *
+ * Returns whether an export is needed before every import-like operation.
+ * This is needed for shared pages, which don't trigger a secure storage
+ * exception when accessed from a different guest.
+ *
+ * Although considered as one, the Unpin Page UVC is not an actual import,
+ * so it is not affected.
+ *
+ * No export is needed also when there is only one protected VM, because the
+ * page cannot belong to the wrong VM in that case (there is no "other VM"
+ * it can belong to).
+ *
+ * Return: true if an export is needed before every import, otherwise false.
+ */
+static bool should_export_before_import(struct uv_cb_header *uvcb, struct mm_struct *mm)
+{
+ /*
+ * The misc feature indicates, among other things, that importing a
+ * shared page from a different protected VM will automatically also
+ * transfer its ownership.
+ */
+ if (uv_has_feature(BIT_UV_FEAT_MISC))
+ return false;
+ if (uvcb->cmd == UVC_CMD_UNPIN_PAGE_SHARED)
+ return false;
+ return atomic_read(&mm->context.protected_count) > 1;
+}
+
/*
* Calculate the expected ref_count for a folio that would otherwise have no
* further pins. This was cribbed from similar functions in other places in
@@ -228,7 +261,7 @@ static int expected_folio_refs(struct folio *folio)
}
/**
- * make_folio_secure() - make a folio secure
+ * __make_folio_secure() - make a folio secure
* @folio: the folio to make secure
* @uvcb: the uvcb that describes the UVC to be used
*
@@ -237,20 +270,18 @@ static int expected_folio_refs(struct folio *folio)
*
* Return: 0 on success;
* -EBUSY if the folio is in writeback or has too many references;
- * -E2BIG if the folio is large;
* -EAGAIN if the UVC needs to be attempted again;
* -ENXIO if the address is not mapped;
* -EINVAL if the UVC failed for other reasons.
*
* Context: The caller must hold exactly one extra reference on the folio
- * (it's the same logic as split_folio())
+ * (it's the same logic as split_folio()), and the folio must be
+ * locked.
*/
-int make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
+static int __make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
{
int expected, cc = 0;
- if (folio_test_large(folio))
- return -E2BIG;
if (folio_test_writeback(folio))
return -EBUSY;
expected = expected_folio_refs(folio) + 1;
@@ -277,7 +308,98 @@ int make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
return -EAGAIN;
return uvcb->rc == 0x10a ? -ENXIO : -EINVAL;
}
-EXPORT_SYMBOL_GPL(make_folio_secure);
+
+static int make_folio_secure(struct mm_struct *mm, struct folio *folio, struct uv_cb_header *uvcb)
+{
+ int rc;
+
+ if (!folio_trylock(folio))
+ return -EAGAIN;
+ if (should_export_before_import(uvcb, mm))
+ uv_convert_from_secure(folio_to_phys(folio));
+ rc = __make_folio_secure(folio, uvcb);
+ folio_unlock(folio);
+
+ return rc;
+}
+
+/**
+ * s390_wiggle_split_folio() - try to drain extra references to a folio and optionally split.
+ * @mm: the mm containing the folio to work on
+ * @folio: the folio
+ * @split: whether to split a large folio
+ *
+ * Context: Must be called while holding an extra reference to the folio;
+ * the mm lock should not be held.
+ * Return: 0 if the folio was split successfully;
+ * -EAGAIN if the folio was not split successfully but another attempt
+ * can be made, or if @split was set to false;
+ * -EINVAL in case of other errors. See split_folio().
+ */
+static int s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio, bool split)
+{
+ int rc;
+
+ lockdep_assert_not_held(&mm->mmap_lock);
+ folio_wait_writeback(folio);
+ lru_add_drain_all();
+ if (split) {
+ folio_lock(folio);
+ rc = split_folio(folio);
+ folio_unlock(folio);
+
+ if (rc != -EBUSY)
+ return rc;
+ }
+ return -EAGAIN;
+}
+
+int make_hva_secure(struct mm_struct *mm, unsigned long hva, struct uv_cb_header *uvcb)
+{
+ struct vm_area_struct *vma;
+ struct folio_walk fw;
+ struct folio *folio;
+ int rc;
+
+ mmap_read_lock(mm);
+ vma = vma_lookup(mm, hva);
+ if (!vma) {
+ mmap_read_unlock(mm);
+ return -EFAULT;
+ }
+ folio = folio_walk_start(&fw, vma, hva, 0);
+ if (!folio) {
+ mmap_read_unlock(mm);
+ return -ENXIO;
+ }
+
+ folio_get(folio);
+ /*
+ * Secure pages cannot be huge and userspace should not combine both.
+ * In case userspace does it anyway this will result in an -EFAULT for
+ * the unpack. The guest is thus never reaching secure mode.
+ * If userspace plays dirty tricks and decides to map huge pages at a
+ * later point in time, it will receive a segmentation fault or
+ * KVM_RUN will return -EFAULT.
+ */
+ if (folio_test_hugetlb(folio))
+ rc = -EFAULT;
+ else if (folio_test_large(folio))
+ rc = -E2BIG;
+ else if (!pte_write(fw.pte) || (pte_val(fw.pte) & _PAGE_INVALID))
+ rc = -ENXIO;
+ else
+ rc = make_folio_secure(mm, folio, uvcb);
+ folio_walk_end(&fw, vma);
+ mmap_read_unlock(mm);
+
+ if (rc == -E2BIG || rc == -EBUSY)
+ rc = s390_wiggle_split_folio(mm, folio, rc == -E2BIG);
+ folio_put(folio);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(make_hva_secure);
/*
* To be called with the folio locked or with an extra reference! This will
diff --git a/arch/s390/kvm/gmap.c b/arch/s390/kvm/gmap.c
index 02adf151d4de4..6d8944d1b4a0c 100644
--- a/arch/s390/kvm/gmap.c
+++ b/arch/s390/kvm/gmap.c
@@ -22,92 +22,6 @@
#include "gmap.h"
-/**
- * should_export_before_import - Determine whether an export is needed
- * before an import-like operation
- * @uvcb: the Ultravisor control block of the UVC to be performed
- * @mm: the mm of the process
- *
- * Returns whether an export is needed before every import-like operation.
- * This is needed for shared pages, which don't trigger a secure storage
- * exception when accessed from a different guest.
- *
- * Although considered as one, the Unpin Page UVC is not an actual import,
- * so it is not affected.
- *
- * No export is needed also when there is only one protected VM, because the
- * page cannot belong to the wrong VM in that case (there is no "other VM"
- * it can belong to).
- *
- * Return: true if an export is needed before every import, otherwise false.
- */
-static bool should_export_before_import(struct uv_cb_header *uvcb, struct mm_struct *mm)
-{
- /*
- * The misc feature indicates, among other things, that importing a
- * shared page from a different protected VM will automatically also
- * transfer its ownership.
- */
- if (uv_has_feature(BIT_UV_FEAT_MISC))
- return false;
- if (uvcb->cmd == UVC_CMD_UNPIN_PAGE_SHARED)
- return false;
- return atomic_read(&mm->context.protected_count) > 1;
-}
-
-static int __gmap_make_secure(struct gmap *gmap, struct page *page, void *uvcb)
-{
- struct folio *folio = page_folio(page);
- int rc;
-
- /*
- * Secure pages cannot be huge and userspace should not combine both.
- * In case userspace does it anyway this will result in an -EFAULT for
- * the unpack. The guest is thus never reaching secure mode.
- * If userspace plays dirty tricks and decides to map huge pages at a
- * later point in time, it will receive a segmentation fault or
- * KVM_RUN will return -EFAULT.
- */
- if (folio_test_hugetlb(folio))
- return -EFAULT;
- if (folio_test_large(folio)) {
- mmap_read_unlock(gmap->mm);
- rc = kvm_s390_wiggle_split_folio(gmap->mm, folio, true);
- mmap_read_lock(gmap->mm);
- if (rc)
- return rc;
- folio = page_folio(page);
- }
-
- if (!folio_trylock(folio))
- return -EAGAIN;
- if (should_export_before_import(uvcb, gmap->mm))
- uv_convert_from_secure(folio_to_phys(folio));
- rc = make_folio_secure(folio, uvcb);
- folio_unlock(folio);
-
- /*
- * In theory a race is possible and the folio might have become
- * large again before the folio_trylock() above. In that case, no
- * action is performed and -EAGAIN is returned; the callers will
- * have to try again later.
- * In most cases this implies running the VM again, getting the same
- * exception again, and make another attempt in this function.
- * This is expected to happen extremely rarely.
- */
- if (rc == -E2BIG)
- return -EAGAIN;
- /* The folio has too many references, try to shake some off */
- if (rc == -EBUSY) {
- mmap_read_unlock(gmap->mm);
- kvm_s390_wiggle_split_folio(gmap->mm, folio, false);
- mmap_read_lock(gmap->mm);
- return -EAGAIN;
- }
-
- return rc;
-}
-
/**
* gmap_make_secure() - make one guest page secure
* @gmap: the guest gmap
@@ -115,24 +29,19 @@ static int __gmap_make_secure(struct gmap *gmap, struct page *page, void *uvcb)
* @uvcb: the UVCB specifying which operation needs to be performed
*
* Context: needs to be called with kvm->srcu held.
- * Return: 0 on success, < 0 in case of error (see __gmap_make_secure()).
+ * Return: 0 on success, < 0 in case of error.
*/
int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb)
{
struct kvm *kvm = gmap->private;
- struct page *page;
- int rc = 0;
+ unsigned long vmaddr;
lockdep_assert_held(&kvm->srcu);
- page = gfn_to_page(kvm, gpa_to_gfn(gaddr));
- mmap_read_lock(gmap->mm);
- if (page)
- rc = __gmap_make_secure(gmap, page, uvcb);
- kvm_release_page_clean(page);
- mmap_read_unlock(gmap->mm);
-
- return rc;
+ vmaddr = gfn_to_hva(kvm, gpa_to_gfn(gaddr));
+ if (kvm_is_error_hva(vmaddr))
+ return -EFAULT;
+ return make_hva_secure(gmap->mm, vmaddr, uvcb);
}
int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 6224e4188c6d6..87f4ae9e3b7e6 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -4841,6 +4841,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
{
unsigned int flags = 0;
unsigned long gaddr;
+ int rc;
gaddr = current->thread.gmap_teid.addr * PAGE_SIZE;
if (kvm_s390_cur_gmap_fault_is_write())
@@ -4850,16 +4851,6 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
case 0:
vcpu->stat.exit_null++;
break;
- case PGM_NON_SECURE_STORAGE_ACCESS:
- kvm_s390_assert_primary_as(vcpu);
- /*
- * This is normal operation; a page belonging to a protected
- * guest has not been imported yet. Try to import the page into
- * the protected guest.
- */
- if (gmap_convert_to_secure(vcpu->arch.gmap, gaddr) == -EINVAL)
- send_sig(SIGSEGV, current, 0);
- break;
case PGM_SECURE_STORAGE_ACCESS:
case PGM_SECURE_STORAGE_VIOLATION:
kvm_s390_assert_primary_as(vcpu);
@@ -4884,6 +4875,20 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
send_sig(SIGSEGV, current, 0);
}
break;
+ case PGM_NON_SECURE_STORAGE_ACCESS:
+ kvm_s390_assert_primary_as(vcpu);
+ /*
+ * This is normal operation; a page belonging to a protected
+ * guest has not been imported yet. Try to import the page into
+ * the protected guest.
+ */
+ rc = gmap_convert_to_secure(vcpu->arch.gmap, gaddr);
+ if (rc == -EINVAL)
+ send_sig(SIGSEGV, current, 0);
+ if (rc != -ENXIO)
+ break;
+ flags = FAULT_FLAG_WRITE;
+ fallthrough;
case PGM_PROTECTION:
case PGM_SEGMENT_TRANSLATION:
case PGM_PAGE_TRANSLATION:
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index 072e3fd01dd3c..719a9adc2ad37 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -2943,31 +2943,3 @@ int s390_replace_asce(struct gmap *gmap)
return 0;
}
EXPORT_SYMBOL_GPL(s390_replace_asce);
-
-/**
- * kvm_s390_wiggle_split_folio() - try to drain extra references to a folio and optionally split
- * @mm: the mm containing the folio to work on
- * @folio: the folio
- * @split: whether to split a large folio
- *
- * Context: Must be called while holding an extra reference to the folio;
- * the mm lock should not be held.
- */
-int kvm_s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio, bool split)
-{
- int rc;
-
- lockdep_assert_not_held(&mm->mmap_lock);
- folio_wait_writeback(folio);
- lru_add_drain_all();
- if (split) {
- folio_lock(folio);
- rc = split_folio(folio);
- folio_unlock(folio);
-
- if (rc != -EBUSY)
- return rc;
- }
- return -EAGAIN;
-}
-EXPORT_SYMBOL_GPL(kvm_s390_wiggle_split_folio);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 827/869] KVM: s390: Fix FOLL_*/FAULT_FLAG_* confusion
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (825 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 826/869] KVM: s390: pv: fix race when making a page secure Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 828/869] s390/kvm: Mask extra bits from program interrupt code Greg Kroah-Hartman
` (42 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Claudio Imbrenda,
Christian Borntraeger, David Hildenbrand, Steffen Eiden,
Christoph Schlameuss, Janosch Frank, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
[ Upstream commit 5f9df945d4e862979b50e4ecaba3dc81fb06e8ed ]
Pass the right type of flag to vcpu_dat_fault_handler(); it expects a
FOLL_* flag (in particular FOLL_WRITE), but FAULT_FLAG_WRITE is passed
instead.
This still works because they happen to have the same integer value,
but it's a mistake, thus the fix.
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Fixes: 05066cafa925 ("s390/mm/fault: Handle guest-related program interrupts in KVM")
Acked-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/kvm/kvm-s390.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 87f4ae9e3b7e6..c11e579e23313 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -4748,12 +4748,12 @@ static void kvm_s390_assert_primary_as(struct kvm_vcpu *vcpu)
* @vcpu: the vCPU whose gmap is to be fixed up
* @gfn: the guest frame number used for memslots (including fake memslots)
* @gaddr: the gmap address, does not have to match @gfn for ucontrol gmaps
- * @flags: FOLL_* flags
+ * @foll: FOLL_* flags
*
* Return: 0 on success, < 0 in case of error.
* Context: The mm lock must not be held before calling. May sleep.
*/
-int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, unsigned int flags)
+int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, unsigned int foll)
{
struct kvm_memory_slot *slot;
unsigned int fault_flags;
@@ -4767,13 +4767,13 @@ int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, u
if (!slot || slot->flags & KVM_MEMSLOT_INVALID)
return vcpu_post_run_addressing_exception(vcpu);
- fault_flags = flags & FOLL_WRITE ? FAULT_FLAG_WRITE : 0;
+ fault_flags = foll & FOLL_WRITE ? FAULT_FLAG_WRITE : 0;
if (vcpu->arch.gmap->pfault_enabled)
- flags |= FOLL_NOWAIT;
+ foll |= FOLL_NOWAIT;
vmaddr = __gfn_to_hva_memslot(slot, gfn);
try_again:
- pfn = __kvm_faultin_pfn(slot, gfn, flags, &writable, &page);
+ pfn = __kvm_faultin_pfn(slot, gfn, foll, &writable, &page);
/* Access outside memory, inject addressing exception */
if (is_noslot_pfn(pfn))
@@ -4789,7 +4789,7 @@ int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, u
return 0;
vcpu->stat.pfault_sync++;
/* Could not setup async pfault, try again synchronously */
- flags &= ~FOLL_NOWAIT;
+ foll &= ~FOLL_NOWAIT;
goto try_again;
}
/* Any other error */
@@ -4809,7 +4809,7 @@ int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, u
return rc;
}
-static int vcpu_dat_fault_handler(struct kvm_vcpu *vcpu, unsigned long gaddr, unsigned int flags)
+static int vcpu_dat_fault_handler(struct kvm_vcpu *vcpu, unsigned long gaddr, unsigned int foll)
{
unsigned long gaddr_tmp;
gfn_t gfn;
@@ -4834,18 +4834,18 @@ static int vcpu_dat_fault_handler(struct kvm_vcpu *vcpu, unsigned long gaddr, un
}
gfn = gpa_to_gfn(gaddr_tmp);
}
- return __kvm_s390_handle_dat_fault(vcpu, gfn, gaddr, flags);
+ return __kvm_s390_handle_dat_fault(vcpu, gfn, gaddr, foll);
}
static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
{
- unsigned int flags = 0;
+ unsigned int foll = 0;
unsigned long gaddr;
int rc;
gaddr = current->thread.gmap_teid.addr * PAGE_SIZE;
if (kvm_s390_cur_gmap_fault_is_write())
- flags = FAULT_FLAG_WRITE;
+ foll = FOLL_WRITE;
switch (current->thread.gmap_int_code) {
case 0:
@@ -4887,7 +4887,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
send_sig(SIGSEGV, current, 0);
if (rc != -ENXIO)
break;
- flags = FAULT_FLAG_WRITE;
+ foll = FOLL_WRITE;
fallthrough;
case PGM_PROTECTION:
case PGM_SEGMENT_TRANSLATION:
@@ -4897,7 +4897,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
case PGM_REGION_SECOND_TRANS:
case PGM_REGION_THIRD_TRANS:
kvm_s390_assert_primary_as(vcpu);
- return vcpu_dat_fault_handler(vcpu, gaddr, flags);
+ return vcpu_dat_fault_handler(vcpu, gaddr, foll);
default:
KVM_BUG(1, vcpu->kvm, "Unexpected program interrupt 0x%x, TEID 0x%016lx",
current->thread.gmap_int_code, current->thread.gmap_teid.val);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 828/869] s390/kvm: Mask extra bits from program interrupt code
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (826 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 827/869] KVM: s390: Fix FOLL_*/FAULT_FLAG_* confusion Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 829/869] scsi: ufs: qcom : Fix NULL pointer dereference in ufs_qcom_setup_clocks Greg Kroah-Hartman
` (41 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christian Borntraeger,
Claudio Imbrenda, Heiko Carstens, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
[ Upstream commit 34fb045eddd300a2d1c0d7de7e83113215c422e3 ]
The program interrupt code has some extra bits that are sometimes set
by hardware for various reasons; those bits should be ignored when the
program interrupt number is needed for interrupt handling.
Fixes: 05066cafa925 ("s390/mm/fault: Handle guest-related program interrupts in KVM")
Reported-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Tested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Link: https://lore.kernel.org/r/20241031120316.25462-1-imbrenda@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/s390/kvm/kvm-s390.c | 2 +-
arch/s390/kvm/vsie.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index c11e579e23313..7bb5640bb8a71 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -4847,7 +4847,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu)
if (kvm_s390_cur_gmap_fault_is_write())
foll = FOLL_WRITE;
- switch (current->thread.gmap_int_code) {
+ switch (current->thread.gmap_int_code & PGM_INT_CODE_MASK) {
case 0:
vcpu->stat.exit_null++;
break;
diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index 44e25b2654a2d..de9f0dd421979 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -923,7 +923,7 @@ static int handle_fault(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
{
int rc;
- if (current->thread.gmap_int_code == PGM_PROTECTION)
+ if ((current->thread.gmap_int_code & PGM_INT_CODE_MASK) == PGM_PROTECTION)
/* we can directly forward all protection exceptions */
return inject_fault(vcpu, PGM_PROTECTION,
current->thread.gmap_teid.addr * PAGE_SIZE, 1);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 829/869] scsi: ufs: qcom : Fix NULL pointer dereference in ufs_qcom_setup_clocks
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (827 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 828/869] s390/kvm: Mask extra bits from program interrupt code Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 830/869] accel/ivpu: Fix race condition when mapping dmabuf Greg Kroah-Hartman
` (40 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Manivannan Sadhasivam,
Neil Armstrong, Dmitry Baryshkov, Naresh Kamboju, Aishwarya,
Ram Kumar Dwivedi, Nitin Rawat, Martin K. Petersen,
Linux Kernel Functional Testing, Marek Szyprowski, Vinod Koul,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nitin Rawat <quic_nitirawa@quicinc.com>
[ Upstream commit 720fa0cb59e411eca6b274f78073b6d2fe68eb45 ]
Fix a NULL pointer dereference in ufs_qcom_setup_clocks due to an
uninitialized 'host' variable. The variable 'phy' is now assigned
after confirming 'host' is not NULL.
Call Stack:
Unable to handle kernel NULL pointer dereference at
virtual address 0000000000000000
ufs_qcom_setup_clocks+0x28/0x148 ufs_qcom (P)
ufshcd_setup_clocks (drivers/ufs/core/ufshcd-priv.h:142)
ufshcd_init (drivers/ufs/core/ufshcd.c:9468)
ufshcd_pltfrm_init (drivers/ufs/host/ufshcd-pltfrm.c:504)
ufs_qcom_probe+0x28/0x68 ufs_qcom
platform_probe (drivers/base/platform.c:1404)
really_probe (drivers/base/dd.c:579 drivers/base/dd.c:657)
__driver_probe_device (drivers/base/dd.c:799)
driver_probe_device (drivers/base/dd.c:829)
__driver_attach (drivers/base/dd.c:1216)
bus_for_each_dev (drivers/base/bus.c:370)
driver_attach (drivers/base/dd.c:1234)
bus_add_driver (drivers/base/bus.c:678)
driver_register (drivers/base/driver.c:249)
__platform_driver_register (drivers/base/platform.c:868)
ufs_qcom_pltform_init+0x28/0xff8 ufs_qcom
do_one_initcall (init/main.c:1274)
do_init_module (kernel/module/main.c:3041)
load_module (kernel/module/main.c:3511)
init_module_from_file (kernel/module/main.c:3704)
__arm64_sys_finit_module (kernel/module/main.c:3715.
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Fixes: 77d2fa54a945 ("scsi: ufs: qcom : Refactor phy_power_on/off calls")
Tested-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Naresh Kamboju <naresh.kamboju@linaro.org>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org>
Reported-by: Aishwarya <aishwarya.tcv@arm.com>
Closes: https://lore.kernel.org/lkml/20250620214408.11028-1-aishwarya.tcv@arm.com/
Reported-by: Naresh Kamboju <naresh.kamboju@linaro.org>
Closes: https://lore.kernel.org/linux-scsi/CA+G9fYuFQ2dBvYm1iB6rbwT=4b1c8e4NJ3yxqFPGZGUKH3GmMA@mail.gmail.com/T/#t
Co-developed-by: Ram Kumar Dwivedi <quic_rdwivedi@quicinc.com>
Signed-off-by: Ram Kumar Dwivedi <quic_rdwivedi@quicinc.com>
Signed-off-by: Nitin Rawat <quic_nitirawa@quicinc.com>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reported-by: Linux Kernel Functional Testing <lkft@linaro.org>
Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Link: https://lore.kernel.org/r/20250623134809.20405-1-quic_nitirawa@quicinc.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/ufs/host/ufs-qcom.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 5fbcc234131f1..ba760aab3a7d7 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -934,7 +934,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
enum ufs_notify_change_status status)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct phy *phy = host->generic_phy;
+ struct phy *phy;
int err;
/*
@@ -945,6 +945,8 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
if (!host)
return 0;
+ phy = host->generic_phy;
+
switch (status) {
case PRE_CHANGE:
if (on) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 830/869] accel/ivpu: Fix race condition when mapping dmabuf
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (828 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 829/869] scsi: ufs: qcom : Fix NULL pointer dereference in ufs_qcom_setup_clocks Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 831/869] KVM: SEV: Drop FOLL_WRITE for encrypted region registration Greg Kroah-Hartman
` (39 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Wludzik, Jozef, Jeff Hugo,
Karol Wachowski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wludzik, Jozef <jozef.wludzik@intel.com>
[ Upstream commit 63c7870fab67b2ab2bfe75e8b46f3c37b88c47a8 ]
Fix a race that can occur when multiple jobs submit the same dmabuf.
This could cause the sg_table to be mapped twice, leading to undefined
behavior.
Fixes: e0c0891cd63b ("accel/ivpu: Rework bind/unbind of imported buffers")
Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
Reviewed-by: Jeff Hugo <jeff.hugo@oss.qualcomm.com>
Signed-off-by: Karol Wachowski <karol.wachowski@linux.intel.com>
Link: https://lore.kernel.org/r/20251014071725.3047287-1-karol.wachowski@linux.intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/accel/ivpu/ivpu_gem.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c
index 1f66355ffe9fb..3929357a61a37 100644
--- a/drivers/accel/ivpu/ivpu_gem.c
+++ b/drivers/accel/ivpu/ivpu_gem.c
@@ -45,12 +45,13 @@ static inline void ivpu_bo_unlock(struct ivpu_bo *bo)
static struct sg_table *ivpu_bo_map_attachment(struct ivpu_device *vdev, struct ivpu_bo *bo)
{
- struct sg_table *sgt = bo->base.sgt;
+ struct sg_table *sgt;
drm_WARN_ON(&vdev->drm, !bo->base.base.import_attach);
ivpu_bo_lock(bo);
+ sgt = bo->base.sgt;
if (!sgt) {
sgt = dma_buf_map_attachment(bo->base.base.import_attach, DMA_BIDIRECTIONAL);
if (IS_ERR(sgt))
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 831/869] KVM: SEV: Drop FOLL_WRITE for encrypted region registration
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (829 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 830/869] accel/ivpu: Fix race condition when mapping dmabuf Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 832/869] net: Fix wild-memory-access in __register_pernet_operations() when CONFIG_NET_NS=n Greg Kroah-Hartman
` (38 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Hildenbrand (Arm),
Pankaj Gupta, Lorenzo Stoakes (ARM), Sean Christopherson,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pankaj Gupta <pankaj.gupta@amd.com>
[ Upstream commit ee1a586dd1fa2f245b3b753a3e44d9263a49240b ]
When pinning SEV guest memory, drop FOLL_WRITE and rely on FOLL_LONGTERM
to break CoW, as *KVM* doesn't actually to the memory using the GUP'd
pages. Omitting FOLL_WRITE fixes a regression when using file-backed guest
memory that was introduced when KVM (correctly) added FOLL_LONG (e.g. to
ensure anonymous memory is migrated out of MIGRATE_CMA/ZONE_MOVABLE before
a long term pin).
Unfortunately, as of commits:
8ac268436e6d ("mm/gup: disallow FOLL_LONGTERM GUP-nonfast writing to file-backed mappings")
a6e79df92e4a ("mm/gup: disallow FOLL_LONGTERM GUP-fast writing to file-backed mappings")
GUP uses FOLL_LONGTERM as a canary of sorts to detect pins that are likely
to be problematic, and disallows WRITE+LONGTERM pins for file-backed memory.
As a result, backing SEV+ guests with file-backed memory, e.g. virtio-pmem,
fails due to the disallowed FOLL_LONGTERM+FOLL_WRITE combination.
Note, in the past, FOLL_WRITE was required to trigger CoW unsharing, to
prevent replacing the page in the (primary MMU's) page tables during a
later write fault after already having pinned a (shared) page in
MAP_PRIVATE mappings. FOLL_LONGTERM does that nowadays, even without
FOLL_WRITE (see gup_must_unshare()).
Fixes: 7e066cb9b71a ("KVM: SEV: Use long-term pin when registering encrypted memory regions")
Cc: stable@vger.kernel.org
Suggested-by: "David Hildenbrand (Arm)" <david@kernel.org>
Link: https://lore.kernel.org/all/ad784f05-b36c-4e91-9f17-4c5b826735d0@kernel.org/
Signed-off-by: Pankaj Gupta <pankaj.gupta@amd.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Link: https://patch.msgid.link/20260715063626.65899-1-pankaj.gupta@amd.com
[sean: massage changelog, add comment about CoW unsharing]
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/x86/kvm/svm/sev.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 02d2bd78f8e7b..c086040ef11d1 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -2719,8 +2719,12 @@ int sev_mem_enc_register_region(struct kvm *kvm,
if (!region)
return -ENOMEM;
+ /*
+ * Do NOT specify FOLL_WRITE, as KVM isn't using the pinned pages to
+ * write memory, and FOLL_LONGTERM itself triggers CoW unshare.
+ */
region->pages = sev_pin_memory(kvm, range->addr, range->size, ®ion->npages,
- FOLL_WRITE | FOLL_LONGTERM);
+ FOLL_LONGTERM);
if (IS_ERR(region->pages)) {
ret = PTR_ERR(region->pages);
goto e_free;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 832/869] net: Fix wild-memory-access in __register_pernet_operations() when CONFIG_NET_NS=n.
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (830 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 831/869] KVM: SEV: Drop FOLL_WRITE for encrypted region registration Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 833/869] mpls: Set rt->rt_nhn just before returning from mpls_nh_build_multi() Greg Kroah-Hartman
` (37 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, kernel test robot, Kuniyuki Iwashima,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@amazon.com>
[ Upstream commit f0cc3777b2db18307d9734edf2d16e046714760f ]
kernel test robot reported the splat below. [0]
Before commit fed176bf3143 ("net: Add ops_undo_single for module
load/unload."), if CONFIG_NET_NS=n, ops was linked to pernet_list
only when init_net had not been initialised, and ops was unlinked
from pernet_list only under the same condition.
Let's say an ops is loaded before the init_net setup but unloaded
after that. Then, the ops remains in pernet_list, which seems odd.
The cited commit added ops_undo_single(), which calls list_add() for
ops to link it to a temporary list, so a minor change was added to
__register_pernet_operations() and __unregister_pernet_operations()
under CONFIG_NET_NS=n to avoid the pernet_list corruption.
However, the corruption must have been left as is.
When CONFIG_NET_NS=n, pernet_list was used to keep ops registered
before the init_net setup, and after that, pernet_list was not used
at all.
This was because some ops annotated with __net_initdata are cleared
out of memory at some point during boot.
Then, such ops is initialised by POISON_FREE_INITMEM (0xcc), resulting
in that ops->list.{next,prev} suddenly switches from a valid pointer
to a weird value, 0xcccccccccccccccc.
To avoid such wild memory access, let's allow the pernet_list
corruption for CONFIG_NET_NS=n.
[0]:
Oops: general protection fault, probably for non-canonical address 0xf999959999999999: 0000 [#1] SMP KASAN NOPTI
KASAN: maybe wild-memory-access in range [0xccccccccccccccc8-0xcccccccccccccccf]
CPU: 2 UID: 0 PID: 346 Comm: modprobe Not tainted 6.15.0-rc1-00294-ga4cba7e98e35 #85 PREEMPT(voluntary)
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014
RIP: 0010:__list_add_valid_or_report (lib/list_debug.c:32)
Code: 48 c1 ea 03 80 3c 02 00 0f 85 5a 01 00 00 49 39 74 24 08 0f 85 83 00 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 1f 01 00 00 4c 39 26 0f 85 ab 00 00 00 4c 39 ee
RSP: 0018:ff11000135b87830 EFLAGS: 00010a07
RAX: dffffc0000000000 RBX: ffffffffc02223c0 RCX: ffffffff8406fcc2
RDX: 1999999999999999 RSI: cccccccccccccccc RDI: ffffffffc02223c0
RBP: ffffffff86064e40 R08: 0000000000000001 R09: fffffbfff0a9f5b5
R10: ffffffff854fadaf R11: 676552203a54454e R12: ffffffff86064e40
R13: ffffffffc02223c0 R14: ffffffff86064e48 R15: 0000000000000021
FS: 00007f6fb0d9e1c0(0000) GS:ff11000858ea0000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f6fb0eda580 CR3: 0000000122fec005 CR4: 0000000000771ef0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe07f0 DR7: 0000000000000400
PKRU: 55555554
Call Trace:
<TASK>
register_pernet_operations (./include/linux/list.h:150 (discriminator 5) ./include/linux/list.h:183 (discriminator 5) net/core/net_namespace.c:1315 (discriminator 5) net/core/net_namespace.c:1359 (discriminator 5))
register_pernet_subsys (net/core/net_namespace.c:1401)
inet6_init (net/ipv6/af_inet6.c:535) ipv6
do_one_initcall (init/main.c:1257)
do_init_module (kernel/module/main.c:2942)
load_module (kernel/module/main.c:3409)
init_module_from_file (kernel/module/main.c:3599)
idempotent_init_module (kernel/module/main.c:3611)
__x64_sys_finit_module (./include/linux/file.h:62 ./include/linux/file.h:83 kernel/module/main.c:3634 kernel/module/main.c:3621 kernel/module/main.c:3621)
do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
RIP: 0033:0x7f6fb0df7e5d
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 73 9f 1b 00 f7 d8 64 89 01 48
RSP: 002b:00007fffdc6a8968 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
RAX: ffffffffffffffda RBX: 000055b535721b70 RCX: 00007f6fb0df7e5d
RDX: 0000000000000000 RSI: 000055b51e44aa2a RDI: 0000000000000004
RBP: 0000000000040000 R08: 0000000000000000 R09: 000055b535721b30
R10: 0000000000000004 R11: 0000000000000246 R12: 000055b51e44aa2a
R13: 000055b535721bf0 R14: 000055b5357220b0 R15: 0000000000000000
</TASK>
Modules linked in: ipv6(+) crc_ccitt
Fixes: fed176bf3143 ("net: Add ops_undo_single for module load/unload.")
Reported-by: kernel test robot <oliver.sang@intel.com>
Closes: https://lore.kernel.org/oe-lkp/202504181511.1c3f23e4-lkp@intel.com
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://patch.msgid.link/20250418215025.87871-1-kuniyu@amazon.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/core/net_namespace.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 9e518df2cfeb5..1b5d151f434e1 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -1309,19 +1309,19 @@ static void __unregister_pernet_operations(struct pernet_operations *ops)
static int __register_pernet_operations(struct list_head *list,
struct pernet_operations *ops)
{
- list_add_tail(&ops->list, list);
-
- if (!init_net_initialized)
+ if (!init_net_initialized) {
+ list_add_tail(&ops->list, list);
return 0;
+ }
return ops_init(ops, &init_net);
}
static void __unregister_pernet_operations(struct pernet_operations *ops)
{
- list_del(&ops->list);
-
- if (init_net_initialized) {
+ if (!init_net_initialized) {
+ list_del(&ops->list);
+ } else {
LIST_HEAD(net_exit_list);
list_add(&init_net.exit_list, &net_exit_list);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 833/869] mpls: Set rt->rt_nhn just before returning from mpls_nh_build_multi().
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (831 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 832/869] net: Fix wild-memory-access in __register_pernet_operations() when CONFIG_NET_NS=n Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 834/869] media: verisilicon: Fix kernel panic due to __initconst misuse Greg Kroah-Hartman
` (36 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Anthony Doeraene, Kuniyuki Iwashima,
Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <kuniyu@google.com>
[ Upstream commit 3671f0419d90b98a02f313830595ab958c8b2025 ]
Commit f0914b8436c5 ("mpls: Hold dev refcnt for mpls_nh.") added
change_nexthops() loop to call netdev_put() for the nexthop devices
before freeing mpls_route.
Then, mpls_nh_build_multi() was also changed to avoid iterating
uninitialised nexthops in mpls_rt_free_rcu().
However, setting rt->rt_nhn to 0 at the entry of mpls_nh_build_multi()
makes the following change_nexthops() no-op.
Let's set rt->rt_nhn just before returning from mpls_nh_build_multi().
Fixes: f0914b8436c5 ("mpls: Hold dev refcnt for mpls_nh.")
Reported-by: Anthony Doeraene <anthony.doeraene@uclouvain.be>
Closes: https://lore.kernel.org/netdev/036a0c95-f5d4-46ab-88e7-1eab567d7a84@uclouvain.be/
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260716170609.804629-1-kuniyu@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/mpls/af_mpls.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 5c293fa655d0d..70035b1a52c48 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -929,8 +929,7 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
struct nlattr *nla_via, *nla_newdst;
int remaining = cfg->rc_mp_len;
int err = 0;
-
- rt->rt_nhn = 0;
+ u8 nhs = 0;
change_nexthops(rt) {
int attrlen;
@@ -966,12 +965,15 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
rt->rt_nhn_alive--;
rtnh = rtnh_next(rtnh, &remaining);
- rt->rt_nhn++;
+ nhs++;
} endfor_nexthops(rt);
+ rt->rt_nhn = nhs;
+
return 0;
errout:
+ rt->rt_nhn = nhs;
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 834/869] media: verisilicon: Fix kernel panic due to __initconst misuse
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (832 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 833/869] mpls: Set rt->rt_nhn just before returning from mpls_nh_build_multi() Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 835/869] soc/tegra: pmc: Document tegra_pmc.syscore field Greg Kroah-Hartman
` (35 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Krzysztof Kozlowski, Franz Schnyder,
Marco Felsch, Ming Qian, Frank Li, stable, Nicolas Dufresne,
Hans Verkuil, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Qian <ming.qian@oss.nxp.com>
[ Upstream commit e8d97c270cb46a2a88739019d0f8547adc7d97da ]
Fix a kernel panic when probing the driver as a module:
Unable to handle kernel paging request at virtual address
ffffd9c18eb05000
of_find_matching_node_and_match+0x5c/0x1a0
hantro_probe+0x2f4/0x7d0 [hantro_vpu]
The imx8mq_vpu_shared_resources array is referenced by variant
structures through their shared_devices field. When built as a
module, __initconst causes this data to be freed after module
init, but it's later accessed during probe, causing a page fault.
The imx8mq_vpu_shared_resources is referenced from non-init code,
so keeping __initconst or __initconst_or_module here is wrong.
Drop the __initconst annotation and let it live in the normal .rodata
section.
A bug of __initconst called from regular non-init probe code
leading to bugs during probe deferrals or during unbind-bind cycles.
Reported-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Closes: https://lore.kernel.org/all/68ef934f-baa0-4bf6-93d8-834bbc441e66@kernel.org/
Reported-by: Franz Schnyder <franz.schnyder@toradex.com>
Closes: https://lore.kernel.org/all/n3qmcb62tepxltoskpf7ws6yiirc2so62ia23b42rj3wlmpl67@rvkbuirx7kkp/
Fixes: e0203ddf9af7 ("media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC")
Suggested-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Suggested-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Marco Felsch <m.felsch@pengutronix.de>
Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Cc: stable@kernel.org
Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/media/platform/verisilicon/imx8m_vpu_hw.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
index cdaac2f18fb54..de27c142b7fe4 100644
--- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
@@ -361,7 +361,7 @@ const struct hantro_variant imx8mq_vpu_variant = {
.num_regs = ARRAY_SIZE(imx8mq_reg_names)
};
-static const struct of_device_id imx8mq_vpu_shared_resources[] __initconst = {
+static const struct of_device_id imx8mq_vpu_shared_resources[] = {
{ .compatible = "nxp,imx8mq-vpu-g1", },
{ .compatible = "nxp,imx8mq-vpu-g2", },
{ /* sentinel */ }
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 835/869] soc/tegra: pmc: Document tegra_pmc.syscore field
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (833 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 834/869] media: verisilicon: Fix kernel panic due to __initconst misuse Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 836/869] soc/tegra: pmc: Add kerneldoc for wake-up variables Greg Kroah-Hartman
` (34 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Thierry Reding, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thierry Reding <treding@nvidia.com>
[ Upstream commit aaca2e9933a362bcd89ec563b3e89de18460335f ]
This eliminates a warning from the documentation build targets.
Signed-off-by: Thierry Reding <treding@nvidia.com>
Stable-dep-of: e6ad1988e568 ("soc/tegra: pmc: Add kerneldoc for wake-up variables")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/soc/tegra/pmc.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 0cca72e18437d..40d6ee8c3988c 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -424,6 +424,7 @@ struct tegra_pmc_soc {
* @wake_sw_status_map: Bitmap to hold raw status of wakes without mask
* @wake_cntrl_level_map: Bitmap to hold wake levels to be programmed in
* cntrl register associated with each wake during system suspend.
+ * @syscore: syscore suspend/resume callbacks
*/
struct tegra_pmc {
struct device *dev;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 836/869] soc/tegra: pmc: Add kerneldoc for wake-up variables
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (834 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 835/869] soc/tegra: pmc: Document tegra_pmc.syscore field Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 837/869] i3c: mipi-i3c-hci: Preserve RUN bit when aborting DMA ring Greg Kroah-Hartman
` (33 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jon Hunter, Thierry Reding,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jon Hunter <jonathanh@nvidia.com>
[ Upstream commit e6ad1988e56834d641ba4aa0d58970723c1c9c9b ]
Commit e6d96073af68 ("soc/tegra: pmc: Fix unsafe generic_handle_irq()
call") added the variables 'wake_work' and 'wake_status' to the
'tegra_pmc' structure but did not add the associated kerneldoc for these
new variables. Add the kerneldoc for these variables.
Fixes: e6d96073af68 ("soc/tegra: pmc: Fix unsafe generic_handle_irq() call")
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/soc/tegra/pmc.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 40d6ee8c3988c..806167724b26d 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -425,6 +425,8 @@ struct tegra_pmc_soc {
* @wake_cntrl_level_map: Bitmap to hold wake levels to be programmed in
* cntrl register associated with each wake during system suspend.
* @syscore: syscore suspend/resume callbacks
+ * @wake_work: IRQ work handler for processing wake-up events.
+ * @wake_status: Status of wake-up events.
*/
struct tegra_pmc {
struct device *dev;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 837/869] i3c: mipi-i3c-hci: Preserve RUN bit when aborting DMA ring
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (835 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 836/869] soc/tegra: pmc: Add kerneldoc for wake-up variables Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 838/869] ceph: do not skip the first folio of the next object in writeback Greg Kroah-Hartman
` (32 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Adrian Hunter, Frank Li,
Alexandre Belloni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <adrian.hunter@intel.com>
[ Upstream commit 093eb8e73c90aa0c8cfb0421aa85bd70c23488be ]
The MIPI I3C HCI specification does not require the DMA ring RUN bit
(RUN_STOP) to be cleared when issuing an ABORT. That allows the DMA ring
to continue to receive IBIs, although an IBI is anyway not lost because it
can be received once the ring restarts if the I3C device has not given up.
Note, currently ABORT is only used on a timeout error path so the change
has very little effect in practice. In the more common case of a transfer
error, the ring (bundle) operation is halted by the controller anyway.
Adjust the RING_CONTROL handling to set ABORT without clearing RUN_STOP,
bringing the driver into alignment with the specification.
Fixes: b795e68bf3073 ("i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue")
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260603090754.16252-3-adrian.hunter@intel.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/i3c/master/mipi-i3c-hci/dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index 845feecc0211f..d61d88b3a47a6 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -465,7 +465,7 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci,
if (ring_status & RING_STATUS_RUNNING) {
/* stop the ring */
reinit_completion(&rh->op_done);
- rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_ABORT);
+ rh_reg_write(RING_CONTROL, rh_reg_read(RING_CONTROL) | RING_CTRL_ABORT);
wait_for_completion_timeout(&rh->op_done, HZ);
ring_status = rh_reg_read(RING_STATUS);
if (ring_status & RING_STATUS_RUNNING) {
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 838/869] ceph: do not skip the first folio of the next object in writeback
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (836 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 837/869] i3c: mipi-i3c-hci: Preserve RUN bit when aborting DMA ring Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 839/869] ceph: fix crash after fscrypt_encrypt_pagecache_blocks() error Greg Kroah-Hartman
` (31 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Hristo Venev, Viacheslav Dubeyko,
Ilya Dryomov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hristo Venev <hristo@venev.name>
[ Upstream commit 081a0b78ef30f5746cda3e92e28b4d4ae92901d1 ]
When `ceph_process_folio_batch` encounters a folio past the end of the
current object, it should leave it in the batch so that it is picked up
in the next iteration.
Removing the folio from the batch means that it does not get written
back and remains dirty instead. This makes `fsync()` silently skip some
of the data, delays capability release, and breaks coherence with
`O_DIRECT`.
The link below contains instructions for reproducing the bug.
Cc: stable@vger.kernel.org
Fixes: ce80b76dd327 ("ceph: introduce ceph_process_folio_batch() method")
Link: https://tracker.ceph.com/issues/75156
Signed-off-by: Hristo Venev <hristo@venev.name>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ceph/addr.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 13508fee6293b..c20ef77bb6f0c 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -1326,7 +1326,6 @@ int ceph_process_folio_batch(struct address_space *mapping,
} else if (rc == -E2BIG) {
rc = 0;
folio_unlock(folio);
- ceph_wbc->fbatch.folios[i] = NULL;
break;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 839/869] ceph: fix crash after fscrypt_encrypt_pagecache_blocks() error
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (837 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 838/869] ceph: do not skip the first folio of the next object in writeback Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 840/869] ceph: introduce ceph_submit_write() method Greg Kroah-Hartman
` (30 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Max Kellermann, Ilya Dryomov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann <max.kellermann@ionos.com>
[ Upstream commit 249e0a47cdb46bb9eae65511c569044bd8698d7d ]
The function move_dirty_folio_in_page_array() was created by commit
ce80b76dd327 ("ceph: introduce ceph_process_folio_batch() method") by
moving code from ceph_writepages_start() to this function.
This new function is supposed to return an error code which is checked
by the caller (now ceph_process_folio_batch()), and on error, the
caller invokes redirty_page_for_writepage() and then breaks from the
loop.
However, the refactoring commit has gone wrong, and it by accident, it
always returns 0 (= success) because it first NULLs the pointer and
then returns PTR_ERR(NULL) which is always 0. This means errors are
silently ignored, leaving NULL entries in the page array, which may
later crash the kernel.
The simple solution is to call PTR_ERR() before clearing the pointer.
Cc: stable@vger.kernel.org
Fixes: ce80b76dd327 ("ceph: introduce ceph_process_folio_batch() method")
Link: https://lore.kernel.org/ceph-devel/aK4v548CId5GIKG1@swift.blarg.de/
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ceph/addr.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index c20ef77bb6f0c..7d24bb943b1ee 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -1259,7 +1259,9 @@ int ceph_move_dirty_page_in_page_array(struct address_space *mapping,
0,
gfp_flags);
if (IS_ERR(pages[index])) {
- if (PTR_ERR(pages[index]) == -EINVAL) {
+ int err = PTR_ERR(pages[index]);
+
+ if (err == -EINVAL) {
pr_err_client(cl, "inode->i_blkbits=%hhu\n",
inode->i_blkbits);
}
@@ -1268,7 +1270,7 @@ int ceph_move_dirty_page_in_page_array(struct address_space *mapping,
BUG_ON(ceph_wbc->locked_pages == 0);
pages[index] = NULL;
- return PTR_ERR(pages[index]);
+ return err;
}
} else {
pages[index] = page;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 840/869] ceph: introduce ceph_submit_write() method
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (838 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 839/869] ceph: fix crash after fscrypt_encrypt_pagecache_blocks() error Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 841/869] ceph: always call ceph_shift_unused_folios_left() Greg Kroah-Hartman
` (29 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Viacheslav Dubeyko, David Howells,
Christian Brauner, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
[ Upstream commit 1551ec61dc551dab1bb40c516a5a096607aff774 ]
Final responsibility of ceph_writepages_start() is
to submit write requests for processed dirty folios/pages.
The ceph_submit_write() summarize all this logic in
one method.
The generic/421 fails to finish because of the issue:
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.894678] INFO: task kworker/u48:0:11 blocked for more than 122 seconds.
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.895403] Not tainted 6.13.0-rc5+ #1
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.895867] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.896633] task:kworker/u48:0 state:D stack:0 pid:11 tgid:11 ppid:2 flags:0x00004000
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.896641] Workqueue: writeback wb_workfn (flush-ceph-24)
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897614] Call Trace:
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897620] <TASK>
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897629] __schedule+0x443/0x16b0
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897637] schedule+0x2b/0x140
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897640] io_schedule+0x4c/0x80
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897643] folio_wait_bit_common+0x11b/0x310
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897646] ? _raw_spin_unlock_irq+0xe/0x50
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897652] ? __pfx_wake_page_function+0x10/0x10
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897655] __folio_lock+0x17/0x30
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897658] ceph_writepages_start+0xca9/0x1fb0
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897663] ? fsnotify_remove_queued_event+0x2f/0x40
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897668] do_writepages+0xd2/0x240
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897672] __writeback_single_inode+0x44/0x350
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897675] writeback_sb_inodes+0x25c/0x550
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897680] wb_writeback+0x89/0x310
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897683] ? finish_task_switch.isra.0+0x97/0x310
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897687] wb_workfn+0xb5/0x410
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897689] process_one_work+0x188/0x3d0
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897692] worker_thread+0x2b5/0x3c0
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897694] ? __pfx_worker_thread+0x10/0x10
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897696] kthread+0xe1/0x120
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897699] ? __pfx_kthread+0x10/0x10
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897701] ret_from_fork+0x43/0x70
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897705] ? __pfx_kthread+0x10/0x10
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897707] ret_from_fork_asm+0x1a/0x30
Jan 3 14:25:27 ceph-testing-0001 kernel: [ 369.897711] </TASK>
There are two problems here:
if (!ceph_inc_osd_stopping_blocker(fsc->mdsc)) {
rc = -EIO;
goto release_folios;
}
(1) ceph_kill_sb() doesn't wait ending of flushing
all dirty folios/pages because of racy nature of
mdsc->stopping_blockers. As a result, mdsc->stopping
becomes CEPH_MDSC_STOPPING_FLUSHED too early.
(2) The ceph_inc_osd_stopping_blocker(fsc->mdsc) fails
to increment mdsc->stopping_blockers. Finally,
already locked folios/pages are never been unlocked
and the logic tries to lock the same page second time.
This patch implements refactoring of ceph_submit_write()
and also it solves the second issue.
Signed-off-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Link: https://lore.kernel.org/r/20250205000249.123054-4-slava@dubeyko.com
Tested-by: David Howells <dhowells@redhat.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Stable-dep-of: cce7c15faaac ("ceph: always call ceph_shift_unused_folios_left()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ceph/addr.c | 461 +++++++++++++++++++++++++++----------------------
1 file changed, 257 insertions(+), 204 deletions(-)
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 7d24bb943b1ee..ded22f066128f 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -1385,6 +1385,245 @@ int ceph_process_folio_batch(struct address_space *mapping,
return rc;
}
+static inline
+void ceph_shift_unused_folios_left(struct folio_batch *fbatch)
+{
+ unsigned j, n = 0;
+
+ /* shift unused page to beginning of fbatch */
+ for (j = 0; j < folio_batch_count(fbatch); j++) {
+ if (!fbatch->folios[j])
+ continue;
+
+ if (n < j) {
+ fbatch->folios[n] = fbatch->folios[j];
+ }
+
+ n++;
+ }
+
+ fbatch->nr = n;
+}
+
+static
+int ceph_submit_write(struct address_space *mapping,
+ struct writeback_control *wbc,
+ struct ceph_writeback_ctl *ceph_wbc)
+{
+ struct inode *inode = mapping->host;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
+ struct ceph_client *cl = fsc->client;
+ struct ceph_vino vino = ceph_vino(inode);
+ struct ceph_osd_request *req = NULL;
+ struct page *page = NULL;
+ bool caching = ceph_is_cache_enabled(inode);
+ u64 offset;
+ u64 len;
+ unsigned i;
+
+new_request:
+ offset = ceph_fscrypt_page_offset(ceph_wbc->pages[0]);
+ len = ceph_wbc->wsize;
+
+ req = ceph_osdc_new_request(&fsc->client->osdc,
+ &ci->i_layout, vino,
+ offset, &len, 0, ceph_wbc->num_ops,
+ CEPH_OSD_OP_WRITE, CEPH_OSD_FLAG_WRITE,
+ ceph_wbc->snapc, ceph_wbc->truncate_seq,
+ ceph_wbc->truncate_size, false);
+ if (IS_ERR(req)) {
+ req = ceph_osdc_new_request(&fsc->client->osdc,
+ &ci->i_layout, vino,
+ offset, &len, 0,
+ min(ceph_wbc->num_ops,
+ CEPH_OSD_SLAB_OPS),
+ CEPH_OSD_OP_WRITE,
+ CEPH_OSD_FLAG_WRITE,
+ ceph_wbc->snapc,
+ ceph_wbc->truncate_seq,
+ ceph_wbc->truncate_size,
+ true);
+ BUG_ON(IS_ERR(req));
+ }
+
+ page = ceph_wbc->pages[ceph_wbc->locked_pages - 1];
+ BUG_ON(len < ceph_fscrypt_page_offset(page) + thp_size(page) - offset);
+
+ if (!ceph_inc_osd_stopping_blocker(fsc->mdsc)) {
+ for (i = 0; i < folio_batch_count(&ceph_wbc->fbatch); i++) {
+ struct folio *folio = ceph_wbc->fbatch.folios[i];
+
+ if (!folio)
+ continue;
+
+ page = &folio->page;
+ redirty_page_for_writepage(wbc, page);
+ unlock_page(page);
+ }
+
+ for (i = 0; i < ceph_wbc->locked_pages; i++) {
+ page = ceph_fscrypt_pagecache_page(ceph_wbc->pages[i]);
+
+ if (!page)
+ continue;
+
+ redirty_page_for_writepage(wbc, page);
+ unlock_page(page);
+ }
+
+ ceph_osdc_put_request(req);
+ return -EIO;
+ }
+
+ req->r_callback = writepages_finish;
+ req->r_inode = inode;
+
+ /* Format the osd request message and submit the write */
+ len = 0;
+ ceph_wbc->data_pages = ceph_wbc->pages;
+ ceph_wbc->op_idx = 0;
+ for (i = 0; i < ceph_wbc->locked_pages; i++) {
+ u64 cur_offset;
+
+ page = ceph_fscrypt_pagecache_page(ceph_wbc->pages[i]);
+ cur_offset = page_offset(page);
+
+ /*
+ * Discontinuity in page range? Ceph can handle that by just passing
+ * multiple extents in the write op.
+ */
+ if (offset + len != cur_offset) {
+ /* If it's full, stop here */
+ if (ceph_wbc->op_idx + 1 == req->r_num_ops)
+ break;
+
+ /* Kick off an fscache write with what we have so far. */
+ ceph_fscache_write_to_cache(inode, offset, len, caching);
+
+ /* Start a new extent */
+ osd_req_op_extent_dup_last(req, ceph_wbc->op_idx,
+ cur_offset - offset);
+
+ doutc(cl, "got pages at %llu~%llu\n", offset, len);
+
+ osd_req_op_extent_osd_data_pages(req, ceph_wbc->op_idx,
+ ceph_wbc->data_pages,
+ len, 0,
+ ceph_wbc->from_pool,
+ false);
+ osd_req_op_extent_update(req, ceph_wbc->op_idx, len);
+
+ len = 0;
+ offset = cur_offset;
+ ceph_wbc->data_pages = ceph_wbc->pages + i;
+ ceph_wbc->op_idx++;
+ }
+
+ set_page_writeback(page);
+
+ if (caching)
+ ceph_set_page_fscache(page);
+
+ len += thp_size(page);
+ }
+
+ ceph_fscache_write_to_cache(inode, offset, len, caching);
+
+ if (ceph_wbc->size_stable) {
+ len = min(len, ceph_wbc->i_size - offset);
+ } else if (i == ceph_wbc->locked_pages) {
+ /* writepages_finish() clears writeback pages
+ * according to the data length, so make sure
+ * data length covers all locked pages */
+ u64 min_len = len + 1 - thp_size(page);
+ len = get_writepages_data_length(inode,
+ ceph_wbc->pages[i - 1],
+ offset);
+ len = max(len, min_len);
+ }
+
+ if (IS_ENCRYPTED(inode))
+ len = round_up(len, CEPH_FSCRYPT_BLOCK_SIZE);
+
+ doutc(cl, "got pages at %llu~%llu\n", offset, len);
+
+ if (IS_ENCRYPTED(inode) &&
+ ((offset | len) & ~CEPH_FSCRYPT_BLOCK_MASK)) {
+ pr_warn_client(cl,
+ "bad encrypted write offset=%lld len=%llu\n",
+ offset, len);
+ }
+
+ osd_req_op_extent_osd_data_pages(req, ceph_wbc->op_idx,
+ ceph_wbc->data_pages, len,
+ 0, ceph_wbc->from_pool, false);
+ osd_req_op_extent_update(req, ceph_wbc->op_idx, len);
+
+ BUG_ON(ceph_wbc->op_idx + 1 != req->r_num_ops);
+
+ ceph_wbc->from_pool = false;
+ if (i < ceph_wbc->locked_pages) {
+ BUG_ON(ceph_wbc->num_ops <= req->r_num_ops);
+ ceph_wbc->num_ops -= req->r_num_ops;
+ ceph_wbc->locked_pages -= i;
+
+ /* allocate new pages array for next request */
+ ceph_wbc->data_pages = ceph_wbc->pages;
+ __ceph_allocate_page_array(ceph_wbc, ceph_wbc->locked_pages);
+ memcpy(ceph_wbc->pages, ceph_wbc->data_pages + i,
+ ceph_wbc->locked_pages * sizeof(*ceph_wbc->pages));
+ memset(ceph_wbc->data_pages + i, 0,
+ ceph_wbc->locked_pages * sizeof(*ceph_wbc->pages));
+ } else {
+ BUG_ON(ceph_wbc->num_ops != req->r_num_ops);
+ /* request message now owns the pages array */
+ ceph_wbc->pages = NULL;
+ }
+
+ req->r_mtime = inode_get_mtime(inode);
+ ceph_osdc_start_request(&fsc->client->osdc, req);
+ req = NULL;
+
+ wbc->nr_to_write -= i;
+ if (ceph_wbc->pages)
+ goto new_request;
+
+ return 0;
+}
+
+static
+void ceph_wait_until_current_writes_complete(struct address_space *mapping,
+ struct writeback_control *wbc,
+ struct ceph_writeback_ctl *ceph_wbc)
+{
+ struct page *page;
+ unsigned i, nr;
+
+ if (wbc->sync_mode != WB_SYNC_NONE &&
+ ceph_wbc->start_index == 0 && /* all dirty pages were checked */
+ !ceph_wbc->head_snapc) {
+ ceph_wbc->index = 0;
+
+ while ((ceph_wbc->index <= ceph_wbc->end) &&
+ (nr = filemap_get_folios_tag(mapping,
+ &ceph_wbc->index,
+ (pgoff_t)-1,
+ PAGECACHE_TAG_WRITEBACK,
+ &ceph_wbc->fbatch))) {
+ for (i = 0; i < nr; i++) {
+ page = &ceph_wbc->fbatch.folios[i]->page;
+ if (page_snap_context(page) != ceph_wbc->snapc)
+ continue;
+ wait_on_page_writeback(page);
+ }
+
+ folio_batch_release(&ceph_wbc->fbatch);
+ cond_resched();
+ }
+ }
+}
+
/*
* initiate async writeback
*/
@@ -1392,17 +1631,12 @@ static int ceph_writepages_start(struct address_space *mapping,
struct writeback_control *wbc)
{
struct inode *inode = mapping->host;
- struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
struct ceph_client *cl = fsc->client;
- struct ceph_vino vino = ceph_vino(inode);
struct ceph_writeback_ctl ceph_wbc;
- struct ceph_osd_request *req = NULL;
int rc = 0;
- bool caching = ceph_is_cache_enabled(inode);
- if (wbc->sync_mode == WB_SYNC_NONE &&
- fsc->write_congested)
+ if (wbc->sync_mode == WB_SYNC_NONE && fsc->write_congested)
return 0;
doutc(cl, "%llx.%llx (mode=%s)\n", ceph_vinop(inode),
@@ -1429,9 +1663,6 @@ static int ceph_writepages_start(struct address_space *mapping,
tag_pages_for_writeback(mapping, ceph_wbc.index, ceph_wbc.end);
while (!has_writeback_done(&ceph_wbc)) {
- unsigned i;
- struct page *page;
-
ceph_wbc.locked_pages = 0;
ceph_wbc.max_pages = ceph_wbc.wsize >> PAGE_SHIFT;
@@ -1449,6 +1680,7 @@ static int ceph_writepages_start(struct address_space *mapping,
if (!ceph_wbc.nr_folios && !ceph_wbc.locked_pages)
break;
+process_folio_batch:
rc = ceph_process_folio_batch(mapping, wbc, &ceph_wbc);
if (rc)
goto release_folios;
@@ -1456,187 +1688,30 @@ static int ceph_writepages_start(struct address_space *mapping,
/* did we get anything? */
if (!ceph_wbc.locked_pages)
goto release_folios;
- if (i) {
- unsigned j, n = 0;
- /* shift unused page to beginning of fbatch */
- for (j = 0; j < ceph_wbc.nr_folios; j++) {
- if (!ceph_wbc.fbatch.folios[j])
- continue;
- if (n < j) {
- ceph_wbc.fbatch.folios[n] =
- ceph_wbc.fbatch.folios[j];
- }
- n++;
- }
- ceph_wbc.fbatch.nr = n;
- if (ceph_wbc.nr_folios && i == ceph_wbc.nr_folios &&
+ if (ceph_wbc.processed_in_fbatch) {
+ ceph_shift_unused_folios_left(&ceph_wbc.fbatch);
+
+ if (folio_batch_count(&ceph_wbc.fbatch) == 0 &&
ceph_wbc.locked_pages < ceph_wbc.max_pages) {
doutc(cl, "reached end fbatch, trying for more\n");
- folio_batch_release(&ceph_wbc.fbatch);
goto get_more_pages;
}
}
-new_request:
- ceph_wbc.offset = ceph_fscrypt_page_offset(ceph_wbc.pages[0]);
- ceph_wbc.len = ceph_wbc.wsize;
-
- req = ceph_osdc_new_request(&fsc->client->osdc,
- &ci->i_layout, vino,
- ceph_wbc.offset, &ceph_wbc.len,
- 0, ceph_wbc.num_ops,
- CEPH_OSD_OP_WRITE, CEPH_OSD_FLAG_WRITE,
- ceph_wbc.snapc, ceph_wbc.truncate_seq,
- ceph_wbc.truncate_size, false);
- if (IS_ERR(req)) {
- req = ceph_osdc_new_request(&fsc->client->osdc,
- &ci->i_layout, vino,
- ceph_wbc.offset, &ceph_wbc.len,
- 0, min(ceph_wbc.num_ops,
- CEPH_OSD_SLAB_OPS),
- CEPH_OSD_OP_WRITE,
- CEPH_OSD_FLAG_WRITE,
- ceph_wbc.snapc,
- ceph_wbc.truncate_seq,
- ceph_wbc.truncate_size, true);
- BUG_ON(IS_ERR(req));
- }
- BUG_ON(ceph_wbc.len <
- ceph_fscrypt_page_offset(ceph_wbc.pages[ceph_wbc.locked_pages - 1]) +
- thp_size(ceph_wbc.pages[ceph_wbc.locked_pages - 1]) -
- ceph_wbc.offset);
-
- if (!ceph_inc_osd_stopping_blocker(fsc->mdsc)) {
- rc = -EIO;
+ rc = ceph_submit_write(mapping, wbc, &ceph_wbc);
+ if (rc)
goto release_folios;
- }
- req->r_callback = writepages_finish;
- req->r_inode = inode;
-
- /* Format the osd request message and submit the write */
- ceph_wbc.len = 0;
- ceph_wbc.data_pages = ceph_wbc.pages;
- ceph_wbc.op_idx = 0;
- for (i = 0; i < ceph_wbc.locked_pages; i++) {
- struct page *page =
- ceph_fscrypt_pagecache_page(ceph_wbc.pages[i]);
-
- u64 cur_offset = page_offset(page);
- /*
- * Discontinuity in page range? Ceph can handle that by just passing
- * multiple extents in the write op.
- */
- if (ceph_wbc.offset + ceph_wbc.len != cur_offset) {
- /* If it's full, stop here */
- if (ceph_wbc.op_idx + 1 == req->r_num_ops)
- break;
-
- /* Kick off an fscache write with what we have so far. */
- ceph_fscache_write_to_cache(inode, ceph_wbc.offset,
- ceph_wbc.len, caching);
-
- /* Start a new extent */
- osd_req_op_extent_dup_last(req, ceph_wbc.op_idx,
- cur_offset -
- ceph_wbc.offset);
- doutc(cl, "got pages at %llu~%llu\n",
- ceph_wbc.offset,
- ceph_wbc.len);
- osd_req_op_extent_osd_data_pages(req,
- ceph_wbc.op_idx,
- ceph_wbc.data_pages,
- ceph_wbc.len, 0,
- ceph_wbc.from_pool, false);
- osd_req_op_extent_update(req, ceph_wbc.op_idx,
- ceph_wbc.len);
-
- ceph_wbc.len = 0;
- ceph_wbc.offset = cur_offset;
- ceph_wbc.data_pages = ceph_wbc.pages + i;
- ceph_wbc.op_idx++;
- }
- set_page_writeback(page);
- if (caching)
- ceph_set_page_fscache(page);
- ceph_wbc.len += thp_size(page);
- }
- ceph_fscache_write_to_cache(inode, ceph_wbc.offset,
- ceph_wbc.len, caching);
-
- if (ceph_wbc.size_stable) {
- ceph_wbc.len = min(ceph_wbc.len,
- ceph_wbc.i_size - ceph_wbc.offset);
- } else if (i == ceph_wbc.locked_pages) {
- /* writepages_finish() clears writeback pages
- * according to the data length, so make sure
- * data length covers all locked pages */
- u64 min_len = ceph_wbc.len + 1 - thp_size(page);
- ceph_wbc.len =
- get_writepages_data_length(inode,
- ceph_wbc.pages[i - 1],
- ceph_wbc.offset);
- ceph_wbc.len = max(ceph_wbc.len, min_len);
- }
- if (IS_ENCRYPTED(inode)) {
- ceph_wbc.len = round_up(ceph_wbc.len,
- CEPH_FSCRYPT_BLOCK_SIZE);
- }
-
- doutc(cl, "got pages at %llu~%llu\n",
- ceph_wbc.offset, ceph_wbc.len);
+ ceph_wbc.locked_pages = 0;
+ ceph_wbc.strip_unit_end = 0;
- if (IS_ENCRYPTED(inode) &&
- ((ceph_wbc.offset | ceph_wbc.len) & ~CEPH_FSCRYPT_BLOCK_MASK))
- pr_warn_client(cl,
- "bad encrypted write offset=%lld len=%llu\n",
- ceph_wbc.offset, ceph_wbc.len);
-
- osd_req_op_extent_osd_data_pages(req, ceph_wbc.op_idx,
- ceph_wbc.data_pages,
- ceph_wbc.len,
- 0, ceph_wbc.from_pool, false);
- osd_req_op_extent_update(req, ceph_wbc.op_idx, ceph_wbc.len);
-
- BUG_ON(ceph_wbc.op_idx + 1 != req->r_num_ops);
-
- ceph_wbc.from_pool = false;
- if (i < ceph_wbc.locked_pages) {
- BUG_ON(ceph_wbc.num_ops <= req->r_num_ops);
- ceph_wbc.num_ops -= req->r_num_ops;
- ceph_wbc.locked_pages -= i;
-
- /* allocate new pages array for next request */
- ceph_wbc.data_pages = ceph_wbc.pages;
- ceph_wbc.pages = kmalloc_array(ceph_wbc.locked_pages,
- sizeof(*ceph_wbc.pages),
- GFP_NOFS);
- if (!ceph_wbc.pages) {
- ceph_wbc.from_pool = true;
- ceph_wbc.pages =
- mempool_alloc(ceph_wb_pagevec_pool, GFP_NOFS);
- BUG_ON(!ceph_wbc.pages);
- }
- memcpy(ceph_wbc.pages, ceph_wbc.data_pages + i,
- ceph_wbc.locked_pages * sizeof(*ceph_wbc.pages));
- memset(ceph_wbc.data_pages + i, 0,
- ceph_wbc.locked_pages * sizeof(*ceph_wbc.pages));
- } else {
- BUG_ON(ceph_wbc.num_ops != req->r_num_ops);
- ceph_wbc.index = ceph_wbc.pages[i - 1]->index + 1;
- /* request message now owns the pages array */
- ceph_wbc.pages = NULL;
+ if (folio_batch_count(&ceph_wbc.fbatch) > 0) {
+ ceph_wbc.nr_folios =
+ folio_batch_count(&ceph_wbc.fbatch);
+ goto process_folio_batch;
}
- req->r_mtime = inode_get_mtime(inode);
- ceph_osdc_start_request(&fsc->client->osdc, req);
- req = NULL;
-
- wbc->nr_to_write -= i;
- if (ceph_wbc.pages)
- goto new_request;
-
/*
* We stop writing back only if we are not doing
* integrity sync. In case of integrity sync we have to
@@ -1656,32 +1731,12 @@ static int ceph_writepages_start(struct address_space *mapping,
if (ceph_wbc.should_loop && !ceph_wbc.done) {
/* more to do; loop back to beginning of file */
doutc(cl, "looping back to beginning of file\n");
- ceph_wbc.end = ceph_wbc.start_index - 1; /* OK even when start_index == 0 */
+ /* OK even when start_index == 0 */
+ ceph_wbc.end = ceph_wbc.start_index - 1;
/* to write dirty pages associated with next snapc,
* we need to wait until current writes complete */
- if (wbc->sync_mode != WB_SYNC_NONE &&
- ceph_wbc.start_index == 0 && /* all dirty pages were checked */
- !ceph_wbc.head_snapc) {
- struct page *page;
- unsigned i, nr;
- ceph_wbc.index = 0;
- while ((ceph_wbc.index <= ceph_wbc.end) &&
- (nr = filemap_get_folios_tag(mapping,
- &ceph_wbc.index,
- (pgoff_t)-1,
- PAGECACHE_TAG_WRITEBACK,
- &ceph_wbc.fbatch))) {
- for (i = 0; i < nr; i++) {
- page = &ceph_wbc.fbatch.folios[i]->page;
- if (page_snap_context(page) != ceph_wbc.snapc)
- continue;
- wait_on_page_writeback(page);
- }
- folio_batch_release(&ceph_wbc.fbatch);
- cond_resched();
- }
- }
+ ceph_wait_until_current_writes_complete(mapping, wbc, &ceph_wbc);
ceph_wbc.start_index = 0;
ceph_wbc.index = 0;
@@ -1692,15 +1747,13 @@ static int ceph_writepages_start(struct address_space *mapping,
mapping->writeback_index = ceph_wbc.index;
out:
- ceph_osdc_put_request(req);
ceph_put_snap_context(ceph_wbc.last_snapc);
doutc(cl, "%llx.%llx dend - startone, rc = %d\n", ceph_vinop(inode),
rc);
+
return rc;
}
-
-
/*
* See if a given @snapc is either writeable, or already written.
*/
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 841/869] ceph: always call ceph_shift_unused_folios_left()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (839 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 840/869] ceph: introduce ceph_submit_write() method Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 842/869] spi: microchip-core-qspi: stop checking viability of op->max_freq in supports_op callback Greg Kroah-Hartman
` (28 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Max Kellermann, Viacheslav Dubeyko,
Ilya Dryomov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann <max.kellermann@ionos.com>
[ Upstream commit cce7c15faaac79b532a07ed6ab8332280ad83762 ]
The function ceph_process_folio_batch() sets folio_batch entries to
NULL, which is an illegal state. Before folio_batch_release() crashes
due to this API violation, the function ceph_shift_unused_folios_left()
is supposed to remove those NULLs from the array.
However, since commit ce80b76dd327 ("ceph: introduce
ceph_process_folio_batch() method"), this shifting doesn't happen
anymore because the "for" loop got moved to ceph_process_folio_batch(),
and now the `i` variable that remains in ceph_writepages_start()
doesn't get incremented anymore, making the shifting effectively
unreachable much of the time.
Later, commit 1551ec61dc55 ("ceph: introduce ceph_submit_write()
method") added more preconditions for doing the shift, replacing the
`i` check (with something that is still just as broken):
- if ceph_process_folio_batch() fails, shifting never happens
- if ceph_move_dirty_page_in_page_array() was never called (because
ceph_process_folio_batch() has returned early for some of various
reasons), shifting never happens
- if `processed_in_fbatch` is zero (because ceph_process_folio_batch()
has returned early for some of the reasons mentioned above or
because ceph_move_dirty_page_in_page_array() has failed), shifting
never happens
Since those two commits, any problem in ceph_process_folio_batch()
could crash the kernel, e.g. this way:
BUG: kernel NULL pointer dereference, address: 0000000000000034
#PF: supervisor write access in kernel mode
#PF: error_code(0x0002) - not-present page
PGD 0 P4D 0
Oops: Oops: 0002 [#1] SMP NOPTI
CPU: 172 UID: 0 PID: 2342707 Comm: kworker/u778:8 Not tainted 6.15.10-cm4all1-es #714 NONE
Hardware name: Dell Inc. PowerEdge R7615/0G9DHV, BIOS 1.6.10 12/08/2023
Workqueue: writeback wb_workfn (flush-ceph-1)
RIP: 0010:folios_put_refs+0x85/0x140
Code: 83 c5 01 39 e8 7e 76 48 63 c5 49 8b 5c c4 08 b8 01 00 00 00 4d 85 ed 74 05 41 8b 44 ad 00 48 8b 15 b0 >
RSP: 0018:ffffb880af8db778 EFLAGS: 00010207
RAX: 0000000000000001 RBX: 0000000000000000 RCX: 0000000000000003
RDX: ffffe377cc3b0000 RSI: 0000000000000000 RDI: ffffb880af8db8c0
RBP: 0000000000000000 R08: 000000000000007d R09: 000000000102b86f
R10: 0000000000000001 R11: 00000000000000ac R12: ffffb880af8db8c0
R13: 0000000000000000 R14: 0000000000000000 R15: ffff9bd262c97000
FS: 0000000000000000(0000) GS:ffff9c8efc303000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000034 CR3: 0000000160958004 CR4: 0000000000770ef0
PKRU: 55555554
Call Trace:
<TASK>
ceph_writepages_start+0xeb9/0x1410
The crash can be reproduced easily by changing the
ceph_check_page_before_write() return value to `-E2BIG`.
(Interestingly, the crash happens only if `huge_zero_folio` has
already been allocated; without `huge_zero_folio`,
is_huge_zero_folio(NULL) returns true and folios_put_refs() skips NULL
entries instead of dereferencing them. That makes reproducing the bug
somewhat unreliable. See
https://lore.kernel.org/20250826231626.218675-1-max.kellermann@ionos.com
for a discussion of this detail.)
My suggestion is to move the ceph_shift_unused_folios_left() to right
after ceph_process_folio_batch() to ensure it always gets called to
fix up the illegal folio_batch state.
Cc: stable@vger.kernel.org
Fixes: ce80b76dd327 ("ceph: introduce ceph_process_folio_batch() method")
Link: https://lore.kernel.org/ceph-devel/aK4v548CId5GIKG1@swift.blarg.de/
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ceph/addr.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index ded22f066128f..5e0f83adc4590 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -1682,6 +1682,7 @@ static int ceph_writepages_start(struct address_space *mapping,
process_folio_batch:
rc = ceph_process_folio_batch(mapping, wbc, &ceph_wbc);
+ ceph_shift_unused_folios_left(&ceph_wbc.fbatch);
if (rc)
goto release_folios;
@@ -1690,8 +1691,6 @@ static int ceph_writepages_start(struct address_space *mapping,
goto release_folios;
if (ceph_wbc.processed_in_fbatch) {
- ceph_shift_unused_folios_left(&ceph_wbc.fbatch);
-
if (folio_batch_count(&ceph_wbc.fbatch) == 0 &&
ceph_wbc.locked_pages < ceph_wbc.max_pages) {
doutc(cl, "reached end fbatch, trying for more\n");
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 842/869] spi: microchip-core-qspi: stop checking viability of op->max_freq in supports_op callback
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (840 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 841/869] ceph: always call ceph_shift_unused_folios_left() Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 843/869] sched/psi: Create the psimon kthread outside of cgroup_mutex Greg Kroah-Hartman
` (27 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Valentina Fernandez, Conor Dooley,
Mark Brown, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Conor Dooley <conor.dooley@microchip.com>
[ Upstream commit 89e7353f522f5cf70cb48c01ce2dcdcb275b8022 ]
In commit 13529647743d9 ("spi: microchip-core-qspi: Support per spi-mem
operation frequency switches") the logic for checking the viability of
op->max_freq in mchp_coreqspi_setup_clock() was copied into
mchp_coreqspi_supports_op(). Unfortunately, op->max_freq is not valid
when this function is called during probe but is instead zero.
Accordingly, baud_rate_val is calculated to be INT_MAX due to division
by zero, causing probe of the attached memory device to fail.
Seemingly spi-microchip-core-qspi was the only driver that had such a
modification made to its supports_op callback when the per_op_freq
capability was added, so just remove it to restore prior functionality.
CC: stable@vger.kernel.org
Reported-by: Valentina Fernandez <valentina.fernandezalanis@microchip.com>
Fixes: 13529647743d9 ("spi: microchip-core-qspi: Support per spi-mem operation frequency switches")
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Message-ID: <20250825-during-ploy-939bdd068593@spud>
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/spi/spi-microchip-core-qspi.c | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c
index bc5e4e4e558a0..2b5271fa870bf 100644
--- a/drivers/spi/spi-microchip-core-qspi.c
+++ b/drivers/spi/spi-microchip-core-qspi.c
@@ -486,10 +486,6 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
static bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct mchp_coreqspi *qspi = spi_controller_get_devdata(mem->spi->controller);
- unsigned long clk_hz;
- u32 baud_rate_val;
-
if (!spi_mem_default_supports_op(mem, op))
return false;
@@ -512,14 +508,6 @@ static bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_
return false;
}
- clk_hz = clk_get_rate(qspi->clk);
- if (!clk_hz)
- return false;
-
- baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * op->max_freq);
- if (baud_rate_val > MAX_DIVIDER || baud_rate_val < MIN_DIVIDER)
- return false;
-
return true;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 843/869] sched/psi: Create the psimon kthread outside of cgroup_mutex
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (841 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 842/869] spi: microchip-core-qspi: stop checking viability of op->max_freq in supports_op callback Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 844/869] ocfs2: use correct endian in ocfs2_dinode_has_extents Greg Kroah-Hartman
` (26 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Edward Adam Davis, Chen Ridong,
Matt Fleming, Tejun Heo, Johannes Weiner, Suren Baghdasaryan,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tejun Heo <tj@kernel.org>
[ Upstream commit fadeedd7cfc5d73d33fa3d7ac54b9b27aabd09d2 ]
a5b98009f16d ("sched/psi: fix race between file release and pressure write")
made pressure_write() hold cgroup_mutex across psi_trigger_create(), which
forks the psimon kthread for the first rtpoll trigger. As kthread creation
depends on the whole fork path, the commit inadvertently created a lot of
unwanted locking dependencies from cgroup_mutex.
sched_ext got hit by one: its enable path blocks forks and then grabs
cgroup_mutex, so a pressure write racing a scheduler enable deadlocks, with
every other fork piling up behind.
Fix it by splitting trigger creation so that the worker is forked with
cgroup_mutex dropped and the kernfs active reference left broken. The latter
matters because rmdir and cgroup.pressure writes drain active references
under cgroup_mutex. Publishing the trigger last keeps error reporting
synchronous and preserves the of->priv lifetime rules.
The trigger registered in the first stage pins the group's rtpoll machinery
across the unlocked window, leaving only creation races to resolve. The
catch-up poll on installation covers scheduling attempts dropped while there
was no worker.
v2: Retagged sched/psi (was cgroup).
Fixes: a5b98009f16d ("sched/psi: fix race between file release and pressure write")
Cc: stable@vger.kernel.org
Cc: Edward Adam Davis <eadavis@qq.com>
Cc: Chen Ridong <chenridong@huaweicloud.com>
Reported-by: Matt Fleming <mfleming@cloudflare.com>
Closes: https://lore.kernel.org/all/20260710100441.2653477-1-matt@readmodwrite.com/
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Tested-by: Matt Fleming <mfleming@cloudflare.com>
Acked-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/psi.h | 4 ++-
kernel/cgroup/cgroup.c | 23 +++++++++++++-
kernel/sched/psi.c | 69 ++++++++++++++++++++++++++++++++----------
3 files changed, 78 insertions(+), 18 deletions(-)
diff --git a/include/linux/psi.h b/include/linux/psi.h
index e0745873e3f26..7966e3ac03b99 100644
--- a/include/linux/psi.h
+++ b/include/linux/psi.h
@@ -25,7 +25,9 @@ void psi_memstall_leave(unsigned long *flags);
int psi_show(struct seq_file *s, struct psi_group *group, enum psi_res res);
struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf,
enum psi_res res, struct file *file,
- struct kernfs_open_file *of);
+ struct kernfs_open_file *of,
+ bool *need_rtpoll_worker);
+int psi_trigger_create_rtpoll_worker(struct psi_group *group);
void psi_trigger_destroy(struct psi_trigger *t);
__poll_t psi_trigger_poll(void **trigger_ptr, struct file *file,
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 38fd322ccf2e9..97d9818db244e 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -3885,6 +3885,7 @@ static ssize_t pressure_write(struct kernfs_open_file *of, char *buf,
struct psi_trigger *new;
struct cgroup *cgrp;
struct psi_group *psi;
+ bool need_rtpoll_worker;
ssize_t ret = 0;
cgrp = cgroup_kn_lock_live(of->kn, false);
@@ -3904,12 +3905,32 @@ static ssize_t pressure_write(struct kernfs_open_file *of, char *buf,
}
psi = cgroup_psi(cgrp);
- new = psi_trigger_create(psi, buf, res, of->file, of);
+ new = psi_trigger_create(psi, buf, res, of->file, of,
+ &need_rtpoll_worker);
if (IS_ERR(new)) {
ret = PTR_ERR(new);
goto out_unlock;
}
+ /*
+ * The worker fork must run with neither cgroup_mutex nor the file's
+ * kernfs active reference held. The latter is broken since
+ * cgroup_kn_lock_live(). @of->priv may be released while unlocked, so
+ * recheck before publishing @new.
+ */
+ if (need_rtpoll_worker) {
+ cgroup_unlock();
+ ret = psi_trigger_create_rtpoll_worker(psi);
+ cgroup_lock();
+
+ if (!ret && !of->priv)
+ ret = -ENODEV;
+ if (ret) {
+ psi_trigger_destroy(new);
+ goto out_unlock;
+ }
+ }
+
smp_store_release(&ctx->psi.trigger, new);
out_unlock:
diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c
index a6fc7ea51d2eb..7550f609e4448 100644
--- a/kernel/sched/psi.c
+++ b/kernel/sched/psi.c
@@ -1289,9 +1289,44 @@ int psi_show(struct seq_file *m, struct psi_group *group, enum psi_res res)
return 0;
}
+/*
+ * Create @group's rtpoll worker after psi_trigger_create() reported the need
+ * for one. kthread creation depends on the whole fork path and we don't want
+ * all of that nested inside cgroup_mutex, so the caller must drop it and any
+ * other lock that forks can wait behind. If two callers race, the loser stops
+ * its never-woken kthread.
+ */
+int psi_trigger_create_rtpoll_worker(struct psi_group *group)
+{
+ struct task_struct *task;
+
+ task = kthread_create(psi_rtpoll_worker, group, "psimon");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+
+ scoped_guard(mutex, &group->rtpoll_trigger_lock) {
+ if (!rcu_access_pointer(group->rtpoll_task)) {
+ atomic_set(&group->rtpoll_wakeup, 0);
+ wake_up_process(task);
+ rcu_assign_pointer(group->rtpoll_task, task);
+
+ /*
+ * Poll once to catch up on scheduling attempts dropped
+ * while there was no rtpoll worker.
+ */
+ psi_schedule_rtpoll_work(group, 1, true);
+ return 0;
+ }
+ }
+
+ kthread_stop(task);
+ return 0;
+}
+
struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf,
enum psi_res res, struct file *file,
- struct kernfs_open_file *of)
+ struct kernfs_open_file *of,
+ bool *need_rtpoll_worker)
{
struct psi_trigger *t;
enum psi_states state;
@@ -1299,6 +1334,8 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf,
bool privileged;
u32 window_us;
+ *need_rtpoll_worker = false;
+
if (static_branch_likely(&psi_disabled))
return ERR_PTR(-EOPNOTSUPP);
@@ -1359,26 +1396,14 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf,
if (privileged) {
mutex_lock(&group->rtpoll_trigger_lock);
- if (!rcu_access_pointer(group->rtpoll_task)) {
- struct task_struct *task;
-
- task = kthread_create(psi_rtpoll_worker, group, "psimon");
- if (IS_ERR(task)) {
- kfree(t);
- mutex_unlock(&group->rtpoll_trigger_lock);
- return ERR_CAST(task);
- }
- atomic_set(&group->rtpoll_wakeup, 0);
- wake_up_process(task);
- rcu_assign_pointer(group->rtpoll_task, task);
- }
-
list_add(&t->node, &group->rtpoll_triggers);
group->rtpoll_min_period = min(group->rtpoll_min_period,
div_u64(t->win.size, UPDATES_PER_WINDOW));
group->rtpoll_nr_triggers[t->state]++;
group->rtpoll_states |= (1 << t->state);
+ *need_rtpoll_worker = !rcu_access_pointer(group->rtpoll_task);
+
mutex_unlock(&group->rtpoll_trigger_lock);
} else {
mutex_lock(&group->avgs_lock);
@@ -1538,6 +1563,8 @@ static ssize_t psi_write(struct file *file, const char __user *user_buf,
size_t buf_size;
struct seq_file *seq;
struct psi_trigger *new;
+ bool need_rtpoll_worker;
+ int ret;
if (static_branch_likely(&psi_disabled))
return -EOPNOTSUPP;
@@ -1562,12 +1589,22 @@ static ssize_t psi_write(struct file *file, const char __user *user_buf,
return -EBUSY;
}
- new = psi_trigger_create(&psi_system, buf, res, file, NULL);
+ new = psi_trigger_create(&psi_system, buf, res, file, NULL,
+ &need_rtpoll_worker);
if (IS_ERR(new)) {
mutex_unlock(&seq->lock);
return PTR_ERR(new);
}
+ if (need_rtpoll_worker) {
+ ret = psi_trigger_create_rtpoll_worker(&psi_system);
+ if (ret) {
+ psi_trigger_destroy(new);
+ mutex_unlock(&seq->lock);
+ return ret;
+ }
+ }
+
smp_store_release(&seq->private, new);
mutex_unlock(&seq->lock);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 844/869] ocfs2: use correct endian in ocfs2_dinode_has_extents
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (842 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 843/869] sched/psi: Create the psimon kthread outside of cgroup_mutex Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 845/869] netfs: release readahead folios on iterator preparation failure Greg Kroah-Hartman
` (25 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Joseph Qi, Heming Zhao, Mark Fasheh,
Joel Becker, Junxiao Bi, Changwei Ge, Jun Piao, Andrew Morton,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joseph Qi <joseph.qi@linux.alibaba.com>
[ Upstream commit c9dff86eb78a4b6b02b1e407993c946ccaf9bfb4 ]
Fields in ocfs2_dinode is little endian, covert to host endian when
checking those contents.
Link: https://lkml.kernel.org/r/20251025123218.3997866-1-joseph.qi@linux.alibaba.com
Fixes: fdbb6cd96ed5 ("ocfs2: correct l_next_free_rec in online check")
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Reviewed-by: Heming Zhao <heming.zhao@suse.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ocfs2/inode.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index eb8de681376bd..ce78ef998217c 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -236,13 +236,15 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
static int ocfs2_dinode_has_extents(struct ocfs2_dinode *di)
{
/* inodes flagged with other stuff in id2 */
- if (di->i_flags & (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL |
- OCFS2_CHAIN_FL | OCFS2_DEALLOC_FL))
+ if (le32_to_cpu(di->i_flags) &
+ (OCFS2_SUPER_BLOCK_FL | OCFS2_LOCAL_ALLOC_FL | OCFS2_CHAIN_FL |
+ OCFS2_DEALLOC_FL))
return 0;
/* i_flags doesn't indicate when id2 is a fast symlink */
- if (S_ISLNK(di->i_mode) && di->i_size && di->i_clusters == 0)
+ if (S_ISLNK(le16_to_cpu(di->i_mode)) && le64_to_cpu(di->i_size) &&
+ !le32_to_cpu(di->i_clusters))
return 0;
- if (di->i_dyn_features & OCFS2_INLINE_DATA_FL)
+ if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)
return 0;
return 1;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 845/869] netfs: release readahead folios on iterator preparation failure
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (843 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 844/869] ocfs2: use correct endian in ocfs2_dinode_has_extents Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 846/869] netfs: Fix folio state after ENOMEM whilst under writeback iteration Greg Kroah-Hartman
` (24 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yichong Chen, David Howells,
Paulo Alcantara, netfs, linux-fsdevel,
Christian Brauner (Amutable), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <chenyichong@uniontech.com>
[ Upstream commit 87eb3d272dcbcbbfe5c1576c10e5dc72810cf1f6 ]
netfs_prepare_read_iterator() batches readahead folios in put_batch so that
the folio references can be dropped after the I/O iterator has been
prepared.
If rolling_buffer_load_from_ra() fails after earlier folios have been
batched, the function returns immediately and leaves those references held.
Release the batch before returning the error.
Fixes: 06fa229ceb36 ("netfs: Abstract out a rolling folio buffer implementation")
Signed-off-by: Yichong Chen <chenyichong@uniontech.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260727130716.1099906-4-dhowells@redhat.com
cc: Paulo Alcantara <pc@manguebit.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/netfs/buffered_read.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c
index 23235e62f33ec..68ad1ece65a03 100644
--- a/fs/netfs/buffered_read.c
+++ b/fs/netfs/buffered_read.c
@@ -101,8 +101,10 @@ static ssize_t netfs_prepare_read_iterator(struct netfs_io_subrequest *subreq)
added = rolling_buffer_load_from_ra(&rreq->buffer, rreq->ractl,
&put_batch);
- if (added < 0)
+ if (added < 0) {
+ folio_batch_release(&put_batch);
return added;
+ }
rreq->submitted += added;
}
folio_batch_release(&put_batch);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 846/869] netfs: Fix folio state after ENOMEM whilst under writeback iteration
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (844 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 845/869] netfs: release readahead folios on iterator preparation failure Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 847/869] net: do not acquire dev->tx_global_lock in netdev_watchdog_up() Greg Kroah-Hartman
` (23 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Paulo Alcantara,
Matthew Wilcox, netfs, linux-fsdevel,
Christian Brauner (Amutable), Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
[ Upstream commit b6a713fd34b9498ee2164d5d3e8460732a392efc ]
Fix the state of the current folio when ENOMEM occurs during writeback
iteration. The folio needs to be redirtied and unlocked before the
terminal writeback_iter() is invoked.
Fixes: 06fa229ceb36 ("netfs: Abstract out a rolling folio buffer implementation")
Link: https://sashiko.dev/#/patchset/20260619140646.2633762-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260625140640.3116900-15-dhowells@redhat.com
cc: Paulo Alcantara <pc@manguebit.org>
cc: Matthew Wilcox <willy@infradead.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/netfs/write_issue.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c
index 4242cfc683d7c..b115f5285f434 100644
--- a/fs/netfs/write_issue.c
+++ b/fs/netfs/write_issue.c
@@ -582,6 +582,10 @@ int netfs_writepages(struct address_space *mapping,
}
error = netfs_write_folio(wreq, wbc, folio);
+ if (error == -ENOMEM) {
+ folio_redirty_for_writepage(wbc, folio);
+ folio_unlock(folio);
+ }
} while ((folio = writeback_iter(mapping, wbc, folio, &error)));
netfs_end_issue_write(wreq);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 847/869] net: do not acquire dev->tx_global_lock in netdev_watchdog_up()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (845 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 846/869] netfs: Fix folio state after ENOMEM whilst under writeback iteration Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 848/869] s390/zcrypt: Fix memory leak with CCA cards used as accelerator Greg Kroah-Hartman
` (22 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Marek Szyprowski, Eric Dumazet,
Simon Horman, Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit d09a78a2a469e4fab75108325efb813c49520809 ]
Marek Szyprowski reported a deadlock during system resume when virtio_net
driver is used.
The deadlock occurs because netif_device_attach() is called while holding
dev->tx_global_lock (via netif_tx_lock_bh() in virtnet_restore_up()).
netif_device_attach() calls __netdev_watchdog_up(), which now also tries
to acquire dev->tx_global_lock to synchronize with dev_watchdog().
This recursive lock acquisition results in a deadlock.
Fix this by removing the tx_global_lock acquisition from netdev_watchdog_up().
The critical state (watchdog_timer and watchdog_ref_held) is already
protected by dev->watchdog_lock, which was introduced in the blamed commit.
Fixes: 8eed5519e496 ("net: watchdog: fix refcount tracking races")
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Closes: https://lore.kernel.org/netdev/a443376e-5187-4268-93b3-58047ef113a8@samsung.com/
Signed-off-by: Eric Dumazet <edumazet@google.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260622110108.69541-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sched/sch_generic.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 7ec650ff9daae..681e0ab6019fb 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -568,9 +568,8 @@ void __netdev_watchdog_up(struct net_device *dev)
return;
if (dev->watchdog_timeo <= 0)
dev->watchdog_timeo = 5*HZ;
- spin_lock_bh(&dev->tx_global_lock);
- spin_lock(&dev->watchdog_lock);
+ spin_lock_bh(&dev->watchdog_lock);
if (!mod_timer(&dev->watchdog_timer,
round_jiffies(jiffies + dev->watchdog_timeo))) {
if (!dev->watchdog_ref_held) {
@@ -579,9 +578,7 @@ void __netdev_watchdog_up(struct net_device *dev)
dev->watchdog_ref_held = true;
}
}
- spin_unlock(&dev->watchdog_lock);
-
- spin_unlock_bh(&dev->tx_global_lock);
+ spin_unlock_bh(&dev->watchdog_lock);
}
EXPORT_SYMBOL_GPL(__netdev_watchdog_up);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 848/869] s390/zcrypt: Fix memory leak with CCA cards used as accelerator
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (846 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 847/869] net: do not acquire dev->tx_global_lock in netdev_watchdog_up() Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 849/869] EDAC/igen6: Fix the flood of invalid error reports Greg Kroah-Hartman
` (21 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Yi Zhang, Nadja Hariz, Ingo Franzki,
Holger Dengler, Heiko Carstens, Harald Freudenberger,
Vasily Gorbik, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harald Freudenberger <freude@linux.ibm.com>
[ Upstream commit c8d46f17c2fc7d25c18e60c008928aecab26184d ]
Tests showed that there is a memory leak if CCA cards are used as
accelerator for clear key RSA requests (ME and CRT). With the last
rework for the memory allocation the AP messages are allocated by
ap_init_apmsg() but for some reason on two places (ME and CRT) the
older allocation was still in place. So the first allocation simple
was never freed.
Fixes: 57db62a130ce ("s390/ap/zcrypt: Rework AP message buffer allocation")
Reported-by: Yi Zhang <yi.zhang@redhat.com>
Closes: https://lore.kernel.org/linux-s390/CAHj4cs9H67Uz0iVaRQv447p7JFPRPy3TKAT4=Y6_e=wSHCZM5w@mail.gmail.com/
Reported-by: Nadja Hariz <Nadia.Hariz@ibm.com>
Cc: stable@vger.kernel.org
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Acked-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/s390/crypto/zcrypt_msgtype6.c | 32 ++++++++++++---------------
1 file changed, 14 insertions(+), 18 deletions(-)
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index 352d5c15f7dcc..2578384705592 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -956,6 +956,10 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0);
/*
* The request distributor calls this function if it picked the CEXxC
* device to handle a modexpo request.
+ * This function assumes that ap_msg has been initialized with
+ * ap_init_apmsg() and thus a valid buffer with the size of
+ * ap_msg->bufsize is available within ap_msg. Also the caller has
+ * to make sure ap_release_apmsg() is always called even on failure.
* @zq: pointer to zcrypt_queue structure that identifies the
* CEXxC device to the request distributor
* @mex: pointer to the modexpo request buffer
@@ -967,21 +971,17 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
struct ap_response_type *resp_type = &ap_msg->response;
int rc;
- ap_msg->msg = (void *)get_zeroed_page(GFP_KERNEL);
- if (!ap_msg->msg)
- return -ENOMEM;
- ap_msg->bufsize = PAGE_SIZE;
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
rc = icamex_msg_to_type6mex_msgx(zq, ap_msg, mex);
if (rc)
- goto out_free;
+ goto out;
resp_type->type = CEXXC_RESPONSE_TYPE_ICA;
init_completion(&resp_type->work);
rc = ap_queue_message(zq->queue, ap_msg);
if (rc)
- goto out_free;
+ goto out;
rc = wait_for_completion_interruptible(&resp_type->work);
if (rc == 0) {
rc = ap_msg->rc;
@@ -994,15 +994,17 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
ap_cancel_message(zq->queue, ap_msg);
}
-out_free:
- free_page((unsigned long)ap_msg->msg);
- ap_msg->msg = NULL;
+out:
return rc;
}
/*
* The request distributor calls this function if it picked the CEXxC
* device to handle a modexpo_crt request.
+ * This function assumes that ap_msg has been initialized with
+ * ap_init_apmsg() and thus a valid buffer with the size of
+ * ap_msg->bufsize is available within ap_msg. Also the caller has
+ * to make sure ap_release_apmsg() is always called even on failure.
* @zq: pointer to zcrypt_queue structure that identifies the
* CEXxC device to the request distributor
* @crt: pointer to the modexpoc_crt request buffer
@@ -1014,21 +1016,17 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
struct ap_response_type *resp_type = &ap_msg->response;
int rc;
- ap_msg->msg = (void *)get_zeroed_page(GFP_KERNEL);
- if (!ap_msg->msg)
- return -ENOMEM;
- ap_msg->bufsize = PAGE_SIZE;
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
rc = icacrt_msg_to_type6crt_msgx(zq, ap_msg, crt);
if (rc)
- goto out_free;
+ goto out;
resp_type->type = CEXXC_RESPONSE_TYPE_ICA;
init_completion(&resp_type->work);
rc = ap_queue_message(zq->queue, ap_msg);
if (rc)
- goto out_free;
+ goto out;
rc = wait_for_completion_interruptible(&resp_type->work);
if (rc == 0) {
rc = ap_msg->rc;
@@ -1041,9 +1039,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
ap_cancel_message(zq->queue, ap_msg);
}
-out_free:
- free_page((unsigned long)ap_msg->msg);
- ap_msg->msg = NULL;
+out:
return rc;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 849/869] EDAC/igen6: Fix the flood of invalid error reports
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (847 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 848/869] s390/zcrypt: Fix memory leak with CCA cards used as accelerator Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 850/869] netfilter: ctnetlink: do not expose expectation DEAD flag Greg Kroah-Hartman
` (20 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ramses, John, Qiuxu Zhuo, Tony Luck,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
[ Upstream commit 267e5b1d267539d9a927dc04aab6f15aca57da92 ]
The ECC_ERROR_LOG register of certain SoCs may contain the invalid value
~0, which results in a flood of invalid error reports in polling mode.
Fix the flood of invalid error reports by skipping the invalid ECC error
log value ~0.
Fixes: e14232afa944 ("EDAC/igen6: Add polling support")
Reported-by: Ramses <ramses@well-founded.dev>
Closes: https://lore.kernel.org/all/OISL8Rv--F-9@well-founded.dev/
Tested-by: Ramses <ramses@well-founded.dev>
Reported-by: John <therealgraysky@proton.me>
Closes: https://lore.kernel.org/all/p5YcxOE6M3Ncxpn2-Ia_wCt61EM4LwIiN3LroQvT_-G2jMrFDSOW5k2A9D8UUzD2toGpQBN1eI0sL5dSKnkO8iteZegLoQEj-DwQaMhGx4A=@proton.me/
Tested-by: John <therealgraysky@proton.me>
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Link: https://lore.kernel.org/r/20250212083354.31919-1-qiuxu.zhuo@intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/edac/igen6_edac.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c
index 3a28b3d6242da..0cf7f8bde6cac 100644
--- a/drivers/edac/igen6_edac.c
+++ b/drivers/edac/igen6_edac.c
@@ -785,13 +785,22 @@ static u64 ecclog_read_and_clear(struct igen6_imc *imc)
{
u64 ecclog = readq(imc->window + ECC_ERROR_LOG_OFFSET);
- if (ecclog & (ECC_ERROR_LOG_CE | ECC_ERROR_LOG_UE)) {
- /* Clear CE/UE bits by writing 1s */
- writeq(ecclog, imc->window + ECC_ERROR_LOG_OFFSET);
- return ecclog;
- }
+ /*
+ * Quirk: The ECC_ERROR_LOG register of certain SoCs may contain
+ * the invalid value ~0. This will result in a flood of invalid
+ * error reports in polling mode. Skip it.
+ */
+ if (ecclog == ~0)
+ return 0;
- return 0;
+ /* Neither a CE nor a UE. Skip it.*/
+ if (!(ecclog & (ECC_ERROR_LOG_CE | ECC_ERROR_LOG_UE)))
+ return 0;
+
+ /* Clear CE/UE bits by writing 1s */
+ writeq(ecclog, imc->window + ECC_ERROR_LOG_OFFSET);
+
+ return ecclog;
}
static void errsts_clear(struct igen6_imc *imc)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 850/869] netfilter: ctnetlink: do not expose expectation DEAD flag
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (848 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 849/869] EDAC/igen6: Fix the flood of invalid error reports Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 851/869] EDAC/igen6: Fix NULL pointer dereference Greg Kroah-Hartman
` (19 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Pablo Neira Ayuso, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <pablo@netfilter.org>
[ Upstream commit 322371b09058ad10d0282a0e7ec8eaa764e6aaac ]
Expose expectation flags included in the NF_CT_EXPECT_MASK bitmask
only. The DEAD flag is internal, do not expose it.
Fixes: b8b09dc2bf35 ("netfilter: nf_conntrack_expect: use conntrack GC to reap expectations")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/netfilter/nf_conntrack_netlink.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 1c2bb4ee84ac2..60a4fb4088963 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -3045,7 +3045,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
#endif
if (nla_put_be32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)) ||
nla_put_be32(skb, CTA_EXPECT_ID, nf_expect_get_id(exp)) ||
- nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
+ nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags & NF_CT_EXPECT_MASK)) ||
nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
goto nla_put_failure;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 851/869] EDAC/igen6: Fix NULL pointer dereference
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (849 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 850/869] netfilter: ctnetlink: do not expose expectation DEAD flag Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 852/869] Revert "esp: do not unref managed frag pages in esp_ssg_unref()" Greg Kroah-Hartman
` (18 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Marek Marczykowski-Górecki,
Borislav Petkov, Qiuxu Zhuo, Tony Luck, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
[ Upstream commit 88efa0de3285be66969b71ec137d9dab1ee19e52 ]
A kernel panic was reported with the following kernel log:
EDAC igen6: Expected 2 mcs, but only 1 detected.
BUG: unable to handle page fault for address: 000000000000d570
...
Hardware name: Notebook V54x_6x_TU/V54x_6x_TU, BIOS Dasharo (coreboot+UEFI) v0.9.0 07/17/2024
RIP: e030:ecclog_handler+0x7e/0xf0 [igen6_edac]
...
igen6_probe+0x2a0/0x343 [igen6_edac]
...
igen6_init+0xc5/0xff0 [igen6_edac]
...
This issue occurred because one memory controller was disabled by
the BIOS but the igen6_edac driver still checked all the memory
controllers, including this absent one, to identify the source of
the error. Accessing the null MMIO for the absent memory controller
resulted in the oops above.
Fix this issue by reverting the configuration structure to non-const
and updating the field 'res_cfg->num_imc' to reflect the number of
detected memory controllers.
Fixes: 20e190b1c1fd ("EDAC/igen6: Skip absent memory controllers")
Reported-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Closes: https://lore.kernel.org/all/aFFN7RlXkaK_loQb@mail-itl/
Suggested-by: Borislav Petkov <bp@alien8.de>
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Tested-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Link: https://lore.kernel.org/r/20250618162307.1523736-1-qiuxu.zhuo@intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/edac/igen6_edac.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c
index 0cf7f8bde6cac..28a6f9e667218 100644
--- a/drivers/edac/igen6_edac.c
+++ b/drivers/edac/igen6_edac.c
@@ -558,7 +558,7 @@ static struct res_config mtl_p_cfg = {
.err_addr_to_imc_addr = adl_err_addr_to_imc_addr,
};
-static const struct pci_device_id igen6_pci_tbl[] = {
+static struct pci_device_id igen6_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, DID_EHL_SKU5), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU6), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU7), (kernel_ulong_t)&ehl_cfg },
@@ -1347,9 +1347,11 @@ static int igen6_register_mcis(struct pci_dev *pdev, u64 mchbar)
return -ENODEV;
}
- if (lmc < res_cfg->num_imc)
+ if (lmc < res_cfg->num_imc) {
igen6_printk(KERN_WARNING, "Expected %d mcs, but only %d detected.",
res_cfg->num_imc, lmc);
+ res_cfg->num_imc = lmc;
+ }
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 852/869] Revert "esp: do not unref managed frag pages in esp_ssg_unref()"
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (850 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 851/869] EDAC/igen6: Fix NULL pointer dereference Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 853/869] mm/hugetlb_vmemmap: fix incorrect vmemmap restore in rollback Greg Kroah-Hartman
` (17 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Steffen Klassert, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steffen Klassert <steffen.klassert@secunet.com>
[ Upstream commit 0fda52de8bbd4ca9a852c8a7ef6536cf82bd71fd ]
This reverts commit 21697720ff43b8dfa25b8e8d9ca7f56f4597fc80.
The patch does not fix the issue completely, so revert for
now and wait for an updated version.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv4/esp4.c | 7 -------
net/ipv6/esp6.c | 7 -------
2 files changed, 14 deletions(-)
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 8944f812e4b55..fb78dc6b7e148 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -104,13 +104,6 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb)
struct aead_request *req;
struct scatterlist *sg;
- /* Managed frags are owned by the zerocopy ubuf; the skb holds no
- * per-frag page reference, so we must not drop one here. Mirrors
- * the SKBFL_MANAGED_FRAG_REFS handling in skb_release_data().
- */
- if (skb_zcopy_managed(skb))
- return;
-
if (x->props.flags & XFRM_STATE_ESN)
extralen += sizeof(struct esp_output_extra);
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 3061e74799170..7411aac0707b2 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -121,13 +121,6 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb)
struct aead_request *req;
struct scatterlist *sg;
- /* Managed frags are owned by the zerocopy ubuf; the skb holds no
- * per-frag page reference, so we must not drop one here. Mirrors
- * the SKBFL_MANAGED_FRAG_REFS handling in skb_release_data().
- */
- if (skb_zcopy_managed(skb))
- return;
-
if (x->props.flags & XFRM_STATE_ESN)
extralen += sizeof(struct esp_output_extra);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 853/869] mm/hugetlb_vmemmap: fix incorrect vmemmap restore in rollback
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (851 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 852/869] Revert "esp: do not unref managed frag pages in esp_ssg_unref()" Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 854/869] PM: sleep: Unblock runtime PM when device prepare fails Greg Kroah-Hartman
` (16 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Muchun Song, Kiryl Shutsemau,
Oscar Salvador (SUSE), David Hildenbrand, Andrew Morton,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muchun Song <songmuchun@bytedance.com>
[ Upstream commit c7bde43f6daf70e05a64fbca7efdf6fa93e057dc ]
vmemmap_restore_pte() rebuilds restored vmemmap pages from a tail-page
template derived from compound_head(). This is wrong when the current PTE
already maps a page whose contents are not tail-page metadata.
In the rollback path of vmemmap_remap_free(), the first restored PTE is
backed by vmemmap_head and contains head-page metadata. Reconstructing
that page from a tail-page template overwrites the head-page state and
corrupts the restored vmemmap page.
Fix this by copying the full page from the page currently mapped by the
PTE. Also pass vmemmap_tail to the rollback walk so only PTEs backed by
the shared tail page are restored, while the head PTE remains mapped to
vmemmap_head. Add VM_WARN_ON_ONCE() checks for unexpected cases.
Link: https://lore.kernel.org/20260525025213.2229628-1-songmuchun@bytedance.com
Fixes: c0b495b91a47 ("mm/hugetlb: refactor code around vmemmap_walk")
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
Acked-by: Kiryl Shutsemau <kas@kernel.org>
Acked-by: Oscar Salvador (SUSE) <osalvador@kernel.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
mm/hugetlb_vmemmap.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c
index 1394c13c1516f..52e68a7df2c88 100644
--- a/mm/hugetlb_vmemmap.c
+++ b/mm/hugetlb_vmemmap.c
@@ -207,6 +207,8 @@ static void vmemmap_remap_pte(pte_t *pte, unsigned long addr,
/* Remapping the head page requires r/w */
if (unlikely(walk->nr_walked == 0 && walk->vmemmap_head)) {
+ VM_WARN_ON_ONCE(!PageHead((const struct page *)addr));
+
list_del(&walk->vmemmap_head->lru);
/*
@@ -218,6 +220,8 @@ static void vmemmap_remap_pte(pte_t *pte, unsigned long addr,
entry = mk_pte(walk->vmemmap_head, PAGE_KERNEL);
} else {
+ VM_WARN_ON_ONCE(!PageTail((const struct page *)addr));
+
/*
* Remap the tail pages as read-only to catch illegal write
* operation to the tail pages.
@@ -232,33 +236,28 @@ static void vmemmap_remap_pte(pte_t *pte, unsigned long addr,
static void vmemmap_restore_pte(pte_t *pte, unsigned long addr,
struct vmemmap_remap_walk *walk)
{
- struct page *page;
- struct page *from, *to;
-
- page = list_first_entry(walk->vmemmap_pages, struct page, lru);
- list_del(&page->lru);
+ struct page *src = pte_page(ptep_get(pte)), *dst;
/*
- * Initialize tail pages in the newly allocated vmemmap page.
- *
- * There is folio-scope metadata that is encoded in the first few
- * tail pages.
- *
- * Use the value last tail page in the page with the head page
- * to initialize the rest of tail pages.
+ * When rolling back vmemmap_remap_free(), keep the copied head page
+ * mapping and restore only PTEs currently pointing at the shared tail
+ * page.
*/
- from = compound_head((struct page *)addr) +
- PAGE_SIZE / sizeof(struct page) - 1;
- to = page_to_virt(page);
- for (int i = 0; i < PAGE_SIZE / sizeof(struct page); i++, to++)
- *to = *from;
+ if (walk->vmemmap_tail && walk->vmemmap_tail != src)
+ return;
+
+ VM_WARN_ON_ONCE(PageHead((const struct page *)addr));
+
+ dst = list_first_entry(walk->vmemmap_pages, struct page, lru);
+ list_del(&dst->lru);
+ copy_page(page_to_virt(dst), page_to_virt(src));
/*
* Makes sure that preceding stores to the page contents become visible
* before the set_pte_at() write.
*/
smp_wmb();
- set_pte_at(&init_mm, addr, pte, mk_pte(page, PAGE_KERNEL));
+ set_pte_at(&init_mm, addr, pte, mk_pte(dst, PAGE_KERNEL));
}
/**
@@ -324,6 +323,7 @@ static int vmemmap_remap_free(unsigned long start, unsigned long end,
*/
walk = (struct vmemmap_remap_walk) {
.remap_pte = vmemmap_restore_pte,
+ .vmemmap_tail = vmemmap_tail,
.vmemmap_pages = vmemmap_pages,
.flags = 0,
};
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 854/869] PM: sleep: Unblock runtime PM when device prepare fails
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (852 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 853/869] mm/hugetlb_vmemmap: fix incorrect vmemmap restore in rollback Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 855/869] soundwire: intel_auxdevice: Fix system suspend/resume handling Greg Kroah-Hartman
` (15 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Shibo Zhu, Rafael J. Wysocki,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shibo Zhu <3499129952@qq.com>
[ Upstream commit cb258d651d747a7f7063d40f145418bee562ceaf ]
device_prepare() blocks runtime PM for a device with runtime PM disabled
before invoking its system-sleep ->prepare() callback. For a device that
has never enabled runtime PM, this changes dev->power.last_status from
RPM_INVALID to RPM_BLOCKED.
If the callback returns an error, dpm_prepare() does not move the device
to dpm_prepared_list. Consequently, the recovery path through
dpm_complete() never calls device_complete() for the failing device.
The error path drops the runtime PM usage reference, but does not clear
RPM_BLOCKED. A later legitimate pm_runtime_enable() then reports:
Attempt to enable runtime PM when it is blocked
before clearing the stale state.
Call pm_runtime_unblock() on the prepare error path before dropping the
runtime PM reference, matching the cleanup performed by device_complete().
The issue was reproduced with a platform test device whose ->prepare()
callback returns -EIO while runtime PM has never been enabled. Before
the fix, last_status remained RPM_BLOCKED after the failed suspend and
the first pm_runtime_enable() produced the warning above. With the fix,
last_status is restored to RPM_INVALID and the warning is absent.
Fixes: 3e5eee147b7b ("PM: Block enabling of runtime PM during system suspend")
Cc: All applicable <stable@vger.kernel.org>
Signed-off-by: Shibo Zhu <3499129952@qq.com>
Link: https://patch.msgid.link/tencent_C5AC0A02FC01F700E764F8C2E3ECE4F41009@qq.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/base/power/main.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index fab8df1e29e62..ab240ccf7fd41 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1888,6 +1888,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
if (ret < 0) {
suspend_report_result(dev, callback, ret);
+ pm_runtime_unblock(dev);
pm_runtime_put(dev);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 855/869] soundwire: intel_auxdevice: Fix system suspend/resume handling
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (853 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 854/869] PM: sleep: Unblock runtime PM when device prepare fails Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 856/869] gpiolib: Allow to use setters with return value for output-only gpios Greg Kroah-Hartman
` (14 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bard Liao, Rafael J. Wysocki,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
[ Upstream commit 533a8a67cc3b072a24122d1ea10a8db66a5c9393 ]
Before commit bca84a7b93fd ("PM: sleep: Use DPM_FLAG_SMART_SUSPEND
conditionally") the runtime PM status of the device in intel_resume()
had always been RPM_ACTIVE because setting DPM_FLAG_SMART_SUSPEND had
caused the core to call pm_runtime_set_active() for that device during
the "noirq" resume phase. For this reason, the pm_runtime_suspended()
check in intel_resume() had never triggered and the code depending on
it had never run. That had not caused any observable functional issues
to appear, so effectively the code in question had never been needed.
After commit bca84a7b93fd the core does not call pm_runtime_set_active()
for all devices with DPM_FLAG_SMART_SUSPEND set any more and the code
depending on the pm_runtime_suspended() check in intel_resume() runs if
the device is runtime-suspended prior to a system-wide suspend
transition. Unfortunately, when it runs, it breaks things due to the
attempt to runtime-resume bus->dev which most likely is not ready for a
runtime resume at that point.
It also does other more-or-less questionable things. Namely, it
calls pm_runtime_idle() for a device with a nonzero runtime PM usage
counter which has no effect (all devices have nonzero runtime PM
usage counters during system-wide suspend and resume). It also calls
pm_runtime_mark_last_busy() for the device even though devices cannot
runtime-suspend during system-wide suspend and resume (because their
runtime PM usage counters are nonzero) and an analogous call is made
in the same function later. Moreover, it sets the runtime PM status
of the device to RPM_ACTIVE before activating it.
For the reasons listed above, remove that code altogether.
On top of that, add a pm_runtime_disable() call to intel_suspend() to
prevent the device from being runtime-resumed at any point after
intel_suspend() has started to manipulate it because the changes
made by that function would be undone by a runtime-suspend of the
device.
Next, once runtime PM has been disabled, the runtime PM status of the
device cannot change, so pm_runtime_status_suspended() can be used
instead of pm_runtime_suspended() in intel_suspend().
Finally, make intel_resume() call pm_runtime_set_active() at the end to
set the runtime PM status of the device to "active" because it has just
been activated and re-enable runtime PM for it after that.
Additionally, drop the setting of DPM_FLAG_SMART_SUSPEND from the
driver because it has no effect on devices handled by it.
Fixes: bca84a7b93fd ("PM: sleep: Use DPM_FLAG_SMART_SUSPEND conditionally")
Reported-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Tested-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Link: https://patch.msgid.link/12680420.O9o76ZdvQC@rjwysocki.net
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/soundwire/intel_auxdevice.c | 36 +++++++++++------------------
1 file changed, 13 insertions(+), 23 deletions(-)
diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c
index 078f9eaf5161b..ae1dfce163e25 100644
--- a/drivers/soundwire/intel_auxdevice.c
+++ b/drivers/soundwire/intel_auxdevice.c
@@ -345,9 +345,6 @@ static int intel_link_probe(struct auxiliary_device *auxdev,
/* use generic bandwidth allocation algorithm */
sdw->cdns.bus.compute_params = sdw_compute_params;
- /* avoid resuming from pm_runtime suspend if it's not required */
- dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND);
-
ret = sdw_bus_master_add(bus, dev, dev->fwnode);
if (ret) {
dev_err(dev, "sdw_bus_master_add fail: %d\n", ret);
@@ -632,7 +629,10 @@ static int __maybe_unused intel_suspend(struct device *dev)
return 0;
}
- if (pm_runtime_suspended(dev)) {
+ /* Prevent runtime PM from racing with the code below. */
+ pm_runtime_disable(dev);
+
+ if (pm_runtime_status_suspended(dev)) {
dev_dbg(dev, "pm_runtime status: suspended\n");
clock_stop_quirks = sdw->link_res->clock_stop_quirks;
@@ -640,7 +640,7 @@ static int __maybe_unused intel_suspend(struct device *dev)
if ((clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) ||
!clock_stop_quirks) {
- if (pm_runtime_suspended(dev->parent)) {
+ if (pm_runtime_status_suspended(dev->parent)) {
/*
* paranoia check: this should not happen with the .prepare
* resume to full power
@@ -707,7 +707,6 @@ static int __maybe_unused intel_resume(struct device *dev)
struct sdw_cdns *cdns = dev_get_drvdata(dev);
struct sdw_intel *sdw = cdns_to_intel(cdns);
struct sdw_bus *bus = &cdns->bus;
- int link_flags;
int ret;
if (bus->prop.hw_disabled || !sdw->startup_done) {
@@ -716,23 +715,6 @@ static int __maybe_unused intel_resume(struct device *dev)
return 0;
}
- if (pm_runtime_suspended(dev)) {
- dev_dbg(dev, "pm_runtime status was suspended, forcing active\n");
-
- /* follow required sequence from runtime_pm.rst */
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_enable(dev);
-
- pm_runtime_resume(bus->dev);
-
- link_flags = md_flags >> (bus->link_id * 8);
-
- if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE))
- pm_runtime_idle(dev);
- }
-
ret = sdw_intel_link_power_up(sdw);
if (ret) {
dev_err(dev, "%s failed: %d\n", __func__, ret);
@@ -752,6 +734,14 @@ static int __maybe_unused intel_resume(struct device *dev)
return ret;
}
+ /*
+ * Runtime PM has been disabled in intel_suspend(), so set the status
+ * to active because the device has just been resumed and re-enable
+ * runtime PM.
+ */
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
/*
* after system resume, the pm_runtime suspend() may kick in
* during the enumeration, before any children device force the
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 856/869] gpiolib: Allow to use setters with return value for output-only gpios
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (854 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 855/869] soundwire: intel_auxdevice: Fix system suspend/resume handling Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 857/869] gpiolib: initialize return value in gpiochip_set_multiple() Greg Kroah-Hartman
` (13 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Mathieu Dubois-Briand,
Bartosz Golaszewski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
[ Upstream commit b424bb88afb6719b30340f059bf50953424cdd9d ]
The gpiod_direction_output_raw_commit() function checks if any setter
callback is present before doing anything. As the new GPIO setters with
return values were introduced, make this check also succeed if one is
present.
Fixes: 98ce1eb1fd87 ("gpiolib: introduce gpio_chip setters that return values")
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
Link: https://lore.kernel.org/r/20250411-mdb-gpiolib-setters-fix-v2-1-9611280d8822@bootlin.com
Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpio/gpiolib.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5f73f0c29cf6a..1e012d5a575e5 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2761,7 +2761,7 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
* output-only, but if there is then not even a .set() operation it
* is pretty tricky to drive the output line.
*/
- if (!guard.gc->set && !guard.gc->direction_output) {
+ if (!guard.gc->set && !guard.gc->set_rv && !guard.gc->direction_output) {
gpiod_warn(desc,
"%s: missing set() and direction_output() operations\n",
__func__);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 857/869] gpiolib: initialize return value in gpiochip_set_multiple()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (855 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 856/869] gpiolib: Allow to use setters with return value for output-only gpios Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 858/869] i3c: master: svc: Fix missed IBI after false SLVSTART on NPCM845 Greg Kroah-Hartman
` (12 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ruoyu Wang, Uwe Kleine-König,
Bartosz Golaszewski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <ruoyuw560@gmail.com>
[ Upstream commit 99dfa46baba29513d1094c8f30bc86c6ef88543a ]
gpiochip_set_multiple() falls back to setting lines one by one when the
chip does not provide set_multiple(). If the fallback path receives an
empty mask, the loop is skipped and ret is returned without being
initialized.
Initialize ret to 0 so an empty mask is treated as a successful no-op.
Fixes: 9b407312755f ("gpiolib: rework the wrapper around gpio_chip::set_multiple()")
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
Acked-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Link: https://patch.msgid.link/20260620155319.79994-1-ruoyuw560@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/gpio/gpiolib.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 1e012d5a575e5..144f1e174c545 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -3437,7 +3437,7 @@ static int gpiochip_set_multiple(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits)
{
unsigned int i;
- int ret;
+ int ret = 0;
lockdep_assert_held(&gc->gpiodev->srcu);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 858/869] i3c: master: svc: Fix missed IBI after false SLVSTART on NPCM845
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (856 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 857/869] gpiolib: initialize return value in gpiochip_set_multiple() Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 859/869] i3c: master: svc: Fix npcm845 FIFO_EMPTY quirk Greg Kroah-Hartman
` (11 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Stanley Chu, Frank Li,
Alexandre Belloni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanley Chu <yschu@nuvoton.com>
[ Upstream commit fa1d4fa118f4229168e9ca88cea260c5e5a94652 ]
The NPCM845 I3C controller may raise a false SLVSTART interrupt. The
handler first latches MSTATUS and then clears SLVSTART. If a real IBI
request arrives after the handler latches MSTATUS but before it clears
the SLVSTART interrupt status, HW sets the SLVREQ state. However, the
handler still relies on the stale MSTATUS snapshot, returns early, and
misses the real IBI. No further interrupt is generated for this pending
IBI.
Re-read MSTATUS to obtain the latest state and avoid missing a real IBI
due to this race condition.
Fixes: 4dd12e944f07 ("i3c: master: svc: Fix npcm845 invalid slvstart event")
Signed-off-by: Stanley Chu <yschu@nuvoton.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260413005040.1211107-2-yschu@nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/i3c/master/svc-i3c-master.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 1948d398ce503..25cdb77973c09 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -600,10 +600,18 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
/* Clear the interrupt status */
writel(SVC_I3C_MINT_SLVSTART, master->regs + SVC_I3C_MSTATUS);
- /* Ignore the false event */
- if (svc_has_quirk(master, SVC_I3C_QUIRK_FALSE_SLVSTART) &&
- !SVC_I3C_MSTATUS_STATE_SLVREQ(active))
- return IRQ_HANDLED;
+ if (svc_has_quirk(master, SVC_I3C_QUIRK_FALSE_SLVSTART)) {
+ /*
+ * Re-read MSTATUS to obtain the latest state and avoid
+ * missing an IBI that arrives after MSTATUS is latched
+ * but before SLVSTART is cleared.
+ */
+ active = readl(master->regs + SVC_I3C_MSTATUS);
+
+ /* Ignore the false event */
+ if (!SVC_I3C_MSTATUS_STATE_SLVREQ(active))
+ return IRQ_HANDLED;
+ }
svc_i3c_master_disable_interrupts(master);
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 859/869] i3c: master: svc: Fix npcm845 FIFO_EMPTY quirk
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (857 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 858/869] i3c: master: svc: Fix missed IBI after false SLVSTART on NPCM845 Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 860/869] i3c: master: svc: Fix i3c_master_get_free_addr return check Greg Kroah-Hartman
` (10 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Stanley Chu, Alexandre Belloni,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanley Chu <yschu@nuvoton.com>
[ Upstream commit bc4a09d8e79cadccdd505f47b01903a80bc666e7 ]
In a private write transfer, the driver pre-fills the FIFO to work around
the FIFO_EMPTY quirk. However, if an IBIWON event occurs, the hardware
emits a NACK and the driver initiates a retry. During the retry, driver
attempts to pre-fill the FIFO again if there is remaining data, but since
the FIFO is already full, this leads to data loss.
Check available space in FIFO to prevent overflow.
Fixes: 4008a74e0f9b ("i3c: master: svc: Fix npcm845 FIFO empty issue")
Signed-off-by: Stanley Chu <yschu@nuvoton.com>
Link: https://lore.kernel.org/r/20250730003719.1825593-1-yschu@nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/i3c/master/svc-i3c-master.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 25cdb77973c09..26e53717b8292 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -103,6 +103,7 @@
#define SVC_I3C_MDATACTRL_TXTRIG_FIFO_NOT_FULL GENMASK(5, 4)
#define SVC_I3C_MDATACTRL_RXTRIG_FIFO_NOT_EMPTY 0
#define SVC_I3C_MDATACTRL_RXCOUNT(x) FIELD_GET(GENMASK(28, 24), (x))
+#define SVC_I3C_MDATACTRL_TXCOUNT(x) FIELD_GET(GENMASK(20, 16), (x))
#define SVC_I3C_MDATACTRL_TXFULL BIT(30)
#define SVC_I3C_MDATACTRL_RXEMPTY BIT(31)
@@ -1285,14 +1286,19 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
* FIFO start filling as soon as possible after EmitStartAddr.
*/
if (svc_has_quirk(master, SVC_I3C_QUIRK_FIFO_EMPTY) && !rnw && xfer_len) {
- u32 end = xfer_len > SVC_I3C_FIFO_SIZE ? 0 : SVC_I3C_MWDATAB_END;
- u32 len = min_t(u32, xfer_len, SVC_I3C_FIFO_SIZE);
-
- writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1);
- /* Mark END bit if this is the last byte */
- writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB);
- xfer_len -= len;
- out += len;
+ u32 space, end, len;
+
+ reg = readl(master->regs + SVC_I3C_MDATACTRL);
+ space = SVC_I3C_FIFO_SIZE - SVC_I3C_MDATACTRL_TXCOUNT(reg);
+ if (space) {
+ end = xfer_len > space ? 0 : SVC_I3C_MWDATAB_END;
+ len = min_t(u32, xfer_len, space);
+ writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1);
+ /* Mark END bit if this is the last byte */
+ writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB);
+ xfer_len -= len;
+ out += len;
+ }
}
ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 860/869] i3c: master: svc: Fix i3c_master_get_free_addr return check
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (858 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 859/869] i3c: master: svc: Fix npcm845 FIFO_EMPTY quirk Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 861/869] tracing: Fix ring_buffer_read_page_size() kernel-doc Greg Kroah-Hartman
` (9 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dan Carpenter, Stanley Chu, Frank Li,
Alexandre Belloni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanley Chu <yschu@nuvoton.com>
[ Upstream commit d6cb667b8e15bac47f19aec4bd81f3916b2ca9f5 ]
The return value of i3c_master_get_free_addr is assigned to a variable
with wrong type, so it can't be negative. Use a signed integer for the
return value. If the value is negative, break the process and propagate
the error code.
This commit also fixes the uninitialized symbol 'dyn_addr', reported
by Smatch static checker.
Fixes: 4008a74e0f9b ("i3c: master: svc: Fix npcm845 FIFO empty issue")
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Closes: https://lore.kernel.org/all/029e5ac0-5444-4a8e-bca4-cec55950d2b9@stanley.mountain/
Signed-off-by: Stanley Chu <yschu@nuvoton.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://lore.kernel.org/r/20250310023304.2335792-1-yschu@nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/i3c/master/svc-i3c-master.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 26e53717b8292..705e7b9256f0c 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -938,7 +938,7 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master,
u8 *addrs, unsigned int *count)
{
u64 prov_id[SVC_I3C_MAX_DEVS] = {}, nacking_prov_id = 0;
- unsigned int dev_nb = 0, last_addr = 0, dyn_addr;
+ unsigned int dev_nb = 0, last_addr = 0, dyn_addr = 0;
u32 reg;
int ret, i;
@@ -993,10 +993,11 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master,
* filling within a few hundred nanoseconds, which is significantly
* faster compared to the 64 SCL clock cycles.
*/
- dyn_addr = i3c_master_get_free_addr(&master->base, last_addr + 1);
- if (dyn_addr < 0)
- return -ENOSPC;
+ ret = i3c_master_get_free_addr(&master->base, last_addr + 1);
+ if (ret < 0)
+ break;
+ dyn_addr = ret;
writel(dyn_addr, master->regs + SVC_I3C_MWDATAB);
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 861/869] tracing: Fix ring_buffer_read_page_size() kernel-doc
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (859 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 860/869] i3c: master: svc: Fix i3c_master_get_free_addr return check Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 862/869] tracing: Fix comment in tracing_buffers_splice_read() Greg Kroah-Hartman
` (8 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Karl Mehltretter, Vincent Donnefort,
Steven Rostedt, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <kmehltretter@gmail.com>
[ Upstream commit 7e645147dfba67edb3ed3090a1ed1d89df77fc27 ]
ring_buffer_read_page_size() takes a parameter named rpage, but its
kernel-doc describes page. As a result, kernel-doc reports rpage as
undescribed and page as an excess parameter description.
Rename the documentation entry to match the function.
Link: https://patch.msgid.link/20260909062917.89482-1-kmehltretter@gmail.com
Fixes: dae8dda341d2 ("tracing: Fix subbuf resize races with trace_pipe_raw readers")
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/trace/ring_buffer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index c89f4f8a33b0e..6e84f2f1eb201 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -6746,7 +6746,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_read_page_data);
/**
* ring_buffer_read_page_size - get size of the read page.
- * @page: the page to get the size from
+ * @rpage: the page to get the size from
*
* Returns size of the page in bytes.
*/
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 862/869] tracing: Fix comment in tracing_buffers_splice_read()
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (860 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 861/869] tracing: Fix ring_buffer_read_page_size() kernel-doc Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 863/869] dm-integrity: fix buffer overflow with keyed discard Greg Kroah-Hartman
` (7 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Steven Rostedt, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <rostedt@goodmis.org>
[ Upstream commit 5cbea500775dd1944995f23320af030b9b24b24b ]
The comment about returning an error if the read fails on the first
iteration is slightly incorrect. It makes it sound like the only reason it
could fail on a later iteration is if the subbuf order changed. That is
incorrect, it could also fail if the length passed in was not a multiple
of the subbuf size. Fix the comment.
Link: https://lore.kernel.org/all/20260904143527.40e73d36@gandalf.local.home/
Link: https://patch.msgid.link/20260904144902.506862a1@gandalf.local.home
Fixes: dae8dda341d2 ("tracing: Fix subbuf resize races with trace_pipe_raw readers")
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/trace/trace.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8af0fe8233433..115963797fab0 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -8107,11 +8107,13 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
r = ring_buffer_read_page(ref->buffer, ref->rpage, len, iter->cpu_file, 1);
} else if (!i) {
/*
- * We failed to read because the length is too small
- * or unaligned. If this is the first iteration, it's
- * an invalid userspace input. Otherwise, this is due
- * to a subbuf order change. Do not report an error
- * and just finish the read.
+ * If this fails to read on the first iteration, it
+ * means the length was too small and an error should
+ * be returned to user space. Otherwise, at least
+ * one sub-buffer was successfully read but this failed
+ * due to either the length was unaligned or the
+ * subbuf order changed. Either case, do not report
+ * an error.
*/
ret = -EINVAL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 863/869] dm-integrity: fix buffer overflow with keyed discard
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (861 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 862/869] tracing: Fix comment in tracing_buffers_splice_read() Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 864/869] types: move struct rcuwait into types.h Greg Kroah-Hartman
` (6 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jose Fernandez (Anthropic),
Ben Cressey, Mikulas Patocka, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ben Cressey <ben@cressey.dev>
[ Upstream commit 59e6f919d77d72ec79cbf171256f2f7819737580 ]
Since commit 68c5c42567bc ("dm-integrity: replace forgeable discard
filler with a keyed sector marker"), integrity_metadata computes a
checksum for every discarded block into the "checksums" buffer.
integrity_sector_checksum always writes the whole digest. So if the tag
size is smaller than the digest size, the checksum of the last block
that fits into the buffer is written past the end of it. For example,
with hmac(sha256) and tag size 16, a 4MiB discard writes 16 bytes past
the kmalloc'ed page.
Fix this by subtracting extra_space from the buffer size when computing
max_blocks, like we do for writes.
Fixes: 68c5c42567bc ("dm-integrity: replace forgeable discard filler with a keyed sector marker")
Reviewed-by: Jose Fernandez (Anthropic) <jose.fernandez@linux.dev>
Signed-off-by: Ben Cressey <ben@cressey.dev>
Assisted-by: Claude:unspecified
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/md/dm-integrity.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index 513c6d5fd74e1..b1313077de7ab 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -1857,7 +1857,7 @@ static void integrity_metadata(struct work_struct *w)
if (unlikely(dio->op == REQ_OP_DISCARD)) {
unsigned int bi_size = dio->bio_details.bi_iter.bi_size;
unsigned int max_size = likely(checksums != checksums_onstack) ? PAGE_SIZE : HASH_MAX_DIGESTSIZE;
- unsigned int max_blocks = max_size / ic->tag_size;
+ unsigned int max_blocks = (max_size - extra_space) / ic->tag_size;
sector_t sector = dio->range.logical_sector;
if (!ic->discard_keyed)
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 864/869] types: move struct rcuwait into types.h
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (862 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 863/869] dm-integrity: fix buffer overflow with keyed discard Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 865/869] irqwork: Move data struct to a types header Greg Kroah-Hartman
` (5 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Matthew Wilcox, Suren Baghdasaryan,
Davidlohr Bueso, Liam R. Howlett, Lorenzo Stoakes, Shivank Garg,
Christian Brauner, David Hildenbrand, David Howells, Hugh Dickins,
Jann Horn, Johannes Weiner, Jonathan Corbet, Klara Modin,
Lokesh Gidra, Mateusz Guzik, Mel Gorman, Michal Hocko,
Minchan Kim, Oleg Nesterov, Pasha Tatashin, Paul E . McKenney,
Peter Xu, Peter Zijlstra (Intel), Shakeel Butt, Sourav Panda,
Vlastimil Babka, Wei Yang, Will Deacon, Heiko Carstens,
Stephen Rothwell, Andrew Morton, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Suren Baghdasaryan <surenb@google.com>
[ Upstream commit 2c2bd11caba2a45445c1f0c722451fe29e59db79 ]
Move rcuwait struct definition into types.h so that rcuwait can be used
without including rcuwait.h which includes other headers. Without this
change mm_types.h can't use rcuwait due to a the following circular
dependency:
mm_types.h -> rcuwait.h -> signal.h -> mm_types.h
Link: https://lkml.kernel.org/r/20250213224655.1680278-7-surenb@google.com
Suggested-by: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Acked-by: Davidlohr Bueso <dave@stgolabs.net>
Acked-by: Liam R. Howlett <Liam.Howlett@Oracle.com>
Acked-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Tested-by: Shivank Garg <shivankg@amd.com>
Link: https://lkml.kernel.org/r/5e19ec93-8307-47c2-bb13-3ddf7150624e@amd.com
Cc: Christian Brauner <brauner@kernel.org>
Cc: David Hildenbrand <david@redhat.com>
Cc: David Howells <dhowells@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Klara Modin <klarasmodin@gmail.com>
Cc: Lokesh Gidra <lokeshgidra@google.com>
Cc: Mateusz Guzik <mjguzik@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Minchan Kim <minchan@google.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: "Paul E . McKenney" <paulmck@kernel.org>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Sourav Panda <souravpanda@google.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Wei Yang <richard.weiyang@gmail.com>
Cc: Will Deacon <will@kernel.org>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/rcuwait.h | 13 +------------
include/linux/types.h | 12 ++++++++++++
2 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/include/linux/rcuwait.h b/include/linux/rcuwait.h
index 27343424225cf..9ad134a04b415 100644
--- a/include/linux/rcuwait.h
+++ b/include/linux/rcuwait.h
@@ -4,18 +4,7 @@
#include <linux/rcupdate.h>
#include <linux/sched/signal.h>
-
-/*
- * rcuwait provides a way of blocking and waking up a single
- * task in an rcu-safe manner.
- *
- * The only time @task is non-nil is when a user is blocked (or
- * checking if it needs to) on a condition, and reset as soon as we
- * know that the condition has succeeded and are awoken.
- */
-struct rcuwait {
- struct task_struct __rcu *task;
-};
+#include <linux/types.h>
#define __RCUWAIT_INITIALIZER(name) \
{ .task = NULL, }
diff --git a/include/linux/types.h b/include/linux/types.h
index 2d7b9ae8714ce..f1356a9a5730a 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -248,5 +248,17 @@ typedef void (*swap_func_t)(void *a, void *b, int size);
typedef int (*cmp_r_func_t)(const void *a, const void *b, const void *priv);
typedef int (*cmp_func_t)(const void *a, const void *b);
+/*
+ * rcuwait provides a way of blocking and waking up a single
+ * task in an rcu-safe manner.
+ *
+ * The only time @task is non-nil is when a user is blocked (or
+ * checking if it needs to) on a condition, and reset as soon as we
+ * know that the condition has succeeded and are awoken.
+ */
+struct rcuwait {
+ struct task_struct __rcu *task;
+};
+
#endif /* __ASSEMBLY__ */
#endif /* _LINUX_TYPES_H */
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 865/869] irqwork: Move data struct to a types header
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (863 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 864/869] types: move struct rcuwait into types.h Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 866/869] bpf, sockmap: Account for receive queue in FIONREAD without a verdict program Greg Kroah-Hartman
` (4 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Thomas Gleixner,
Peter Zijlstra (Intel), Mathieu Desnoyers, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <tglx@linutronix.de>
[ Upstream commit c809f081fe400cb1b9898f4791c0d33146315161 ]
... to avoid header recursion hell.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Link: https://patch.msgid.link/20251119172550.152813625@linutronix.de
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/linux/irq_work.h | 9 ++-------
include/linux/irq_work_types.h | 14 ++++++++++++++
2 files changed, 16 insertions(+), 7 deletions(-)
create mode 100644 include/linux/irq_work_types.h
diff --git a/include/linux/irq_work.h b/include/linux/irq_work.h
index 136f2980cba30..c5afd053ae32c 100644
--- a/include/linux/irq_work.h
+++ b/include/linux/irq_work.h
@@ -2,8 +2,9 @@
#ifndef _LINUX_IRQ_WORK_H
#define _LINUX_IRQ_WORK_H
-#include <linux/smp_types.h>
+#include <linux/irq_work_types.h>
#include <linux/rcuwait.h>
+#include <linux/smp_types.h>
/*
* An entry can be in one of four states:
@@ -14,12 +15,6 @@
* busy NULL, 2 -> {free, claimed} : callback in progress, can be claimed
*/
-struct irq_work {
- struct __call_single_node node;
- void (*func)(struct irq_work *);
- struct rcuwait irqwait;
-};
-
#define __IRQ_WORK_INIT(_func, _flags) (struct irq_work){ \
.node = { .u_flags = (_flags), }, \
.func = (_func), \
diff --git a/include/linux/irq_work_types.h b/include/linux/irq_work_types.h
new file mode 100644
index 0000000000000..73abec5bb06ed
--- /dev/null
+++ b/include/linux/irq_work_types.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_IRQ_WORK_TYPES_H
+#define _LINUX_IRQ_WORK_TYPES_H
+
+#include <linux/smp_types.h>
+#include <linux/types.h>
+
+struct irq_work {
+ struct __call_single_node node;
+ void (*func)(struct irq_work *);
+ struct rcuwait irqwait;
+};
+
+#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 872+ messages in thread
* [PATCH 6.12 866/869] bpf, sockmap: Account for receive queue in FIONREAD without a verdict program
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (864 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 865/869] irqwork: Move data struct to a types header Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 867/869] wifi: atk9k: Revert "wifi: ath9k: reject short WMI command responses" Greg Kroah-Hartman
` (3 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Mattia Meleleo, Jiayuan Chen,
Emil Tsalapatis, John Fastabend, Kumar Kartikeya Dwivedi,
Sasha Levin
6.12-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 ce8464324d42f..ae2b34cc10eea 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 0e7e121179134..4d3315ff45227 100644
--- a/net/ipv4/tcp_bpf.c
+++ b/net/ipv4/tcp_bpf.c
@@ -335,6 +335,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)
@@ -345,7 +346,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] 872+ messages in thread
* [PATCH 6.12 867/869] wifi: atk9k: Revert "wifi: ath9k: reject short WMI command responses"
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (865 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 866/869] bpf, sockmap: Account for receive queue in FIONREAD without a verdict program Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 868/869] s390/uv: Dont return 0 from make_hva_secure() if the operation was not successful Greg Kroah-Hartman
` (2 subsequent siblings)
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Mehmet Fide,
Toke Høiland-Jørgensen, Linus Torvalds, Sasha Levin
6.12-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(-)
--- 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(struc
{
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 wm
/* 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
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));
--- 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;
^ permalink raw reply [flat|nested] 872+ messages in thread
* [PATCH 6.12 868/869] s390/uv: Dont return 0 from make_hva_secure() if the operation was not successful
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (866 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 867/869] wifi: atk9k: Revert "wifi: ath9k: reject short WMI command responses" Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 869/869] drm/panfrost: Fix scheduler workqueue bug Greg Kroah-Hartman
2026-10-17 17:19 ` [PATCH 6.12 000/869] 6.12.114-rc1 review Brett A C Sheffield
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, David Hildenbrand, Claudio Imbrenda
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Hildenbrand <david@redhat.com>
commit 3ec8a8330a1aa846dffbf1d64479213366c55b54 upstream.
If s390_wiggle_split_folio() returns 0 because splitting a large folio
succeeded, we will return 0 from make_hva_secure() even though a retry
is required. Return -EAGAIN in that case.
Otherwise, we'll return 0 from gmap_make_secure(), and consequently from
unpack_one(). In kvm_s390_pv_unpack(), we assume that unpacking
succeeded and skip unpacking this page. Later on, we run into issues
and fail booting the VM.
So far, this issue was only observed with follow-up patches where we
split large pagecache XFS folios. Maybe it can also be triggered with
shmem?
We'll cleanup s390_wiggle_split_folio() a bit next, to also return 0
if no split was required.
Fixes: d8dfda5af0be ("KVM: s390: pv: fix race when making a page secure")
Cc: stable@vger.kernel.org
Signed-off-by: David Hildenbrand <david@redhat.com>
Link: https://lore.kernel.org/r/20250516123946.1648026-2-david@redhat.com
Message-ID: <20250516123946.1648026-2-david@redhat.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
arch/s390/kernel/uv.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
--- a/arch/s390/kernel/uv.c
+++ b/arch/s390/kernel/uv.c
@@ -393,8 +393,11 @@ int make_hva_secure(struct mm_struct *mm
folio_walk_end(&fw, vma);
mmap_read_unlock(mm);
- if (rc == -E2BIG || rc == -EBUSY)
+ if (rc == -E2BIG || rc == -EBUSY) {
rc = s390_wiggle_split_folio(mm, folio, rc == -E2BIG);
+ if (!rc)
+ rc = -EAGAIN;
+ }
folio_put(folio);
return rc;
^ permalink raw reply [flat|nested] 872+ messages in thread
* [PATCH 6.12 869/869] drm/panfrost: Fix scheduler workqueue bug
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (867 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 868/869] s390/uv: Dont return 0 from make_hva_secure() if the operation was not successful Greg Kroah-Hartman
@ 2026-10-17 16:01 ` Greg Kroah-Hartman
2026-10-17 17:19 ` [PATCH 6.12 000/869] 6.12.114-rc1 review Brett A C Sheffield
869 siblings, 0 replies; 872+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-17 16:01 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Tvrtko Ursulin, Philipp Stanner,
Steven Price
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Philipp Stanner <phasta@kernel.org>
commit cb345f954eacd162601e7d07ca2f0f0a17b54ee3 upstream.
When the GPU scheduler was ported to using a struct for its
initialization parameters, it was overlooked that panfrost creates a
distinct workqueue for timeout handling.
The pointer to this new workqueue is not initialized to the struct,
resulting in NULL being passed to the scheduler, which then uses the
system_wq for timeout handling.
Set the correct workqueue to the init args struct.
Cc: stable@vger.kernel.org # 6.15+
Fixes: 796a9f55a8d1 ("drm/sched: Use struct for drm_sched_init() params")
Reported-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Closes: https://lore.kernel.org/dri-devel/b5d0921c-7cbf-4d55-aa47-c35cd7861c02@igalia.com/
Signed-off-by: Philipp Stanner <phasta@kernel.org>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
Link: https://lore.kernel.org/r/20250709102957.100849-2-phasta@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/gpu/drm/panfrost/panfrost_job.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -835,7 +835,6 @@ int panfrost_job_init(struct panfrost_de
.num_rqs = DRM_SCHED_PRIORITY_COUNT,
.credit_limit = 2,
.timeout = msecs_to_jiffies(JOB_TIMEOUT_MS),
- .timeout_wq = pfdev->reset.wq,
.name = "pan_js",
.dev = pfdev->dev,
};
@@ -873,6 +872,7 @@ int panfrost_job_init(struct panfrost_de
pfdev->reset.wq = alloc_ordered_workqueue("panfrost-reset", 0);
if (!pfdev->reset.wq)
return -ENOMEM;
+ args.timeout_wq = pfdev->reset.wq;
for (j = 0; j < NUM_JOB_SLOTS; j++) {
js->queue[j].fence_context = dma_fence_context_alloc(1);
^ permalink raw reply [flat|nested] 872+ messages in thread
* Re: [PATCH 6.12 205/869] ALSA: ctxfi: Refactor resource alloc for sparse mappings
2026-10-17 15:50 ` [PATCH 6.12 205/869] ALSA: ctxfi: Refactor resource alloc for sparse mappings Greg Kroah-Hartman
@ 2026-10-17 17:10 ` Harin Lee
0 siblings, 0 replies; 872+ messages in thread
From: Harin Lee @ 2026-10-17 17:10 UTC (permalink / raw)
To: Greg Kroah-Hartman, stable; +Cc: patches, Takashi Iwai, Sasha Levin
On 10/18/26 12:50 AM, Greg Kroah-Hartman wrote:
> 6.12-stable review patch. If anyone has any objections, please let me know.
>
> ------------------
>
> From: Harin Lee <me@harin.net>
>
> [ Upstream commit a2dbaeb5c61ef110ceefe0d48fe94d428d3bcf16 ]
>
> Refactor atc_get_resources(), atc_connect_resources(), and
> atc_release_resources() to allocate resources based on maximum type
> definitions.
>
> This allows specific resources to be conditionally skipped based on
> capabilities. This is necessary for hardware variants where resource
> allocations do not follow a sequential order.
>
> Signed-off-by: Harin Lee <me@harin.net>
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> Link: https://patch.msgid.link/20251124180501.2760421-5-me@harin.net
> Stable-dep-of: 277c6960d4dd ("ALSA: ctxfi: Check the error for index mapping")
> Signed-off-by: Sasha Levin <sashal@kernel.org>
> ---
> sound/pci/ctxfi/ctatc.c | 60 ++++++++++++++++++++++++-----------------
> sound/pci/ctxfi/ctatc.h | 4 ---
> 2 files changed, 35 insertions(+), 29 deletions(-)
>
> diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
> index fa70c4504db5f..6f0695efaafc8 100644
> --- a/sound/pci/ctxfi/ctatc.c
> +++ b/sound/pci/ctxfi/ctatc.c
> @@ -25,6 +25,9 @@
> #include <sound/control.h>
> #include <sound/asoundef.h>
>
> +#define NUM_ATC_SRCS 6
> +#define NUM_ATC_PCM (2 * 4)
> +
> #define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */
> #define MAX_MULTI_CHN 8
>
> @@ -1164,8 +1167,10 @@ static int atc_release_resources(struct ct_atc *atc)
>
> if (atc->daios) {
> daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
> - for (i = 0; i < atc->n_daio; i++) {
> + for (i = 0; i < NUM_DAIOTYP; i++) {
> daio = atc->daios[i];
> + if (!daio)
> + continue;
> if (daio->output) {
> dao = container_of(daio, struct dao, daio);
> dao->ops->clear_left_input(dao);
> @@ -1179,8 +1184,9 @@ static int atc_release_resources(struct ct_atc *atc)
>
> if (atc->pcm) {
> sum_mgr = atc->rsc_mgrs[SUM];
> - for (i = 0; i < atc->n_pcm; i++)
> - sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
> + for (i = 0; i < NUM_ATC_PCM; i++)
> + if (atc->pcm[i])
> + sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
>
> kfree(atc->pcm);
> atc->pcm = NULL;
> @@ -1188,8 +1194,9 @@ static int atc_release_resources(struct ct_atc *atc)
>
> if (atc->srcs) {
> src_mgr = atc->rsc_mgrs[SRC];
> - for (i = 0; i < atc->n_src; i++)
> - src_mgr->put_src(src_mgr, atc->srcs[i]);
> + for (i = 0; i < NUM_ATC_SRCS; i++)
> + if (atc->srcs[i])
> + src_mgr->put_src(src_mgr, atc->srcs[i]);
>
> kfree(atc->srcs);
> atc->srcs = NULL;
> @@ -1197,7 +1204,9 @@ static int atc_release_resources(struct ct_atc *atc)
>
> if (atc->srcimps) {
> srcimp_mgr = atc->rsc_mgrs[SRCIMP];
> - for (i = 0; i < atc->n_srcimp; i++) {
> + for (i = 0; i < NUM_ATC_SRCS; i++) {
> + if (!atc->srcimps[i])
> + continue;
> srcimp = atc->srcimps[i];
> srcimp->ops->unmap(srcimp);
> srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]);
> @@ -1370,30 +1379,32 @@ static int atc_get_resources(struct ct_atc *atc)
> struct srcimp_mgr *srcimp_mgr;
> struct sum_desc sum_dsc = {0};
> struct sum_mgr *sum_mgr;
> - int err, i, num_srcs, num_daios;
> + struct capabilities cap;
> + int err, i;
>
> - num_daios = ((atc->model == CTSB1270) ? 8 : 7);
> - num_srcs = ((atc->model == CTSB1270) ? 6 : 4);
> + cap = atc->capabilities(atc);
>
> - atc->daios = kcalloc(num_daios, sizeof(void *), GFP_KERNEL);
> + atc->daios = kcalloc(NUM_DAIOTYP, sizeof(void *), GFP_KERNEL);
> if (!atc->daios)
> return -ENOMEM;
>
> - atc->srcs = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL);
> + atc->srcs = kcalloc(NUM_ATC_SRCS, sizeof(void *), GFP_KERNEL);
> if (!atc->srcs)
> return -ENOMEM;
>
> - atc->srcimps = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL);
> + atc->srcimps = kcalloc(NUM_ATC_SRCS, sizeof(void *), GFP_KERNEL);
> if (!atc->srcimps)
> return -ENOMEM;
>
> - atc->pcm = kcalloc(2 * 4, sizeof(void *), GFP_KERNEL);
> + atc->pcm = kcalloc(NUM_ATC_PCM, sizeof(void *), GFP_KERNEL);
> if (!atc->pcm)
> return -ENOMEM;
>
> daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
> da_desc.msr = atc->msr;
> - for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
> + for (i = 0; i < NUM_DAIOTYP; i++) {
> + if ((i == MIC) && !cap.dedicated_mic)
> + continue;
> da_desc.type = (atc->model != CTSB073X) ? i :
> ((i == SPDIFIO) ? SPDIFI1 : i);
> da_desc.output = i < LINEIM;
> @@ -1405,42 +1416,39 @@ static int atc_get_resources(struct ct_atc *atc)
> i);
> return err;
> }
> - atc->n_daio++;
> }
>
> src_mgr = atc->rsc_mgrs[SRC];
> src_dsc.multi = 1;
> src_dsc.msr = atc->msr;
> src_dsc.mode = ARCRW;
> - for (i = 0, atc->n_src = 0; i < num_srcs; i++) {
> + for (i = 0; i < NUM_ATC_SRCS; i++) {
> + if (((i > 3) && !cap.dedicated_mic))
> + continue;
> err = src_mgr->get_src(src_mgr, &src_dsc,
> (struct src **)&atc->srcs[i]);
> if (err)
> return err;
> -
> - atc->n_src++;
> }
>
> srcimp_mgr = atc->rsc_mgrs[SRCIMP];
> srcimp_dsc.msr = 8;
> - for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) {
> + for (i = 0; i < NUM_ATC_SRCS; i++) {
> + if (((i > 3) && !cap.dedicated_mic))
> + continue;
> err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
> (struct srcimp **)&atc->srcimps[i]);
> if (err)
> return err;
> -
> - atc->n_srcimp++;
> }
>
> sum_mgr = atc->rsc_mgrs[SUM];
> sum_dsc.msr = atc->msr;
> - for (i = 0, atc->n_pcm = 0; i < (2*4); i++) {
> + for (i = 0; i < NUM_ATC_PCM; i++) {
> err = sum_mgr->get_sum(sum_mgr, &sum_dsc,
> (struct sum **)&atc->pcm[i]);
> if (err)
> return err;
> -
> - atc->n_pcm++;
> }
>
> return 0;
> @@ -1493,9 +1501,11 @@ static void atc_connect_resources(struct ct_atc *atc)
> struct sum *sum;
> struct ct_mixer *mixer;
> struct rsc *rscs[2] = {NULL};
> + struct capabilities cap;
> int i, j;
>
> mixer = atc->mixer;
> + cap = atc->capabilities(atc);
>
> for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) {
> mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]);
> @@ -1513,7 +1523,7 @@ static void atc_connect_resources(struct ct_atc *atc)
> src = atc->srcs[3];
> mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
>
> - if (atc->model == CTSB1270) {
> + if (cap.dedicated_mic) {
> /* Titanium HD has a dedicated ADC for the Mic. */
> dai = container_of(atc->daios[MIC], struct dai, daio);
> atc_connect_dai(atc->rsc_mgrs[SRC], dai,
> diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h
> index 0bc7b71d910b0..671edc46bd503 100644
> --- a/sound/pci/ctxfi/ctatc.h
> +++ b/sound/pci/ctxfi/ctatc.h
> @@ -132,10 +132,6 @@ struct ct_atc {
> void **pcm; /* SUMs for collecting all pcm stream */
> void **srcs; /* Sample Rate Converters for input signal */
> void **srcimps; /* input mappers for SRCs */
> - unsigned char n_daio;
> - unsigned char n_src;
> - unsigned char n_srcimp;
> - unsigned char n_pcm;
>
> struct ct_timer *timer;
>
Hello,
Please check my earlier emails if you missed them:
https://lore.kernel.org/stable/e5b53e3f-02ac-4afc-9fa1-823ddb80875e@harin.net/
https://lore.kernel.org/stable/d19f3435-57fd-4ddf-9465-36f359c8b8bd@harin.net/
Thanks,
Harin Lee
^ permalink raw reply [flat|nested] 872+ messages in thread
* Re: [PATCH 6.12 000/869] 6.12.114-rc1 review
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
` (868 preceding siblings ...)
2026-10-17 16:01 ` [PATCH 6.12 869/869] drm/panfrost: Fix scheduler workqueue bug Greg Kroah-Hartman
@ 2026-10-17 17:19 ` Brett A C Sheffield
869 siblings, 0 replies; 872+ 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.12.114-rc1-g1cda2e472e80 #1 SMP PREEMPT_DYNAMIC Sat Oct 17 16:40:18 -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] 872+ messages in thread
end of thread, other threads:[~2026-10-17 17:19 UTC | newest]
Thread overview: 872+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-17 15:47 [PATCH 6.12 000/869] 6.12.114-rc1 review Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 001/869] spi: mpc52xx: clean up interrupt handling Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 002/869] usb: gadget: f_hid: Add missing error code Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 003/869] iommu/amd: Disable AMD IOMMU if CMPXCHG16B feature is not supported Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 004/869] iommu/amd: Fix ivrs_base memleak in early_amd_iommu_init() Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 005/869] ice: fix use-after-free in dynamic port cleanup Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 006/869] xfs: stop exchanging reflink flags when exchanging mappings Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 007/869] xfs: fix exchange-range-to-eof file size exchange Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 008/869] ip6_gre: remove obsolete ERSPAN PMTU update Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 009/869] xfs: xfs_ifree_cluster vs xfs_iflush_shutdown_abort deadlock Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 010/869] xfs: catch stale AGF/AGF metadata Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 011/869] xfs: avoid dquot buffer pin deadlock Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 012/869] xfs: rearrange code in xfs_buf_item.c Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 013/869] xfs: factor out stale buffer item completion Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 014/869] xfs: fix unmount hang with unflushable inodes stuck in the AIL Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 015/869] drm/amd: Create a device link between APU display and XHCI devices Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 016/869] ata: libata-scsi: do not lose CHECK CONDITION for failed ATAPI commands Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 017/869] mm/mremap: fix locked_vm leak by splitting VMA for MREMAP_DONTUNMAP Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 018/869] mm/mremap: fix locked_vm leak from MREMAP_DONTUNMAP self-merge Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 019/869] wifi: mt76: connac: tolerate inactive BSS deactivation Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 020/869] net: team: Remove unused team_mode_op, port_enabled Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 021/869] net: team: Rename port_disabled team mode op to port_tx_disabled Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 022/869] net: team: fix NULL pointer dereference in team_xmit during mode change Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 023/869] net: team: stop reusing skb after queue override Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 024/869] sched_ext: Fix CPU hotplug hang when a dying CPUs tasks sit in the BPF scheduler Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 025/869] Bluetooth: hci_sync: Fix command skb lifetime during scan setup Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 026/869] Bluetooth: RFCOMM: connect the session socket without rfcomm_mutex Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 027/869] drm/vmwgfx: Stop using dev_private to store driver data Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 028/869] drm/vmwgfx: validate pitch coming from userspace Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 029/869] namespace: dont inherit MNT_UMOUNT in clone_mnt() Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 030/869] namespace: check the mounts before reading their parents in pivot_root() Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 031/869] dm-integrity: use internal variable for digestsize Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 032/869] dm-integrity: rename internal_hash Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 033/869] dm-integrity: fix buffer overflow in inline mode with large tag size Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 034/869] net: xilinx: axienet: Free outstanding DMA buffers on dmaengine stop Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 035/869] riscv: patch: Avoid early phys_to_page() Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 036/869] riscv: patch: fix handling of bpf-jit execmem addresses Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 037/869] scsi: ufs: core: Decouple CQ sweep from request iterator in MCQ Greg Kroah-Hartman
2026-10-17 15:47 ` [PATCH 6.12 038/869] scsi: ch: Do not keep references to data transfer element devices Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 039/869] scsi: ufs: core: Move an assignment in ufshcd_mcq_process_cqe() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 040/869] scsi: ufs: core: Add debug log for MCQ command timeout Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 041/869] scsi: ufs: core: Add a comment block above ufshcd_mcq_compl_all_cqes_lock() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 042/869] scsi: ufs: core: Avoid unsafe MMIO reads in ufshcd_mcq_compl_all_cqes_lock() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 043/869] drm/vc4: Use video aperture helpers Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 044/869] drm/vc4: Fix firmware reference leak in vc4_drm_bind() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 045/869] namespace: unhash a dentry before detaching the mounts on it Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 046/869] namespace: check the target before walking it in do_mount_setattr() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 047/869] fcntl: refuse F_SET_RW_HINT on an immutable inode Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 048/869] namespace: handle mount locking for automounts correctly Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 049/869] smb: client: improve compound padding in encryption Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 050/869] smb: client: get rid of bounds check in SMB2_ioctl_init() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 051/869] smb: client: fix compound alignment with encryption Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 052/869] um: work around sched_yield not yielding in time-travel mode Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 053/869] drm/i915/display: pass display to intel_crtc_for_pipe() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 054/869] drm/i915/vga: Convert VGA code to intel_display Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 055/869] drm/i915/display: convert I915_STATE_WARN() to struct intel_display Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 056/869] drm/i915/gmbus: convert " Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 057/869] drm/i915/crt: " Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 058/869] drm/i915: Grab intel_display from the encoder to avoid potential oopsies Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 059/869] ax25: Remove broken autobind Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 060/869] f2fs: quota: fix to avoid warning in dquot_writeback_dquots() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 061/869] RISC-V: KVM: Teardown riscv specific bits after kvm_exit Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 062/869] wifi: ath12k: fix struct hal_rx_phyrx_rssi_legacy_info Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 063/869] wifi: ath12k: fix incorrect TID updation in DP monitor status path Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 064/869] wifi: ath12k: Avoid explicit type cast in monitor status parse handler Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 065/869] wifi: ath12k: Avoid memory leak while enabling statistics Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 066/869] perf/dwc_pcie: Qualify RAS DES VSEC Capability by Vendor, Revision Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 067/869] perf/dwc_pcie: fix duplicate pci_dev devices Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 068/869] ublk: fix race between io_uring_cmd_complete_in_task and ublk_cancel_cmd Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 069/869] kasan: avoid sleepable page allocation from atomic context Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 070/869] clk: sunxi-ng: h616: Reparent CPU clock during frequency changes Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 071/869] clk: sunxi-ng: h616: Reparent GPU " Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 072/869] net: ethernet: ti: am65-cpsw: streamline RX queue creation and cleanup Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 073/869] dmaengine: ti: k3-udma-glue: Drop skip_fdq argument from k3_udma_glue_reset_rx_chn Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 074/869] virtio: break and reset virtio devices on device_shutdown() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 075/869] coresight: holding cscfg_csdev_lock while removing cscfg from csdev Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 076/869] PCI/pwrctl: Use of_platform_device_create() to create pwrctl devices Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 077/869] PCI/pwrctl: Create pwrctl device only if at least one power supply is present Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 078/869] PCI/pwrctrl: Cancel outstanding rescan work when unregistering Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 079/869] drm/nouveau: fix a use-after-free in r535_gsp_rpc_push() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 080/869] wifi: ath12k: convert struct ath12k_sta::update_wk to use struct wiphy_work Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 081/869] wifi: ath12k: ath12k_mac_op_sta_state(): clean up update_wk cancellation Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 082/869] wifi: ath12k: prepare vif data structure for MLO handling Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 083/869] wifi: ath12k: Fix memory leak due to multiple rx_stats allocation Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 084/869] mm: fix uprobe pte be overwritten when expanding vma Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 085/869] riscv: Enable cbo.zero only when all harts support Zicboz Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 086/869] riscv: Add support for per-thread envcfg CSR values Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 087/869] riscv: save the SR_SUM status over switches Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 088/869] wifi: rtw89: pci: configure manual DAC mode via PCI config API only Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 089/869] s390/entry: Remove __GMAP_ASCE and use _PIF_GUEST_FAULT again Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 090/869] s390/kvm: Remove kvm_arch_fault_in_page() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 091/869] s390/mm/fault: Handle guest-related program interrupts in KVM Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 092/869] s390/mm: Simplify get_fault_type() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 093/869] s390/mm: Get rid of fault type switch statements Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 094/869] s390/mm: Fix in_atomic() handling in do_secure_storage_access() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 095/869] platform/x86/amd/pmf: Switch to platform_get_resource() and devm_ioremap_resource() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 096/869] platform/x86/amd: pmf: Use device managed allocations Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 097/869] drm/rockchip: vop2: Consistently use dev_err_probe() Greg Kroah-Hartman
2026-10-17 15:48 ` [PATCH 6.12 098/869] drm/rockchip: vop2: Register the primary plane and overlay plane separately Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 099/869] drm/rockchip: vop2: fail cleanly if missing a primary plane for a video-port Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 100/869] wifi: ath12k: Pass ab pointer directly to ath12k_dp_tx_get_encap_type() Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 101/869] rv: Remove trailing whitespace from tracepoint string Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 102/869] rv: Use strings in da monitors tracepoints Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 103/869] wifi: iwlwifi: return ERR_PTR from opmode start() Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 104/869] wifi: iwlwifi: Fix error code in iwl_op_mode_dvm_start() Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 105/869] net/sched: Fix backlog accounting in qdisc_dequeue_internal Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 106/869] mm/mremap: fix WARN with uffd that has remap events disabled Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 107/869] crypto: x86/aegis128 - eliminate some indirect calls Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 108/869] crypto: x86/aegis128 - optimize length block preparation using SSE4.1 Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 109/869] crypto: x86/aegis128 - improve assembly function prototypes Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 110/869] crypto: x86/aegis - Fix sleeping when disallowed on PREEMPT_RT Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 111/869] crypto: x86/aegis - Add missing error checks Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 112/869] net/mlx5: HWS, denote how refcounts are protected Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 113/869] net/mlx5: HWS, simplify allocations as we support only FDB Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 114/869] net/mlx5: HWS, handle returned error value in pool alloc Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 115/869] net/mlx5: HWS, update flow - remove the use of dual RTCs Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 116/869] net/mlx5: HWS, Remove unused element array Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 117/869] net/mlx5: HWS, Make pool single resource Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 118/869] net/mlx5: HWS, Refactor pool implementation Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 119/869] net/mlx5: HWS, Fix memory leak in hws_pool_buddy_init error path Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 120/869] net/mlx5: HWS, Fix memory leak in hws_action_get_shared_stc_nic error flow Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 121/869] ptp: ocp: fix use-after-free bugs causing by ptp_ocp_watchdog Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 122/869] wifi: mt76: mt7915: fix list corruption after hardware restart Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 123/869] mm/vmalloc, mm/kasan: respect gfp mask in kasan_populate_vmalloc() Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 124/869] smb: client: let recv_done verify data_offset, data_length and remaining_data_length Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 125/869] iommu/s390: handle IOAT registration based on domain Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 126/869] iommu/s390: set appropriate IOTA region type Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 127/869] iommu/s390: Make attach succeed when the device was surprise removed Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 128/869] RISC-V: KVM: Write hgatp register with valid mode bits Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 129/869] drm/xe: Dont allow evicting of BOs in same VM in array of VM binds Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 130/869] remoteproc: Switch back to struct platform_driver::remove() Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 131/869] remoteproc: qcom: pas: Make remoteproc name human friendly Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 132/869] remoteproc: qcom_q6v5_pas: Simplify with dev_err_probe() Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 133/869] remoteproc: qcom: pas: Conclude the rename from adsp Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 134/869] remoteproc: qcom: pas: Shutdown lite ADSP DTB on X1E Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 135/869] scsi: ufs: core: Fix data race in CPU latency PM QoS request handling Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 136/869] crypto: hisilicon/hpre - enable all clusters clock gating Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 137/869] crypto: hisilicon/qm - request reserved interrupt for virtual function Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 138/869] ASoC: Intel: avs: Use topology information for endpoint numbers Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 139/869] ASoC: Intel: avs: Do not share the name pointer between components Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 140/869] sysfs: check visibility before changing group attribute ownership Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 141/869] amd/amdkfd: enhance kfd process check in switch partition Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 142/869] drm/xe/guc: Add devm release action to safely tear down CT Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 143/869] RDMA/mlx5: Remove the redundant MLX5_IB_STAGE_UAR stage Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 144/869] net/mlx5: HWS, fix bad parameter in CQ creation Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 145/869] net/mlx5: Fix typo of MLX5_EQ_DOORBEL_OFFSET Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 146/869] net/mlx5: Store the global doorbell in mlx5_priv Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 147/869] net/mlx5e: Prepare for using different CQ doorbells Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 148/869] mlx5: Fix default values in create CQ Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 149/869] scsi: ufs: qcom : Refactor phy_power_on/off calls Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 150/869] scsi: ufs: ufs-qcom: Fix UFS OCP issue during UFS power down (PC=3) Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 151/869] clk: thead: th1520-ap: set all AXI clocks to CLK_IS_CRITICAL Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 152/869] netconsole: Acquire su_mutex before navigating configs hierarchy Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 153/869] net: vxlan: prevent NULL deref in vxlan_xmit_one Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 154/869] btrfs: fix double free of qgroup record after failure to add delayed ref head Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 155/869] wifi: mt76: wed: use proper wed reference in mt76 wed driver callabacks Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 156/869] md: init bioset in mddev_init Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 157/869] coresight-tmc: change tmc_drvdata spinlocks type to raw_spinlock_t Greg Kroah-Hartman
2026-10-17 15:49 ` [PATCH 6.12 158/869] coresight: ETR: Fix ETR buffer use-after-free issue Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 159/869] wifi: ath12k: Fix MSDU buffer types handling in RX error path Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 160/869] accel/ivpu: Allow to import single buffer into multiple contexts Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 161/869] accel/ivpu: Rework bind/unbind of imported buffers Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 162/869] accel/ivpu: Fix page fault in ivpu_bo_unbind_all_bos_from_context() Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 163/869] drm/panthor: Prevent potential UAF in group creation Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 164/869] scsi: qla2xxx: Clear cmds after chip reset Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 165/869] s390/fpu: Fix false-positive kmsan report in fpu_vstl() Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 166/869] staging: most: remove broken i2c driver Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 167/869] wifi: mac80211: fix typo in HE MCS check Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 168/869] wifi: mac80211: log link information in ieee80211_determine_chan_mode Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 169/869] wifi: mac80211: dont WARN for connections on invalid channels Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 170/869] accel/qaic: Add config structs for supported cards Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 171/869] net: qrtr: Drop the MHI auto_queue feature for IPCR DL channels Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 172/869] PCI: endpoint: Add missing NULL check for alloc_workqueue() Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 173/869] bpf: Mark bpf_refcount field as unique Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 174/869] staging: rtl8723bs: fix xmit_frame/xmit_buf leaks on mgnt-frame error paths Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 175/869] drm/msm: Recover HW before retire hung submit Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 176/869] block: zero non-PI portion of auto integrity buffer Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 177/869] idpf: fix error handling in the init_task on load Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 178/869] stddef: Introduce TRAILING_OVERLAP() helper macro Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 179/869] virtio_net: Fix misalignment bug in struct virtnet_info Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 180/869] ALSA: usb-audio: Prevent excessive number of frames Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 181/869] riscv: trace: fix snapshot deadlock with sbi ecall Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 182/869] io_uring/rw: free potentially allocated iovec on cache put failure Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 183/869] cxl/mbox: validate payload size before accessing contents in cxl_payload_from_user_allowed() Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 184/869] sched/deadline: Fix missing ENQUEUE_REPLENISH during PI de-boosting Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 185/869] ice: change XDP RxQ frag_size from DMA write length to xdp.frame_sz Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 186/869] netfilter: nf_tables: clone set on flush only Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 187/869] serial: rename local uart_port_lock() -> uart_port_ref_lock() Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 188/869] serial: core: fix infinite loop in handle_tx() for PORT_UNKNOWN Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 189/869] RDMA/efa: Fix use of completion ctx after free Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 190/869] bpf: Fix exception exit lock checking for subprogs Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 191/869] drm/mediatek: dsi: Store driver data before invoking mipi_dsi_host_register Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 192/869] s390/mm: Add missing secure storage access fixups for donated memory Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 193/869] dm: limit swapping tables for devices with zone write plugs Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 194/869] drm/tilcdc: Fix removal actions in case of failed probe Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 195/869] net: Factorise setup_net() and cleanup_net() Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 196/869] net: Add ops_undo_single for module load/unload Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 197/869] net: Add ->exit_rtnl() hook to struct pernet_operations Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 198/869] wireguard: device: use exit_rtnl callback instead of manual rtnl_lock in pre_exit Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 199/869] KVM: SEV: Use long-term pin when registering encrypted memory regions Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 200/869] KVM: SEV: Protect *all* of sev_mem_enc_register_region() with kvm->lock Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 201/869] rxrpc: proc: size address buffers for %pISpc output Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 202/869] Bluetooth: hci_event: move wake reason storage into validated event handlers Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 203/869] ALSA: ctxfi: Add hw parameter to daio_mgr_dao_init() Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 204/869] ALSA: ctxfi: Use explicit output flag for DAIO resources Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 205/869] ALSA: ctxfi: Refactor resource alloc for sparse mappings Greg Kroah-Hartman
2026-10-17 17:10 ` Harin Lee
2026-10-17 15:50 ` [PATCH 6.12 206/869] ALSA: ctxfi: Check the error for index mapping Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 207/869] bpf: Factor out atomic_ptr_type_ok() Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 208/869] bpf: Factor out check_atomic_rmw() Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 209/869] bpf: Factor out check_load_mem() and check_store_reg() Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 210/869] bpf: Fix incorrect pruning due to atomic fetch precision tracking Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 211/869] Bluetooth: hci_sync: hci_cmd_sync_queue_once() return -EEXIST if exists Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 212/869] mptcp: move the whole rx path under msk socket lock protection Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 213/869] mptcp: cleanup mem accounting Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 214/869] mptcp: leverage skb deferral free Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 215/869] mptcp: add eat_recv_skb helper Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 216/869] mptcp: fix soft lockup in mptcp_recvmsg() Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 217/869] bnxt_en: Update firmware interface spec to 1.10.3.85 Greg Kroah-Hartman
2026-10-17 15:50 ` [PATCH 6.12 218/869] bnxt_en: set backing store type from query type Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 219/869] mpls: Hold dev refcnt for mpls_nh Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 220/869] mpls: Unify return paths in mpls_dev_notify() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 221/869] mpls: Add mpls_dev_rcu() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 222/869] mpls: Pass net to mpls_dev_get() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 223/869] mpls: Add mpls_route_input() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 224/869] mpls: Convert mpls_dump_routes() to RCU Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 225/869] mpls: Protect net->mpls.platform_label with a per-netns mutex Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 226/869] mpls: add seqcount to protect the platform_label{,s} pair Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 227/869] HID: core: Add reserved item tag for main items Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 228/869] HID: rate-limit hid_warn to prevent log flooding Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 229/869] HID: core: Mitigate potential OOB by removing bogus memset() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 230/869] xfs: remove bp->b_error check in xfs_attr3_root_inactive Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 231/869] xfs: factor out xfs_attr3_node_entry_remove Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 232/869] xfs: close crash window in attr dabtree inactivation Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 233/869] net: ioam6: fix OOB and missing lock Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 234/869] ipv6: ioam: fix potential NULL dereferences in __ioam6_fill_trace_data() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 235/869] srcu: Use irq_work to start GP in tiny SRCU Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 236/869] btrfs: tree-log: dont use token set/get accessors in fill_inode_item() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 237/869] btrfs: fix zero size inode with non-zero size after log replay Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 238/869] fs/ntfs3: Accumulated refactoring changes Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 239/869] ntfs3: fix circular locking dependency in run_unpack_ex Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 240/869] wifi: iwlwifi: fix 22000 series SMEM parsing Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 241/869] ksmbd: fix signededness bug in smb_direct_prepare_negotiation() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 242/869] drm/amd/display: Adjust PHY FSM transition to TX_EN-to-PLL_ON for TMDS on DCN35 Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 243/869] ASoC: qcom: q6asm: handle the responses after closing Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 244/869] ASoC: qcom: q6asm: drop DSP responses for closed data streams Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 245/869] wifi: rtw89: pci: validate sequence number of TX release report Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 246/869] team: avoid NETDEV_CHANGEMTU event when unregistering slave Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 247/869] media: chips-media: wave5: Fix Null reference while testing fluster Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 248/869] ring-buffer: Fix possible dereference of uninitialized pointer Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 249/869] drm: renesas: rz-du: mipi_dsi: fix kernel panic when rebooting for some panels Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 250/869] drm/amdgpu: Skip vcn poison irq release on VF Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 251/869] btrfs: do not ASSERT() when the fs flips RO inside btrfs_repair_io_failure() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 252/869] btrfs: remove reserved argument from btrfs_pin_extent() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 253/869] btrfs: dont BUG() on unexpected delayed ref type in run_one_delayed_ref() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 254/869] md raid: fix hang when stopping arrays with metadata through dm-raid Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 255/869] media: v4l2-mem2mem: Add a kref to the v4l2_m2m_dev structure Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 256/869] media: verisilicon: Avoid G2 bus error while decoding H.264 and HEVC Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 257/869] KVM: Export hardware virtualization enabling/disabling functions Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 258/869] syscore: Pass context data to callbacks Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 259/869] soc/tegra: pmc: Fix unsafe generic_handle_irq() call Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 260/869] wifi: iwlwifi: mvm: dont send a 6E related command when not supported Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 261/869] drm/amd/display: Fix NULL pointer dereference in dcn401_init_hw() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 262/869] ice: ptp: dont WARN when controlling PF is unavailable Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 263/869] i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 264/869] i3c: mipi-i3c-hci: Fix race in DMA ring dequeue Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 265/869] scsi: qla2xxx: Completely fix fcport double free Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 266/869] ASoC: amd: acp-mach-common: Add missing error check for clock acquisition Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 267/869] rxrpc: kdoc: Update function descriptions and add link from rxrpc.rst Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 268/869] rxrpc, afs: Fix missing error pointer check after rxrpc_kernel_lookup_peer() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 269/869] net/mlx5e: RX, Fix XDP multi-buf frag counting for legacy RQ Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 270/869] net/mlx5e: RX, Fix XDP multi-buf frag counting for striding RQ Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 271/869] nouveau/gsp: drop WARN_ON in ACPI probes Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 272/869] bpf: Fix tcx/netkit detach permissions when prog fd isnt given Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 273/869] btrfs: fix EEXIST abort due to non-consecutive gaps in chunk allocation Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 274/869] net: stmmac: fix oops when split header is enabled Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 275/869] drm/exynos: vidi: use priv->vidi_dev for ctx lookup in vidi_connection_ioctl() Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 276/869] gfs2: fix memory leaks in gfs2_fill_super error path Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 277/869] KVM: SVM: Add missing save/restore handling of LBR MSRs Greg Kroah-Hartman
2026-10-17 15:51 ` [PATCH 6.12 278/869] ipmi:ssif: Clean up kthread on errors Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 279/869] KVM: x86: Rename "governed features" helpers to use "guest_cpu_cap" Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 280/869] KVM: nSVM: Always use NextRIP as vmcb02s NextRIP after first L2 VMRUN Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 281/869] ceph: Remove call to PagePrivate2() Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 282/869] ceph: extend ceph_writeback_ctl for ceph_writepages_start() refactoring Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 283/869] ceph: introduce ceph_process_folio_batch() method Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 284/869] ceph: Remove uses of page from ceph_process_folio_batch() Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 285/869] ceph: fix num_ops off-by-one when crypto allocation fails Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 286/869] KVM: nSVM: Avoid clearing VMCB_LBR in vmcb12 Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 287/869] dm-verity-fec: fix reading parity bytes split across blocks (take 3) Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 288/869] spi: microchip-core-qspi: Support per spi-mem operation frequency switches Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 289/869] spi: microchip-core-qspi: set min_speed_hz during probe Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 290/869] spi: microchip-core-qspi: remove unused param from mchp_coreqspi_write_op() Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 291/869] spi: microchip-core-qspi: control built-in cs manually Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 292/869] riscv: kvm: fix vector context allocation leak Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 293/869] f2fs: fix fsck inconsistency caused by FGGC of node block Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 294/869] refcount: provide ops for cases when objects memory can be reused Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 295/869] RDMA/mlx4: Fix mis-use of RCU in mlx4_srq_event() Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 296/869] spi: ch341: switch to use devm_spi_alloc_host() Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 297/869] spi: ch341: fix devres lifetime Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 298/869] drm/amd/display: Fix dc_link NULL handling in HPD init Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 299/869] NFS/localio: prevent direct reclaim recursion into NFS via nfs_writepages Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 300/869] coresight: tmc-etr: Fix race condition between sysfs and perf mode Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 301/869] selinux: allow multiple opens of /sys/fs/selinux/policy Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 302/869] netfilter: nf_tables: use list_del_rcu for netlink hooks Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 303/869] RDMA/rxe: Move some code to rxe_loc.h in preparation for ODP Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 304/869] RDMA/rxe: Fix iova-to-va conversion for MR page sizes != PAGE_SIZE Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 305/869] Revert "net/smc: Introduce TCP ULP support" Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 306/869] tap: fix stack info leak in tap_ioctl() SIOCGIFHWADDR Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 307/869] libceph: Fix potential out-of-bounds access in __ceph_x_decrypt() Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 308/869] net: airoha: fix BQL imbalance in TX path Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 309/869] sched/psi: fix race between file release and pressure write Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 310/869] netfilter: nat: use kfree_rcu to release ops Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 311/869] ice: fix double-free of tx_buf skb Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 312/869] f2fs: fix data loss caused by incorrect use of nat_entry flag Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 313/869] f2fs: avoid reading already updated pages during GC Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 314/869] greybus: raw: fix use-after-free on cdev close Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 315/869] net: pull headers in qdisc_pkt_len_segs_init() Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 316/869] wifi: mt76: mt7925: fix potential deadlock in mt7925_roc_abort_sync Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 317/869] wifi: mt76: Fix memory leak destroying device Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 318/869] powerpc/64s: Fix unmap race with PMD migration entries Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 319/869] powerpc/pgtable-frag: Fix bad page state in pte_frag_destroy Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 320/869] vdpa: use generic driver_override infrastructure Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 321/869] staging: rtl8723bs: rtw_mlme: add bounds checks before ie_length subtraction Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 322/869] sctp: validate embedded INIT chunk and address list lengths in cookie Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 323/869] wifi: fix leak if split 6 GHz scanning fails Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 324/869] KVM: arm64: Take the SRCU lock for page table walks in fault injection and AT emulation Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 325/869] iommu/vt-d: Avoid NULL pointer dereference or refcount corruption Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 326/869] btrfs: only release the dirty pages io tree after successful writes Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 327/869] drm/amd/display: Wrap DCN32 phantom-plane allocation in DC_RUN_WITH_PREEMPTION_ENABLED Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 328/869] net: phonet: do not BUG_ON() in pn_socket_autobind() on failed bind Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 329/869] net: mana: Guard mana_remove against double invocation Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 330/869] io_uring/napi: protect concurrent io_napi_entry timeout accesses Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 331/869] io_uring/napi: improve __io_napi_add Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 332/869] io_uring/napi: Use lock guards Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 333/869] io_uring/napi: clean up __io_napi_do_busy_loop Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 334/869] io_uring/napi: cap busy_poll_to 10 msec Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 335/869] drm/amd/display: Fix out-of-bounds read in dp_get_eq_aux_rd_interval() Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 336/869] f2fs: fix fsck inconsistency caused by incorrect nat_entry flag usage Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 337/869] drm/msm: always recover the gpu Greg Kroah-Hartman
2026-10-17 15:52 ` [PATCH 6.12 338/869] fbdev: omap2: fix inconsistent lock returns in omapfb_mmap Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 339/869] fbdev: omap2: fix use-after-free " Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 340/869] f2fs: read COW data with the original inode during atomic write Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 341/869] gcov: use atomic counter updates to fix concurrent access crashes Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 342/869] wifi: mt76: add wcid publish check in mt76_sta_add Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 343/869] drm/amdgpu/vcn: set no_user_fence for VCN v4.0 enc ring Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 344/869] net: airoha: Do not read uninitialized fragment address in airoha_dev_xmit() Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 345/869] net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue() Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 346/869] drm/amdgpu: fix amdgpu_hmm_range_get_pages Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 347/869] net/handshake: hand off the pinned file reference to accept_doit Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 348/869] ethtool: module: call ethnl_ops_complete() on module flash errors Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 349/869] ethtool: rss: fix indir_table and hkey leak on get_rxfh failure Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 350/869] netfilter: nf_tables: fix dst corruption in same register operation Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 351/869] tcp: Remove sk->sk_prot->orphan_count Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 352/869] tcp: fix stale per-CPU tcp_tw_isn leak enabling ISN prediction Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 353/869] cgroup/rstat: validate cpu before css_rstat_cpu() access Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 354/869] hwmon: (lm90) Stop work before releasing hwmon device Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 355/869] netfs: Fix leak of request in netfs_write_begin() error handling Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 356/869] netfs: Fix missing locking around retry adding new subreqs Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 357/869] netfilter: bridge: eb_tables: close module init race Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 358/869] netfilter: ebtables: move to two-stage removal scheme Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 359/869] netfilter: x_tables: allow initial table replace without emitting audit log message Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 360/869] netfilter: x_tables: allocate hook ops while under mutex Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 361/869] wifi: mac80211: fix missing RX bitrate update for mesh forwarding path Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 362/869] wifi: mac80211: capture fast-RX rate before mesh reuses skb->cb Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 363/869] erofs: fix metabuf leak in inode xattr initialization Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 364/869] drm/msm/adreno: Fix a reference leak in a6xx_gpu_init() Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 365/869] netfs: Fix zeropoint update where i_size > remote_i_size Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 366/869] hwmon: (lm90) Add lock protection to lm90_alert Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 367/869] KVM: guest_memfd: Treat memslot binding offset+size as unsigned values Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 368/869] smb/client: fix chown/chgrp with SMB3 POSIX Extensions Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 369/869] ksmbd: validate NTLMv2 response before updating session key Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 370/869] ksmbd: prevent path traversal bypass by restricting caseless retry Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 371/869] KVM: x86: Drop superfluous kvm_lapic_set_base() call when setting APIC state Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 372/869] KVM: x86: Move kvm_set_apic_base() implementation to lapic.c (from x86.c) Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 373/869] KVM: x86: Rename APIC base setters to better capture their relationship Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 374/869] KVM: x86: Move update_cr8_intercept() to lapic.c Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 375/869] KVM: x86: Unconditionally recompute CR8 intercept on PPR update Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 376/869] KVM: nVMX: Put vmcs12 pages if nested VM-Enter fails due to invalid guest state Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 377/869] drm/amdgpu: Fix kernel panic during driver load failure Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 378/869] media: stm32: dcmipp: use v4l2_subdev_is_streaming Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 379/869] media: stm32: dcmipp: replace s_stream with enable/disable_streams Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 380/869] media: stm32-dcmipp: Return queued buffers on start_streaming() failure Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 381/869] drm/vc4: Shut down BO cache timer before teardown Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 382/869] drm/amdgpu: Use dbg level for VBIOS check messages Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 383/869] drm/amdgpu: Add wrapper for freeing vbios memory Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 384/869] drm/amdgpu: Release VFCT ACPI table reference Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 385/869] drm/i915/mst: limit DP MST ESI service loop Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 386/869] drm/i915/gt: Fix NULL deref on sched_engine alloc failure Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 387/869] drm/amdkfd: Check bounds on CRIU restore queue type and mqd size Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 388/869] idpf: fix max_vport related crash on allocation error during init Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 389/869] LoongArch: BPF: Zero-extend signed ALU32 div/mod results Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 390/869] cifs: prevent readdir from changing file size due to stale directory metadata Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 391/869] cifs: fix cifsFileInfo leak on kmalloc failure in deferred close drain paths Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 392/869] tipc: serialize udp bearer replicast list updates Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 393/869] fwctl/bnxt_en: Refactor aux bus functions to be more generic Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 394/869] bnxt_en: Handle partially initialized auxiliary devices Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 395/869] drm/xe/guc: Keep scheduler timeline name alive Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 396/869] Bluetooth: hci_sync: extend conn_hash lookup critical sections Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 397/869] bpf: Disable migration when destroying sock storage Greg Kroah-Hartman
2026-10-17 15:53 ` [PATCH 6.12 398/869] bpf: Disable migration when cloning " Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 399/869] rcu: add rcu_read_lock_dont_migrate() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 400/869] bpf: Use rcu_read_lock_dont_migrate in bpf_sk_storage.c Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 401/869] bpf: Fix UAF in sock clone early bailouts Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 402/869] firmware: arm_ffa: Fix out-of-bound writes in ffa_setup_and_transmit() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 403/869] wifi: cfg80211: use wiphy work for socket owner autodisconnect Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 404/869] wifi: mac80211: refactor populating mesh related fields in sinfo Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 405/869] wifi: cfg80211: add link_station_info structure to support MLO statistics Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 406/869] wifi: mac80211: defer link RX stats percpu free to RCU Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 407/869] wifi: cfg80211: Fix an error handling path in cfg80211_wext_siwscan() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 408/869] RDMA/irdma: Prevent user-triggered null deref on QP create Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 409/869] sched_ext: Dont warn on core-sched forced idle in put_prev_task_scx() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 410/869] xfrm: fix stale skb->prev after async crypto steals a GSO segment Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 411/869] LoongArch: Fix address space mismatch in kexec command line lookup Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 412/869] drm/amd/display: use kvzalloc to allocate struct dc Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 413/869] net/sched: Handle TC_ACT_REDIRECT from qdisc filter chains Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 414/869] drm/amdkfd: clamp v9 CRIU control stack checkpoint copy to BO size Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 415/869] ovl: check access to copy_file_range source with src mounter creds Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 416/869] s390/zcrypt: Fix buffer over-read in cca_cipher2protkey Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 417/869] wifi: mac80211: validate extension-frame layout before RX Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 418/869] wifi: ieee80211: validate MLE common info length Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 419/869] ata: libata-core: Disable LPM on Silicon Motion MD619{H,G}XCLDE3TC Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 420/869] ata: libata-core: Add NOLPM quirk for PNY CS900 1TB SSD Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 421/869] mmc: vub300: Use devm_mmc_alloc_host() helper Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 422/869] mmc: vub300: fix use-after-free on disconnect Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 423/869] mmc: vub300: rename probe error labels Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 424/869] mmc: vub300: fix use-after-free on probe failure Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 425/869] dm-verity: fix buffer overflow in FEC calculation Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 426/869] ocfs2: correct l_next_free_rec in online check Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 427/869] ocfs2: add suballoc slot check in ocfs2_validate_inode_block() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 428/869] ocfs2: add extra consistency checks for chain allocator dinodes Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 429/869] ocfs2: validate i_refcount_loc when refcount flag is set Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 430/869] ocfs2: fix UBSAN array-index-out-of-bounds in ocfs2_sum_rightmost_rec Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 431/869] KVM: arm64: vgic: Handle race between interrupt affinity change and LPI disabling Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 432/869] ipv4: igmp: Fix potential memory leaks in igmp_mod_timer() and igmp_stop_timer() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 433/869] net/liquidio: drop cached VF pci_dev LUT Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 434/869] Bluetooth: 6lowpan: avoid untracked enable work Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 435/869] net/mlx5e: Fix publication race for priv->channel_stats[] Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 436/869] netfs: Clean up some whitespace in trace header Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 437/869] netfs: Use a folio_queue allocation and free functions Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 438/869] netfs: Add a tracepoint to log the lifespan of folio_queue structs Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 439/869] netfs: Abstract out a rolling folio buffer implementation Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 440/869] netfs: Drop the was_async arg from netfs_read_subreq_terminated() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 441/869] netfs: Fix netfs_create_write_req() to handle async cache object creation Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 442/869] iomap: guard io_size EOF trim against concurrent truncate underflow Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 443/869] afs: Fix reinitialisation of the inode, in particular ->lock_work Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 444/869] xen/pvcalls: bound backend response req_id before indexing rsp[] Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 445/869] sctp: fix addr_wq_timer race in sctp_free_addr_wq() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 446/869] drm/panthor: Always use the IRQ-safe variant when acquiring the fence lock Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 447/869] hwmon: (pmbus/core) honor vrm_version in pmbus_data2reg_vid() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 448/869] sctp: add INIT verification after cookie unpacking Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 449/869] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 450/869] bpf: Guard conntrack opts error writes Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 451/869] md/raid10: fix writes_pending leak on write request failures Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 452/869] md/raid1: fix writes_pending and barrier reference leaks on write failures Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 453/869] soundwire: fix bug in sdw_add_element_group_count found by syzkaller Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 454/869] net: serialize netif_running() check in enqueue_to_backlog() Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 455/869] RDMA/irdma: Replace waitqueue and flag with completion Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 456/869] RDMA/bnxt_re: Avoid repeated requests to allocate WC pages Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 457/869] RDMA/bnxt_re: Add a max slot check for SQ Greg Kroah-Hartman
2026-10-17 15:54 ` [PATCH 6.12 458/869] RDMA/bnxt_re: Free CQ toggle page after firmware teardown Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 459/869] RDMA/bnxt_re: Fix budget handling of notification queue Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 460/869] RDMA/bnxt_re: Remove unusable nq variable Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 461/869] RDMA/bnxt_re: Free SRQ toggle page after firmware teardown Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 462/869] RDMA/bnxt_re: Initialize dpi variable to zero Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 463/869] sockmap: Fix use-after-free in udp_bpf_recvmsg() Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 464/869] ALSA: seq: Clean up fifo locking with guard Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 465/869] ALSA: seq: avoid stale FIFO cells during resize Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 466/869] net: watchdog: fix refcount tracking races Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 467/869] bnxt: fix head underflow on XDP head-grow Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 468/869] cxl/region: Block region delete during region creation Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 469/869] ixgbe: do not configure xps for XDP queues Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 470/869] bpf: Reject sleepable BPF_LSM_CGROUP programs at load time Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 471/869] ocfs2: validate fast symlink target during inode read Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 472/869] wifi: ath12k: fix memory leak in ath12k_wifi7_dp_rx_h_verify_tkip_mic() Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 473/869] md: replace wait loop with wait_event() in md_handle_request() Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 474/869] md/raid1,raid10: fix deadlock in read error recovery path Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 475/869] md/raid1,raid10: fix bio accounting for split md cloned bios Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 476/869] md/raid1,raid10: fix error-path detection with md_cloned_bio() Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 477/869] nvmet-tcp: check return value of nvmet_tcp_set_queue_sock Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 478/869] ALSA: seq: oss: Fix UAF at handling events with embedded SysEx data Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 479/869] OPP: Fix race between OPP addition and lookup Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 480/869] wifi: ath11k: cancel SSR work items during PCI shutdown Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 481/869] drm/amd/display: Fix divide-by-zero in calculate_mcache_setting on zero viewport Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 482/869] s390/ap: Move response_type struct into ap_msg struct Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 483/869] s390/ap/zcrypt: Rework AP message buffer allocation Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 484/869] s390/ap: Introduce ap message buffer pool Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 485/869] s390/ap/zcrypt: New xflag parameter Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 486/869] s390/zcrypt: Move inline function rng_type6cprb_msgx from header to code Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 487/869] s390/zcrypt: Rework domain processing within zcrypt device driver Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 488/869] s390/zcrypt: Close speculative mem read possibility Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 489/869] afs: Fix UAF when sending a message Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 490/869] dibs: fix use-after-free of dmb_node in loopback attach/detach/unregister Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 491/869] iommu/iommufd: Fix IOPF group ownership UAF Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 492/869] octeontx2-af: Block VFs from clobbering special CGX PKIND state Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 493/869] Bluetooth: hci_sync: hold conn in hci_connect_pa_sync() callback Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 494/869] Bluetooth: hci_sync: hold conn in hci_connect_big_sync() callback Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 495/869] Bluetooth: ISO: hold sk properly in iso_conn_ready Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 496/869] Bluetooth: ISO: lock sk in iso_connect_ind Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 497/869] netfs: Fix folio_queue ENOMEM in writeback by adding a mempool Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 498/869] net/sched: cls_u32: validate offshift to prevent shift-out-of-bounds Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 499/869] xsk: drain continuation descs after overflow in xsk_build_skb() Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 500/869] xsk: provide sufficient space in pool->tx_descs Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 501/869] xsk: reclaim invalid Tx descriptors in ZC batch path Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 502/869] btrfs: skip global block reserve accounting for rescue mounts Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 503/869] mm/page_table_check: skip special zero mappings Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 504/869] eventfs: Use children field for rcu head and add memory barriers Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 505/869] selftests: tls: add rekey tests Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 506/869] tls: rx: restore msg_iter before TLS 1.3 optimistic retry Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 507/869] watchdog: at91sam9_wdt: prevent timer rearm during teardown Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 508/869] s390/ism: Fix UAF of sba and ieq during ism_dev_exit() Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 509/869] netfilter: nf_flow_table: drop existing skb dst before skb_dst_set_noref() Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 510/869] bnxt_en: Disable EOP for TPA on all chips to prevent data corruption Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 511/869] hwmon: (pmbus) Fix type confusion in notification logic Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 512/869] vhost_iotlb: bound map allocation in add_range Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 513/869] bpf: Fix netns reference imbalance in conntrack kfuncs Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 514/869] btrfs: lzo: reject inline extents without valid headers Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 515/869] xfs: handle NULL b_addr in xfs_buf_free Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 516/869] soc: aspeed: lpc-snoop: Fix usercopy overflow in snoop_file_read Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 517/869] gpio: pca953x: fix pca953x_irq_bus_sync_unlock regmap lock Greg Kroah-Hartman
2026-10-17 15:55 ` [PATCH 6.12 518/869] firewire: ohci: fix NULL pointer dereference in ar_context_release Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 519/869] ipvs: revalidate ihl to prevent out-of-bounds access Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 520/869] sctp: validate cookie AUTH state before use Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 521/869] scsi: core: pair EH runtime PM get and put Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 522/869] ASoC: SOF: Relocate and rework functionality for PCM stream freeing Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 523/869] ASoC: SOF: pcm: Move period/buffer configuration print after platform open Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 524/869] ASoC: SOF: pcm: Add snd_sof_pcm specific wrappers for dev_dbg() and dev_err() Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 525/869] ASoC: SOF: ipc4-pcm: Continue the pipeline trigger in case of IPC timeout Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 526/869] tracing/probes: Remove WARN_ON_ONCE from parse_btf_arg Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 527/869] net: ibm: emac: use devm_platform_ioremap_resource Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 528/869] net: ibm: emac: use platform_get_irq Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 529/869] net: emac: Fix NULL pointer dereference in emac_probe Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 530/869] ieee802154: Avoid calling WARN_ON() on -ENOMEM in cfg802154_switch_netns() Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 531/869] coresight: ete: Always save state on power down Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 532/869] ALSA: seq: oss: Serialize readq reset state with q->lock Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 533/869] btrfs: lzo: reject compressed segment that overflows the compressed input Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 534/869] netfilter: flowtable: avoid num_encaps underflow on bridge VLAN untag Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 535/869] EDAC/igen6: Initialize edac_op_state according to the configuration data Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 536/869] EDAC/igen6: Add polling support Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 537/869] EDAC/igen6: Skip absent memory controllers Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 538/869] EDAC/igen6: Fix call trace due to missing release() Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 539/869] scsi: hisi_sas: Add slave_destroy interface for v3 hw Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 540/869] soc: xilinx: Fix race condition in event registration Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 541/869] cxl: Fix CXL_HEADERLOG_SIZE to match RAS Capability size Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 542/869] netfilter: nf_conntrack_expect: use conntrack GC to reap expectations Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 543/869] perf tools: Use perf_env__get_cpu_topology() in machine__resolve() Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 544/869] Bluetooth: hci_sync: hold conn in hci_connect_acl/le_sync() callbacks Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 545/869] idpf: bound interrupt-vector register fill to the allocated array Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 546/869] dmaengine: idxd: fix double free of wq, engine, and group structs Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 547/869] drm/amd/display: check if dml21_add_phantom_plane() is successful Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 548/869] btrfs: initialize inode mapping flags for cached inodes Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 549/869] bpf: Check sk_state before sk_protocol in bpf_tcp_*_syncookie Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 550/869] drm/amdkfd: Fix infinite loop parsing CRAT with zero subtype length Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 551/869] drm/amdkfd: Add bounds check for CRAT " Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 552/869] Bluetooth: ISO: zero the sockaddr before returning it in getname Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 553/869] fbdev: Wrap user-invoked calls to fb_set_var() in helper Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 554/869] tipc: avoid busy looping in tipc_exit_net() Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 555/869] NTB: core: Add .get_dma_dev() callback to ntb_dev_ops Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 556/869] NTB: ntb_transport: Use ntb_get_dma_dev() for DMA buffers Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 557/869] ntb: Store original DMA address for future release Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 558/869] tap: Keep hdr_len in tap_get_user() Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 559/869] net: tap: fix wrong transport_header when sending VLAN-tagged frame Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 560/869] io_uring: defer eventfd signaling when queued from a wakeup handler Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 561/869] wifi: iwlwifi: dvm: pair transport op-mode enter/leave Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 562/869] wifi: iwlwifi: dvm: fix memory leak in iwl_op_mode_dvm_start() Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 563/869] svcrdma: Reject Read lists that exceed the page budget Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 564/869] svcrdma: Add Write chunk WRs to the RPCs Send WR chain Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 565/869] svcrdma: wake sq waiters when the transport closes Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 566/869] svcrdma: Clear sc_cm_id when ADDR_CHANGE replacement fails Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 567/869] SUNRPC: Reject short RFC 4121 MIC tokens in gss_krb5_verify_mic_v2 Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 568/869] ext2: Fix lost inode updates for IS_SYNC inodes Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 569/869] smb: client: reject a tree connect response whose byte count is too small Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 570/869] cifs: call pagecache_isize_extended() in cifs_setsize() when extending Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 571/869] ceph: cap delegated inode count in ceph_parse_deleg_inos() Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 572/869] ceph: fix UAF in check_new_map() on session freed during unlock Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 573/869] nfsd: fix fcache_disposal UAF by inlining dispose state into nfsd_net Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 574/869] nfsd: restore rq_status_counter to even on all nfsd_dispatch() exit paths Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 575/869] lockd, nfsd: RCU-protect nlmsvc_ops dispatch Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 576/869] mm/mglru: reset page lru tier bits when activating Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 577/869] mm/mglru: use the common routine for dirty/writeback reactivation Greg Kroah-Hartman
2026-10-17 15:56 ` [PATCH 6.12 578/869] mm/mglru: fix and remove redundant unevictable folio handling Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 579/869] ksmbd: fix tree connection use-after-free in smb2_tree_connect() Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 580/869] drm/amdkfd: Fix partial migrate issue Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 581/869] drm/amdkfd: return migration pages from copy function Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 582/869] Revert "drm/amdkfd: return migration pages from copy function" Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 583/869] drm/amdkfd: Fix the case that vm range is hole at svm_migrate_copy_to_vram Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 584/869] drm/amdkfd: return migration pages from copy function - again Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 585/869] drm/amdkfd: Fix error path at svm_migrate_copy_to_ram Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 586/869] drm/amdkfd: Add TLB flush after MES queue eviction/suspension Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 587/869] drm/amdgpu: force complete the MES ring fences on reset Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 588/869] drm/amdgpu: force complete the KIQ " Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 589/869] f2fs: fix to avoid potential deadloop in f2fs_fsync_node_pages() Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 590/869] LoongArch: BPF: Refactor jump offset calculation in tail call Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 591/869] KVM: arm64: vgic-v3: take an LPI reference in vgic_v3_save_pending_tables Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 592/869] KVM: s390: Fix memory corruption by not reinjecting CK machine checks Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 593/869] mm/huge_memory: transfer the pmd dirty bit to the folio on zap Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 594/869] netfilter: nf_tables: prefer nft_trans_elem_alloc helper Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 595/869] netfilter: nf_tables: add nft_trans_commit_list_add_elem helper Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 596/869] netfilter: nf_tables: prepare for multiple elements in nft_trans_elem structure Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 597/869] netfilter: nf_tables: skip double clone set expressions on element insert Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 598/869] net_sched: sch_fq: add three drop_reason Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 599/869] net/sched: add qstats_cpu_drop_inc() helper Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 600/869] net/sched: act_ife: Only operate on Ethernet frames Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 601/869] octeontx2-vf: fix workqueue and netdev race in probe/remove Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 602/869] xsk: honor XDP_TX_METADATA in zero-copy path Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 603/869] Bluetooth: do not leak an hci_conn when a second LE connect is rejected Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 604/869] net: add getsockopt_iter callback to proto_ops Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 605/869] Bluetooth: L2CAP: convert to getsockopt_iter Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 606/869] Bluetooth: L2CAP: access chan->conn safely in get/setsockopt Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 607/869] Drivers: hv: vmbus: Skip VMBus module cleanup for non-nested root partition Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 608/869] net/sched: account classifier filter allocations to memcg Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 609/869] NFSv4.1: zero referring call lists before decoding Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 610/869] vxlan: fix reading neigh ha Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 611/869] net: bridge: arp/nd proxy: " Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 612/869] ip6mr: do not clone dst in ip6mr_cache_report() Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 613/869] ALSA: mtpav: shut down output timer before card teardown Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 614/869] virtio_net: Fix resize of the RX ring Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 615/869] dpll: fix NULL deref in dpll_device_ops() during teardown race Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 616/869] bpf, xdp: move offload check into dev_xdp_install() Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 617/869] NFSv4/flexfiles: fix NULL dereference for NFSv4.0 data servers Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 618/869] ksmbd: scope session state changes to bound connections Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 619/869] ksmbd: detach blocked lock requests before freeing Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 620/869] ksmbd: safely discard unregistered deferred locks Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 621/869] erofs: fix interlaced ztailpacking pclusters Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 622/869] ksmbd: defer publishing granted locks to prevent UAF/double-free race Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 623/869] ksmbd: serialize oplock close with pending break ownership Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 624/869] ksmbd: fix slab-out-of-bounds read in ksmbd_alloc_user() Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 625/869] bpf: Check pointer type for all atomic RMW paths Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 626/869] apparmor: fix deadlock in complain-mode change_hat Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 627/869] blk-cgroup: delay freeing policy data after rcu grace period Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 628/869] blk-iocost: clear delay state when freeing policy data Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 629/869] blk-iolatency: " Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 630/869] ocfs2: validate DIO orphan slot during inode read Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 631/869] ocfs2: validate " Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 632/869] nvmet: fix max_qid race between configfs and controller allocation Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 633/869] clocksource/drivers/samsung_pwm: Switch to raw_spinlock_t type Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 634/869] bpf, s390: Clear fetch destination on faulting arena atomic Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 635/869] bpf: Compare iterator types during state pruning Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 636/869] apparmor: fix unconfined user namespace restriction forced stack Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 637/869] amt: Dont support cross-netns setup Greg Kroah-Hartman
2026-10-17 15:57 ` [PATCH 6.12 638/869] NFS: Return a delegation the client fails to record Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 639/869] iommu/vt-d: Flush context cache with correct SID when tearing down aliases Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 640/869] bpf: Fix mmap_lock leak in irq_work path Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 641/869] Bluetooth: ISO: fix race of kfree vs kref_get_unless_zero Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 642/869] Bluetooth: L2CAP: use proto_lock for l2cap_data to fix l2cap_disconn_ind Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 643/869] btrfs: qgroup: fix a wrong length calculation in qgroup_free_reserved_data() Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 644/869] btrfs: zoned: dont clobber the extent buffer when zeroing it out Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 645/869] btrfs: check if root is readonly when setting posix acl Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 646/869] btrfs: always wait for ordered extents to avoid OE races Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 647/869] btrfs: defrag: fix deadlock between defrag and delalloc space reservation Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 648/869] scsi: sd: Move the sd_config_discard() function definition Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 649/869] scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 650/869] coresight: etm4x: missing cscfg_csdev_disable_active_config() in perf enable Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 651/869] drm/amd/display: disable replay when crc source is enabled Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 652/869] drm/amd/display: Resize MST HDCP per-connector arrays to 32 Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 653/869] bpf: Factor callchain_store function from __bpf_get_stack Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 654/869] bpf: Factor callchain_finalize " Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 655/869] bpf: Remove trace_in argument " Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 656/869] bpf: Clear buf on error in __bpf_get_task_stack Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 657/869] ocfs2/heartbeat: fix slot mapping rollback leaks on error paths Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 658/869] ocfs2: o2hb: quiesce negotiate handlers and timeout work Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 659/869] ARM: 9481/2: breakpoint: CFI breakpoints only on demand Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 660/869] thermal: hwmon: Remove hwmon class device along with its parent Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 661/869] ocfs2: validate inline xattrs during inode block validation Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 662/869] ublk: check import_ubuf() return value Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 663/869] blk-cgroup: fix race between policy activation and blkg destruction Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 664/869] HID: steam: Reject short reads Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 665/869] HID: logitech-hidpp: Fix FF device cleanup on init failure Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 666/869] tty: skip cdev_del() when no cdev is registered Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 667/869] serial: core: clear freed pointers on uart_register_driver() failure Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 668/869] serial: core: do fallible allocations before the console can be registered Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 669/869] wifi: cfg80211: stop PMSR before P2P and NAN teardown Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 670/869] wifi: brcmfmac: fix P2P action frame handling without device vif Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 671/869] wifi: nl80211: check link is beaconing for color change Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 672/869] wifi: nl80211: clean up color-change beacon data on errors Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 673/869] arm64: ptrace: Keep orig_x0 in-sync with x0 on syscall entry Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 674/869] wifi: mt76: mt7996: do not attach hif2 WED when the main WED attach failed Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 675/869] bpf: Reject >8 byte return values on return-reading trampoline paths Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 676/869] drm/msm: dont tear down KMS twice when KMS init fails Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 677/869] wifi: mt76: cancel reset and rc work on device unregister Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 678/869] wifi: mt76: mt7996: hold dev->mt76.mutex while disabling tx worker in SER Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 679/869] wifi: ath12k: fix overreads in ath12k_wmi_process_csa_switch_count_event() Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 680/869] drm/i915: rename range_overflows_end() to range_end_overflows() Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 681/869] drm/i915: document range_overflows() and range_end_overflows() macros Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 682/869] overflow: add range_overflows() and range_end_overflows() Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 683/869] drm/panthor: Add vm_bind region with kbo range overlap check Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 684/869] RDMA/cxgb4: Fix dereg_skb leak and double free in write_tpt_entry() Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 685/869] PCI: Make pci_match_one_device() match on ID instead of device Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 686/869] PCI: Fix dyn_id add TOCTOU Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 687/869] PCI: Fix UAF when probe runs concurrent to dyn ID removal Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 688/869] clk: mediatek: pllfh: Fix IO remapping leak in register_pllfhs error path Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 689/869] iommu/tegra241-cmdqv: Fix VINTF0 leak on the init-failure path Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 690/869] iommu/tegra241-cmdqv: Dont fall back to a freed smmu after devm_krealloc() Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 691/869] scsi: ufs: core: Convert string descriptor format macros to enum Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 692/869] scsi: ufs: core: Validate string descriptors Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 693/869] pinctrl: mediatek: use devm_gpiochip_add_data() for GPIO chip Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 694/869] bpf: Fix WARNING in bpf_tracing_link_release Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 695/869] ext4: fix ABBA deadlock in ext4_xattr_inode_cache_find() Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 696/869] kcfi: Rename CONFIG_CFI_CLANG to CONFIG_CFI Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 697/869] riscv, bpf: Fix kernel stack corruption in tailcall with CFI Greg Kroah-Hartman
2026-10-17 15:58 ` [PATCH 6.12 698/869] bpf: Zero queue and stack outputs on lock failure Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 699/869] drm/sched: Use struct for drm_sched_init() params Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 700/869] drm/msm: Only fini scheduler after successful init Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 701/869] firmware: arm_scmi: Fix SCMI device destroy lifetimes Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 702/869] fs/resctrl: Prevent use-after-free in rdtgroup_kn_put() Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 703/869] RDMA/rvt: Return NULL after port allocation failure Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 704/869] esp: do not unref managed frag pages in esp_ssg_unref() Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 705/869] platform/x86: asus-wmi: fix resource leaks on probe failure Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 706/869] usb: gadget: uac: validate rate list length before storing Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 707/869] bpf: Reject rdonly/rdwr_buf_size kfunc arguments that exceed u32 max Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 708/869] platform/x86: dell-wmi-base: Fix handling of ultra performance key Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 709/869] bpf: Reject writes through untrusted BTF pointers Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 710/869] time/namespace: Validate nanosecond field in proc_timens_set_offset() Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 711/869] bpf: Reject MEM_ALLOC BTF accesses past object bounds Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 712/869] dmaengine: xilinx_dma: Fix CPU stall in xilinx_dma_poll_timeout Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 713/869] drm/amd/display: Fix dangling pointer in CRTC reset function Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 714/869] drm/amd/display: Fix dangling pointer in plane " Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 715/869] mm/page_owner: use memcg_data snapshot to avoid TOCTOU in print_page_owner_memcg() Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 716/869] nfsd: convert nfsd_net boolean flags to unsigned long flags word Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 717/869] mm/hugetlb: refactor code around vmemmap_walk Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 718/869] mm/hugetlb: initialize gigantic bootmem hugepage struct pages earlier Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 719/869] ACPI: bus: Introduce acpi_bus_get_primary_device() Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 720/869] powerpc/xive: add error return value to xive_smp_probe() Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 721/869] powerpc/xive: propagate IPI init errors to prevent use-after-free Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 722/869] remoteproc: qcom_wcnss: Fix handling the lack of PD regulators in v3 Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 723/869] ksmbd: remove redundant DACL check in smb_check_perm_dacl Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 724/869] ksmbd: fix maximum allowed access checks Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 725/869] drm/amdkfd: fix SMI event cross-process information leak Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 726/869] drm/amdgpu: Update SRIOV Exchange Headers for RAS Telemetry Support Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 727/869] drm/amdgpu/ras: add ras_suspend callback and use it for cp_ecc_error_irq Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 728/869] wifi: iwlwifi: simplify nested if checks Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 729/869] wifi: iwlwifi: mvm: fix P2P-Device binding handling Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 730/869] RDMA/counter: Fix num_counters leak on bind_qp failure in alloc_and_bind() Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 731/869] virt: acrn: Remove unused list acrn_irqfd_clients Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 732/869] virt: acrn: Fix irqfd use-after-free during eventfd shutdown Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 733/869] PM: sleep: core: Synchronize runtime PM status of parents and children Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 734/869] PM: sleep: core: Restrict power.set_active propagation Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 735/869] PM: Rearrange documentation related to __pm_runtime_disable() Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 736/869] PM: Block enabling of runtime PM during system suspend Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 737/869] PM: runtime: Introduce pm_runtime_blocked() Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 738/869] PM: sleep: Use DPM_FLAG_SMART_SUSPEND conditionally Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 739/869] PM: sleep: Fix bit masking operation Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 740/869] driver core: Add device_link_test() for testing device link flags Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 741/869] driver core: Avoid warning when removing a device while its supplier is unbinding Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 742/869] serial: 8250: invert serial8250_register_8250_port() CIR condition Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 743/869] tty: serial: 8250: protect against NULL uart->port.dev in register Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 744/869] drm/amdgpu: Remove unused amdgpu_i2c functions Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 745/869] drm/amdgpu/atombios: drop empty function Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 746/869] drm/amdgpu: rework i2c init and fini Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 747/869] drm/amdgpu: Bound GPIO I2C table entry count from VBIOS Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 748/869] gpiolib: make value setters have return values Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 749/869] gpiolib: wrap gpio_chip::set() Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 750/869] gpiolib: rework the wrapper around gpio_chip::set_multiple() Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 751/869] gpiolib: introduce gpio_chip setters that return values Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 752/869] pinctrl: mediatek: paris: dont double-check the GPIO number Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 753/869] pinctrl: mediatek: paris: use new GPIO line value setter callbacks Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 754/869] pinctrl: mediatek: paris: bypass pinctrl GPIO layer in set GPIO direction Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 755/869] genirq/proc: Switch to lock guards Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 756/869] genirq: Consistently use %u format specifier for unsigned int variables Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 757/869] genirq/proc: Size interrupt directory names for 10-digit interrupt numbers Greg Kroah-Hartman
2026-10-17 15:59 ` [PATCH 6.12 758/869] media: chips-media: wave5: Release m2m_ctx after Instance Removed from List Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 759/869] i3c: master: svc: Fix npcm845 FIFO empty issue Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 760/869] i3c: master: svc: Fix npcm845 invalid slvstart event Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 761/869] i3c: master: svc: Prevent IRQ storm from false SLVSTART on NPCM845 Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 762/869] hwmon: (asus_rog_ryujin) Rely on subsystem locking Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 763/869] hwmon: (asus_rog_ryujin) Add per-device configuration Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 764/869] hwmon: (asus_rog_ryujin) Validate HID report lengths Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 765/869] smb: client: avoid using uninitialized SIDs in cifs_posix_to_fattr() Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 766/869] smb: client: honor forceuid/forcegid when mapping SIDs to uid/gid Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 767/869] drm/amdgpu: skip the VMID 0 flush for VRAM Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 768/869] perf/x86/intel: Prevent drain_pebs() reentry Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 769/869] net/mlx5e: Move representor vnic reporter to eswitch devlink port Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 770/869] Bluetooth: hci_sysfs: Fix NULL pointer dereference in device_del() Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 771/869] vhost: invalidate vring access on IOTLB transitions Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 772/869] vduse: validate virtqueue alignment Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 773/869] virtio_ring: fix stale descriptor flags after a failed packed add Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 774/869] iommu/amd: Do not reallocate GA log buffers on resume Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 775/869] bpf: mark a NULL call argument precise Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 776/869] tracing: Fix subbuf resize races with trace_pipe_raw readers Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 777/869] bpf: Preserve inner map identity in callback frames Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 778/869] bpf: Mark NULL kptr stores precise Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 779/869] bpf: Keep refcount_acquire nullable for borrowed RCU kptrs Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 780/869] bpf: Dont infer non-NULL from a pointer with an unbounded offset Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 781/869] bpf: Reject legacy packet loads from callbacks Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 782/869] bpf: Check ancestor frames for rbtree callbacks Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 783/869] bpf: dont rewrite bpf_fastcall patterns entered by a jump Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 784/869] bpf: zero extend the result of an arena 32-bit cmpxchg Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 785/869] ASoC: Intel: avs: Refactor and fix init_config access Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 786/869] bpf: Mark syscall helpers as sleepable Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 787/869] bpf: Mark signal tracepoint siginfo arguments as scalar Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 788/869] erofs: disable LZ4 rolling decompression for now Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 789/869] net: rename netns_local to netns_immutable Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 790/869] net: plumb extack in __dev_change_net_namespace() Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 791/869] net: Remove conflicting altnames for dying netns " Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 792/869] btrfs: zstd: fix lost wakeup when waiting for a workspace Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 793/869] bpf: backtracking shouldnt clear outer frame R1-R5 for callbacks Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 794/869] bpf: backtrack_insn(): Handle ld_{abs,ind} subprog exit edge Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 795/869] ipv6: mcast: use rcu_assign_pointer() for __rcu list updates Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 796/869] smb/client: invalidate fscache for fallocate range operations Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 797/869] net: stmmac: fix dma mapping leak in stmmac_tso_xmit() Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 798/869] bpf: check_cond_jmp_op(): properly infer if register is null Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 799/869] printk: Dont WARN on kthread_run failure Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 800/869] drm/gud: validate GUD_ROTATION_0 is present in supported rotations Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 801/869] drm/virtio: Use drm_gem_plane_helper_prepare_fb() Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 802/869] drm/virtio: Add a helper to map and note the dma addrs and lengths Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 803/869] drm/virtio: use the DMA API for resource backing on Xen Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 804/869] functionfs: fix the open/removal races Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 805/869] ACPI: platform: Use acpi_bus_get_primary_device() Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 806/869] KVM: nSVM: Triple fault if restore host CR3 fails on nested #VMEXIT Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 807/869] greybus: raw: fix use-after-free if write is called after disconnect Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 808/869] firmware: arm_ffa: Add support for IMPDEF value in the memory access descriptor Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 809/869] firmware: arm_ffa: Fix Endpoint Memory Access Descriptor offset calculation Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 810/869] pmdomain: imx93-blk-ctrl: Extract PHY as shared domain for DSI/CSI Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 811/869] cxl/region: Resolve region deletion races Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 812/869] bpf: Remove migrate_{disable|enable} in bpf_obj_free_fields() Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 813/869] bpf: Clear rb node linkage when freeing bpf_rb_root Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 814/869] ocfs2: validate external xattr entries when reading metadata Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 815/869] dm-integrity: replace forgeable discard filler with a keyed sector marker Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 816/869] perf/x86/intel/uncore: Fix uncore_box ref/unref ordering Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 817/869] i3c: master: Fix recursive locking during device registration Greg Kroah-Hartman
2026-10-17 16:00 ` [PATCH 6.12 818/869] xfs: remove unused trace event xfs_dqreclaim_dirty Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 819/869] ublk: fix dead loop when canceling io command Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 820/869] riscv: uaccess: Only restore the CSR_STATUS SUM bit Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 821/869] s390/kvm: Initialize uninitialized flags variable Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 822/869] KVM: s390: wrapper for KVM_BUG Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 823/869] KVM: s390: move pv gmap functions into kvm Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 824/869] KVM: s390: use __kvm_faultin_pfn() Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 825/869] KVM: s390: move gmap_shadow_pgt_lookup() into kvm Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 826/869] KVM: s390: pv: fix race when making a page secure Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 827/869] KVM: s390: Fix FOLL_*/FAULT_FLAG_* confusion Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 828/869] s390/kvm: Mask extra bits from program interrupt code Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 829/869] scsi: ufs: qcom : Fix NULL pointer dereference in ufs_qcom_setup_clocks Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 830/869] accel/ivpu: Fix race condition when mapping dmabuf Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 831/869] KVM: SEV: Drop FOLL_WRITE for encrypted region registration Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 832/869] net: Fix wild-memory-access in __register_pernet_operations() when CONFIG_NET_NS=n Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 833/869] mpls: Set rt->rt_nhn just before returning from mpls_nh_build_multi() Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 834/869] media: verisilicon: Fix kernel panic due to __initconst misuse Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 835/869] soc/tegra: pmc: Document tegra_pmc.syscore field Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 836/869] soc/tegra: pmc: Add kerneldoc for wake-up variables Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 837/869] i3c: mipi-i3c-hci: Preserve RUN bit when aborting DMA ring Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 838/869] ceph: do not skip the first folio of the next object in writeback Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 839/869] ceph: fix crash after fscrypt_encrypt_pagecache_blocks() error Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 840/869] ceph: introduce ceph_submit_write() method Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 841/869] ceph: always call ceph_shift_unused_folios_left() Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 842/869] spi: microchip-core-qspi: stop checking viability of op->max_freq in supports_op callback Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 843/869] sched/psi: Create the psimon kthread outside of cgroup_mutex Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 844/869] ocfs2: use correct endian in ocfs2_dinode_has_extents Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 845/869] netfs: release readahead folios on iterator preparation failure Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 846/869] netfs: Fix folio state after ENOMEM whilst under writeback iteration Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 847/869] net: do not acquire dev->tx_global_lock in netdev_watchdog_up() Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 848/869] s390/zcrypt: Fix memory leak with CCA cards used as accelerator Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 849/869] EDAC/igen6: Fix the flood of invalid error reports Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 850/869] netfilter: ctnetlink: do not expose expectation DEAD flag Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 851/869] EDAC/igen6: Fix NULL pointer dereference Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 852/869] Revert "esp: do not unref managed frag pages in esp_ssg_unref()" Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 853/869] mm/hugetlb_vmemmap: fix incorrect vmemmap restore in rollback Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 854/869] PM: sleep: Unblock runtime PM when device prepare fails Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 855/869] soundwire: intel_auxdevice: Fix system suspend/resume handling Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 856/869] gpiolib: Allow to use setters with return value for output-only gpios Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 857/869] gpiolib: initialize return value in gpiochip_set_multiple() Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 858/869] i3c: master: svc: Fix missed IBI after false SLVSTART on NPCM845 Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 859/869] i3c: master: svc: Fix npcm845 FIFO_EMPTY quirk Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 860/869] i3c: master: svc: Fix i3c_master_get_free_addr return check Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 861/869] tracing: Fix ring_buffer_read_page_size() kernel-doc Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 862/869] tracing: Fix comment in tracing_buffers_splice_read() Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 863/869] dm-integrity: fix buffer overflow with keyed discard Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 864/869] types: move struct rcuwait into types.h Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 865/869] irqwork: Move data struct to a types header Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 866/869] bpf, sockmap: Account for receive queue in FIONREAD without a verdict program Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 867/869] wifi: atk9k: Revert "wifi: ath9k: reject short WMI command responses" Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 868/869] s390/uv: Dont return 0 from make_hva_secure() if the operation was not successful Greg Kroah-Hartman
2026-10-17 16:01 ` [PATCH 6.12 869/869] drm/panfrost: Fix scheduler workqueue bug Greg Kroah-Hartman
2026-10-17 17:19 ` [PATCH 6.12 000/869] 6.12.114-rc1 review Brett A C Sheffield
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.